Array of functions behaves differently when it is of length 1 vs longer

I want to do something where I can call different functions on the same value, and that number of functions varies depending on how I use it. I’ve been using an array of functions to accomplish this, but I am getting an error when that array is length 1.

As an example bar and foo both operate on floats, and foobar loops over functions to print out the values of each of those functions when they are applied to the same float.

function bar(a::Float64)
 a
end

function foo(a::Float64)
 a+1.0
end

function foobar(functionlist::Array{Function})
  x=1.0
  for f in functionlist
    println(f(x))
  end
end

Example:

foobar([foo,bar])

yields

2.0
1.0

However, using a vector that only has length one (as follows), gives an error:

foobar([foo])
 ERROR: MethodError: no method matching foobar(::Vector{typeof(foo)})
Closest candidates are:
  foobar(::Array{Function}) at REPL[3]:1
Stacktrace:
 [1] top-level scope

Of course typeof(foo) is Function, so I can’t see why this isn’t working.

I can remove explicit typing of the foobar argument and this all works, but that doesn’t feel right to me.

Is this intended behavior? If it is, is there a better way to accomplish what I’m doing than just abandoning typing in this instance?

you either need foobar(functionlist::Array{<:Function}) or foobar(Function[foo]) Julia types are covariant.

2 Likes

One you create an array with a single function, the array type is the function type, which is unique for each function. And in that signature you are expecting a an array with the abstract function signature.

Use Array{<:Function}

Which indicates that the array can be of any subtype of function. Check this:

julia> f(a::Array{Function}) = 1
f (generic function with 1 method)

julia> f([sin, cos])
1

julia> f([sin, sin])
ERROR: MethodError: no method matching f(::Vector{typeof(sin)})
Closest candidates are:
  f(::Array{Function}) at REPL[1]:1
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1

julia> f([sin])
ERROR: MethodError: no method matching f(::Vector{typeof(sin)})
Closest candidates are:
  f(::Array{Function}) at REPL[1]:1
Stacktrace:
 [1] top-level scope
   @ REPL[4]:1

julia> typeof([sin, sin])
Vector{typeof(sin)} (alias for Array{typeof(sin), 1})

julia> typeof([sin, cos])
Vector{Function} (alias for Array{Function, 1})

julia> f(a::Array{<:Function}) = 2
f (generic function with 2 methods)

julia> f([sin])
2

julia> Function[sin, sin]
2-element Vector{Function}:
 sin (generic function with 13 methods)
 sin (generic function with 13 methods)

julia> [sin, sin]
2-element Vector{typeof(sin)}:
 sin (generic function with 13 methods)
 sin (generic function with 13 methods)



1 Like

I marked the other one as a solution due to the longer explanation, but you’ve got it, too. Thanks!

1 Like