# Understanding error "function type in method definition is not a type" for function-like types

**URL:** https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105
**Category:** General Usage
**Tags:** type, dispatch, function
**Created:** [June 23, 2024, 2:59am UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105 "2024-06-23T02:59:15Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)
#### Post date: [June 23, 2024, 2:59am UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/1 "2024-06-23T02:59:15Z")

</div>

I don’t understand why the second way to construct a method (dispatched by `::Val{2}`) is not allowed:

```julia
julia> abstract type MyFunc <: Function end

julia> struct MyF1 <: MyFunc end

julia> (f::MyFunc)(::Val{1}) = "method 1"

julia> MyF1()(Val(1))
"method 1"

julia> function (f::F)(::Val{2}) where {F<:MyFunc}
           "method 2"
       end
ERROR: function type in method definition is not a type

```

Even though

```julia
julia> (F where {F<:MyFunc}) == MyFunc
true

```

Thanks!!

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [June 23, 2024, 5:20am UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/2 "2024-06-23T05:20:32Z")

</div>

I agree the error message could be improved. Technically, the method type parameter `(f::F)(::Val{2})` is not a parametric type like `(f::(F where {F<:MyFunc}))(::Val{3})`, which can’t share a `where` clause with arguments and is simplified to `f::MyFunc` (see `methods`). There’s not much reason to let the callable have or share method type parameters like arguments; the non-specialization heuristic that is overridden by method type parameters only applies to arguments, and restricting the callable and an argument to ~~the same concrete type~~ matching type parameters or concrete argument types only makes an unnecessary argument for recursion. I don’t see a reason why it can’t be done, either.

---

<div class="post-metadata">

### Author: ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)
#### Post date: [June 24, 2024, 1:20pm UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/3 "2024-06-24T13:20:17Z")

</div>

Though you can do

```julia-repl
julia> function (f::F where {F<:MyFunc})(::Val{3})
           "method 3"
       end

julia> MyF1()(Val(3))
"method 3"

julia> function (f::F where {F<:MyFunc})(::Val{4}) # F will not be available within the function body
           return F
       end

julia> MyF1()(Val(4))
ERROR: UndefVarError: `F` not defined

```

See that this is still useful for dispatch, but not for parameter extraction. Although in this case one could use `typeof(f)` within the body.

---

<div class="post-metadata">

### Author: ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)
#### Post date: [June 25, 2024, 5:54pm UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/4 "2024-06-25T17:54:29Z")

</div>

Yeah. I understand the third approach. Unfortunately, what I showed is just a minimal demonstration. In my code, I actually do want to capture the type information `F` in the function body.

I can actually bypass this issue by enclose `F` in a parametric type. For instance:

```julia
julia> function (f::Type{F})(::Val{5}) where {F<:MyFunc}
           "method 5"
       end

julia> MyF1(Val(5))
"method 5"

```

However, practically, this is simply “method 2” with an extra step. So I’m just curious from a language design perspcetive why “method 2” is forbidden. More specifically, why is the `F` in a function definition form

```julia
function (f::F)(::Val{2}) where {F<:MyFunc}
    "method 2"
end

```

not considered a `UnionAll` type?

---

<div class="post-metadata">

### Author: ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)
#### Post date: [June 25, 2024, 6:02pm UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/5 "2024-06-25T18:02:43Z")

</div>

I wasn’t really trying to share parameters between the callable object `F` and its arguments but wanting to capture its type information in the function body. In reality, I was trying to define a set of callable types that share similar traits but also slight differ from each other in a few cases when they are called. I did find a workaround:

> ```julia
> julia> function (f::Type{F})(::Val{5}) where {F<:MyFunc}
> "method 5"
> end
> 
> julia> MyF1(Val(5))
> "method 5"
> 
> ```

I am still curious about the reason for original restriction (“method 2”) in the first place.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [June 25, 2024, 7:35pm UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/6 "2024-06-25T19:35:25Z")

</div>

> [@frankwswang](#):
>
> why is the `F` in a function definition form not considered a `UnionAll` type?

It’s just a type parameter, not a parametric type. The method’s `where` clause doesn’t actually belong to any of the type annotations, but even if we do incorporate it, the bare parameter does not make a `UnionAll`:

```julia
julia> (Type{F} where F<:Function)
Type{F} where F<:Function

julia> (Type{F} where F<:Function) |> typeof
UnionAll

julia> (F where F<:Function)
Function

julia> (F where F<:Function) |> typeof
DataType

```

In actuality, the method’s `where` clause belongs to the method signature’s tuple type:

```julia
julia> (f::MyType{F})(x::F) where F<:Function = 0

julia> methods(MyType(+))[1].sig
Tuple{MyType{F}, F} where F<:Function

```

And it’s possible to annotate bare parameters for arguments for such a type. It’s just not supported for callables, and I can’t find compelling reasons for or against it. `(callable::T)(data::T) where T<:AbstractCallableData` sounds like a neat bonus feature.

> [@frankwswang](#):
>
> `function (f::Type{F})(::Val{5})`

This changes the callable from the instances to the `MyFunc` subtypes, making a method that mingles with the constructors. I’d avoid that.

> [@frankwswang](#):
>
> I wasn’t really trying to share parameters between the callable object `F` and its arguments but wanting to capture its type information in the function body.

Could just do `typeof(f)` in method 1, it’s simple enough to do at compile-time.

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [June 25, 2024, 10:36pm UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/7 "2024-06-25T22:36:53Z")

</div>

> [@frankwswang](#):
>
> I don’t understand why the second way to construct a method (dispatched by `::Val{2}`) is not allowed:

I don’t know enough about the dispatch implementation to be able to give a definite answer. I think, however, that you’re asking for a very powerful feature: you’re really trying to define an infinite family of methods using the usual syntax, which is only able to define a single method at a time.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [June 26, 2024, 4:06am UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/8 "2024-06-26T04:06:06Z")

</div>

> [@nsajko](#):
>
> infinite family of methods using the usual syntax, which is only able to define a single method at a time.

Parametric methods involving the callable aren’t that crazy, unless I’m missing the distinction being made between the unsupported method `(::T)(x::T) where T<:MyType` and:

```julia-auto
julia> @which Number(2)
(::Type{T})(x::T) where T<:Number

```

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [June 26, 2024, 8:00am UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/9 "2024-06-26T08:00:54Z")

</div>

A complication with this feature request is that it could be a major foot gun. A method like this would match any and all calls, as far as I see:

```julia
(::T)(::Vararg) where {T} = 7

```

---

<div class="post-metadata">

### Author: ![kapple](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kapple/32/218915_2.png) [@kapple](https://discourse.julialang.org/u/kapple)
#### Post date: [July 23, 2024, 5:16pm UTC](https://discourse.julialang.org/t/understanding-error-function-type-in-method-definition-is-not-a-type-for-function-like-types/116105/10 "2024-07-23T17:16:15Z")

</div>

This has been my approach to a similar problem in my use case. I haven’t found any issues with it so far, let me know if you guys know any. In summary I use `@eval` in a macro which gets around the function definition not knowing the parametric type of the function.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/a/ca3b336045388dae155aa3eea969efeaaa983642.png)
