Sort of. But the type of a function is not the same as the function signature, like it would be in C where you can supply a pointer to any function so long as the signature matches. Each individual function is a specific subtype of Function.
Multiple dispatch code selection happens when you call the supplied function, not when you call with it (although that sentence probably makes more sense in my head!).
However, you can despatch on the specific function
julia> f1(a::Int)::String = "f1"
f1 (generic function with 1 method)
julia> isa(f1, Function)
true
julia> typeof(f1)
typeof(f1)
julia> typeof(f1) in subtypes(Function)
true
julia> ff(f::typeof(f1), a::Int) = f1(a)
ff (generic function with 1 method)
julia> ff(f1, 1)
"f1"
julia> f2(a::Int)::String = "f2"
f2 (generic function with 1 method)
julia> typeof(f1) == typeof(f2)
false
julia> ff(f2, 2)
ERROR: MethodError: no method matching ff(::typeof(f2), ::Int64)
Closest candidates are:
ff(::typeof(f1), ::Int64) at REPL[17]:1
Stacktrace:
[1] top-level scope
@ REPL[22]:1
julia> ff(f::Function, a::Int) = "f(a) = $(f(a))"
ff (generic function with 2 methods)
julia> ff(f2, 1)
"f(a) = f2"
julia> ff(f1, 1)
"f1"
and it gets more interesting if there are multiple methods of f1
julia> f1(a::Int, b::Int)::String = "f1 a b"
f1 (generic function with 2 methods)
julia> ff(f1::typeof(f1), a::Int, b::Int) = "f1(a,b) = $(f1(a, b))"
ff (generic function with 3 methods)
julia> ff(f1, 1)
"f1"
julia> ff(f1, 1, 2)
"f1(a,b) = f1 a b"
I’ve not encountered situations where this was useful, but I am sure there are occasions where specialising on supplied functions might be useful, due to implementation differences, e.g. thread safety or some sort of Abstract Type interface.