# Argument type of higher order functions

If I define:

``````function myfunc(f::T, g::T; b=2.5 ) where T<:Function
#some lines here
h(t) = b*(f(t) +g(t)^2)
end
f(t; a=2)=a*t
g(t; a=3)=a+exp(t)
h=myfunc(f, g)
h(1.3)
``````

it is thrown the error:

``````MethodError: no method matching myfunc(::typeof(f), ::typeof(g))
Closest candidates are:
myfunc(::T, ::T; b) where T<:Function at In[2]:1

Stacktrace:
[1] top-level scope
@ In[2]:7
``````

but the following two definitions work:

``````function myfunc(f::Function, g::Function)
#...
h(t) = f(t) +g(t)^2
end
h=myfunc(f,g)
h(1.3)
function myfunc(f::T) where T<:Function
#...
h(t)=exp(f(t))-f(t)
end
k=myfunc(t->-t^2)
k(4)
``````

Why the last one works, but the first one doesnâ€™t?

First version is enforcing that both functions share 1 unknown type `T`, but `f` and `g` have different types. Try `function myfunc(f::T, g::S; b=2.5 ) where {T<:Function, S<:Function}`

3 Likes

In case it isnâ€™t obvious to you why this is so, as stated here in the Julia documentation, every function in Julia has a distinct type.

3 Likes

Technically, the first version couldâ€™ve worked with `T == Function`. Then, both `f::T` and `g::T`, and `T <: Function`.
The reason why it doesnâ€™t actually work is that Julia implicitly constrains `T` to be a concrete type in this case.

Both arguments need to be of the same type, and due to only concrete types of the passed in objects (instead of their abstract super types) being used in dispatch, the constraint that the types must be the same results in dispatch saying â€śthe types donâ€™t match, ergo thereâ€™s a `MethodError`â€ť. Runtime objects can never have an abstract type.

Julia doesnâ€™t implicitly constrain `T` to be a concrete type - itâ€™s the concreteness of the types of the objects that results in the `MethodError`.