Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Multiple dispatch
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
=== Languages with built-in multiple dispatch === ==== C# ==== [[C Sharp (programming language)|C#]] introduced support for dynamic multimethods in version 4<ref>{{cite web |url=https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic |title=Using type dynamic (C# Programming Guide) |access-date=2020-05-14 }}</ref> (April 2010) using the 'dynamic' keyword. The following example demonstrates multimethods. Like many other statically-typed languages, C# also supports static method overloading.<ref>{{cite web |url=https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/basic-concepts#signatures-and-overloading |title=Basic concepts |access-date=2020-05-14 }}</ref> Microsoft expects that developers will choose static typing over dynamic typing in most scenarios.<ref>{{cite web |url=https://docs.microsoft.com/en-us/archive/msdn-magazine/2011/february/msdn-magazine-dynamic-net-understanding-the-dynamic-keyword-in-csharp-4 |title=Dynamic .NET - Understanding the Dynamic Keyword in C# 4 |date=10 August 2015 |access-date=2020-05-14 }}</ref> The 'dynamic' keyword supports interoperability with COM objects and dynamically-typed .NET languages. [[File:Csharp ColliderLibrary.svg]] The example below uses features introduced in C# 9 and C# 10. <syntaxhighlight lang="c#"> using static ColliderLibrary; Console.WriteLine(Collide(new Asteroid(101), new Spaceship(300))); Console.WriteLine(Collide(new Asteroid(10), new Spaceship(10))); Console.WriteLine(Collide(new Spaceship(101), new Spaceship(10))); string Collide(SpaceObject x, SpaceObject y) => x.Size > 100 && y.Size > 100 ? "Big boom!" : CollideWith(x as dynamic, y as dynamic); // Dynamic dispatch to CollideWith method class ColliderLibrary { public static string CollideWith(Asteroid x, Asteroid y) => "a/a"; public static string CollideWith(Asteroid x, Spaceship y) => "a/s"; public static string CollideWith(Spaceship x, Asteroid y) => "s/a"; public static string CollideWith(Spaceship x, Spaceship y) => "s/s"; } abstract record SpaceObject(int Size); record Asteroid(int Size) : SpaceObject(Size); record Spaceship(int Size) : SpaceObject(Size); </syntaxhighlight> Output: <syntaxhighlight lang="output"> Big boom! a/s s/s </syntaxhighlight> ==== Groovy ==== [[Apache Groovy|Groovy]] is a general purpose [[Java (programming language)|Java]] compatible/interusable [[Java virtual machine|JVM]] language, which, contrary to Java, uses late binding / multiple dispatch.<ref>[https://groovy-lang.org/differences.html#_multi_methods Groovy - Multi-methods]</ref> <syntaxhighlight lang="groovy"> /* Groovy implementation of C# example above Late binding works the same when using non-static methods or compiling class/methods statically (@CompileStatic annotation) */ class Program { static void main(String[] args) { println Collider.collide(new Asteroid(101), new Spaceship(300)) println Collider.collide(new Asteroid(10), new Spaceship(10)) println Collider.collide(new Spaceship(101), new Spaceship(10)) } } class Collider { static String collide(SpaceObject x, SpaceObject y) { (x.size > 100 && y.size > 100) ? "big-boom" : collideWith(x, y) // Dynamic dispatch to collideWith method } private static String collideWith(Asteroid x, Asteroid y) { "a/a" } private static String collideWith(Asteroid x, Spaceship y) { "a/s" } private static String collideWith(Spaceship x, Asteroid y) { "s/a" } private static String collideWith(Spaceship x, Spaceship y) { "s/s"} } class SpaceObject { int size SpaceObject(int size) { this.size = size } } @InheritConstructors class Asteroid extends SpaceObject {} @InheritConstructors class Spaceship extends SpaceObject {} </syntaxhighlight> ==== Common Lisp ==== In a language with multiple dispatch, such as [[Common Lisp]], it might look more like this (Common Lisp example shown): <syntaxhighlight lang="lisp"> (defclass asteroid () ((size :reader size :initarg :size))) (defclass spaceship () ((size :reader size :initarg :size))) (defun space-object (class size) (make-instance class :size size)) ; collide-with is a generic function with multiple dispatch (defmethod collide-with ((x asteroid) (y asteroid)) "a/a") (defmethod collide-with ((x asteroid) (y spaceship)) "a/s") (defmethod collide-with ((x spaceship) (y asteroid)) "s/a") (defmethod collide-with ((x spaceship) (y spaceship)) "s/s") (defun collide (x y) (if (and (> (size x) 100) (> (size y) 100)) "big-boom" (collide-with x y))) (print (collide (space-object 'asteroid 101) (space-object 'spaceship 300))) (print (collide (space-object 'asteroid 10) (space-object 'spaceship 10))) (print (collide (space-object 'spaceship 101) (space-object 'spaceship 10))) </syntaxhighlight> and similarly for the other methods. Explicit testing and "dynamic casting" are not used. In the presence of multiple dispatch, the traditional idea of methods as being defined in classes and contained in objects becomes less appealing—each ''collide-with'' method above is attached to two different classes, not one. Hence, the special syntax for method invocation generally disappears, so that method invocation looks exactly like ordinary function invocation, and methods are grouped not in classes but in [[generic function]]s. ==== Julia ==== [[Julia (programming language)|Julia]] has built-in multiple dispatch, and it is central to the language design.<ref name=julia-review>{{cite journal |last1=Bezanson |first1=Jeff |last2=Edelman |first2=Alan |last3=Karpinski |first3=Stefan |last4=Shah |first4=Viral B. |title=Julia: A fresh approach to numerical computing |journal=SIAM Review |volume=59 |issue=1 |pages=65–98 |date=7 February 2017 |doi=10.1137/141000671 |arxiv=1411.1607|s2cid=13026838 }}</ref> The Julia version of the example above might look like: <syntaxhighlight lang="julia"> abstract type SpaceObject end struct Asteroid <: SpaceObject size::Int end struct Spaceship <: SpaceObject size::Int end collide_with(::Asteroid, ::Spaceship) = "a/s" collide_with(::Spaceship, ::Asteroid) = "s/a" collide_with(::Spaceship, ::Spaceship) = "s/s" collide_with(::Asteroid, ::Asteroid) = "a/a" collide(x::SpaceObject, y::SpaceObject) = (x.size > 100 && y.size > 100) ? "Big boom!" : collide_with(x, y) </syntaxhighlight> Output: <syntaxhighlight lang="julia-repl"> julia> collide(Asteroid(101), Spaceship(300)) "Big boom!" julia> collide(Asteroid(10), Spaceship(10)) "a/s" julia> collide(Spaceship(101), Spaceship(10)) "s/s" </syntaxhighlight> ==== Raku ==== [[Raku (programming language)|Raku]], like Perl, uses proven ideas from other languages, and type systems have shown themselves to offer compelling advantages in compiler-side code analysis and powerful user-side semantics via multiple dispatch. It has both multimethods, and multisubs. Since most operators are subroutines, it also has multiple dispatched operators. Along with the usual type constraints, it also has ''where'' constraints that allow making very specialized subroutines. <syntaxhighlight lang="raku"> subset Mass of Real where 0 ^..^ Inf; role Stellar-Object { has Mass $.mass is required; method name () returns Str {...}; } class Asteroid does Stellar-Object { method name () { 'an asteroid' } } class Spaceship does Stellar-Object { has Str $.name = 'some unnamed spaceship'; } my Str @destroyed = < obliterated destroyed mangled >; my Str @damaged = « damaged 'collided with' 'was damaged by' »; # We add multi candidates to the numeric comparison operators because we are comparing them numerically, # but makes no sense to have the objects coerce to a Numeric type. # ( If they did coerce we wouldn't necessarily need to add these operators. ) # We could have also defined entirely new operators this same way. multi sub infix:« <=> » ( Stellar-Object:D $a, Stellar-Object:D $b ) { $a.mass <=> $b.mass } multi sub infix:« < » ( Stellar-Object:D $a, Stellar-Object:D $b ) { $a.mass < $b.mass } multi sub infix:« > » ( Stellar-Object:D $a, Stellar-Object:D $b ) { $a.mass > $b.mass } multi sub infix:« == » ( Stellar-Object:D $a, Stellar-Object:D $b ) { $a.mass == $b.mass } # Define a new multi dispatcher, and add some type constraints to the parameters. # If we didn't define it we would have gotten a generic one that didn't have constraints. proto sub collide ( Stellar-Object:D $, Stellar-Object:D $ ) {*} # No need to repeat the types here since they are the same as the prototype. # The 'where' constraint technically only applies to $b not the whole signature. # Note that the 'where' constraint uses the `<` operator candidate we added earlier. multi sub collide ( $a, $b where $a < $b ) { say "$a.name() was @destroyed.pick() by $b.name()"; } multi sub collide ( $a, $b where $a > $b ) { # redispatch to the previous candidate with the arguments swapped samewith $b, $a; } # This has to be after the first two because the other ones # have 'where' constraints, which get checked in the # order the subs were written. ( This one would always match. ) multi sub collide ( $a, $b ) { # randomize the order my ($n1, $n2) = ( $a.name, $b.name ).pick(*); say "$n1 @damaged.pick() $n2"; } # The following two candidates can be anywhere after the proto, # because they have more specialized types than the preceding three. # If the ships have unequal mass one of the first two candidates gets called instead. multi sub collide ( Spaceship $a, Spaceship $b where $a == $b ){ my ($n1, $n2) = ( $a.name, $b.name ).pick(*); say "$n1 collided with $n2, and both ships were ", ( @destroyed.pick, 'left damaged' ).pick; } # You can unpack the attributes into variables within the signature. # You could even have a constraint on them `(:mass($a) where 10)`. multi sub collide ( Asteroid $ (:mass($a)), Asteroid $ (:mass($b)) ){ say "two asteroids collided and combined into one larger asteroid of mass { $a + $b }"; } my Spaceship $Enterprise .= new(:mass(1),:name('The Enterprise')); collide Asteroid.new(:mass(.1)), $Enterprise; collide $Enterprise, Spaceship.new(:mass(.1)); collide $Enterprise, Asteroid.new(:mass(1)); collide $Enterprise, Spaceship.new(:mass(1)); collide Asteroid.new(:mass(10)), Asteroid.new(:mass(5)); </syntaxhighlight>
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)