Documentation for syntax
class assembled from the following types:
From Object orientation
Classes are declared using the
class keyword, typically followed by a name.
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:
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 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
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).
This defaults to providing a read-only accessor. In order to allow changes to the attribute, add the is rw trait:
Now, after a
Journey object is created, its
.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.
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 = Journey.new(origin => 'Sweden',destination => 'Switzerland',notes => 'Pack hiking gear!');# Use an accessor; this outputs Sweden.say .origin;# Use an rw accessor to change the value..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 are declared with the
method keyword inside a class body.
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 in the method
$!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 thingmy = Journey.new( :origin<Here>, :destination<There>,travelers => <þor Freya> );.notes("First steps");notes : "Almost there";print ;# 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:
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 names can be resolved at runtime with the
;my = 'b';A.new."$name"().say;# OUTPUT: «(Any)␤»
The syntax used to update
$.notes changed in this section with respect to the previous Attributes section. Instead of an assignment:
.notes = 'Pack hiking gear and sunglasses!';
we now do a method call:
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. 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.
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.
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).
my = Pizza.from-ingredients: <cheese pepperoni vegetables>;say .ingredients; # OUTPUT: «[cheese pepperoni vegetables]␤»say .get-radius; # OUTPUT: «42␤»say Pizza.get-radius; # This will fail.CATCH ;# 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:
C.f; # OUTPUT: «class method␤»C.new.f; # OUTPUT: «object method␤»
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:
self can be used in class or instance methods as well, though beware of trying to invoke one type of method from the other:
C.f; # OUTPUT: «42␤»C.new.d; # This will fail.CATCH ;# 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
$.a, since the latter will itemize;
$.a will be equivalent to
;my = A.new(numbers => [1, 2, 3]);.show-diff; # OUTPUT: «1␤2␤3␤(1 2 3)␤»say .twice; # OUTPUT: «(2 4 6)␤»say .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
thrice in the example above.
Note that if the relevant methods
CREATE of Mu are not overloaded,
self will point to the type object in those methods.
On the other hand, the submethods
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.
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:
my = FunMath.new(value => 5);say .minus(6); # OUTPUT: «-1␤»say .do-subtraction(6);CATCH# OUTPUT: «X::Method::NotFound:# No such method 'do-subtraction' for invocant of type# 'FunMath'. Did you mean '!do-subtraction'?␤»
Private methods are not inherited by subclasses.
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.
is Point2Dsay InvertiblePoint2D.new(x => 1, y => 2);# OUTPUT: «Initializing Point2D␤»# OUTPUT: «Initializing InvertiblePoint2D␤»# OUTPUT: «InvertiblePoint2D.new(x => 1, y => 2)␤»
See also: Object construction.
Classes can have parent classes.
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))
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:
is Parentmy Parent ;= Child.new;.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:
.Parent::frob; # calls the frob method of Parent# OUTPUT: «the parent class frobs␤»
Delegation is a technique whereby a member of an object (the delegatee) is evaluated in the context of another original object (the delegator). In other words, all method calls on the delegator are delegated to the delegatee.
In Raku, delegation is specified by applying the handles trait to an attribute. The arguments provided to the trait specify the methods the current object and the delegatee object will have in common. Instead of a list of method names, a
Pair (for renaming), a list of
Regex or a
Whatever can be provided.
my = Book.new::title<Dune>,:author('Frank Herbert'),:language<English>,:publication<1965>;given Product.new(:)
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
Productclass that we invoked in its instance object. Instead, we instructed the class to delegate a call to any those methods to the
We've specified the method names
languageas they appear in the
Bookclass. On the other hand, we've renamed the
yearby providing the appropriate
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.,
my Queue .= new;.enqueue() for 1..5;.push(6);say .shift; # OUTPUT: «1␤»say .dequeue while .elems; # OUTPUT: «2␤3␤4␤5␤6␤».enqueue() for <Perl Python Raku Ruby>;say .head; # OUTPUT: «Perl␤»say .tail; # OUTPUT: «Ruby␤»say ; # OUTPUT: «[Perl, Python, Raku, Ruby]␤».dequeue while .elems;say ; # OUTPUT: «␤»
Objects are generally created through method calls, either on the type object or on another object of the same type.
my = Point.new( x => 5, y => 2);# ^^^ inherited from class Musay "x: ", .x;say "y: ", .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
BUILDmethod 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';
This object construction scheme has several implications:
Named arguments to the default
newconstructor (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
BUILDmethods 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
BUILDmay 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.
TWEAKon 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:say RectangleWithCachedArea.new( x2 => 5, x1 => 1, y2 => 1, y1 => 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
BUILDmethod:my = Point.new( x => 10, y => 5 );
BUILDmethod is equivalent to the above:submethod BUILD(:, :)
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: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:
Be careful when using parameter binding of attributes when the attribute has a special type requirement such as an
newis called without this parameter, then a default of
Anywill be assigned, which will cause a type error. The easy fix is to add a default value to the
BUILDparameter.say A.new(attr => 1).raku;say A.new().raku;# OUTPUT: «A.new(attr => 1)␤»# OUTPUT: «A.new(attr => 0)␤»
BUILDallows to create aliases for attribute initialization:my = EncodedBuffer.new( encoding => 'UTF-8', data => [64, 65] );my = EncodedBuffer.new( enc => 'UTF-8', data => [64, 65] );# both enc and encoding are allowed now
Note that the name
newis not special in Raku. It is merely a common convention, one that is followed quite thoroughly in most Raku classes. You can call
blessfrom any method, or use
CREATEto fiddle around with low-level workings.
If you want a constructor that accepts positional arguments, you must write your own
Do note, however, that
newis a normal method and not involved in any of the construction process of
bless. So any logic placed in the
newmethod will not be called when using a different
newmethod or a
newof a subclass.is Vectormy = Vector.new: 2, 3;say .length; # OUTPUT: «6␤»my = NamedVector.new: 'Francis', 3, 5;say .length; # OUTPUT: «(Any)␤»
Here is an example where we enrich the
Str class with an auto-incrementing ID:
is Strsay Str-with-ID.new("1.1,2e2").ID; # OUTPUT: «0␤»my = Str-with-ID.new("3,4");say "$enriched-str, , ";# 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
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.
my = Foo.new;my = .clone: :bar(5000);say ; # Foo.new(foo => 42, bar => 100)say ; # 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.