When type inference falters (::Any in @code_warntype printout), my understanding is that function calls are dynamically dispatched. In other words, at run-time, the arguments' types are checked to find the specialization (MethodInstance) for the concrete argument types. Needing to do this at run-time instead of compile-time incurs performance costs.
(EDIT: originally, I said "multiple dispatch finds the fitting method" between the type-checking and specialization-finding, but I don't actually know if this part happens at runtime. It seems that it only needs to happen if no valid specialization exists and one needs to be compiled.)
In cases where only one argument's concrete type needs to be checked, is it possible to do a faster dynamic single dispatch instead, like in some sort of lookup table of specializations? I just can't find a way to access and call MethodInstances as if they were functions.
When it comes to altering dispatch or specialization, I thought of invoke and @nospecialize. invoke looks like it might skip right to a specified method, but checking multiple argument types and specialization must still happen. @nospecialize doesn't skip any part of the dispatch process, just results in different specializations.
EDIT: A minimal example with comments that hopefully describe what I'm talking about.
struct Foo end
struct Bar end
# want to dispatch only on 1st argument
# still want to specialize on 2nd argument
baz(::Foo, ::Integer) = 1
baz(::Foo, ::AbstractFloat) = 1.0
baz(::Bar, ::Integer) = 1im
baz(::Bar, ::AbstractFloat) = 1.0im
x = Any[Foo(), Bar(), Foo()]
# run test1(x, 1) or test1(x, 1.0)
function test1(x, second)
# first::Any in @code_warntype printout
for first in x
# first::Any requires dynamic dispatch of baz
println(baz(first, second))
# Is it possible to only dispatch -baz- on -first- given
# the concrete types of the other arguments -second-?
end
end
The easiest way to do what you ask is to simply not dispatch on the second argument (by not specifying a type assertion on the second variable specific enough to trigger dispatch), and instead specialize with an
ifstatement within your function. For example:Now, this will do what you want
and since this effectively manually picks only two cases to specialize out of all the possible types to specialize on, I could imagine scenarios where this sort of technique has performance benefits (though, of course, it goes without saying in Julia that generally even better would be to find and eliminate the source of the type instability in the first place if at all possible).
However, it is critically important in the context of this question as written to point out that that even though we have eliminated dispatch on the second argument of the function, these
bazfunctions may still have poor performance if the first argument (i.e., the one you are dispatching on) is type-unstable – as is the case in the question as written because of the use of anArray{Any}.Instead, try to use an array with at least some type constraint. Ex: