Yup, perfectly safe. It is not uncommon for me to do this (I go pretty crazy with multiple dispatch).
It’s funny, Julia isn’t object oriented, but another way of looking at it is that everything is an object. You can add methods to functions, so in a sense every function in Julia is a “functor” (this is a common but clearly incorrect use of the word, the true definition is here).
Almost forgot, the one caveat I’d give is that you should only do this on named functions that appear in the global scope of your package. I’m not sure whether it’s possible to do this with functions for which this is not true, but if it is, I’d imagine there are probably lots of “gotchas”.
It’s actually also used in Base for optimizations, when for a specific function a general operation can be optimized. For example this was done here for reduce(hcat, v) where v is a vector of vectors. Naively this would keep reallocating the result of each hcat, but now Julia overloads this signature to make it efficient:
julia> v = [rand(1_000) for _ in 1:1000];
julia> function f1(v)
h = reshape(v[1], :, 1)
for i in 2:length(v)
h = hcat(h, v[i])
end
h
end
f1 (generic function with 1 method)
julia> f2(v) = reduce(hcat, v)
f2 (generic function with 1 method)
julia> @benchmark f1($v)
BenchmarkTools.Trial:
memory estimate: 3.73 GiB
allocs estimate: 2998
--------------
minimum time: 318.887 ms (9.31% GC)
median time: 337.090 ms (9.61% GC)
mean time: 338.537 ms (11.05% GC)
maximum time: 419.100 ms (27.04% GC)
--------------
samples: 15
evals/sample: 1
julia> @benchmark f2($v)
BenchmarkTools.Trial:
memory estimate: 7.63 MiB
allocs estimate: 2
--------------
minimum time: 700.406 μs (0.00% GC)
median time: 756.052 μs (0.00% GC)
mean time: 839.459 μs (10.05% GC)
maximum time: 40.769 ms (93.56% GC)
--------------
samples: 5912
evals/sample: 1
So if I see that correctly, Julia does dispatch on function types but not on the individual methods that belong to that function?
And Julia usually compiles a different method for each combinations of argument types that are passed to a function. Does it also do that, when you pass a function to a function?
Be careful about that. Sometimes julia saves compile time by not specializing on function arguments. This is a good heuristic but can come to bite you and is hard to debug. Last paragraph: