Beginner

Operators in Raku

Explore arithmetic, comparison, logical, assignment, and string operators in Raku, plus unique features like chained comparisons, junctions, and smart matching

Operators are the verbs of a programming language—they take values and combine them into new ones. Raku has one of the richest operator vocabularies of any language, including familiar arithmetic and comparison operators alongside unusual ones like the three-way comparison <=>, the defined-or //, and junction operators that let a single value be “any of these” at once.

Because Raku is a multi-paradigm language with gradual typing, its operators are carefully separated by purpose. Numeric comparisons (==, <, >) are distinct from string comparisons (eq, lt, gt), so the language never has to guess what you meant. This is a deliberate departure from Perl 5’s context-driven behavior, and it makes Raku code easier to reason about.

In this tutorial you’ll work through arithmetic, comparison, logical, assignment, and string operators, then explore a few operators that are distinctly Raku: chained comparisons, the smart-match operator ~~, and junctions. Every example is runnable with Docker.

Arithmetic Operators

Raku’s arithmetic operators include the usual suspects plus a couple of distinctions worth knowing. The / operator produces an exact rational number (a Rat), not a truncated integer, while div performs integer division and mod gives the integer remainder.

Create a file named arithmetic.raku:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
my $a = 17;
my $b = 5;

say $a + $b;    # addition
say $a - $b;    # subtraction
say $a * $b;    # multiplication
say $a / $b;    # division (exact rational)
say $a % $b;    # modulo (remainder)
say $a ** $b;   # exponentiation
say $a div $b;  # integer division
say $a mod $b;  # integer modulo

Notice that 17 / 5 yields 3.4 exactly—Raku stores it as a rational rather than a lossy floating-point value. Use div when you specifically want integer division.

Comparison and Logical Operators

Raku splits comparison into numeric and string families. Numeric operators are the symbolic ones (==, !=, <, >, <=, >=), and string operators are spelled out (eq, ne, lt, gt, le, ge). The three-way operators <=> (numeric) and cmp (generic) return an Order value of Less, Same, or More.

Create a file named comparison.raku:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
say 5 == 5;      # numeric equality
say 5 != 3;      # numeric inequality
say 5 < 10;      # less than
say 5 >= 5;      # greater than or equal

# Three-way comparison returns an Order
say 3 <=> 7;     # numeric spaceship
say 7 <=> 3;
say 5 <=> 5;

# String comparison operators
say "apple" eq "apple";   # string equality
say "apple" lt "banana";  # string less than
say "cat" cmp "car";      # generic three-way

# Logical operators
say True && False;   # logical AND
say True || False;   # logical OR
say !True;           # logical NOT

# Chained comparisons (a Raku feature)
say 1 < 2 < 3;       # reads like math
say 1 < 5 < 3;

The chained comparison 1 < 2 < 3 is genuine mathematical notation—Raku evaluates it as 1 < 2 && 2 < 3 without you having to spell it out.

Assignment Operators

Every binary operator in Raku has a corresponding assignment form built by appending =. The string concatenation operator ~ becomes ~=, and the defined-or operator // becomes //=, which assigns only when the variable is currently undefined.

Create a file named assignment.raku:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
my $n = 10;
$n += 5;    say $n;   # add and assign
$n -= 3;    say $n;   # subtract and assign
$n *= 2;    say $n;   # multiply and assign
$n /= 4;    say $n;   # divide and assign
$n **= 2;   say $n;   # exponentiate and assign

# String concatenation assignment
my $greeting = "Hello";
$greeting ~= ", World!";
say $greeting;

# Defined-or assignment: only sets when undefined
my $value;
$value //= "default";
say $value;

The //= operator is especially handy for supplying defaults: it leaves a defined value untouched but fills in undefined ones.

String and List Operators

Raku uses ~ for string concatenation (not +, which is strictly numeric), x for string repetition, and xx for list repetition. Ranges are built with .., and the smart-match operator ~~ tests whether a value matches a type, range, or regex.

Create a file named string_ops.raku:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Concatenation with ~
my $first = "Code";
my $second = "Archaeology";
say $first ~ $second;

# String repetition with x
say "=" x 10;

# List repetition with xx
say (0 xx 5);

# Ranges with ..
say (1..5);              # a Range object
say (1..5).list;         # expanded to a list
say (1..5).sum;          # summed

# Smart match with ~~
say 5 ~~ Int;            # type match
say 5 ~~ 1..10;          # range match
say "hello" ~~ /ell/;    # regex match

The smart-match operator adapts to whatever is on its right side: a type check against Int, a membership test against a range, or a pattern match against a regex. The regex match returns a Match object, which prints with corner brackets around the matched text.

Precedence and Junctions

Raku follows conventional precedence: exponentiation binds tightest, then multiplication and division, then addition and subtraction. Parentheses override the defaults. Raku also offers junctions—values built with | (any), & (all), or ^ (one)—that let a single comparison test against multiple possibilities at once.

Create a file named precedence.raku:

1
2
3
4
5
6
7
8
9
# Standard precedence: ** before * before +
say 2 + 3 * 4;        # multiplication first
say 2 + 3 * 4 ** 2;   # exponentiation first, then multiply
say (2 + 3) * 4;      # parentheses override

# Junctions: one value, many possibilities
my $x = 1 | 2 | 3;    # an "any" junction
say so $x == 2;       # True if any matches
say so 5 == (1 | 2);  # False if none match

The junction 1 | 2 | 3 behaves like all three values simultaneously. Comparing it with == 2 succeeds because one branch matches. The so operator collapses the resulting junction down to a single Bool.

Running with Docker

1
2
3
4
5
6
7
8
9
# Pull the official Rakudo Star image
docker pull rakudo-star:alpine

# Run each example
docker run --rm -v $(pwd):/app -w /app rakudo-star:alpine raku arithmetic.raku
docker run --rm -v $(pwd):/app -w /app rakudo-star:alpine raku comparison.raku
docker run --rm -v $(pwd):/app -w /app rakudo-star:alpine raku assignment.raku
docker run --rm -v $(pwd):/app -w /app rakudo-star:alpine raku string_ops.raku
docker run --rm -v $(pwd):/app -w /app rakudo-star:alpine raku precedence.raku

Expected Output

# arithmetic.raku
22
12
85
3.4
2
1419857
3
2

# comparison.raku
True
True
True
True
Less
More
Same
True
True
More
False
True
False
True
False

# assignment.raku
15
12
24
6
36
Hello, World!
default

# string_ops.raku
CodeArchaeology
==========
(0 0 0 0 0)
1..5
(1 2 3 4 5)
15
True
True
「ell」

# precedence.raku
14
50
20
True
False

Key Concepts

  • Numeric vs. string operators are separate: use ==/</> for numbers and eq/lt/gt for strings—Raku never guesses which you meant.
  • / returns an exact rational (Rat), so 17 / 5 is 3.4 precisely; use div and mod for integer division and remainder.
  • ~ is concatenation, x repeats strings, xx repeats lists—string joining never overloads the numeric +.
  • Three-way operators (<=> for numbers, cmp for anything) return an Order of Less, Same, or More, ideal for sorting.
  • Chained comparisons like 1 < 2 < 3 work as written, matching mathematical notation.
  • The smart-match operator ~~ flexibly tests values against types, ranges, and regexes.
  • // and //= test definedness rather than truth, making them perfect for supplying defaults without clobbering a valid 0 or empty string.
  • Junctions (|, &, ^) let one value stand for many, so a single comparison can test against several possibilities at once.

Running Today

All examples can be run using Docker:

docker pull rakudo-star:alpine
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining