3

I'm gonna explain my problem on a minimal example. Let's say I have three files:

A.jl

module A

export Atype, f

type Atype  
end

f = function(x::Atype)
    println("f called with A")
end
end #module

B.jl

module B

export Btype, f

type Btype  
end

f = function(x::Btype)
    println("f called with B")
end
end #module

Main.jl

 using A
 using B

 main = function()
    x = Atype()
    f(x)
 end

 main()

Here I have two versions of f function. If I understand the idea of the multiple dispatch correctly, it should be deducted during runtime which version should be used. Hence, I expected that running Main.jl would print f called with A. Unfortunately, I get

$ julia Main.jl 
ERROR: type: anonymous: in typeassert, expected Btype, got Atype
 in include at /usr/bin/../lib64/julia/sys.so
 in process_options at /usr/bin/../lib64/julia/sys.so
 in _start at /usr/bin/../lib64/julia/sys.so
while loading /home/grzes/julia_sucks/Main.jl, in expression starting on line 9

If I comment out using B, it works fine. Clearly, f from B.jl overwrote f from A.jl.

So, the question is: where does the problem lie? In my approach or in the version of Julia I use (0.3.7)? How can I circumvent this?

Note that replacing using A with import A and using fully qualified names (e.g. A.f) is not a good solution. It contradicts with the crux of multiple dispatch -- at compile time I don't know if I should use A.f or B.f.

grześ
  • 467
  • 3
  • 21

1 Answers1

7

You have to make A.f and B.f the same function (in the example above they are just different functions with the same name). Then you can overload one method in each of the modules and multiple dispatch will do its job.

The way to achieve this is either to have one of the modules import the function f from the other (eg import A.f in B) before extending it with a new method, or adding a third module C with an f function that both A and B import (you can use a dummy signature like f(::Union()) = nothing that never applies to create a function without adding any real method). Our extend the function from the other module directly, as in

function A.f(x::Atype)
    println("f called with A")
end

This will make Julia understand that the two f refer to the same concept, and they will actually be the same object in both modules. Adding a method modifies the generic function object, so this change will be visible everywhere that f is used.

Toivo Henningsson
  • 2,689
  • 12
  • 10
  • Does it mean that a "generic function" has its own scope? For example, A.f() is a function only generic in the scope of module A? – roygvib May 14 '15 at 08:06
  • Works for me, thanks! However it took me a while to notice that I should use `importall C` instead of `using C` :) – grześ May 14 '15 at 12:35
  • Bindings have scope, not values (objects). A generic function is a (mutable) value, and doesn't intrinsically belong to any scope. However, if you try to add a method to a function `f` that doesn't exist in the current scope, Julia will create a new generic function object implicitly and create a binding for it under the name `f` in the current scope. But if you import it to another module, it belongs a much there as in the original one. – Toivo Henningsson May 14 '15 at 16:44
  • Please use specific imports (eg `import A.f`) instead of `importall`, it tends to avoid some unexpected side effects. Or just extend e.g `A.f` directly with `A.f(x) = ...`. – Toivo Henningsson May 14 '15 at 16:47