@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 >> > >
