# Multiple dispatch

> Source: https://aiwiki.ai/wiki/multiple_dispatch
> Updated: 2026-06-28
> Categories: Computer Science, Programming Languages
> From AI Wiki (https://aiwiki.ai), a free encyclopedia of artificial intelligence. Quote with attribution.

**Multiple dispatch** (also called **multimethods**) is a programming-language feature in which the implementation of a function or method is selected at run time from the types of all of its arguments, not just one privileged receiver [1][22]. As the [Julia](/wiki/julia) language documentation puts it, "Using all of a function's arguments to choose which method should be invoked, rather than just the first, is known as multiple dispatch" [22]. It generalizes the more familiar [single dispatch](/wiki/single_dispatch) model of conventional object-oriented programming, where method selection considers only the type of one receiver object.

Multiple dispatch is the central organizing principle of object-oriented programming in [Common Lisp](/wiki/common_lisp)'s [CLOS](/wiki/clos), [Dylan](/wiki/dylan_programming_language), [Julia](/wiki/julia), [Cecil](/wiki/cecil), and several other languages [2][3]. The mechanism addresses the [expression problem](/wiki/expression_problem) that troubles both functional and conventional OO designs, and is especially valuable in scientific computing, [symbolic computation](/wiki/symbolic_computation), [machine learning](/wiki/machine_learning), and AI knowledge representation [4][5]. Julia, released publicly in 2012 and downloaded more than 3 million times across over 1,500 universities by 2018, has popularized multiple dispatch outside the Lisp community by showing that specialization can make multimethods perform comparably to statically dispatched code [4][23].

## What is multiple dispatch?

The word "dispatch" refers to how a language runtime decides which concrete implementation of an operation to invoke. Disciplines differ in two axes: how many arguments participate, and whether the decision is made at compile time or run time.

- **Single dispatch.** The implementation is selected on the type of one privileged "receiver." In Java, C++, [Smalltalk](/wiki/smalltalk), [Python](/wiki/python), and most mainstream OO languages, `obj.method(args)` looks up `method` in a virtual table tied to the runtime class of `obj`. The remaining arguments do not affect which body runs.
- **Multiple dispatch.** The implementation is chosen on the runtime types of two or more arguments simultaneously. There is no privileged receiver; `f(a, b, c)` selects the most specific applicable method given the types of all arguments together.
- **Static overloading.** Languages such as C++ and Java let several functions share a name and disambiguate by parameter types, but the compiler resolves the call against the static types of arguments [6]. Static overloading cannot react to runtime type information, and is therefore a different mechanism.
- **Predicate dispatch.** A generalization in which methods are selected by arbitrary boolean predicates over arguments, not only type tests [7]. Multiple dispatch is the special case where predicates are restricted to type membership.
- **Pattern matching.** A mechanism in [Haskell](/wiki/haskell), Scala, ML, and Rust where function clauses are guarded by structural [pattern matching](/wiki/pattern_matching) on argument shape. It is related but distinct: it dispatches on values and constructors rather than a class hierarchy.

The term "multimethod" was popularized by [CLOS](/wiki/clos) in 1988, although the idea appeared earlier in Xerox PARC's [CommonLoops](/wiki/commonloops) experiment [8][9].

## How is it different from single dispatch?

The difference is which arguments are allowed to influence method selection. Single dispatch uses the runtime type of just the first (receiver) argument; multiple dispatch uses the runtime types of all of the arguments. [Python](/wiki/python) makes the contrast concrete: its standard-library `functools.singledispatch` decorator, introduced by PEP 443 in Python 3.4 (2014), "dispatches on the type of the first argument" only and is therefore single-dispatch, whereas third-party packages such as `multipledispatch` and `multimethod` add true all-argument dispatch [24].

Consider a physics simulation in which two objects collide. The classes are `Asteroid` and `Spaceship`, and `collide(x, y)` produces a different effect depending on which kinds of object collide.

In a single-dispatch language this is awkward. The call `x.collide(y)` selects on the class of `x` only, so the method body must inspect `y` with `instanceof` or `isinstance` checks, or the programmer must encode a [visitor pattern](/wiki/visitor_pattern). Both approaches scale poorly as more classes are added.

In a multiple-dispatch language the four cases are written directly:

```julia
collide(::Asteroid,  ::Asteroid)  = "shatter both"
collide(::Asteroid,  ::Spaceship) = "asteroid impacts hull"
collide(::Spaceship, ::Asteroid)  = "asteroid impacts hull"
collide(::Spaceship, ::Spaceship) = "ships collide"
```

The runtime examines the types of both arguments and selects the matching method. No `if` ladder is needed; adding a new class such as `SpaceStation` only requires new method clauses. Multiple dispatch treats all arguments as equal participants in the dispatch decision.

## The expression problem

In 1998 [Phil Wadler](/wiki/phil_wadler) popularized the term "[expression problem](/wiki/expression_problem)" to describe a long-standing tension in language design [10]. The problem asks how to build a system in which programmers can (1) add new data types, (2) add new operations on those types, (3) without recompiling or modifying existing code, and (4) while retaining static type safety.

Conventional OO makes (1) easy and (2) hard: adding a subclass is local, but adding a new operation requires editing every class. Functional programming organized around algebraic data types and pattern matching has the opposite weakness: a new operation is just a new function, but a new constructor forces every existing function to add a clause.

Multiple dispatch makes both new types and new operations external to existing definitions. A new type can be introduced together with method clauses for any existing generic function, and a new generic function can be introduced together with methods covering any existing types. Neither extension requires modifying the original sources [4][10].

## Which languages support multiple dispatch?

Several languages support multiple dispatch as a first-class feature; many others provide it through libraries.

| Language | Year | Mechanism | Notes |
|---|---|---|---|
| [Common Lisp](/wiki/common_lisp) ([CLOS](/wiki/clos)) | 1988 | `defgeneric`, `defmethod` | Canonical multimethod system with method combination [2] |
| [Dylan](/wiki/dylan_programming_language) | 1992 | Generic functions and methods | Apple project; only OO model [11] |
| [Cecil](/wiki/cecil) | 1992 | Multimethods, predicate guards | Research language by Craig Chambers [7] |
| Diesel | 2002 | Multimethods | Cecil's successor |
| Nice | 1999 | Statically typed multimethods | JVM bytecode |
| [Julia](/wiki/julia) | 2012 | Generic functions, JIT-specialized | Primary paradigm; fast via specialization [4] |
| [Raku](/wiki/raku) ([Perl](/wiki/perl) 6) | 2015 | `multi sub`, `multi method` | Native multi-dispatch on type and arity [12] |
| [Clojure](/wiki/clojure) | 2007 | `defmulti`/[`defmethod`](/wiki/defmulti) | Dispatch on user-defined function [13] |
| [Groovy](/wiki/groovy) | 2003 | Runtime overload resolution | Dynamic dispatch on runtime types |
| [C#](/wiki/c_sharp) | 2010+ | `dynamic` keyword | Multimethod-like since 4.0 [14] |
| [Python](/wiki/python) | n/a | `multimethod`, `multipledispatch` libs | `functools.singledispatch` is single-only [24] |
| [Haskell](/wiki/haskell) | 1990 | [Type classes](/wiki/type_class) | Compile-time, parametric form |
| Tiny CLOS | 1992 | Library | CLOS-style multimethods for Scheme |

Elixir and Erlang dispatch function clauses by pattern matching on values, which is multi-argument and dynamic but not type-driven. Tim Sweeney's game language Skookumchuck, in his 2006 POPL keynote "The Next Mainstream Programming Language," also included multimethod dispatch [15].

## CLOS multimethods

The [CLOS](/wiki/clos) specification by [Daniel Bobrow](/wiki/daniel_bobrow), Linda DeMichiel, Richard Gabriel, Sonya Keene, Gregor Kiczales, and [David Moon](/wiki/david_moon) introduced multimethods to a wide audience of [Common Lisp](/wiki/common_lisp) programmers in 1988 [2]. CLOS treats methods not as belonging to a class but to a generic function, an object holding a collection of methods specialized on tuples of argument types.

The principal forms are `defgeneric`, which declares a generic function, and `defmethod`, which adds a single specialized clause. When the function is called, CLOS computes the **applicable methods** by checking each method's specializers against the actual argument classes, then orders them by specificity using each argument's **class precedence list** (CPL), a linearization of the multiple-inheritance graph. The most specific method runs first, and `call-next-method` chains to the next [16].

CLOS also supports **method combination**. Methods can be qualified `:before`, `:after`, or `:around`, which run unconditionally alongside the primary method. Custom combinations such as `progn`, `+`, `min`, `max`, `append`, and `nconc` let the language combine results from many methods, a feature often used in framework design. A logging `:before` method, for example, runs whenever any specialization of a generic function fires, without modifying the primary methods.

## Why does Julia use multiple dispatch?

In [Julia](/wiki/julia), designed by Jeff Bezanson, [Stefan Karpinski](/wiki/stefan_karpinski), Viral Shah, and Alan Edelman, multiple dispatch is the only object-oriented mechanism the language provides [4]. There are no classes with bound methods. Every function is generic, and the runtime selects a method by examining the concrete types of all positional arguments. Work on the language began in 2009 and the first public release came on 14 February 2012; the four co-creators received the 2019 James H. Wilkinson Prize for Numerical Software for the design [23].

The authors of "Julia: A Fresh Approach to Numerical Computing" frame the language as "a dance between specialization and abstraction," in which "Multiple dispatch, a technique from computer science, picks the right algorithm for the right circumstance" [4]. They argue that "This paradigm is a natural fit for numerical computing, since so many important operations involve interactions among multiple values or entities" [4], for example arithmetic between an integer and a floating-point number, where neither operand is a more natural receiver than the other.

Julia compiles each method specialization to native code on demand using its [JIT compilation](/wiki/jit_compilation) infrastructure built on LLVM. The first call to `f(x::Int, y::Float64)` triggers the compiler to generate a version specialized to those argument types. Later calls with the same signature reuse the compiled method directly, with no dispatch overhead beyond a cached method-table lookup. The dispatch decision is logically dynamic, but the executed code is essentially monomorphized [4].

Methods can be specialized on abstract types, concrete types, parametric types, and type unions. Dispatch operates on positional arguments only, not on keyword arguments, which keeps the method-table semantics tractable.

In his 2019 JuliaCon talk "The Unreasonable Effectiveness of Multiple Dispatch," Karpinski argued that multiple dispatch is unusually effective at enabling **package composability** [5]. Because methods belong to generic functions rather than classes, an unrelated package can extend an existing function with new methods for its own types. A `DataFrame` from one package accepts statistics from another, plotting from a third, and gradient-based optimization from a fourth, without any of those packages having anticipated the others. Karpinski emphasized that this was empirical: the community discovered that multiple dispatch reused existing definitions across packages far more often than the designers had expected.

## How fast is multiple dispatch?

The cost of dispatch depends on how much work the runtime does to pick a method.

- **Compile-time overloading** in C++ and Java is free at run time. The generated code is a direct call.
- **Single dispatch** in conventional VMs is cheap: a virtual call reads a function pointer from a per-class table.
- **Naive multiple dispatch** is more expensive because the system must intersect the applicable-method set across all argument types and order it by specificity. A table indexed by tuples would be exponential in the number of arguments.
- **[Inline caching](/wiki/inline_caching)** mitigates this by remembering, at each call site, the most recent dispatch decision. Most call sites see only a few type combinations, so cache hits avoid the full search.
- **Method specialization** is Julia's approach: the compiler generates separate native code for each combination of types observed at run time, treating each specialization as an independent statically dispatched function [4].
- **Discrimination networks** and tree-shaped lookup are alternatives studied in the CLOS and Cecil communities [7].

CLOS implementations such as SBCL combine generic-function caches with type-discriminating networks, and Julia's specialization makes hot dispatch in numerical code competitive with hand-written C [4].

## How does it compare with related concepts?

| Concept | When resolved | Selection criterion | Typical languages |
|---|---|---|---|
| Single dispatch | Run time | Type of one receiver | [Smalltalk](/wiki/smalltalk), [Java](/wiki/java), Python, Ruby |
| Multiple dispatch | Run time | Tuple of argument types | CLOS, [Dylan](/wiki/dylan_programming_language), Julia |
| [Predicate dispatch](/wiki/predicate_dispatch) | Run time | Arbitrary boolean over arguments | Cecil, Diesel |
| Pattern matching | Compile or run time | Structural shape of values | Haskell, Scala, Rust, ML |
| Type classes / traits | Compile time | Constraints on type parameters | Haskell, Rust |
| [Method overloading](/wiki/method_overloading) | Compile time | Static argument types | [C++](/wiki/c_plus_plus), Java, C# |
| [Visitor pattern](/wiki/visitor_pattern) | Run time | Two indirections through single dispatch | Java, C++ |
| [`defmulti`](/wiki/defmulti) (Clojure) | Run time | Result of arbitrary dispatch function | Clojure |

Multiple dispatch is dynamic, type-driven, and symmetric across arguments. Predicate dispatch is strictly more general but harder to implement efficiently. Pattern matching is comparably expressive but usually closed: each function lists clauses in one place, whereas multimethods can be extended externally. Type classes give similar extensibility at compile time but require the dispatched value's type to be known statically.

## Why is it useful for scientific computing and AI?

Multiple dispatch is a good fit for scientific computing, [symbolic computation](/wiki/symbolic_computation), [machine learning](/wiki/machine_learning), and AI knowledge representation. As the Julia designers note, the paradigm fits numerical work "since so many important operations involve interactions among multiple values or entities" [4].

**Numerical type promotion.** Numerical libraries must handle every combination of argument types (`Int + Float64`, `Rational + Complex`, and so on). With multiple dispatch each combination is one method, and a standard-library promotion mechanism reduces N x N cases to a few base rules. The same is awkward in single-dispatch languages because either `x` or `y` must asymmetrically be the receiver.

**Symbolic algebra.** Computer algebra systems in [Common Lisp](/wiki/common_lisp), Dylan, and Julia express simplification rules as multimethods. `simplify(::Sum, ::Sum)` and `simplify(::Product, ::Sum)` are each separate methods, declared wherever the operator types are defined.

**Composable scientific libraries.** Julia's [`DifferentialEquations.jl`](/wiki/differentialequations_julia), `Flux.jl`, and `JuMP.jl` interoperate without explicit adapters because they extend the same generic functions on shared abstract types. A custom `AbstractMatrix` subtype works with linear solvers, automatic differentiation, and plotting from independent packages [4][5].

**Machine learning and automatic differentiation.** In [machine learning](/wiki/machine_learning) frameworks, multiple dispatch lets a single set of generic operators run unchanged across plain arrays, GPU arrays, and dual numbers carrying derivatives. Julia's `Flux.jl` and the `Zygote`/`ChainRules` autodiff stack rely on this: a new numeric type (for tracking gradients, intervals, or units) becomes differentiable simply by adding methods to existing operators, rather than reimplementing the model [5].

**AI knowledge representation.** [CLOS](/wiki/clos)-based AI systems including [Cyc](/wiki/cyc) and earlier [expert system](/wiki/expert_system) shells use multimethods for inference rules. Adding a new fact type only requires methods for rules that should observe it.

**Domain-specific languages.** Operator overloading combined with multiple dispatch makes it easy to extend arithmetic and comparison operators across user-defined types, heavily used in automatic differentiation, interval arithmetic, and units of measure.

## What are the limitations of multiple dispatch?

Multiple dispatch comes with trade-offs that single-dispatch languages mostly avoid.

- **Larger search space.** Methods are indexed by tuples of types, so candidate signatures grow combinatorially. Programmers must reason about how their methods compose with all others on the same generic function.
- **Method ambiguity.** With multiple inheritance, methods like `f(::A, ::AB)` and `f(::AB, ::A)` can both match `f(ab, ab)`. Julia raises a method-ambiguity error and asks for an explicit tie-breaker `f(::AB, ::AB)`; CLOS uses the class precedence list but can still produce ambiguous orderings [16].
- **Static type checking is harder.** Type inference must reason about the union of all method signatures, and the inferred result type may depend on which method is selected. Cecil and Nice explored sound static type systems for multimethods, often requiring all methods of a generic function to be declared in a single module [7].
- **Discoverability.** In a single-dispatch language a programmer asks "what methods does this class have?" In a multi-dispatch language the question is "what generic functions accept this type?" Julia provides `methodswith` and `which`, and CLOS environments offer similar tools, but newcomers find it harder to navigate large codebases.
- **Tooling and encapsulation.** Rename and find-references are harder when methods are not lexically bound to a class. Single dispatch co-locates data and behavior, doubling as an encapsulation boundary; multiple dispatch separates them, so visibility must be enforced through module systems.

## Historical context

Multiple dispatch did not appear all at once. Its history runs through the [Lisp](/wiki/common_lisp) family and several research projects of the 1980s.

[Symbolics](/wiki/symbolics) [Flavors](/wiki/flavors), the object system used on Lisp machines from the late 1970s, was strictly single-receiver but introduced influential ideas about generic functions, mixins, and method combinations [17]. New Flavors added "daemons" for before- and after-method combinations later generalized by CLOS.

In 1986 [Daniel Bobrow](/wiki/daniel_bobrow) and colleagues at [Xerox PARC](/wiki/xerox_parc) presented [CommonLoops](/wiki/commonloops), the first widely circulated object system to dispatch on multiple arguments [9]. Two years later the merger of CommonLoops, Symbolics's New Flavors, and Lucid's ObjectLisp produced CLOS, codified by the ANSI Common Lisp standard [18]. Guy Steele's *Common Lisp the Language* (second edition, 1990) popularized the design [19].

By the early 1990s Apple had launched [Dylan](/wiki/dylan_programming_language), a CLOS descendant influenced by writing the original Newton software in CLOS, and Craig Chambers at the University of Washington had begun designing [Cecil](/wiki/cecil), a research language using multimethods to investigate static analysis and predicate dispatch [3][7]. Through the 2000s, multiple dispatch was largely confined to research and to the Lisp/Dylan diaspora.

That changed in the 2010s with [Julia](/wiki/julia), which made multiple dispatch the foundation of a numerically focused language with a working JIT compiler [4]. Julia has since become the largest user community for multiple dispatch, reviving interest in the Python scientific stack and Clojure.

Giovanni Castagna's 1995 paper "Covariance and contravariance: conflict without a cause" formalized how subtyping interacts with multimethod selection [6]. Scheme has long supported library-level multimethods through Tiny CLOS [20]; the [homoiconicity](/wiki/homoiconicity) of Lisp dialects made it easy to retrofit multimethod systems as user-level macros, and earlier work by Steele and [Gerald Sussman](/wiki/gerald_sussman) on first-class procedures laid groundwork for the study of generic functions.

## Code examples

The following fragments express the same `collide(a, b)` multimethod in several languages.

**Common Lisp / CLOS.**

```lisp
(defgeneric collide (a b))
(defmethod collide ((a asteroid)  (b asteroid))  "shatter both")
(defmethod collide ((a asteroid)  (b spaceship)) "asteroid impacts hull")
(defmethod collide ((a spaceship) (b asteroid))  "asteroid impacts hull")
(defmethod collide ((a spaceship) (b spaceship)) "ships collide")
```

**Clojure**, dispatching on a vector of class symbols.

```clojure
(defmulti collide (fn [a b] [(class a) (class b)]))
(defmethod collide [Asteroid  Spaceship] [_ _] "asteroid impacts hull")
(defmethod collide [Spaceship Spaceship] [_ _] "ships collide")
```

**Python** with the third-party `multimethod` package.

```python
from multimethod import multimethod

@multimethod
def collide(a: Asteroid, b: Spaceship): return "asteroid impacts hull"
@multimethod
def collide(a: Spaceship, b: Spaceship): return "ships collide"
```

**C#** uses the `dynamic` keyword to defer overload resolution to run time, the idiomatic multimethod-like dispatch in C# 4.0 and later [14].

```csharp
string Collide(Asteroid a, Spaceship b)  => "asteroid impacts hull";
string Collide(Spaceship a, Spaceship b) => "ships collide";

dynamic x = ..., y = ...;
var result = Collide(x, y);  // resolved at run time on actual types
```

**Raku** (Perl 6).

```raku
multi collide(Asteroid  $a, Spaceship $b) { "asteroid impacts hull" }
multi collide(Spaceship $a, Spaceship $b) { "ships collide" }
```

All forms compile to a runtime selection on the types of both arguments. They differ in syntax and in the dispatch machinery but share the same conceptual content.

## ELI5: Multiple dispatch in one picture

Imagine a rule that says what happens when two things bump into each other. With **single dispatch**, only the first thing gets a say: the asteroid decides what "bump" means and then has to look at the other object to figure out the rest. With **multiple dispatch**, both things vote at the same time. "Asteroid plus spaceship" is one rule, "spaceship plus spaceship" is another rule, and the computer simply looks at the pair and runs the matching rule. Nobody is the boss; the combination chooses the behavior.

## See also

- [Single dispatch](/wiki/single_dispatch), [Dynamic dispatch](/wiki/dynamic_dispatch), [Static dispatch](/wiki/static_dispatch), [Method overloading](/wiki/method_overloading)
- [Predicate dispatch](/wiki/predicate_dispatch), [Pattern matching](/wiki/pattern_matching), [Visitor pattern](/wiki/visitor_pattern), [Type class](/wiki/type_class)
- [Expression problem](/wiki/expression_problem), [CLOS](/wiki/clos), [Common Lisp](/wiki/common_lisp), [Dylan](/wiki/dylan_programming_language), [Julia](/wiki/julia), [Clojure](/wiki/clojure)

## References

1. Wikipedia, "Multiple dispatch." https://en.wikipedia.org/wiki/Multiple_dispatch
2. Bobrow, D. G., DeMichiel, L. G., Gabriel, R. P., Keene, S. E., Kiczales, G., & Moon, D. A. (1988). "Common Lisp Object System Specification." *SIGPLAN Notices* 23(SI), 1-142. https://dl.acm.org/doi/10.1145/885631.885633
3. Shalit, A. (1996). *The Dylan Reference Manual*. Apple / Addison-Wesley. https://opendylan.org/books/drm/
4. Bezanson, J., Edelman, A., Karpinski, S., & Shah, V. B. (2017). "Julia: A Fresh Approach to Numerical Computing." *SIAM Review* 59(1), 65-98. https://epubs.siam.org/doi/10.1137/141000671
5. Karpinski, S. (2019). "The Unreasonable Effectiveness of Multiple Dispatch." JuliaCon 2019. https://www.youtube.com/watch?v=kc9HwsxE1OY
6. Castagna, G. (1995). "Covariance and contravariance: conflict without a cause." *ACM TOPLAS* 17(3), 431-447. https://dl.acm.org/doi/10.1145/203095.203096
7. Chambers, C. (1992). "Object-Oriented Multi-Methods in Cecil." *ECOOP '92*. https://link.springer.com/chapter/10.1007/BFb0053029
8. Holst, K. M., & Bobrow, D. G. (1989). "Dispatch on Multiple Argument Types in Object-Oriented Programming." Xerox PARC technical report.
9. Bobrow, D. G., Kahn, K., Kiczales, G., Masinter, L., Stefik, M., & Zdybel, F. (1986). "CommonLoops: Merging Lisp and Object-Oriented Programming." *OOPSLA '86*. https://dl.acm.org/doi/10.1145/28697.28700
10. Wadler, P. (1998). "The Expression Problem." https://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt
11. Apple Computer (1992). *Dylan: An Object-Oriented Dynamic Language*. Apple Technical Publications.
12. Raku Documentation, "Multi-dispatch." https://docs.raku.org/language/functions#Multi-dispatch
13. Hickey, R. "Multimethods and Hierarchies." *Clojure documentation*. https://clojure.org/reference/multimethods
14. Microsoft, "Using type dynamic." *C# Programming Guide*. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic
15. Sweeney, T. (2006). "The Next Mainstream Programming Language: A Game Developer's Perspective." POPL keynote. https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/sweeny.pdf
16. Keene, S. E. (1989). *Object-Oriented Programming in Common Lisp: A Programmer's Guide to CLOS*. Addison-Wesley.
17. Cannon, H. I. (1982). "Flavors: A Non-Hierarchical Approach to Object-Oriented Programming." Symbolics technical report.
18. ANSI INCITS 226-1994 (R2004), "American National Standard for Information Systems: Programming Language Common Lisp."
19. Steele, G. L. (1990). *Common Lisp the Language*, 2nd edition. Digital Press. https://www.cs.cmu.edu/Groups/AI/html/cltl/cltl2.html
20. Kiselyov, O. "Tiny CLOS for Scheme." https://okmij.org/ftp/Scheme/index.html#tiny-clos
21. Ernst, M., Kaplan, C., & Chambers, C. (1998). "Predicate Dispatching: A Unified Theory of Dispatch." *ECOOP '98*. https://link.springer.com/chapter/10.1007/BFb0054099
22. Julia Documentation, "Methods." https://docs.julialang.org/en/v1/manual/methods/
23. MIT News (2018). "MIT-created programming language Julia 1.0 debuts." https://news.mit.edu/2018/mit-developed-julia-programming-language-debuts-juliacon-0827
24. Coghlan, N. (2013). "PEP 443: Single-dispatch generic functions." Python Enhancement Proposals. https://peps.python.org/pep-0443/

