# Is it possible to get the most fitting dispatch types?

**URL:** <https://discourse.julialang.org/t/is-it-possible-to-get-the-most-fitting-dispatch-types/97909>\
**Category:** General Usage\
**Created:** [April 25, 2023, 4:29pm UTC](https://discourse.julialang.org/t/is-it-possible-to-get-the-most-fitting-dispatch-types/97909 "2023-04-25T16:29:04Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![jt1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jt1/32/38331_2.png) [@jt1](https://discourse.julialang.org/u/jt1)\
**Post date:** [April 25, 2023, 4:29pm UTC](https://discourse.julialang.org/t/is-it-possible-to-get-the-most-fitting-dispatch-types/97909/1 "2023-04-25T16:29:04Z")

</div>

Say that I have a list of function argument types

```julia
possible_argument_types = [(Int,), (Int,Union{Real,Char}), (Float64,Int), (Any,Int)]

```

And the input type

```julia
input_type = (String,Int)

```

Is it possible for a function like this to work?

```julia
would_dispatch_to(input_type, possible_argument_types)
# returns (Any,Int)

```

I don’t know where to look for this functionallity in the internals of Julia.

* * *

An alternative option that works for my problem would be to allow dispatch with a list of anonymous functions

```julia
f1 = (a::Int) -> ...
f2 = (a::Int,b::Union{Real,Char}) -> ...
f3 = (a::Float64,b::Int) -> ... 
f4 = (a,b::Int) -> ...
would_dispatch_to(input_type, [f1,f2,f3,f4])
# returns f4

```

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [April 25, 2023, 4:55pm UTC](https://discourse.julialang.org/t/is-it-possible-to-get-the-most-fitting-dispatch-types/97909/2 "2023-04-25T16:55:19Z")

</div>

Not knowing the context, this may not be helpful, but: Since you mention dispatch, I infer that you are trying to find out which method (signature) is called for a given input combination. `@which` may help:

```julia
julia> foo(x :: Union{Float64,Int}) = 1
foo (generic function with 1 method)

julia> foo(x :: String) = 2
foo (generic function with 2 methods)

julia> meth = @which foo(1)
foo(x::Union{Float64, Int64}) in Main at REPL[2]:1

julia> meth.sig
Tuple{typeof(foo), Union{Float64, Int64}}

```

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [April 25, 2023, 4:57pm UTC](https://discourse.julialang.org/t/is-it-possible-to-get-the-most-fitting-dispatch-types/97909/3 "2023-04-25T16:57:24Z")

</div>

Another interesting method to learn about the actual dispatch is to use the VSCode debugger.

You can type:

```julia
@enter fun(x, y, z)

```

in the VSCode repl and it will follow you through the exact execution path.

---

<div class="post-metadata">

**Author:** ![jt1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jt1/32/38331_2.png) [@jt1](https://discourse.julialang.org/u/jt1)\
**Post date:** [April 25, 2023, 5:51pm UTC](https://discourse.julialang.org/t/is-it-possible-to-get-the-most-fitting-dispatch-types/97909/4 "2023-04-25T17:51:46Z")

</div>

Thanks for the responses, I think i didn’t make myself clear enough. So i’ll give some extra information.

What i’m looking for is to do “rule-based transformation”. I want to transform the input to some output dependent on some rules. Think of f1… f4 in the seocnd part of the question as the rules.

The problem is that I also want to be able to add and remove rules based on user input. Thus dispatch with a function is not enough as removing rules wouldn’t be possible then.  
A solution to any of the 2 questions would allow me to build such a system.

---

<div class="post-metadata">

**Author:** ![screw\_dog](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/screw_dog/32/48119_2.png) [@screw\_dog](https://discourse.julialang.org/u/screw_dog)\
**Post date:** [April 26, 2023, 8:05am UTC](https://discourse.julialang.org/t/is-it-possible-to-get-the-most-fitting-dispatch-types/97909/5 "2023-04-26T08:05:11Z")

</div>

Simply finding the first type signature that matches is fairly straightforward:

```julia
types_match(input, possible) = all(input .<: possible)
types_match(input) = possible -> types_match(input, possible)

function would_dispatch_to(input, possibles)
    i = findfirst(types_match(input), possibles)
    i ≡ nothing && return nothing
    return possibles[i]
end

```

Assuming your use-case is fairly simple this should be fine but the actual dispatch algorithm that Julia uses is more complicated than this. In particular, the way that you build your `possible_argument_types` is crucial, as well as detecting when you have ambiguous/overlapping definitions.

---

<div class="post-metadata">

**Author:** ![jt1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jt1/32/38331_2.png) [@jt1](https://discourse.julialang.org/u/jt1)\
**Post date:** [April 26, 2023, 2:27pm UTC](https://discourse.julialang.org/t/is-it-possible-to-get-the-most-fitting-dispatch-types/97909/6 "2023-04-26T14:27:29Z")

</div>

For future reference, I got it to work AFAIK starting from your solution. This one accounts for multiple possible matches.

```julia
types_match(input, possible) = all(input .<: possible)
function would_dispatch_to(input_sig, d::Set)
    input_sig in d && return input_sig
    most_specific = nothing
    equaly_specific = Any[]
    for sig in d
        if types_match(input_sig, sig)
            if most_specific === nothing
                most_specific = sig
            else
                if types_match(sig, most_specific)
                    most_specific = sig
                    empty!(equaly_specific)
                elseif !types_match(most_specific, sig) #test for ambiguity
                    push!(equaly_specific, sig)
                end
            end
        end
    end
    length(equaly_specific) > 0 && error("MethodError: $input_sig is ambiguous. The candidates are:\n\t$(mapreduce(identity, (a,b)-> (string(a)*"\n\t"*string(b)), (most_specific, equaly_specific...)))")
    most_specific === nothing && error("MethodError: no method matching $input_sig")
    most_specific
end

possible_argument_types = Set([(Int,), (Int,Union{Real,Char}), (Float64,Int), (Any,Int)])
input_type = (String,Int)
would_dispatch_to(input_type, possible_argument_types)

```
