Can Julia dispatch on the function itself?
test_func1(i::Int)=i+1
test_func2(i::Int)=i-1
(x::U{typeof(test_func1),typeof(test_func2)})(g::V)=println("ddd")
So the twos functions can do this:
test_func1([1,2,3])
"ddd"
test_func2([1,2,3])
"ddd"
Can Julia dispatch on the function itself?
test_func1(i::Int)=i+1
test_func2(i::Int)=i-1
(x::U{typeof(test_func1),typeof(test_func2)})(g::V)=println("ddd")
So the twos functions can do this:
test_func1([1,2,3])
"ddd"
test_func2([1,2,3])
"ddd"
I’m not sure what you trying to accomplish, but the following code works:
julia> struct F{T} <: Function
f::T
end
julia> (self::F)(x) = self.f(x)
julia> test_func1 = F(i::Int -> i + 1)
(::F{var"#3#4"}) (generic function with 1 method)
julia> test_func2 = F(i::Int -> i - 1)
(::F{var"#5#6"}) (generic function with 1 method)
julia> test_func1(1)
2
julia> test_func2(1)
0
julia> (self::F)(x) = println("ddd")
julia> test_func1([1, 2, 3])
ddd
julia> test_func2([1, 2, 3])
ddd
julia>
I’m also not sure what you mean, but to answer your question:
Yes, Julia can dispatch on functions:
julia> f() = "f"
f (generic function with 1 method)
julia> g(::typeof(f)) = "I called $(f())"
g (generic function with 1 method)
julia> g(::Any) = "hello"
g (generic function with 2 methods)
julia> g(1)
"hello"
julia> g(f)
"I called f"
Or maybe you’re trying to add a common method to two different functions, but you want to avoid redundant typing? In that case you could use @eval:
julia> test_func1(i::Int) = i + 1
test_func1 (generic function with 1 method)
julia> test_func2(i::Int) = i - 1
test_func2 (generic function with 1 method)
julia> for f in (:test_func1, :test_func2)
@eval ($f)(g) = println("ddd")
end
julia> test_func1([1,2,3])
ddd
julia> test_func2([1,2,3])
ddd
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.
while not exactly the same, you could do:
for f in (:test_func1,:test_func2)
@eval $f(g::Vector) = println("ddd")
end
in this case, :test_func1 is a symbol, not the function itself.