I would like to define a function f(x, t::Type)
that executes different behavior depending on whether isa(x, t)
. Let's say that I want to call b1(x)
if it is, and b2(x)
otherwise.
I know that I can do a dynamic check at runtime like this:
function f(x, t::Type)
if isa(x, t)
b1(x)
else
b2(x)
end
end
However, is there a way to do this purely with parametric method dispatch? For example, if I define
f{T}(x::T, t::Type{T}) = b1(x)
f(x, t::Type) = b2(x)
for f(1, Int)
and f(1.0, Int)
the correct behavior is called. But I want this to also work for all subtypes of t
:
f(1, Number)
This actually calls b2
because the first signature of f
does not match. Interestingly, though, f(x::Number, t::Type{Number}) = b1(x)
would match in this case.
Am I missing something obvious here?
This was appearently a bug and is fixed in 0.4.
Questions:
Why does f{T}(x::T, t::Type{T})
not match for f(1, Number)
, even though there is a type substitution for T
(Number
) that would match?
Using f{T2, T1 <: T2}(x::T1, t::Type{T2})
or something similar does not work because appearently all static parameters come in scope only after the complete static parameter list is closed. Why?
Are there any performance penalties for using the dynamic approach instead?
What about defining the methods as an inner function, so I can bind t
to a local variable, like this:
function f(x, t::Type); g(x::t) = b1(x); g(x) = b2(x); g(x) end
That works, but what are the performance costs?
What's the idiomatic/preferred way to solve this?
(I had tried this on 0.3.2.)
Using all of a function's arguments to choose which method should be invoked, rather than just the first, is known as multiple dispatch.
The where keyword creates a type that is an iterated union of other types, over all values of some variable. For example Vector{T} where T<:Real includes all Vector s where the element type is some kind of Real number.
To answer your questions:
isa(x, t)
at compile time and eliminate the branch. However, there are still a few possible ways using isa
could be suboptimal:
isa(x, t)
is made into a constant. (This would likely be costly; the other possible deoptimizations below are probably not a big deal.)isa
and more.isa
is not a bad approach provided that it doesn't cause a type inference issue.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With