Variables and Types in Raku
Learn how Raku uses sigils, gradual typing, type coercion, constants, and constrained subsets to describe data with elegance and precision.
Raku approaches variables differently from most languages you may have seen. Rather than variable type determining the sigil (as in Perl 5), Raku uses sigils to identify the kind of container a name refers to: a scalar, an array, a hash, or a callable. The actual type of the value inside can be constrained separately — or left entirely flexible.
This freedom is a direct consequence of Raku’s gradual typing model. A variable can be fully dynamic (no type annotation), partially typed, or fully constrained with a user-defined subset. Whichever style you choose, the runtime enforces the constraints you opt into. Raku also distinguishes between several numeric types — most notably Int (arbitrary precision integers), Rat (exact rationals), and Num (double-precision floats) — giving you more accurate arithmetic than many mainstream languages provide out of the box.
In this tutorial you’ll learn how to declare variables with my, how the sigil system works across container types, how to constrain variables with type annotations and subsets, how to convert between types via coercion methods, and how Raku represents “no value yet” using type objects.
Sigils and Basic Variables
Raku has four sigils, each indicating a different container:
$— scalar (one value)@— positional (ordered collection)%— associative (keyed collection)&— callable (a function or block)
Unlike Perl 5, the sigil stays the same whether you access the whole container or a single element: @languages[0], not $languages[0].
Create a file named variables.raku:
| |
A few things worth noticing:
myintroduces a lexically scoped variable — the most common declarator.- Inside double-quoted strings,
@array[]interpolates the whole array separated by spaces, and%hash<key>interpolates a specific value. - Use
{ ... }inside a string to interpolate any expression, like a method call or arithmetic. - The
&sigil lets you store and call functions as values —doubler(7)invokes the block.
Typed Variables, Conversions, and Constraints
Raku’s gradual typing means you can opt into as much type discipline as you like. Add a type name between my and the variable to enforce that constraint at runtime. You can also define entirely new constrained types using subset.
Create a file named types.raku:
| |
Some important ideas on display here:
.WHATreturns the type object of a value, and.^nameasks the metaclass for its textual name — a common idiom for inspecting types at runtime.- The coercion methods (
.Int,.Num,.Str,.so,.Bool) are the standard way to convert values. They’re just methods on every type, not special syntax. Ratpreserves exact rational values —1/4stays exactly0.25, not a floating-point approximation.constantproduces a true compile-time binding. Constants have no sigil and cannot be reassigned.subset T of BaseType where CONDITIONdefines a new type that the runtime will check on assignment. Assigning a value that fails thewhereclause throws a type error.- When you declare
my Int $x;without a value, the variable holds theInttype object — an undefined value still tagged with a type. Use.definedto tell a value from a type object.
Running with Docker
| |
Expected Output
Running variables.raku:
Name: Camelia
Year: 2015
Pi: 3.14
Active: True
Languages: Perl Raku Python
First: Perl
Count: 3
Raku is version 6
Keys: Perl Python Raku
Double of 7: 14
Running types.raku:
count (Int): 42
greeting (Str): Hello
fraction (Rat): 0.25
ready (Bool): True
"123".Int = 123 (now Int)
"2.5".Num = 2.5
42.Str = "42" (now Str)
0.so = False
1.so = True
PI = 3.14159
GREETING = Hello, World!
age = 30 (constrained to positive integers)
code = RAKU (constrained to max 5 chars)
maybe defined? False
maybe type: Any
typed_maybe defined? False
typed_maybe type: Int
Key Concepts
- Sigils describe containers, not value types —
$,@,%,&stay the same whether you access the whole container or a single element. - Gradual typing — add a type name between
myand the variable when you want the runtime to enforce a constraint; omit it for fully dynamic behavior. - Coercion is method-based —
.Int,.Str,.Num,.Bool,.soconvert between types without special cast syntax. Int,Rat, andNumare distinct —Intis arbitrary-precision,Ratkeeps exact fractions, andNumis double-precision floating point. Choose deliberately.constantfor compile-time bindings — constants use no sigil and are fixed at declaration time.subsetcreates validated types — combine a base type with awhereclause to define custom constraints the runtime enforces on every assignment.- Type objects stand in for “undefined” — an unset typed variable holds the type object itself; use
.definedto check whether a real value is present. - Expression interpolation with
{ }— inside double-quoted strings, any Raku expression can be embedded in curly braces, including method calls and arithmetic.
Running Today
All examples can be run using Docker:
docker pull rakudo-star:alpine
Comments
Loading comments...
Leave a Comment