module A
import Base: convert
export Foo
type Foo
a::Float64
b::Float64
end
function convert(::Type{Foo}, a::Tuple{Float64,Float64})
Foo(a[1], a[2])
end
end
module B
using A
export Bar
type Bar
x1 :: Foo
x2 :: Foo
function Bar(a::Foo, b::Foo) new(a,b) end
end
end
The test code in a separated file
using B
b = Bar((1.0,2.0), (1.0,2.0))
println(b)
ERROR: LoadError: MethodError: no method matching B.Bar(::Tuple{Float64,Float64}, ::Tuple{Float64,Float64})
Closest candidates are:
B.Bar{T}(::Any) at sysimg.jl:53
When I remove the internal constructor everything works as expected.
I was hoping somebody could explain why that is.
I can fix it by creating an external constructor which matches on Tuples.
Thank you.
1 Like
The auto conversion is done only in new
not for function dispatch. So basically if you declared a type
type Bar
x::Foo
end
You can pass a Tuple{Float64,Float64}
to it’s default constructor or new
used in your own inner constructor and the conversion will be done automatically. However, if you have a function foo(::Foo)
it’ll not be able to accept a Tuple{Float64,Float64}
object, inner constructor included. If you want to accept a wider range of types and do conversion, then just specify that in the signature (i.e. remove the type constraint on it).
P.S. Auto conversion is also done on assignment to typed slot. Mentioning this mainly for completion and not directly related to this issue.
Thanks for you help.
I changed
function Bar(a::Foo, b::Foo) new(a,b) end
to
function Bar(a, b) new(a,b) end
and that works.
I guess I’m surprised that the type signature breaks it.
Why doesn’t the compiler look at the fact that it needs a Foo, got a tuple, and goes off and looks for a conversion/promotion ? Or maybe the problem is I need promote instead of convert ?
Because that’s not how dispatch works. Given the number of convertion methods defined, it’ll be extremely ambiguous in general which one should actually be called. (e.g. If you also have a convertion from NTuple{2,Float64}
to Bar
and have another method Bar(::Bar, ::Bar)
, which one do you want to call?)
It’s probably not impossible to come up with a set of rules to determine what is ambiguous and what’s not but given the “non-locality” of the information (i.e. it’s stored both in the method table of the method you are calling as well as the whole set of convertion rules, possibly chained) it’ll likely be very hard to predict and will certainly be extremely hard to implement dynamically with any reasonable performance.