# The Unreasonable Efficiency and Effectiveness of Multiple Dispatch: Your Favourite Examples

**URL:** https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477
**Category:** General Usage
**Tags:** question, multiple-dispatch
**Created:** [September 17, 2024, 3:07am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477 "2024-09-17T03:07:25Z")
**Posts on this page:** 17
**Page:** 2

<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: [September 24, 2024, 8:59am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/21 "2024-09-24T08:59:43Z")

</div>

> [@xiaodai](#):
>
> Isn’t multiple-dispatch kinda like overloading on steroids?

[Yesn’t](https://discourse.julialang.org/t/is-multiple-dispatch-the-same-as-function-overloading/4145/17). Short version: Both are kinds of polymorphism where a function has multiple methods, though multimethods is only synonymous with multiple dispatch. Function overloading is compile-time polymorphism over compile-time information like types or arity. Multiple dispatch works on runtime information instead and is typically thought to be done at runtime, but Julia’s type inference can resolve dispatch at compile-time, which confuses people used to statically typed languages’ starker divide between static and dynamic.

> [@xiaodai](#):
>
> In Julia, a function’s definition could be set in multiple locations depending on which method is dispatched. This makes it hard to understand the code or it could give you the false sense that you understood it but the implementation could literally be unchanged from under your feet but defining a method with a more restrictive type signature.

This is a downside of polymorphism in general, which is why static analysis is such a big want. It’s easier to do by eye in statically typed languages with type declarations, but some rely on type inference, too.

---

<div class="post-metadata">

### Author: ![Barget](https://avatars.discourse-cdn.com/v4/letter/b/94ad74/32.png) [@Barget](https://discourse.julialang.org/u/Barget)
#### Post date: [September 24, 2024, 9:53pm UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/22 "2024-09-24T21:53:40Z")

</div>

> [@Benny](#):
>
> Multiple dispatch works on runtime information

I’m surprised by that. As I see it, it’s totally possible to program in Julia with concret types only, which would then be a defacto static-like subset of the language. This would still be multiple dispatch. So from a theoretical point of view, this would mean multiple dispatch concept is orthogonal to runtime’s. Maybe I’m missing something?

> [@xiaodai](#):
>
> In Julia, a function’s definition could be set in multiple locations depending on which method is dispatched. This makes it hard to understand the code or it could give you the false sense that you understood it but the implementation could literally be unchanged from under your feet but defining a method with a more restrictive type signature.

This is why I think it would be great to have systematically the discipline to “stay true” to the original intent of a function (not methods, which are “just” implementations of the aforementioned function).  
Most of the confusions arise when function naming is too vague, or generic.  
In such case, inferring what the pair (function name + arguments) is expected to do becomes quite subjective. Which results in surprises…  
To be more specific with an example, `getperimeter(::AbstractPolygon)` is quite clear, and so is what’s expected from any method that would implements the function. Conversely, `conjugation(::AbstractFoo)` isn’t.

My point is, multiple dispatch can be so powerful that it must be accompanied with some care and good practices. And these are quite specific to this language (or other niche languages), which means it’s not widespread programming knowledge.

… this is unfortunately the flip side of the unreasonable efficiency of multiple dispatch.

---

<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: [September 24, 2024, 10:23pm UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/23 "2024-09-24T22:23:03Z")

</div>

> [@Barget](#):
>
> I’m surprised by that. As I see it, it’s totally possible to program in Julia with concret types only, which would then be a defacto static-like subset of the language. This would still be multiple dispatch.

Correct. That would mean the compiler can and has figured out what the runtime information will be. You don’t need to program “with concrete types only” to accomplish this, you just need the compiler to always infer concrete types. If the compiler infers abstract types, then it will make extra code to work on runtime information anyway.

This stands in contrast to statically typed languages where the compile-time information and the code compiled for it can deviate from runtime information. Say we instantiate `Super x = new Sub();`, `x.staticfoo()` will work on the static type `Super` while `x.dynamicfoo()` will work on the runtime type made by `Sub`. The types can even deviate when there is type inference instead of explicit declarations. This doesn’t happen in Julia because 1) it is a dynamically typed language, and 2) it doesn’t have concrete supertypes to even instantiate and compile code for. Some newer statically typed languages eschew inheritance in part due to the simplicity of (2).

“Runtime information sometimes known at compile-time” may seem like a terminological copout, especially since we freely differentiate “static dispatch” from “dynamic dispatch” and loosely say “static Julia” when avoiding the latter. But bear in mind most of the terminology and lines were drawn by older popular statically typed languages, so it’s understandably awkward for describing a newer unusual dynamically typed language.

---

<div class="post-metadata">

### Author: ![Barget](https://avatars.discourse-cdn.com/v4/letter/b/94ad74/32.png) [@Barget](https://discourse.julialang.org/u/Barget)
#### Post date: [September 25, 2024, 7:10pm UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/24 "2024-09-25T19:10:09Z")

</div>

Thanks for the explanation.

After digging a bit, I found out why I was bothered by the fact that “multiple” implies “dynamic”: it’s just a matter of convention 😅  
(looking only at the definition of “multiple” and “dispatch” was not enough)

For exemple, c++ templates are considered to be a kind of dispatch, but “static”.  
So it appears that “multiple dispatch” requires, _by definition_, to also involve runtime.

Anyway, so the answer to @xiaodai is … “yes”, it’s a superset.

---

<div class="post-metadata">

### Author: ![sairus7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sairus7/32/10816_2.png) [@sairus7](https://discourse.julialang.org/u/sairus7)
#### Post date: [October 16, 2024, 6:56pm UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/25 "2024-10-16T18:56:07Z")

</div>

> **[Conversion and Promotion · The Julia Language](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#Defining-Promotion-Rules)**
>
> Documentation for The Julia Language.

---

<div class="post-metadata">

### Author: ![StevenSiew](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevensiew/32/218393_2.png) [@StevenSiew](https://discourse.julialang.org/u/StevenSiew)
#### Post date: [October 17, 2024, 12:27am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/26 "2024-10-17T00:27:10Z")

</div>

In chemistry we have the ideal gas Law PV=NRT

So do anyone program like this?

```julia
function CalcVIR(v::Union{Number,Missing},
                 i::Union{Number,Missing},
                 r::Union{Number,Missing})
    ''' If voltage is missing then calc v = i * r
        If current is missing then calc i = v / r
        If resistance is missing then calc r = v / i
    '''
    if ismissing(v)
        return i * r
    elseif ismissing(i)
        return v / r
    elseif ismissing(r)
        return v / i
    end
end

```

And using it like

Starting Julia…

```_
   _ _ _(_)_ | Documentation: https://docs.julialang.org
  (_) | (_) (_) |
   _ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _ | |
  | | |_| | | | (_| | | Version 1.2.0 (2019-08-20)
 _/ |\ ___|_|_|\__ _| | Official https://julialang.org/ release
|__/ |

julia> v = CalcVIR(missing,3,5)
15

julia> v = CalcVIR(missing,3.4,5.6)
19.04

julia> i = CalcVIR(7,missing,3)
2.3333333333333335

```

---

<div class="post-metadata">

### Author: ![liuyxpp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/liuyxpp/32/9870_2.png) [@liuyxpp](https://discourse.julialang.org/u/liuyxpp)
#### Post date: [October 17, 2024, 2:43am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/27 "2024-10-17T02:43:01Z")

</div>

I like the following multiple dispatch way:

```julia
calcvir(::Missing, i::Number, r::Number) = i * r
calcvir(v::Number, ::Missing, r::Number) = v / r
calcvir(v::Number, i::Number, ::Missing) = v / i

```

---

<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: [October 17, 2024, 4:39am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/28 "2024-10-17T04:39:41Z")

</div>

`CalcVIR` and `calcvir` seem unnecessarily vague, take the varying output meanings and types given `Int64` inputs for example. If the `missing` position is fixed, I’d rather they be clearer, separate functions that don’t need me to write `missing` to begin with. If the `missing` position varies for some reason (maybe read from a file), I’d rather `calcvir` output a consistently typed, `v,i,r`-named 3-tuple, and I’d wrap it in another function that takes keyword arguments defaulting to `missing` so I don’t have to write `missing` manually.

---

<div class="post-metadata">

### Author: ![liuyxpp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/liuyxpp/32/9870_2.png) [@liuyxpp](https://discourse.julialang.org/u/liuyxpp)
#### Post date: [October 17, 2024, 5:07am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/29 "2024-10-17T05:07:43Z")

</div>

You are right. But I intend to replicate what CalcVIR does, which is not necessary reflecting my preference.

---

<div class="post-metadata">

### Author: ![StevenSiew](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevensiew/32/218393_2.png) [@StevenSiew](https://discourse.julialang.org/u/StevenSiew)
#### Post date: [October 17, 2024, 7:09am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/30 "2024-10-17T07:09:51Z")

</div>

> [@StevenSiew](#):
>
> `i = CalcVIR(7,missing,3)`

I just want to show the bizarre way, you can use julia. I don’t think you can do this in C++

Yes, you can do it via multiple dispatch as well.

---

<div class="post-metadata">

### Author: ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)
#### Post date: [October 17, 2024, 8:25am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/31 "2024-10-17T08:25:53Z")

</div>

I guess an alternative would be to just have a 2-arg version and put the information about whether a number is representing current, voltage or resistance into the type domain like:

```julia
struct Voltage; v; end
struct Current; i; end
struct Resistance; r; end

calcivr(x::Current, y::Resistance) = x.i * y.r;
calcivr(x::Voltage, y::Resistance) = x.v / x.r;
calcivr(x::Current, y::Voltage) = y.v / x.i;

```

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [October 17, 2024, 8:34am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/32 "2024-10-17T08:34:25Z")

</div>

Perhaps, a good case for Unitful.jl:

```julia
using Unitful

calcvir(I::Unitful.Current, R::Unitful.ElectricalResistance) = I * R
calcvir(V::Unitful.Voltage, R::Unitful.ElectricalResistance) = V / R
calcvir(V::Unitful.Voltage, I::Unitful.Current) = V / I

v = 10u"V"; i = 5u"A"; r = 2u"Ω"

calcvir(v,i)
calcvir(v,r)
calcvir(i,r)

```

PS:  
Would need to define more methods with arguments’ order swapped.

---

<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: [October 18, 2024, 12:13am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/33 "2024-10-18T00:13:09Z")

</div>

Personally, I like naming my functions after the thing it calculates, e.g.

```julia
voltage(i::Number, r::Number) = i * r
current(v::Number, , r::Number) = v / r
resistance(v::Number, i::Number) = v / i

```

The next layer of challenge I experience in general is the fact that there’s many ways to compute these terms. At first I tried dispatching off `Val`s, e.g. (with `p`ower)

```julia
voltage(::Val{:IR}, i::Number, r::Number) = i * r
voltage(::Val{:PI}, p::Number, i::Number) = p / i
voltage(::Val{:PR}, p::Number, r::Number) = sqrt(p * r)

```

I thereafter realised that users can’t extend my interfaces/models without piracy. And in my field, there are A LOT of metrics and A LOT of models for computing those metrics, and those models can use the same parameters which have the same units, which throws the dispatching by Unitful.jl quantities out the window 😭. (See [Speed of sound in sea water](http://resource.npl.co.uk/acoustics/techguides/soundseawater/underlying-phys.html) for an example of what I’m talking about, and that’s just for ocean sound speed; it’s only a small subset of equations for sound speed; there’s many metrics in ocean acoustics that also have a variety of models). So the number of models and functions I need to define starts to proliferate in my field of ocean sonar. (For those interested in why, it’s because the theoretical models have proven insufficient in modelling reality — we need real-world-data-interpolated models, and there’ve been so many papers on developing equations based on recorded data for ocean sound speed alone. The same is true for bottom reflection, acoustical scattering, ambient noise, … this list of things is very long.)

Defining a new type ala `Voltage`, `Resistance`, `Current` above will very quickly start overpopulating and overpolluting the namespace. Additionally, while “Sound Speed” would be a desired output metric — so there’d be a function named `sound_speed`, there’ll also be other metrics that will be best labelled by a model named “Sound Speed” so I’d have `SoundSpeed` as a type. Again, this leads to namespace overpopulation and overpollution. Plus the inconsistency of having `SoundSpeed` as a type for numeric dispatch, and `SoundSpeed` as a type for model dispatch, just clashes.

I’ve started exploring having one abstract type, `abstract type ModelName end` which my users and I can `MyModelName <: ModelName` and then extend `sound_speed` and other functions by the new model.

Another layer of complexity is that in my field of ocean sonar, `sound_speed` also needs to be calculated for the seabed (and atmosphere), so I’ve tried out having `sound_speed(::Seabed, ::Clay, z::Real)` with `sound_speed(::Ocean, ::Mackenzie, z::Real)`

OR

`ocean_sound_speed(::Mackenzie, z::Real)` with `seabed_sound_speed(::Clay, z::Real)`.

OR (and I gave up on this one very early because nested module navigation and namespace management between the layers was a bit of a nightmare in Julia, which I assume/hope will get easier in the future)

```julia
module OceanSonar
  abstract type ModelName end

  struct Mackenzie <: ModelName end
  struct Clay <: ModelName end

  module Ocean
    using ..OceanSonar: Mackenzie

    sound_speed(::Mackenzie, z::Real) = ...
  end

  module Seabed
    using ..OceanSonar: Clay

    sound_speed(::Clay, z::Real) = ...
  end
end

```

which will require e.g. `import OceanSonar.Ocean: sound_speed` for extension.  
I think the latter needs to be my solution. The top level `OceanSonar` will contain all the `<:ModelName` subtypes for dispatching, and then the inner modules will define methods on them.

Finally, my users (and I) will DEFINITELY want to query what models are available for what function, and what inputs are needed for each model. Maybe traits? Either traits or introspection with things like InteractiveUtils.jl and MethodInspector.jl. I think I’ll have to go with traits, but this is the the layer of exploration I’m up to right now, and I’ve explored the latter plenty and the former a little but currently. On top of that, as per Julia’s progress in the generation of binaries, I may have troubles with introspection moving ahead.

I can’t find much in the Julia ecosystem that explores this. As far as I’ve seen, they resort to defining new types for each _model_. As argued above, I arguably can’t do that.

So to bring this thread full circle, the above complexity is most easily simplified and implemented in Julia with its multiple dispatch paradigm. I’ve been trying it out in various languages (i.e. MATLAB and C++) and OH BOY I definitely, _definitely_ want to use Julia for this. You should see my boss’ code for trying to do this model and input variable dispatching in MATLAB. So. Much. Boilerplate. Even more boilerplate in C++ where it’s a whole lot of nested conditionals and doesn’t have introspection. I still have plans on exploring how other languages would handle this, but the fact that Julia is the only language that has multiple dispatch as the main paradigm makes me somewhat content for the time being.

Bringing this comment full circle, I also have plans on exploring acausal modelling both in differential equations (which applies to the field of ocean acoustics as a subfield of ocean sonar) and in just the equation above. The implementations of the VIR relationship are just one equation, so in the spirit of acausal modelling it should be theoretically possible to define the equation V = IR and then somehow specify the inputs and desired output, obviating the boilerplate of writing a function for every manipulated version of the equation. This is possible with the [recent advances](https://discourse.julialang.org/t/new-symbolic-solver-for-symbolics-jl/118466) of Symbolics.jl in symbolic equation solving.

Additional Thoughts: I’ve also been thinking a lot (long before this thread), how best to do something like how packages can write code for something that is Tables.jl compliant, i.e. it will accept types defined off Tables.jl but it will be completely unaware of what that type is, and it will “just work.” For example, the ocean acoustics submodule of OceanSonar will have a variety of ways to solve the wave equation (Helmholtz equation, Eikonal equation, etc.) and various solvers from DifferentialEquations.jl should be accessible by my package, without my package knowing what that solver is. There’s a few other contexts where such a composable design pattern is needed. Julia enables such composable design to increase linearly with the number of types, with a multiplicatively exploding number of functionalities. In half-theory at least (half because we’ve already demonstrated this in so many places, a recent magical moment I had was seeing how DimensionalData.jl works [so well](https://github.com/rafaqz/DimensionalData.jl/issues/821) with AlgebraOfGraphics.jl, and they don’t even know each other, but Tables.jl facilitated their composability — the other half is, I’m still writing my package so we’ll see how I go).

---

<div class="post-metadata">

### Author: ![dubosipsl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dubosipsl/32/52998_2.png) [@dubosipsl](https://discourse.julialang.org/u/dubosipsl)
#### Post date: [October 18, 2024, 6:28am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/34 "2024-10-18T06:28:18Z")

</div>

FWIW, we have a (non-registered, in-progress) package handling thermodynamic functions for a few idealized models. The variety of possible inputs is handled by letting the input be a named tuple. Each thermodynamic function (e.g., `pressure`, `temperature`) dispatches on both the model and the input. Plus some syntactic sugar to make broadcasting easier, and unit tests with autodiff to check as many relationships between functions as we can. This works for us so far. Extensibility relies heavily on multiple dispatch and other core Julia features, and seems hard to obtain without them.

> **[GitHub - ClimFlows/ClimFluids.jl: Thermodynamic functions for climate-relevant...](https://github.com/ClimFlows/ClimFluids.jl)**
>
> Thermodynamic functions for climate-relevant fluids such as air and seawater.

---

<div class="post-metadata">

### Author: ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)
#### Post date: [December 5, 2024, 7:19pm UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/35 "2024-12-05T19:19:34Z")

</div>

I hit another anti-example today in Python. I’m writing a small library for generic database interactions. I have a represent various database types as classes (Varchar, Int, Array, etc.). They each encapsulate the logic for turning into a string when they are interpolated into SQL queries.

But different databases represent some types differently – an array of integers is `Array(Int NOT NULL)` in Snowflake, but `Int[]` in postgres.

So that means the database connection needs to contain logic for overriding the default ` __str__ ()` behavior for some but not all types. And what about defining new datatypes that are unique to certain databases?

I am pining for multiple dispatch right now.

---

<div class="post-metadata">

### Author: ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)
#### Post date: [December 5, 2024, 7:44pm UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/36 "2024-12-05T19:44:15Z")

</div>

> [@mrufsvold](#):
>
> I’m writing a small library for generic database interactions.

Is using [sqlalchemy](https://www.sqlalchemy.org/) an option?

---

<div class="post-metadata">

### Author: ![dmetivie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmetivie/32/6926_2.png) [@dmetivie](https://discourse.julialang.org/u/dmetivie)
#### Post date: [January 10, 2025, 9:38am UTC](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477/37 "2025-01-10T09:38:16Z")

</div>

The `rand` function!

```julia
methods(rand)
# 252 methods for generic function "rand" from Base

```

It has so many possible dispatches with `rng`, types, number of argument to generate scalar, vectors, matrix, tensor, …

Related is of course the [Distributions.jl](https://juliastats.org/Distributions.jl/stable/) ecosystem with `rand(Exponential())`, `rand(Normal())` etc. (Other stat functions have a lot of methods like `fit!` (or `fit_mle`), `logdensityof` (or `logpdf`) etc. + all related packages using that [Copulas.jl](https://github.com/lrnv/Copulas.jl), [HiddenMarkovModels.jl](https://github.com/gdalle/HiddenMarkovModels.jl) and so on! I would not have written [ExpectationMaximization.jl](https://github.com/dmetivie/ExpectationMaximization.jl) without multiple dispatch.

[Previous page](https://discourse.julialang.org/t/the-unreasonable-efficiency-and-effectiveness-of-multiple-dispatch-your-favourite-examples/119477.md?page=1)
