Object orientation
ErrorsCollection

Object orientation

Object orientation in Raku

Raku provides strong support for Object Oriented Programming (OOP). Although Raku allows programmers to program in multiple paradigms, Object Oriented Programming is at the heart of the language.

Raku comes with a wealth of predefined types, which can be classified in two categories: regular and native types. Everything that you can store in a variable is either a native value or an object. That includes literals, types (type objects), code and containers.

Native types are used for low-level types (like uint64). Even if native types do not have the same capabilities as objects, if you call methods on them, they are automatically boxed into normal objects.

Everything that is not a native value is an object. Objects do allow for both inheritance and encapsulation.

Using objects

To call a method on an object, add a dot, followed by the method name:

say "abc".uc;
# OUTPUT: «ABC␤» 

This calls the uc method on "abc", which is an object of type Str. To supply arguments to the method, add arguments inside parentheses after the method.

my $formatted-text = "Fourscore and seven years ago...".indent(8);
say $formatted-text;
# OUTPUT: «        Fourscore and seven years ago...␤» 

$formatted-text now contains the above text, but indented 8 spaces.

Multiple arguments are separated by commas:

my @words = "Abe""Lincoln";
@words.push("said"$formatted-text.comb(/\w+/));
say @words;
# OUTPUT: «[Abe Lincoln said (Fourscore and seven years ago)]␤» 

Similarly, multiple arguments can be specified by placing a colon after the method and separating the argument list with a comma:

say @words.join('--').subst: 'years''DAYS';
# OUTPUT: «Abe--Lincoln--said--Fourscore and seven DAYS ago␤» 

Since you have to put a : after the method if you want to pass arguments without parentheses, a method call without a colon or parentheses is unambiguously a method call without an argument list:

say 4.log:   ; # OUTPUT: «1.38629436111989␤» ( natural logarithm of 4 ) 
say 4.log: +2# OUTPUT: «2␤» ( base-2 logarithm of 4 ) 
say 4.log  +2# OUTPUT: «3.38629436111989␤» ( natural logarithm of 4, plus 2 )

Many operations that don't look like method calls (for example, smartmatching or interpolating an object into a string) might result in method calls under the hood.

Methods can return mutable containers, in which case you can assign to the return value of a method call. This is how read-writable attributes to objects are used:

$*IN.nl-in = "\r\n";

Here, we call method nl-in on the $*IN object, without arguments, and assign to the container it returned with the = operator.

All objects support methods from class Mu, which is the type hierarchy root. All objects derive from Mu.

Object equality needs a specific operator: eqv, the structural comparison operator:

class Foo {
    has $.bar;
    has $.baz
};
my $bar = "42";
my $baz = 24;
my $zipi = Foo.new:$baz:$bar);
my $zape = Foo.new:$bar:$baz);
say $zipi eqv $zape# OUTPUT: «True␤» 

Object identity, on the other hand, uses ===. Using it above will return False, for instance.

Type objects

Types themselves are objects and you can get the type object by writing its name:

my $int-type-obj = Int;

You can request the type object of anything by calling the WHAT method, which is actually a macro in method form:

my $int-type-obj = 1.WHAT;

Type objects (other than Mu) can be compared for equality with the === identity operator:

sub f(Int $x{
    if $x.WHAT === Int {
        say 'you passed an Int';
    }
    else {
        say 'you passed a subtype of Int';
    }
}

Although, in most cases, the .isa method will suffice:

sub f($x{
    if $x.isa(Int{
        ...
    }
    ...
}

Subtype checking is done by smartmatching:

if $type ~~ Real {
    say '$type contains Real or a subtype thereof';
}

Classes

Classes are declared using the class keyword, typically followed by a name.

class Journey { }

This declaration results in a type object being created and installed in the current package and current lexical scope under the name Journey. You can also declare classes lexically:

my class Journey { }

This restricts their visibility to the current lexical scope, which can be useful if the class is an implementation detail nested inside a module or another class.

Attributes

Attributes are variables that exist per instance of a class; when instantiated to a value, the association between the variable and its value is called a property. They are where the state of an object is stored. In Raku, all attributes are private, which means they can be accessed directly only by the class instance itself. They are typically declared using the has declarator and the ! twigil.

class Journey {
    has $!origin;
    has $!destination;
    has @!travelers;
    has $!notes;
}

Alternatively, you can omit the twigil, which will still create the private attribute (with a ! twigil), and will also create an alias that binds the name (without the twigil) to that attribute. Thus, you can declare the same class above with

class Journey {
    has $origin;
    has $destination;
    has @travelers;
    has $notes;
}

If you declare the class like this, you can subsequently access the attributes either with or without the twigil – e.g., $!origin and $origin refer to same attribute.

While there is no such thing as a public (or even protected) attribute, there is a way to have accessor methods generated automatically: replace the ! twigil with the . twigil (the . should remind you of a method call).

class Journey {
    has $.origin;
    has $.destination;
    has @!travelers;
    has $.notes;
}

This defaults to providing a read-only accessor. In order to allow changes to the attribute, add the is rw trait:

class Journey {
    has $.origin;
    has $.destination;
    has @!travelers;
    has $.notes is rw;
}

Now, after a Journey object is created, its .origin, .destination, and .notes will all be accessible from outside the class, but only .notes can be modified.

If an object is instantiated without certain attributes, such as origin or destination, we may not get the desired result. To prevent this, provide default values or make sure that an attribute is set on object creation by marking an attribute with an is required trait.

class Journey {
    # error if origin is not provided 
    has $.origin is required;
    # set the destination to Orlando as default (unless that is the origin!) 
    has $.destination = self.origin eq 'Orlando' ?? 'Kampala' !! 'Orlando';
    has @!travelers;
    has $.notes is rw;
}

Since classes inherit a default constructor from Mu and we have requested that some accessor methods are generated for us, our class is already somewhat functional.

# Create a new instance of the class. 
my $vacation = Journey.new(
    origin      => 'Sweden',
    destination => 'Switzerland',
    notes       => 'Pack hiking gear!'
);
 
# Use an accessor; this outputs Sweden. 
say $vacation.origin;
 
# Use an rw accessor to change the value. 
$vacation.notes = 'Pack hiking gear and sunglasses!';

Note that, although the default constructor can initialize read-only attributes, it will only set attributes that have an accessor method. That is, even if you pass travelers => ["Alex", "Betty"] to the default constructor, the attribute @!travelers is not initialized.

Methods

Methods are declared with the method keyword inside a class body.

class Journey {
    has $.origin;
    has $.destination;
    has @!travelers;
    has $.notes is rw;
 
    method add-traveler($name{
        if $name ne any(@!travelers{
            push @!travelers$name;
        }
        else {
            warn "$name is already going on the journey!";
        }
    }
 
    method describe() {
        "From $!origin to $!destination"
    }
}

A method can have a signature, just like a subroutine. Attributes can be used in methods and can always be used with the ! twigil, even if they are declared with the . twigil. This is because the . twigil declares a ! twigil and generates an accessor method.

Looking at the code above, there is a subtle but important difference between using $!origin and $.origin in the method describe. $!origin is an inexpensive and obvious lookup of the attribute. $.origin is a method call and thus may be overridden in a subclass. Only use $.origin if you want to allow overriding.

Unlike subroutines, additional named arguments will not produce compile time or runtime errors. That allows chaining of methods via Re-dispatching.

You may write your own accessors to override any or all of the autogenerated ones.

my $ = " " xx 4# A tab-like thing 
class Journey {
    has $.origin;
    has $.destination;
    has @.travelers;
    has Str $.notes is rw;
 
    multi method notes() { "$!notes\n" };
    multi method notesStr $note ) { $!notes ~= "$note\n$" };
 
    method Str { "⤷ $!origin\n$" ~ self.notes() ~ "$!destination ⤶\n" };
}
 
my $trip = Journey.new:origin<Here>:destination<There>,
                        travelers => <þor Freya> );
 
$trip.notes("First steps");
notes $trip: "Almost there";
print $trip;
 
# OUTPUT: 
#⤷ Here 
#       First steps 
#       Almost there 
# 
#There ⤶ 

The declared multi method notes overrides the auto-generated methods implicit in the declaration of $.notes, using a different signature for reading and writing.

Please note that in notes $trip: "Almost there" we are using indirect invocant syntax, which puts first the method name, then the object, and then, separated by a colon, the arguments: method invocant: arguments. We can use this syntax whenever it feels more natural than the classical period-and-parentheses one. It works exactly in the same way.

Note how the call to the notes method in the Str method is made on self. Writing method calls this way will leave the return value of the method as is with regards to containers. To containerize return values, you can make method calls on a sigil instead of self. This calls various methods on the return value of the method depending on the sigil used to containerize it:

SigilMethod
$item
@list
%hash
&item

For example, the Str method of Journey can be rewritten not to use the ~ operator by embedding a sigiled method call in the string it returns:

method Str { "⤷ $!origin\n$$.notes()$!destination ⤶\n" }

The syntax used to update $.notes changed in this section with respect to the previous #Attributes section. Instead of an assignment:

$vacation.notes = 'Pack hiking gear and sunglasses!';

we now do a method call:

$trip.notes("First steps");

Classes Overriding the default auto-generated accessor means it is no longer available to provide a mutable container on return for an assignment. A method call is the preferred approach to adding computation and logic to the update of an attribute (see 'programmatic use' of such calls in the following section). Many modern languages can update an attribute by overloading assignment with a “setter” method. While Raku can overload the assignment operator for this purpose with a Proxy object, overloading assignment to set attributes with complex logic is currently discouraged as weaker object oriented design.

Class and instance methods

Classes Method names can be resolved at runtime with the ."" operator which enables programmatic use of such names. For example, since an attribute name is also a method, we can show attribute a's value by calling the a method:

class A { has $.a = 9 }
my $method = 'a';
A.new."$method"().say;
# OUTPUT: «9␤» 

A method with arguments may be called in a similar manner:

class B {
    has $.b = 9;
    method mul($n{
        $!b * $n
    }
}
my $method = 'mul';
B.new."$method"(6).say;
# OUTPUT: «54␤» 

Classes A method's signature can have an explicit invocant as its first parameter followed by a colon, which allows for the method to refer to the object it was called on.

class Foo {
    method greet($me: $person{
        say "Hi, I am $me.^name(), nice to meet you, $person";
    }
}
Foo.new.greet("Bob");    # OUTPUT: «Hi, I am Foo, nice to meet you, Bob␤» 

Providing an invocant in the method signature also allows for defining the method as either as a class method, or as an object method, through the use of type constraints. The ::?CLASS variable can be used to provide the class name at compile time, combined with either :U (for class methods) or :D (for instance methods).

class Pizza {
    has $!radius = 42;
    has @.ingredients;
 
    # class method: construct from a list of ingredients 
    method from-ingredients(::?CLASS:U $pizza: @ingredients{
        $pizza.newingredients => @ingredients );
    }
 
    # instance method 
    method get-radius(::?CLASS:D:{ $!radius }
}
my $p = Pizza.from-ingredients: <cheese pepperoni vegetables>;
say $p.ingredients;     # OUTPUT: «[cheese pepperoni vegetables]␤» 
say $p.get-radius;      # OUTPUT: «42␤» 
say Pizza.get-radius;   # This will fail. 
CATCH { default { put .^name ~ ":\n" ~ .Str } };
# OUTPUT: «X::Parameter::InvalidConcreteness:␤ 
#          Invocant of method 'get-radius' must be 
#          an object instance of type 'Pizza', 
#          not a type object of type 'Pizza'. 
#          Did you forget a '.new'?» 

A method can be both a class and object method by using the multi declarator:

class C {
    multi method f(::?CLASS:U:{ say "class method"  }
    multi method f(::?CLASS:D:{ say "object method" }
}
C.f;       # OUTPUT: «class method␤» 
C.new.f;   # OUTPUT: «object method␤» 

self

Inside a method, the term self is available and bound to the invocant object. self can be used to call further methods on the invocant, including constructors:

class Box {
  has $.data;
 
  method make-new-box-from() {
      self.new: data => $!data;
  }
}

self can be used in class or instance methods as well, though beware of trying to invoke one type of method from the other:

class C {
    method g()            { 42     }
    method f(::?CLASS:U:{ self.g }
    method d(::?CLASS:D:{ self.f }
}
C.f;        # OUTPUT: «42␤» 
C.new.d;    # This will fail. 
CATCH { default { put .^name ~ ":\n" ~ .Str } };
# OUTPUT: «X::Parameter::InvalidConcreteness:␤ 
#          Invocant of method 'f' must be a type object of type 'C', 
#          not an object instance of type 'C'.  Did you forget a 'multi'?» 

self can also be used with attributes, as long as they have an accessor. self.a will call the accessor for an attribute declared as has $.a. However, there is a difference between self.a and $.a, since the latter will itemize; $.a will be equivalent to self.a.item or $(self.a).

class A {
    has Int @.numbers;
    has $.x = (123);
 
    method show-diff() { .say for self.x.say for $.x }
 
    method twice  { self.times: 2 }
    method thrice { $.times: 3    }
 
    method times($val = 1{ @!numbers.map(* * $val).list }
};
 
my $obj = A.new(numbers => [123]);
$obj.show-diff;   # OUTPUT: «1␤2␤3␤(1 2 3)␤» 
say $obj.twice;   # OUTPUT: «(2 4 6)␤» 
say $obj.thrice;  # OUTPUT: «(3 6 9)␤» 

The colon-syntax for method arguments is supported for method calls using either self or the shortcut, as illustrated with the methods twice and thrice in the example above.

Note that if the relevant methods bless, CREATE of Mu are not overloaded, self will point to the type object in those methods.

On the other hand, the submethods BUILD and TWEAK are called on instances, in different stages of initialization. Submethods of the same name from subclasses have not yet run, so you should not rely on potentially virtual method calls inside these methods.

Private methods

Methods with an exclamation mark ! before the method name are not callable from anywhere outside the defining class; such methods are private in the sense that they are not visible from outside the class that declares them. Private methods are invoked with an exclamation mark instead of a dot:

class FunMath {
    has $.value is required;
    method !do-subtraction$num ) {
        if $num ~~ Str {
            return $!value + (-1 * $num.chars);
        }
        return $!value + (-1 * $num);
    }
    method minus$minuend: $subtrahend ) {
        # invoking the private method on the explicit invocant 
        $minuend!do-subtraction($subtrahend);
    }
}
my $five = FunMath.new(value => 5);
say $five.minus(6);         # OUTPUT: «-1␤» 
 
say $five.do-subtraction(6);
CATCH { default { put .^name ~ ":\n" ~ .Str } }
# OUTPUT: «X::Method::NotFound: 
# No such method 'do-subtraction' for invocant of type 
# 'FunMath'. Did you mean '!do-subtraction'?␤» 

Private methods have their own namespace. They're not virtual, i.e., private methods cannot be overridden within the inheriting class to provide any polymorphic behavior, thus missing ones are detected at compile time. Unlike in some languages where private is an accessibility modifier on a method, in Raku "private methods" and "methods" are quite different things - that is to say, it's better to read "private method" as a compound noun rather than an adjective describing a noun.

Private methods are not inherited by subclasses.

Submethods

Submethods are public methods that will not be inherited by subclasses. The name stems from the fact that they are semantically similar to subroutines.

Submethods are useful for object construction and destruction tasks, as well as for tasks that are so specific to a certain type that subtypes would certainly have to override them.

For example, the default method new calls submethod BUILD on each class in an inheritance chain:

class Point2D {
    has $.x;
    has $.y;
 
    submethod BUILD(:$!x:$!y{
        say "Initializing Point2D";
    }
}
 
class InvertiblePoint2D is Point2D {
    submethod BUILD() {
        say "Initializing InvertiblePoint2D";
    }
    method invert {
        self.new(x => - $.x=> - $.y);
    }
}
 
say InvertiblePoint2D.new(x => 1=> 2);
# OUTPUT: «Initializing Point2D␤» 
# OUTPUT: «Initializing InvertiblePoint2D␤» 
# OUTPUT: «InvertiblePoint2D.new(x => 1, y => 2)␤» 

See also: Object construction.

Inheritance

Classes can have parent classes.

class Child is Parent1 is Parent2 { }

If a method is called on the child class, and the child class does not provide that method, the method of that name in one of the parent classes is invoked instead, if it exists. The order in which parent classes are consulted is called the method resolution order (MRO). Raku uses the C3 method resolution order. You can ask a type for its MRO through a call to its metaclass:

say List.^mro;      # ((List) (Cool) (Any) (Mu)) 

If a class does not specify a parent class, Any is assumed by default. All classes directly or indirectly derive from Mu, the root of the type hierarchy.

All calls to public methods are "virtual" in the C++ sense, which means that the actual type of an object determines which method to call, not the declared type:

class Parent {
    method frob {
        say "the parent class frobs"
    }
}
 
class Child is Parent {
    method frob {
        say "the child's somewhat more fancy frob is called"
    }
}
 
my Parent $test;
$test = Child.new;
$test.frob;          # calls the frob method of Child rather than Parent 
# OUTPUT: «the child's somewhat more fancy frob is called␤» 

If you want to explicitly call the parent method on a child object, refer to its full name in the parent namespace:

$test.Parent::frob;  # calls the frob method of Parent 
# OUTPUT: «the parent class frobs␤» 

Delegation

Delegation is a technique whereby an object, the delegator, accepts a method call but has designated another object, the delegatee, to process the call in its place. In other words, the delegator publishes one or more of the delegatee's methods as its own.

In Raku, delegation is specified by applying the handles trait to an attribute. The arguments provided to the trait specify the methods the object and the delegatee attribute will have in common. Instead of a list of method names, you can provide a Pair (to rename; the key becomes the new name), a Regex (to handle every method with a matching name), a Whatever (to delegate all methods that the attribute can call), or a HyperWhatever (to delegate all method calls, even ones that will lead to the attribute's FALLBACK method). You can also provide a List providing any of those items to delegate multiple methods. Note that the Regex, Whatever, and HyperWhatever forms do not delegate any methods that the class has inherited (for example, from Any or Mu) but that explicitly naming the method does delegate it.

class Book {
    has Str  $.title;
    has Str  $.author;
    has Str  $.language;
    has Cool $.publication;
}
 
class Product {
    has Book $.book handles('title''author''language'year => 'publication');
}
 
my $book = Book.new:
    :title<Dune>,
    :author('Frank Herbert'),
    :language<English>,
    :publication<1965>
;
 
given Product.new(:$book{
    say .title;    # OUTPUT: «Dune␤» 
    say .author;   # OUTPUT: «Frank Herbert␤» 
    say .language# OUTPUT: «English␤» 
    say .year;     # OUTPUT: «1965␤» 
}

In the example above, the class Product defines the attribute $.book and mark it with the handles trait to specify the methods that will be forwarded to the class Book whenever they're invoked on an instance object of the Product class. There are a few things to notice here:

  • We didn't write any methods inside the Product class that we invoked in its instance object. Instead, we instructed the class to delegate a call to any those methods to the Book class.

  • We've specified the method names title, author, and language as they appear in the Book class. On the other hand, we've renamed the publication method to year by providing the appropriate Pair.

Delegation can be used as an alternative to inheritance by delegating to the parent class and not inheriting all of its methods. For example, the following Queue class delegates several methods proper of queues to the Array class while also providing a preferred interface for a few of those methods (e.g., enqueue for push):

class Queue {
    has @!q handles(
        enqueue => 'push'dequeue => 'shift',
        'push''shift''head''tail''elems''splice'
    );
 
    method gist {
        '[' ~ @!q.join(''~ ']'
    }
}
 
my Queue $q .= new;
$q.enqueue($_for 1..5;
$q.push(6);
say $q.shift;                  # OUTPUT: «1␤» 
say $q.dequeue while $q.elems# OUTPUT: «2␤3␤4␤5␤6␤» 
 
$q.enqueue($_for <Perl Python Raku Ruby>;
say $q.head;                   # OUTPUT: «Perl␤» 
say $q.tail;                   # OUTPUT: «Ruby␤» 
say $q;                        # OUTPUT: «[Perl, Python, Raku, Ruby]␤» 
$q.dequeue while $q.elems;
say $q;                        # OUTPUT: «[]␤» 

Object construction

Objects are generally created through method calls, either on the type object or on another object of the same type.

Class Mu provides a constructor method called new, which takes named arguments and uses them to initialize public attributes.

class Point {
    has $.x;
    has $.y;
}
my $p = Point.newx => 5=> 2);
#             ^^^ inherited from class Mu 
say "x: "$p.x;
say "y: "$p.y;
# OUTPUT: «x: 5␤» 
# OUTPUT: «y: 2␤» 

Mu.new calls method bless on its invocant, passing all the named arguments. bless creates the new object, and then walks all subclasses in reverse method resolution order (i.e. from Mu to most derived classes). In each class bless executes the following steps in the order given here:

  • It checks for the existence of a method named BUILD. If the method exists, the method is called with all the named arguments it received (from the new method).

  • If no BUILD method was found, the public attributes from this class are initialized from named arguments of the same name.

  • All attributes that have not been touched in any of the previous steps have their default values applied:

    has $.attribute = 'default value';

  • TWEAK is called should it exist. It will receive the same arguments BUILD receives.

This object construction scheme has several implications:

  • Named arguments to the default new constructor (inherited from Mu) can correspond directly to public attributes of any of the classes in the method resolution order, or to any named parameter of any BUILD or TWEAK submethod.

  • Custom BUILD methods should always be submethods, otherwise they are inherited to subclasses and prevent default attribute initialization (item two in the above list) should the subclass not have its own BUILD method.

  • BUILD may set an attribute, but it does not have access to the contents of the attribute declared as its default as they are only applied later. TWEAK on the other hand is called after default values have been applied and will thus find the attributes initialized. So it can be used to check things or modify attributes after object construction:

    class RectangleWithCachedArea {
        has ($.x1$.x2$.y1$.y2);
        has $.area;
        submethod TWEAK() {
            $!area = abs( ($!x2 - $!x1* ( $!y2 - $!y1) );
        }
    }
     
    say RectangleWithCachedArea.newx2 => 5x1 => 1y2 => 1y1 => 0).area;
    # OUTPUT: «4␤» 
  • Since passing arguments to a routine binds the arguments to the parameters, one can simplify BUILD methods by using the attribute as a parameter.

    A class using ordinary binding in the BUILD method:

    class Point {
        has $.x;
        has $.y;
     
        submethod BUILD(:$x:$y{
            $!x := $x;
            $!y := $y;
        }
    }
    my $p1 = Point.newx => 10=> 5 );

    The following BUILD method is equivalent to the above:

    submethod BUILD(:$!x:$!y{
        # Nothing to do here anymore, the signature binding 
        # does all the work for us. 
    }
  • In order to use default values together with a `BUILD()` method one can't use parameter binding of attributes, as that will always touch the attribute and thus prevent the automatic assignment of default values (step three in the above list). Instead one would need to conditionally assign the value:

    class A {
        has $.attr = 'default';
        submethod BUILD(:$attr{
            $!attr = $attr if defined $attr;
        }
    }
    say A.new(attr => 'passed').raku;
    say A.new().raku;
    # OUTPUT: «A.new(attr => "passed")␤» 
    # OUTPUT: «A.new(attr => "default")␤» 

    It's simpler to set a default value of the `BUILD` parameter instead though:

    class A {
        has $.attr;
        submethod BUILD(:$!attr = 'default'{}
    }
  • Be careful when using parameter binding of attributes when the attribute has a special type requirement such as an Int type. If new is called without this parameter, then a default of Any will be assigned, which will cause a type error. The easy fix is to add a default value to the BUILD parameter.

    class A {
        has Int $.attr;
        submethod BUILD(:$!attr = 0{}
    }
    say A.new(attr => 1).raku;
    say A.new().raku;
    # OUTPUT: «A.new(attr => 1)␤» 
    # OUTPUT: «A.new(attr => 0)␤» 
  • BUILD allows to create aliases for attribute initialization:

    class EncodedBuffer {
        has $.enc;
        has $.data;
     
        submethod BUILD(:encoding(:$!enc), :$!data{ }
    }
    my $b1 = EncodedBuffer.newencoding => 'UTF-8'data => [6465] );
    my $b2 = EncodedBuffer.newenc      => 'UTF-8'data => [6465] );
    #  both enc and encoding are allowed now 
  • Note that the name new is not special in Raku. It is merely a common convention, one that is followed quite thoroughly in new. You can call bless from any method, or use CREATE to fiddle around with low-level workings.

  • If you want a constructor that accepts positional arguments, you must write your own new method:

    class Point {
        has $.x;
        has $.y;
        method new($x$y{
            self.bless(:$x:$y);
        }
    }

    Do note, however, that new is a normal method and not involved in any of the construction process of bless. So any logic placed in the new method will not be called when using a different new method or a new of a subclass.

    class Vector {
        has $.x;
        has $.y;
        has $.length;
        method new($x$y{
            self.bless(:$x:$ylength => sqrt($x**2 * $y**2));
        }
    }
     
    class NamedVector is Vector {
        has $.name;
        method new($name$x$y{
            self.bless(:$name:$x:$y);
        }
    }
     
    my $v = Vector.new: 23;
    say $v.length# OUTPUT: «6␤» 
     
    my $f = NamedVector.new: 'Francis'35;
    say $f.length# OUTPUT: «(Any)␤» 

Here is an example where we enrich the Str class with an auto-incrementing ID:

class Str-with-ID is Str {
    my $counter = 0;
    has Int $.ID  is rw = 0;
 
    multi method new$str ) {
        self.blessvalue => $str );
    }
    submethod BUILD:$!ID = $counter++ ) {}
}
 
say Str-with-ID.new("1.1,2e2").ID;                  # OUTPUT: «0␤» 
my $enriched-str = Str-with-ID.new("3,4");
say "$enriched-str{$enriched-str.^name}{$enriched-str.ID}";
# OUTPUT: «3,4, Str-with-ID, 1␤» 

We create a custom new since we want to be able to be able to initialize our new class with a bare string. bless will call Str.BUILD which will capture the value it's looking for, the pair value => $str and initialize itself. But we have to also initialize the properties of the subclass, which is why within BUILD we initialize $.ID. As seen in the output, the objects will be correctly initialized with an ID and can be used just like a normal Str.

Object cloning

The cloning is done using the clone method available on all objects, which shallow-clones both public and private attributes. New values for public attributes can be supplied as named arguments.

class Foo {
    has $.foo = 42;
    has $.bar = 100;
}
 
my $o1 = Foo.new;
my $o2 = $o1.clone: :bar(5000);
say $o1# Foo.new(foo => 42, bar => 100) 
say $o2# Foo.new(foo => 42, bar => 5000) 

See document for clone for details on how non-scalar attributes get cloned, as well as examples of implementing your own custom clone methods.

Roles

Roles are a collection of attributes and methods; however, unlike classes, roles are meant for describing only parts of an object's behavior; this is why, in general, roles are intended to be mixed in classes and objects. In general, classes are meant for managing objects and roles are meant for managing behavior and code reuse within objects.

Roles use the keyword role preceding the name of the role that is declared. Roles are mixed in using the does keyword preceding the name of the role that is mixed in.

Roles can also be mixed into a class using is. However, the semantics of is with a role are quite different from those offered by does. With is, a class is punned from the role, and then inherited from. Thus, there is no flattening composition, and none of the safeties which does provides.

constant ⲧ = " " xx 4#Just a ⲧab 
role Notable {
    has Str $.notes is rw;
 
    multi method notes() { "$!notes\n" };
    multi method notesStr $note ) { $!notes ~= "$note\n" ~ ⲧ };
 
}
 
class Journey does Notable {
    has $.origin;
    has $.destination;
    has @.travelers;
 
    method Str { "⤷ $!origin\n" ~ ⲧ ~ self.notes() ~ "$!destination ⤶\n" };
}
 
my $trip = Journey.new:origin<Here>:destination<There>,
                        travelers => <þor Freya> );
 
$trip.notes("First steps");
notes $trip: "Almost there";
print $trip;
# OUTPUT: 
#⤷ Here 
#       First steps 
#       Almost there 
# 
#There ⤶ 

Roles are immutable as soon as the compiler parses the closing curly brace of the role declaration.

Applying roles

Role application differs significantly from class inheritance. When a role is applied to a class, the methods of that role are copied into the class. If multiple roles are applied to the same class, conflicts (e.g. attributes or non-multi methods of the same name) cause a compile-time error, which can be solved by providing a method of the same name in the class.

This is much safer than multiple inheritance, where conflicts are never detected by the compiler, but are instead resolved to the superclass that appears earlier in the method resolution order, which might not be what the programmer wanted.

For example, if you've discovered an efficient method to ride cows, and are trying to market it as a new form of popular transportation, you might have a class Bull, for all the bulls you keep around the house, and a class Automobile, for things that you can drive.

class Bull {
    has Bool $.castrated = False;
    method steer {
        # Turn your bull into a steer 
        $!castrated = True;
        return self;
    }
}
class Automobile {
    has $.direction;
    method steer($!direction{ }
}
class Taurus is Bull is Automobile { }
 
my $t = Taurus.new;
say $t.steer;
# OUTPUT: «Taurus.new(castrated => Bool::True, direction => Any)␤» 

With this setup, your poor customers will find themselves unable to turn their Taurus and you won't be able to make more of your product! In this case, it may have been better to use roles:

role Bull-Like {
    has Bool $.castrated = False;
    method steer {
        # Turn your bull into a steer 
        $!castrated = True;
        return self;
    }
}
role Steerable {
    has Real $.direction;
    method steer(Real $d = 0{
        $!direction += $d;
    }
}
class Taurus does Bull-Like does Steerable { }

This code will die with something like:

===SORRY!===
Method 'steer' must be resolved by class Taurus because it exists in
multiple roles (SteerableBull-Like)

This check will save you a lot of headaches:

class Taurus does Bull-Like does Steerable {
    method steer($direction?{
        self.Steerable::steer($direction)
    }
}

When a role is applied to a second role, the actual application is delayed until the second role is applied to a class, at which point both roles are applied to the class. Thus

role R1 {
    # methods here 
}
role R2 does R1 {
    # methods here 
}
class C does R2 { }

produces the same class C as

role R1 {
    # methods here 
}
role R2 {
    # methods here 
}
class C does R1 does R2 { }

Stubs

When a role contains a stubbed method, that is, a method whose code is limited to ..., a non-stubbed version of a method of the same name must be supplied at the time the role is applied to a class. This allows you to create roles that act as abstract interfaces.

role AbstractSerializable {
    method serialize() { ... }        # literal ... here marks the 
                                      # method as a stub 
}
 
# the following is a compile time error, for example 
#        Method 'serialize' must be implemented by Point because 
#        it's required by a role 
 
class APoint does AbstractSerializable {
    has $.x;
    has $.y;
}
 
# this works: 
class SPoint does AbstractSerializable {
    has $.x;
    has $.y;
    method serialize() { "p($.x$.y)" }
}

The implementation of the stubbed method may also be provided by another role.

Inheritance

Roles cannot inherit from classes, but they may carry classes, causing any class which does that role to inherit from the carried classes. So if you write:

role A is Exception { }
class X::Ouch does A { }
X::Ouch.^parents.say # OUTPUT: «((Exception))␤» 

then X::Ouch will inherit directly from Exception, as we can see above by listing its parents.

As they do not use what can properly be called inheritance, roles are not part of the class hierarchy. Roles are listed with the .^roles metamethod instead, which uses transitive as flag for including all levels or just the first one. Despite this, a class or instance may still be tested with smartmatches or type constraints to see if it does a role.

role F { }
class G does F { }
G.^roles.say;                    # OUTPUT: «((F))␤» 
role Ur {}
role Ar does Ur {}
class Whim does Ar {}Whim.^roles(:!transitive).say;   # OUTPUT: «((Ar))␤» 
say G ~~ F;                      # OUTPUT: «True␤» 
multi a (F $a{ "F".say }
multi a ($a)   { "not F".say }
a(G);                            # OUTPUT: «F␤» 

Pecking order

A method defined directly in a class will always override definitions from applied roles or from inherited classes. If no such definition exists, methods from roles override methods inherited from classes. This happens both when said class was brought in by a role, and also when said class was inherited directly.

role M {
  method f { say "I am in role M" }
}
 
class A {
  method f { say "I am in class A" }
}
 
class B is A does M {
  method f { say "I am in class B" }
}
 
class C is A does M { }
 
B.new.f# OUTPUT: «I am in class B␤» 
C.new.f# OUTPUT: «I am in role M␤» 

Note that each candidate for a multi-method is its own method. In this case, the above only applies if two such candidates have the same signature. Otherwise, there is no conflict, and the candidate is just added to the multi-method.

Automatic role punning

Any attempt to directly instantiate a role or use it as a type object will automatically create a class with the same name as the role, making it possible to transparently use a role as if it were a class.

role Point {
    has $.x;
    has $.y;
    method abs { sqrt($.x * $.x + $.y * $.y}
    method dimensions { 2 }
}
say Point.new(x => 6=> 8).abs# OUTPUT: «10␤» 
say Point.dimensions;              # OUTPUT: «2␤» 

We call this automatic creation of classes punning, and the generated class a pun.

Punning is not caused by most metaprogramming constructs, however, as those are sometimes used to work directly with roles.

Parameterized roles

Roles can be parameterized, by giving them a signature in square brackets:

role BinaryTree[::Type{
    has BinaryTree[Type$.left;
    has BinaryTree[Type$.right;
    has Type $.node;
 
    method visit-preorder(&cb{
        cb $.node;
        for $.left$.right -> $branch {
            $branch.visit-preorder(&cbif defined $branch;
        }
    }
    method visit-postorder(&cb{
        for $.left$.right -> $branch {
            $branch.visit-postorder(&cbif defined $branch;
        }
        cb $.node;
    }
    method new-from-list(::?CLASS:U: *@el{
        my $middle-index = @el.elems div 2;
        my @left         = @el[0 .. $middle-index - 1];
        my $middle       = @el[$middle-index];
        my @right        = @el[$middle-index + 1 .. *];
        self.new(
            node    => $middle,
            left    => @left  ?? self.new-from-list(@left)  !! self,
            right   => @right ?? self.new-from-list(@right!! self,
        );
    }
}
 
my $t = BinaryTree[Int].new-from-list(456);
$t.visit-preorder(&say);    # OUTPUT: «5␤4␤6␤» 
$t.visit-postorder(&say);   # OUTPUT: «4␤6␤5␤» 

Here the signature consists only of a type capture, but any signature will do:

enum Severity <debug info warn error critical>;
 
role Logging[$filehandle = $*ERR{
    method log(Severity $sev$message{
        $filehandle.print("[{uc $sev}$message\n");
    }
}
 
Logging[$*OUT].log(debug'here we go'); # OUTPUT: «[DEBUG] here we go␤» 

You can have multiple roles of the same name, but with different signatures; the normal rules of multi dispatch apply for choosing multi candidates.

Mixins of roles

Roles can be mixed into objects. A role's given attributes and methods will be added to the methods and attributes the object already has. Multiple mixins and anonymous roles are supported.

role R { method Str() {'hidden!'} };
my $i = 2 but R;
sub f(\bound){ put bound };
f($i); # OUTPUT: «hidden!␤» 
my @positional := <a b> but R;
say @positional.^name# OUTPUT: «List+{R}␤» 

Note that the object got the role mixed in, not the object's class or the container. Thus, @-sigiled containers will require binding to make the role stick as is shown in the example with @positional. Some operators will return a new value, which effectively strips the mixin from the result. That is why it might be more clear to mix in the role in the declaration of the variable using does:

role R {};
my @positional does R = <a b>;
say @positional.^name# OUTPUT: «Array+{R}␤» 

The operator infix:<but> is narrower than the list constructor. When providing a list of roles to mix in, always use parentheses.

role R1 { method m {} }
role R2 { method n {} }
my $a = 1 but R1,R2# R2 is in sink context, issues a WARNING 
say $a.^name;
# OUTPUT: «Int+{R1}␤» 
my $all-roles = 1 but (R1,R2);
say $all-roles.^name# OUTPUT: «Int+{R1,R2}␤» 

If the role supplies exactly one attribute, an initializer can be passed in parentheses:

role Named {
    has $.name;
}
my $hero = 1.Rat but Named('Remy');
say $hero.name;     # OUTPUT: «Remy␤» 

Mixins can be used at any point in your object's life.

# A counter for Table of Contents 
role TOC-Counter {
    has Int @!counters is default(0);
    method Str() { @!counters.join: '.' }
    method inc($level{
        @!counters[$level - 1]++;
        @!counters.splice($level);
        self
    }
}
 
my Num $toc-counter = NaN;     # don't do math with Not A Number 
say $toc-counter;              # OUTPUT: «NaN␤» 
$toc-counter does TOC-Counter# now we mix the role in 
$toc-counter.inc(1).inc(2).inc(2).inc(1).inc(2).inc(2).inc(3).inc(3);
put $toc-counter / 1;          # OUTPUT: «NaN␤» (because that's numerical context) 
put $toc-counter;              # OUTPUT: «2.2.2␤» (put will call TOC-Counter::Str) 

Roles can be anonymous.

my %seen of Int is default(0 but role :: { method Str() {'NULL'} });
say %seen<not-there>;          # OUTPUT: «NULL␤» 
say %seen<not-there>.defined;  # OUTPUT: «True␤» (0 may be False but is well defined) 
say Int.new(%seen<not-there>); # OUTPUT: «0␤» 

Metaobject programming and introspection

Raku has a metaobject system, which means that the behavior of objects, classes, roles, grammars, enums, etc. are themselves controlled by other objects; those objects are called metaobjects. Metaobjects are, like ordinary objects, instances of classes, in this case we call them metaclasses.

For each object or class you can get the metaobject by calling .HOW on it. Note that although this looks like a method call, it works more like a macro.

So, what can you do with the metaobject? For one you can check if two objects have the same metaclass by comparing them for equality:

say 1.HOW ===   2.HOW;      # OUTPUT: «True␤» 
say 1.HOW === Int.HOW;      # OUTPUT: «True␤» 
say 1.HOW === Num.HOW;      # OUTPUT: «False␤» 

Raku uses the word HOW (Higher Order Workings) to refer to the metaobject system. Thus it should be no surprise that in Rakudo, the class name of the metaclass that controls class behavior is called Perl6::Metamodel::ClassHOW. For each class there is one instance of Perl6::Metamodel::ClassHOW.

But the metamodel does much more for you. For example, it allows you to introspect objects and classes. The calling convention for methods on metaobjects is to call the method on the metaobject and pass in the object of interest as first argument to the object. So to get the name of the class of an object, you could write:

my $object = 1;
my $metaobject = 1.HOW;
say $metaobject.name($object);      # OUTPUT: «Int␤» 
 
# or shorter: 
say 1.HOW.name(1);                  # OUTPUT: «Int␤» 

(The motivation is that Raku also wants to allow a more prototype-based object system, where it's not necessary to create a new metaobject for every type).

There's a shortcut to keep from using the same object twice:

say 1.^name;                        # OUTPUT: «Int␤» 
# same as 
say 1.HOW.name(1);                  # OUTPUT: «Int␤» 

See Metamodel::ClassHOW for documentation on the metaclass of class and also the metaprogramming.