# Dispatching on function types?

**URL:** <https://discourse.julialang.org/t/dispatching-on-function-types/34983>\
**Category:** General Usage\
**Created:** [February 21, 2020, 4:28pm UTC](https://discourse.julialang.org/t/dispatching-on-function-types/34983 "2020-02-21T16:28:32Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [February 21, 2020, 4:28pm UTC](https://discourse.julialang.org/t/dispatching-on-function-types/34983/1 "2020-02-21T16:28:33Z")

</div>

Motivating problem:

```julia
julia> struct MappedElement{F <: Function,T <: Real} <: Real 
           x::T
           fx::T
           MappedElement{F}(x::T, fx::T) where {F,T} = new{F,T}(x, fx)
           MappedElement{F}(x, fx) where {F} = MappedElement{F}(promote(x, fx)...)
       end

julia> MappedElement(f::F, x) where {F} = MappedElement{F}(x, f(x))
MappedElement

julia> (::typeof(F))(x::MappedElement{typeof(F)}) where {F} = x.fx # errors
ERROR: TypeError: in MappedElement, in F, expected F<:Function, got Type{TypeVar}
Stacktrace:
 [1] top-level scope at REPL[3]:1

julia> (::typeof(F))(x::MappedElement{F}) where {F} = x.fx # does not error

julia> meexp = MappedElement(exp, 2.3);

julia> exp(meexp) # errors
ERROR: MethodError: no method matching exp(::MappedElement{typeof(exp),Float64})
Closest candidates are:
  exp(::BigFloat) at mpfr.jl:618
  exp(::Missing) at math.jl:1138
  exp(::Complex{Float16}) at math.jl:1086
  ...
Stacktrace:
 [1] top-level scope at REPL[6]:1

julia> (::typeof(log))(x::MappedElement{typeof(log)}) = x.fx

julia> melog = MappedElement(log, 2.3); # works

julia> log(melog) #works
0.8329091229351039

```

The idea would be to have a number that caches the result of some function applied to it.

The definition:

```julia
 (::typeof(F))(x::MappedElement{F}) where {F} = x.fx # does not error

```

looks wrong, and also fails to actually work, but evaluating it does not error, unlike

```julia
 (::typeof(F))(x::MappedElement{typeof(F)}) where {F} = x.fx

```

For what it’s worth, lowered forms of the expressions:

```julia
julia> Meta.@lower (::typeof(log))(x::MappedElement{typeof(log)}) = x.fx
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope'
1 ─ %1 = typeof(log)
│ %2 = typeof(log)
│ %3 = Core.apply_type(MappedElement, %2)
│ %4 = Core.svec(%1, %3)
│ %5 = Core.svec()
│ %6 = Core.svec(%4, %5)
│ $(Expr(:method, false, :(%6), CodeInfo(quote
    Base.getproperty(x, :fx)
    return %1
end)))
└── return
))))

julia> Meta.@lower (::typeof(F))(x::MappedElement{::typeof(F)}) where {F} = x.fx
:($(Expr(:error, "invalid \"::\" syntax")))

julia> Meta.@lower (::typeof(F))(x::MappedElement{typeof(F)}) where {F} = x.fx
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope'
1 ─ %1 = Core.TypeVar(:F)
│ %2 = typeof(%1)
│ %3 = typeof(%1)
│ %4 = Core.apply_type(MappedElement, %3)
│ %5 = Core.svec(%2, %4)
│ %6 = Core.svec(%1)
│ %7 = Core.svec(%5, %6)
│ $(Expr(:method, false, :(%7), CodeInfo(quote
    Base.getproperty(x, :fx)
    return %1
end)))
└── return
))))

julia> (::typeof(F))(x::MappedElement{typeof(F)}) where {F} = x.fx
ERROR: TypeError: in MappedElement, in F, expected F<:Function, got Type{TypeVar}
Stacktrace:
 [1] top-level scope at REPL[19]:1

julia> Meta.@lower (::typeof(F))(x::MappedElement{F}) where {F} = x.fx
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope'
1 ─ %1 = Core.TypeVar(:F)
│ %2 = typeof(%1)
│ %3 = Core.apply_type(MappedElement, %1)
│ %4 = Core.svec(%2, %3)
│ %5 = Core.svec(%1)
│ %6 = Core.svec(%4, %5)
│ $(Expr(:method, false, :(%6), CodeInfo(quote
    Base.getproperty(x, :fx)
    return %1
end)))
└── return
))))

```

In the case where I write `::MappedElement{typeof(F}}`, the code contains

```julia
1 ─ %1 = Core.TypeVar(:F)
│ %3 = typeof(%1)
│ %4 = Core.apply_type(MappedElement, %3)

```

Removing the `typeof` eliminates the `%3`. The non-parameteric `typeof(log)` version directly `Core.apply_type`s using `typeof(log)`.

To overload calls to functions passed a function, I cannot use `typeof`:  
`Base.broadcasted(::F, x::MappedElement{F}) where {F} = x.fx`  
But this does not work for defining a call:

```julia
julia> (::F)(x::MappedElement{F}) where {F} = x.fx
ERROR: function type in method definition is not a type
Stacktrace:
 [1] top-level scope at REPL[27]:1

```

Any ideas?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 22, 2020, 9:37am UTC](https://discourse.julialang.org/t/dispatching-on-function-types/34983/2 "2020-02-22T09:37:00Z")

</div>

> [@Elrod](#):
>
> But this does not work for defining a call:
> 
> ```julia
> julia> (::F)(x::MappedElement{F}) where {F} = x.fx
> ERROR: function type in method definition is not a type
> Stacktrace:
> [1] top-level scope at REPL[27]:1
> 
> ```
> 
> Any ideas?

The concrete version of this works:

```julia
meexp = MappedElement(exp, 2.3);
Base.exp(x::MappedElement{typeof(exp)}) = x.fx
exp(meexp) # works

```

so I think this is a bug (or missing feature). I would recommend opening an issue.
