I have an object that stores (amongst other things) a vector of functions. When I use multiple functions, everything works nicely. However, if I pass it a vector with a single function, I’m getting type-inference problems.
Here’s a simplified example:
function times2(i)
2i
end
function times_n(i,n)
i*n
end
Which is what I want (would’ve preferred a more informative name but that’s just a matter of convenience).
However, instead if I try:
l = [times2]
push!(l, i -> times_n(i,8))
I get an error:
MethodError: Cannot `convert` an object of type var"#168#169" to an object of type typeof(times2)
Closest candidates are:
convert(::Type{T}, !Matched::T) where T at essentials.jl:171
Stacktrace:
[1] push!(::Array{typeof(times2),1}, ::Function) at ./array.jl:913
[2] top-level scope at In[152]:2
This also happens if I initialise l with the anonymous function and then try to add times2.
I’ve tried annotating the relevant expressions with ::Function but I still get that l is a list of objects of type typeof(times2).
I apologise if this is a trivial question - I’ve tried to search for an answer on the forum but couldn’t find any. Any help would be much appreciated!
The reason you cannot push to the [times2] vector is this:
julia> typeof([times2])
Array{typeof(times2),1}
The array created with [times2] is specifically an array that is allowed to contain objects of type typeof(times2). This is in much the same way that an array of Ints may only store Ints and initializing [15] will create such a vector (you cannot then push 1.6 to it).
This works just fine:
julia> v = [times2]
1-element Array{typeof(times2),1}:
times2 (generic function with 1 method)
julia> push!(v, times2)
2-element Array{typeof(times2),1}:
times2 (generic function with 1 method)
times2 (generic function with 1 method)
If you want a vector that can store generic Functions, you can declare it like so:
julia> v = Function[times2]
1-element Array{Function,1}:
times2 (generic function with 1 method)
julia> push!(v, times_n)
2-element Array{Function,1}:
times2 (generic function with 1 method)
times_n (generic function with 1 method)
Just out of curiosity - if I’ve just defined times2 as a function, why can’t Julia infer that its type is Function? And why doesn’t type annotation help?
I think that has to do with multiple dispatch. When you create a function a struct with that function is created and the different methods are then instances of this struct.
So
It does, but Function is an abstract type, and julia will always prefer a concrete type when possible
julia> typeof(times2)
typeof(times2)
julia> supertype(typeof(times2))
Function
Another way to look at this:
julia> times2 isa Function
true
julia> isconcretetype(Function)
false
julia> length(subtypes(Function)) # how many things are there that are <: Function
13829