Multi Dispatch
2026-03-27
Multi dispatch is one of Raku's most distinctive features. Instead of writing one function with a tangle of conditionals, you write multiple variants of the same function, each handling a specific case. Raku picks the right one at call time based on the arguments you pass.
Multi Subs
Declare multiple variants of a sub using the multi keyword:
multi sub greet(Str $name) {
say "Hello, $name!";
}
multi sub greet(Str $name, Int $times) {
say "Hello, $name!" for ^$times;
}
multi sub greet() {
say "Hello, stranger!";
}
greet("Alice");
greet("Bob", 3);
greet();
Raku examines the number and types of arguments and dispatches to the most specific matching candidate.
Type-Based Dispatch
The real power comes from dispatching on types:
multi sub describe(Int $n) {
say "$n is an integer";
}
multi sub describe(Str $s) {
say "'$s' is a string of {$s.chars} characters";
}
multi sub describe(Array $a) {
say "An array with {$a.elems} elements";
}
multi sub describe(Hash $h) {
say "A hash with {$h.keys.elems} keys";
}
describe(42);
describe("hello");
describe([1, 2, 3]);
describe({a => 1, b => 2});# A hash with 2 keys
Where Clauses
Add where constraints for even more specific dispatch:
multi sub classify(Int $n where * > 0) { say "$n is positive" }
multi sub classify(Int $n where * < 0) { say "$n is negative" }
multi sub classify(Int $n where 0) { say "zero" }
classify(42);
classify(-7);
classify(0);
multi sub fizzbuzz(Int $n where * %% 15) { "FizzBuzz" }
multi sub fizzbuzz(Int $n where * %% 3) { "Fizz" }
multi sub fizzbuzz(Int $n where * %% 5) { "Buzz" }
multi sub fizzbuzz(Int $n) { ~$n }
say (1..20).map(&fizzbuzz).join(", ");
Multi Methods
Multi dispatch works with methods too:
class Shape {
multi method area(Shape:U:) {
say "Call area on a specific shape instance";
}
}
class Circle is Shape {
has $.radius;
multi method area() {
pi * $!radius ** 2
}
}
class Rectangle is Shape {
has $.width;
has $.height;
multi method area() {
$!width * $!height
}
}
my @shapes = Circle.new(radius => 5), Rectangle.new(width => 3, height => 4);
for @shapes -> $s {
say "{$s.^name}: {$s.area}";
}
Dispatch Order
Raku tries the most specific candidate first. Specificity is determined by:
- Number of parameters
- Type constraints (more specific types win)
- Where clauses (add specificity)
multi sub process(Any $x) { say "Any: $x" }
multi sub process(Numeric $x) { say "Numeric: $x" }
multi sub process(Int $x) { say "Int: $x" }
multi sub process(Int $x where * > 100) { say "Big Int: $x" }
process("hello");
process(3.14);
process(42);
process(200);
Pattern Matching with Multi
Multi dispatch gives you pattern matching for free:
multi sub fact(0) { 1 }
multi sub fact(Int $n where * > 0) { $n * fact($n - 1) }
say fact(10);
multi sub fib(0) { 0 }
multi sub fib(1) { 1 }
multi sub fib(Int $n where * > 1) { fib($n - 1) + fib($n - 2) }
say fib(10);
This reads like a mathematical definition.
Multi and Coercion
You can use multi dispatch to handle type coercion cleanly:
multi sub to-number(Str $s) { $s.Numeric }
multi sub to-number(Numeric $n) { $n }
multi sub to-number(Bool $b) { $b ?? 1 !! 0 }
say to-number("42");
say to-number(3.14);
say to-number(True);
Proto Declarations
A proto declaration constrains all multi variants:
proto sub temperature(Str $scale, Numeric $degrees --> Str) {*}
multi sub temperature('C', Numeric $c) {
"{ $c * 9/5 + 32 }F"
}
multi sub temperature('F', Numeric $f) {
"{ ($f - 32) * 5/9 }C"
}
multi sub temperature('K', Numeric $k) {
"{ $k - 273.15 }C"
}
say temperature('C', 100);
say temperature('F', 32);
say temperature('K', 373.15);# 100C
The {*} in the proto body means "dispatch to the appropriate multi candidate."
Practical Example: Command Dispatcher
class CLI {
multi method run('help') {
say "Available commands: help, list, add, remove";
}
multi method run('list') {
say "Listing all items...";
}
multi method run('add', Str $item) {
say "Adding: $item";
}
multi method run('remove', Str $item) {
say "Removing: $item";
}
multi method run(Str $cmd, *@args) {
say "Unknown command: $cmd";
}
}
my $cli = CLI.new;
$cli.run('help');
$cli.run('add', 'milk');
$cli.run('remove', 'bread');
$cli.run('frobnicate');
Nextsame and Nextwith
Inside a multi candidate, you can delegate to the next matching candidate:
multi sub log-it(Str $msg) {
note "[LOG] $msg";
}
multi sub log-it(Str $msg where *.contains('ERROR')) {
note "[!!!] ALERT: error detected";
nextsame;
}
log-it("all good");
log-it("ERROR: disk full");
Multi dispatch eliminates large if/elsif chains, makes code self-documenting, and lets Raku optimize dispatch for you. It is one of the features that makes Raku uniquely expressive.