Vector of functions as kwarg

Good evening,

what is wrong with the following?

function foo(; b::Vector{Function} = [(x)->x*x])
    print(b[1](2))
end

foo()

ERROR: MethodError: no method matching var"#foo#7"(::Vector{var"#8#10"}, ::typeof(foo))

It needs a <: because

julia> [(x->x)] isa Vector{Function}
false

julia> [(x->x)] isa Vector{<:Function}
true

so

julia> function foo(; b::Vector{<:Function} = [(x)->x*x])
           print(b[1](2))
       end
foo (generic function with 1 method)

julia> foo()
4
5 Likes

jar1 basically got it. Basically [x->x] is a Vector of a specific function by default. If you want a Vector{Function} you need to say Function[x->x]

julia> function foo(; b::Vector{Function} = Function[x->x*x])
           print(b[1](2))
       end
foo (generic function with 1 method)

julia> foo()
4

julia> [x->x]
1-element Vector{var"#24#25"}:
 #24 (generic function with 1 method)

julia> Function[x->x]
1-element Vector{Function}:
 #26 (generic function with 1 method)
4 Likes

Cheers guys!
I assumed the problem was with the keyword-argument placing. Before, I tried

function foo( b::Vector{Function})

and it worked fine.
So the error was with the default value assignment and had nothing to do with the argument type…

1 Like

That will also only work if you pass it a Vector{Function} and would fail with a one-argument literal like [x->x]. It can often be a best-practice to not worry about the exact types of function arguments.

The technical language that describes this problem is the term “invariant parameters”.

The issue here is that the array [x -> x*x] has a different type than [x -> x*x, x -> 2x, ...].

A function in julia like x -> x*x has its own type, when you create an array with different types of elements, they are promoted to a common type, in case of functions, it is the abstract type Function. However, if there is only one element, there’s no need to promote, so the array will have the type of that single function, which is not the type Function.

1 Like