Raku by Example: Types

Raku is a gradually typed language which means a variable can be either untyped or typed. If untyped, the variable can store data of different types. If typed, the variable can only store values of that type. In Raku, a type defines a new object by creating a type object that provides an interface to create instances of objects or to check values against.

Raku is also object oriented to the core and there is a class (or role) for any construct you might find yourself working with. Some of the most commonplace types are:

  • Str for string of characters.
  • Int for integer (arbitrary-precision).
  • UInt for unsigned integer (arbitrary-precision).
  • Rat for rational number (limited-precision).
  • Num for floating-point number.
  • Complex for complex numbers.
  • Bool for boolean values.
  • Sub for subroutines.
  • Signature for the parameter list pattern
  • Capture for argument list suitable for passing to a Signature.
  • Nil for absence of a value or a benign failure.
say 12;               # Int
say 'Hi';             # Str
say ½;                # Rat
say 12.5;             # Rat
say 2e0;              # Num
say 3+i;              # Complex
say sub { "Hi" }();   # Sub
say True              # Bool
$ perl6 type01.p6
12
Hi
0.5
12.5
2
Hi
True

One way of declaring a variable of a certain type is to place the type between the declarator (my, our, etc.) and the variable name:

my Str $person = "Heya";
my Int $age    = 25;

say "Name: ", $name;
say "Age: ", $age;

# Assigning a different type will cause a type check failure at runtime
$person = 23;
$ perl6 type02.p6
Name: Heya
Age: 25
Type check failed in assignment to $person; expected Str but got Int (23)

To find out the type of an object, use the .^name method on the object:

my $greet = "Hi";
my $num   = 2;
my $bool  = True;

say $greet.^name;  # returns `Str`, the type of the string 'Hi'
say $num.^name;    # returns `Int`, the type of the integer 2
say $bool.^name;   # returns `Bool`, the type of the boolean True
say 'Hi' ~~ Str;   # smartmatching against a type
say 'Hi' ~~ Int;   # same as above
$ perl6 type03.p6 
Str
Int
Bool
True
False

Smartmatching (through the ~~ operator) against a type smiley (either :D for defined values or :U for undefined values) will let you know if a particular invocant is a type object (:U) or an instance object (:D) of a certain type. The default type smiley is :_.

say 2 ~~ Int:D;   # `True` because 2 is an instance of the `Int` type
say 2 ~~ Int:U;   # `False` because 2 isn't a type object

say Int ~~ Int:D; # `False` because `Int` isn't an instance object
say Int ~~ Int:U; # `True` because `Int` is type object

say 2 ~~ Int:_;   # same as `2 ~~ Int:U`
say Int ~~ Int:_; # same as `Int ~~ Int:U`

# Similarly, the `.DEFINITE` method can be used to test for
# the definedness of an object.
say "I am string".DEFINITE; # returns `True` because it's an instance object
say Str.DEFINITE;           # returns `False` because it's an type object
$ perl6 type04.p6
True
False
False
True
True
True
True
False

Subsets

To subtype a given type, use the subset keyword. To apply further constraints to the subtype, append the where clause with a constraint.

# A `BigInt` is type object that defines a number
# greater than a million.
subset BigInt of Int where { $_ > 1_000_000 }; 

say 1_000_001 ~~ BigInt;
say 100 ~~ BigInt;

# An `Exclamation` is a type object that defines a string
# containing at least an exclamation mark.
subset Exclamation of Str where *.contains('!'); # using the Whatever Star
                                                 # instead of a block
say "Hello" ~~ Exclamation;
say "Hi!!!" ~~ Exclamation;
$ perl6 subset.p6
True
False
False
True

Enumerations

To declare an enumeration of constant key-value pairs with an associated type, use the enum keyword.

enum Direction <East North South West>;

say Direction.enums;
my $alaska = North;
say $alaska ~~ Direction;
say $alaska;
say "Type: ",  $alaska.^name;
say "Value: ", $alaska.value;

# Operations can be performed with the names since increasing
# integer values, starting at 0, are assigned to each name.
say "Sum: ", East + South + West + North; 
$ perl6 enum01.p6
Map.new((East => 0, North => 1, South => 2, West => 3))
True
North
Type: Direction
Value: 1
Sum: 6

If the values are meaningful, they can be specified explicitly.

enum Shape (Triangle => 3, Square => 4, Pentagon => 5);

say Shape.enums;
say Triangle ~~ Shape;
say Triangle.^name;
say Triangle.value;

# Values need not be integer values.
enum TrafficLight ( Red => "Go", Green => "Go", YELLOW => "SLOW DOWN" );

say "-" x 15;
say Red ~~ TrafficLight;
say Red.value;
$ perl6 enum02.p6
Map.new((Pentagon => 5, Square => 4, Triangle => 3))
True
Shape
3
---------------
True
Go

For more info, go to

Back to main