# Function types unexpectedly equal

**URL:** https://discourse.julialang.org/t/function-types-unexpectedly-equal/94674
**Category:** Performance
**Tags:** functions
**Created:** [February 15, 2023, 9:33am UTC](https://discourse.julialang.org/t/function-types-unexpectedly-equal/94674 "2023-02-15T09:33:07Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![fph](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fph/32/17159_2.png) [@fph](https://discourse.julialang.org/u/fph)
#### Post date: [February 15, 2023, 9:33am UTC](https://discourse.julialang.org/t/function-types-unexpectedly-equal/94674/1 "2023-02-15T09:33:08Z")

</div>

```julia
julia> T = [x->x*k for k in 1:3]
3-element Vector{var"#54#56"{Int64}}:
 #54 (generic function with 1 method)
 #54 (generic function with 1 method)
 #54 (generic function with 1 method)

```

The three functions in the array are different, but they share the same type. Is this intended? I got the impression that each distinct anonymous function should have its own different type.

Depending on the type of `x` the functions could even return different types, so that seems strange to me.

Is there a way to avoid it and generate different function types instead? Use case: I would like to use function types to dispatch a hand-written `derivative(f)` function, for instance

```julia
derivative(f::typeof(T[1])) = 1;
derivative(f::typeof(T[2])) = 2;
derivative(f::typeof(T[3])) = 3;

```

but then the last definition applies to all functions: `derivative(T[1])` returns `3`.

---

<div class="post-metadata">

### Author: ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)
#### Post date: [February 15, 2023, 9:58am UTC](https://discourse.julialang.org/t/function-types-unexpectedly-equal/94674/2 "2023-02-15T09:58:12Z")

</div>

> [@fph](#):
>
> Is this intended?

Yes. The language is more efficient this way.

Functions are just [callable structs](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects) that subtype `Function`, and the captured value is a field of the struct.

```julia
julia> T = [x->x*k for k=1:3];

julia> dump(first(T))
#34 (function of type var"#34#36"{Int64})
  k: Int64 1

julia> [T[i].k for i=1:3]
3-element Vector{Int64}:
 1
 2
 3

```

Conveniently, because they share the same type, they can reside in the same array while maintaining type-stability.

> [@](#):
>
> Depending on the type of `x` the functions could even return different types

This is not a problem; when a specialization on a different argument type is compiled for one, it is compiled for all.

> [@](#):
>
> Is there a way to avoid it and generate different function types instead?

For with Julia all things are possible.

```julia
julia> macro foo(n::Int) :( ($((:(x->x*$k) for k=1:n)...),) ) end
@foo (macro with 1 method)

julia> const fs = @foo(3)
(var"#5#8"(), var"#6#9"(), var"#7#10"())

julia> map(fs) do f; f(2) end
(2, 4, 6)

```

However, looking at what you’re doing, this will be better served by leaving them all the same type and just accessing their member field:

```julia
derivative(f::typeof(T[1])) = f.k;

```

That said, this isn’t public API (who knows, maybe one day we’ll hash anonymized function bodies so anonymous functions don’t need to be recompiled); you’re better served by going the direct route and making your own callable struct:

```julia
struct Foo{K} <: Function; k::K end
(f::Foo)(x) = x*f.k
derivative(f::Foo) = f.k
T = [Foo(k) for k=1:3]

```

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [February 15, 2023, 10:10am UTC](https://discourse.julialang.org/t/function-types-unexpectedly-equal/94674/3 "2023-02-15T10:10:52Z")

</div>

> [@uniment](#):
>
> `struct Foo{K} <: Function; k::K end`

It is not necessary to subtype `Function` here - that type has some assumptions in addition to being callable.

---

<div class="post-metadata">

### Author: ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)
#### Post date: [February 15, 2023, 10:16am UTC](https://discourse.julialang.org/t/function-types-unexpectedly-equal/94674/4 "2023-02-15T10:16:14Z")

</div>

Indeed, but I figure if we’re replacing a lambda (which subtypes `Function` anyway) it’s probable that we’d want to opt-in to some of those e.g. broadcasting behaviors.

---

<div class="post-metadata">

### Author: ![fph](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fph/32/17159_2.png) [@fph](https://discourse.julialang.org/u/fph)
#### Post date: [February 15, 2023, 10:31am UTC](https://discourse.julialang.org/t/function-types-unexpectedly-equal/94674/5 "2023-02-15T10:31:42Z")

</div>

> [@uniment](#):
>
> Yes. The language is more efficient this way.
> 
> Functions are just [callable structs](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects) that subtype `Function`, and the captured value is a field of the struct.

Thanks, this clears things up for me.

One additional question then: what can I assume on the type of functions? For instance, can I assume that anonymous functions generated in different lines of code with different `->` expressions will have different types?

---

<div class="post-metadata">

### Author: ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)
#### Post date: [February 15, 2023, 10:42am UTC](https://discourse.julialang.org/t/function-types-unexpectedly-equal/94674/6 "2023-02-15T10:42:20Z")

</div>

> [@fph](#):
>
> can I assume that anonymous functions generated in different lines of code with different `->` expressions will have different types?

Yes, this is correct for now. I don’t know if it will remain correct forever though, as there’s an implicit assumption with anonymous functions that you don’t care about their name.

If you want greater assurance, you can use `gensym` with named function syntax:

```julia
julia> macro foo(n::Int) :( ($((esc(:($(gensym(:foo))(x) = x*$k;)) for k=1:n)...),) ) end
@foo (macro with 1 method)

julia> @foo(3)
(var"##foo#304", var"##foo#305", var"##foo#306")

```
