# \[ANN\] EnforcedTypeSignatureCallables.jl

**URL:** <https://discourse.julialang.org/t/ann-enforcedtypesignaturecallables-jl/117280>\
**Category:** Package Announcements\
**Tags:** package, announcement, function, type-stability, functors\
**Created:** [July 20, 2024, 6:16pm UTC](https://discourse.julialang.org/t/ann-enforcedtypesignaturecallables-jl/117280 "2024-07-20T18:16:57Z")\
**Posts on this page:** 1\
**Showing post:** 6

<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:** [July 20, 2024, 11:50pm UTC](https://discourse.julialang.org/t/ann-enforcedtypesignaturecallables-jl/117280/6 "2024-07-20T23:50:43Z")

</div>

> [@ForceBru](#):
>
> Why not use multiple dispatch when passing a function as an argument?

This technically already happens, just not in the way you think it can.

First, we have to throw out the `U` part because a specific call signature with a unique piece of compiled code may not have a fixed return type, so it’s not a useful part; you could make `U` abstract and leave it entirely up to the compiler, but that’s not controllable or stable. Second, 1 method (and method signature) can have an infinite number of call signatures (and thus compiled _specializations_) at once e.g. `foo(x::Real)` can be compiled for `foo(::Int)` and `foo(::Float64)`. Type stability and control makes _call signatures_ (like this very package!) better to specify, so you wouldn’t in fact want to dispatch on methods in any sense. Even in your example, `T=Float64`, and you make it clear no method `fn(::Float64)` exists, only `fn(::Real)`. I see what you want, but the type system does not allow `Blah{Float64}` and `Blah{Real}` to share an instance. It also doesn’t allow multiple supertypes; `T=Int` in the example calls in fact, so `sin`, `sum`, etc need to subtype `Function{Int}` as well.

The good news is you don’t need any of that stuff. The first hint is that when a function call is dispatched, the types of the callable _and_ the arguments are taken into account, so the types of functions like `sin` and `sum` only have to care about the callable. That’s how we can write methods for callable instances and vary positional arguments in multimethods, yet let the compiler infer specific compiled code so often.

So if we can already dispatch on all parts of a call, why the concept of `FunctionWrapper`s in the first place? Sometimes we can’t narrow down a call site to 1 specialization because one position, often the callable, has to change types at runtime, and that normally needs possibly costly dynamic dispatch and ruins type inference downstream. So FunctionWrappers.jl wrapped specializations with input/output type conversions, putting that information in a concrete type (and parameters) so we can lump many callables together. EnforcedTypeSignatureCallables won’t be able to elide the dynamic dispatch part because most different functions will be represented by an abstract type parameter, but it does provide more inferrability and it’s not subject to many of FunctionWrappers’ constraints and dynamism shortcoming ([example](https://discourse.julialang.org/t/no-allocs-after-restart/117273/14)).

---

_[View the full topic](https://discourse.julialang.org/t/ann-enforcedtypesignaturecallables-jl/117280)._
