This package is not currently registered, but you can use the REPL to clone it for yourself with
(::Module, ::Function)arguments for
Suppose we create a function
julia> f() = nothing f (generic function with 1 method)
Suppose also that we also intend to use the following modules
module A export f immutable Foo end f(::Foo) = print("This is Foo.") f(x::Int64) = x end module B export f immutable Bar end f(::Bar) = print("This is Bar.") f(x::Int64) = 2x end
As of Julia 0.3.7, unqualified use of a name common to both modules -- say, the name '
f' -- will elicit behavior that depends on the order in which we declare to be
using the modules:
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> f(A.Foo()) ERROR: `f` has no method matching f(::Foo) julia> A.f(A.Foo()) This is Foo.
But suppose we want unqualified use of '
f' to refer to the correct object --- either
B.f --- depending on the signature of the argument on which
f is called. The present "package" offers this functionality through the
fmerge!() function, which "merges" the methods of
B.f into our original function
f as defined in
Main. (At its core, this is just extending the
f defined in
Main.) This allows unqualified use of the name '
f' to dispatch on signatures for which methods are defined in other modules:
julia> fmerge!(f, (A,f), (B,f)) julia> methods(f) # 3 methods for generic function "f": f() at none:1 f(x1_A::Foo) f(x1_B::Bar) julia> f(A.Foo()) This is Foo. julia> f(B.Bar()) This is Bar.
For merged methods with at least one argument, the name of the module from which the method originates is appended to the first argument in the method definition, as can be seen above. This can help one keep track of which methods come from which modules. However, this machinery only keeps track of the most recent module from which the method originates. If a method has been merged multiple times through multiple modules, its ultimate origin will be obscured.
Note that no method for the signature
(x::Int64,) was merged since both
B.f have methods for this signature. To choose one to merge, use the optional
priority keyword argument, which takes an array of
(::Module, ::Function) tuples in the order of priority rank:
julia> fmerge!(f, (A,f), (B,f), priority=[(A,f)]) julia> methods(f) # 4 methods for generic function "f": f() at none:1 f(x1_A::Foo) f(x1_B::Bar) f(x1_A::Int64) julia> f(3) 3
If, for a given signature, a method exists in both
Module2.f, then the method from whichever of
(Module2, f) with the greater rank (so lower numerical rank, e.g. 1 is greatest) will be merged.
(::Module, ::Function) arguments passed to
fmerge!() but omitted from
priority are by default given the lowest possible rank. If
(Module2, f) have the same rank (which will only occur if they are not specified in
priority) then neither method will be merged. This means that if one omits the
priority argument, then only those methods whose signatures unambiguously specify precisely one of the
(::Module, ::Function) arguments passed to
fmerge!() will be merged.
WARNING: As of yet I haven't figured out how to use reflection to distinguish between otherwise identical signatures with user-defined types of the same name. Thus if module
B above also defined a
Foo type and defined a method for
f(::Foo), these two methods would be seen to conflict by
One can call
fmerge!() in modules other than
module C export f using MetaMerge, A, B f(::Union()) = nothing fmerge!(f, (A,f), (B,f), conflicts_favor=A) h(x::Int64) = f(x) end
The result is that unqualified use of
f in the module
C will dispatch across methods defined for
B.f. We can check this in the REPL:
julia> methods(C.f) # 4 methods for generic function "f": f(::None) at none:5 f(x1_A::Foo) f(x1_A::Int64) f(x1_B::Bar) julia> C.h(2) 2
I hope that this versatility makes
fmerge!() suitable for more general use outside the REPL.
One is also free to
fmerge!() functions of different names, as well as functions from the same module.
merge!()only handles two
(Module, Function)tuples in its argument. In the future, one should be able to call
merge!()on any number of such arguments, e.g.
merge!(f, (A,f), (B,f), (C,f)).~~ featured in v0.3.
merge!()each set of names individually. In the future, there should be a
mergeall()function that automatically merges all commonly named functions between two modules, e.g.
mergeall(A, B, conflicts_favor=A)generates a list of function names common to
over 1 year ago