@Stefan: Based on my experiences implementing this feature, I have to 
agree. In particular, I imagine that any attempt to include an "un-merge" 
feature would run into a lot of trouble from the fact that function names 
are constants. Once you've merged methods into a function 'f', they are 
there to stay (in the sense that you can't reassign the name 'f' to a new 
function that has no such methods at all).

For the record, I think that the best default behavior is to drop all 
conflicting imported names. Any alternative that doesn't involve automatic 
merging is arbitrary (in 0.3.7 the arbitrariness comes from the order in 
which the names were imported). My three main reasons to reject default 
merging are: (1) Stefan's point above; (2) if one subscribes to the view 
that modularity is primarily about reference, and not about the properties 
of the things, then it is unsavory that simply importing a name should 
automatically change the actual properties of an object somewhere; and (3) 
as long as users can merge functions easily *if they want to*, then it 
seems like we've got the best of both worlds.

I'll also note that dropping all conflicting imported names provides the 
easiest platform for a user to merge the ones she wants. In 0.3.7, where 
the last imported name shadows the previously imported ones, it's easy to 
accidentally merge methods into the wrong function object. For example, 
unless one has defined an f in module Main before importing f from module A 
and then f from module B, calling merge!(f, (A,f), (B,f)) in the REPL (so 
in module Main) will (in 0.3.7) merge the methods into B.f. But I imagine 
that, for the most part, the user who calls merge!(f, (A,f), (B,f)) from 
module Main expects the merged function to live in Main. On the other hand, 
if all conflicting imported names are dropped by default, then this will 
never happen; the merged function will always live in the module that calls 
merge!().

In any case, users can now hopefully do what they want to do, whether that 
involves merging or otherwise. That's the main point of this thread. =)

@Tom: Please do! I hope it's useful. Let me know what changes you'd like to 
see!


On Monday, May 4, 2015 at 3:36:28 PM UTC-4, Stefan Karpinski wrote:
>
> Cool. The fact that you can do this implies that the current behavior is 
> in a sense more fundamental than merging since you can implement merging 
> like this, whereas if merging were the default, it's unclear how you would 
> recover the current behavior.
>
> On Mon, May 4, 2015 at 3:08 PM, David Gold <[email protected] 
> <javascript:>> wrote:
>
>> Based on recent discussions, it seems that at least some people would 
>> like the option to have unqualified use of a function name dispatch 
>> "across" modules when the argument on which the function is called 
>> unambiguously specifies an exported method. While Julia doesn't do this 
>> automatically, one option is for the user explicitly to "merge" functions 
>> defined in different modules. I've been working on an implementation of 
>> this functionality that doesn't require users to copy a bunch of method 
>> definitions:
>>
>> julia> using MetaMerge
>>
>> julia> f() = nothing
>> f (generic function with 1 method)
>>
>> julia> module A
>>
>>        export f
>>        immutable Foo end
>>        f(::Foo) = print("This is Foo.")
>>        f(x::Int64) = x
>>
>>        end
>>
>> julia> module B
>>
>>        export f
>>        immutable Bar end
>>        f(::Bar) = print("This is Bar.")
>>        f(x::Int64) = 2x
>>
>>        end
>>
>> julia> using A, B
>> Warning: using A.f in module Main conflicts with an existing identifier.
>> Warning: using B.f in module Main conflicts with an existing identifier.
>>
>> julia> methods(f)
>> # 1 method for generic function "f":
>> f() at none:1
>>
>> julia> merge!(f, (A,f), (B,f))
>>
>> julia> methods(f)
>> # 3 methods for generic function "f":
>> f() at none:1
>> f(x1::Foo)
>> f(x1::Bar)
>>
>> julia> f(A.Foo())
>> This is Foo.
>> julia> f(B.Bar())
>> This is Bar.
>>
>>
>> One can also use merge!() while writing modules to allow for unqualified 
>> use of a name within the module, such as in the definition of h below:
>>
>> julia> module C
>>
>>        export f
>>        using MetaMerge, A, B
>>        f(::Union()) = nothing
>>        merge!(f, (A,f), (B,f), conflicts_favor=A)
>>        h(x::Int64) = f(x)
>>
>>        end
>>
>> julia> using C
>> Warning: using C.f in module Main conflicts with an existing identifier.
>>
>> julia> C.h(2)
>> 2
>>
>>
>> The repo is here: https://github.com/davidagold/MetaMerge.jl (I've never 
>> versioned anything before, so I apologize in advance if the numbers seem 
>> silly/arbitrary). I hope it can be useful to some. Folks should feel free 
>> to leave suggestions, bug reports or requests for other kinds of 
>> functionality that they'd like to see from something like this. I'll do my 
>> best to accommodate, though I'm rather new to programming and hence cannot 
>> make any promises.
>>
>> Cheers,
>> David
>>
>
>

Reply via email to