Jump to content

Raku Programming/Classes And Attributes

From Wikibooks, open books for an open world

Classes and Objects

[edit | edit source]

What we've seen so far are the building blocks for procedural programming: Lists of expressions, branches, loops, and subroutines that tell the computer what job to do and exactly how to do it. Raku supports procedural programming very well, but this isn't the only style of programming that Raku supports. Another common paradigm that Raku fits nicely is the object-oriented approach.

Objects are combinations of data and the operations that act on that data. The data of an object are called its attributes, and the operations of an object are called its methods. In this sense, the attributes define the state and the methods define the behavior of the objects.

Classes are templates for creating objects. When referring to an object of a specific class, it's customary to call the object an instance of the class.

Classes

[edit | edit source]

Classes are defined using the class keyword, and are given a name:

class MyClass {

}

Inside that class declaration you can define attributes, methods, or submethods.

Attributes

[edit | edit source]

Attributes are defined with the has keyword, and are specified with a special syntax. For example, let's consider the following class:

class Point3D {
    has $!x-axis;
    has $!y-axis;
    has $!z-axis;
}

The class Point2D defines a point in 3D coordinates with three attributes named x-axis, y-axis and z-axis.

In Raku, all attributes are private and one way to express this explicitly is by using the ! twigil. An attribute declared with the ! twigil can only be accessed directly within the class by using !attribute-name. Another important consequence of declaring attributes this way is that objects cannot be populated by using the default new constructor.

If you declare an attribute with the . twigil instead, a read-only accessor[check spelling] method will be automatically generated. You can think of the . twigil as "attribute + accesor". This accesor, which is a method named after its attribute, can be called from outside the class and return the value of its attribute. In order to allow changes to the attributes through the provided accesors, the trait is rw must be added to the attributes.

The previous class Point3D could be declared as follows:

class Point3D {
    has $.x-axis;
    has $.y-axis;
    has $.z-axis is rw;
}

Given that the . twigil declares a ! twigil and an accesor[check spelling] method, atrributes can always be used with the ! twigil even if they're declared using the . twigil.

Methods

[edit | edit source]

Methods are defined just like normal subroutines except for a few key differences:

  1. Methods use the method keyword instead of sub.
  2. Methods have the special variable self, which refers to the object that the method is being called on. This is known as the invocant.
  3. Methods can access the internal traits of the object directly.

When defining the method, you can specify a different name for the invocant, instead of having to use self. To do this, you put it at the beginning of the method's signature and separate it from the rest of the signature with a colon:

method myMethod($invocant: $x, $y)

In this context, the colon is treated like a special type of comma, so you can write it with additional whitespace if that is easier:

method myMethod($invocant  :  $x, $y)

Here's an example:

class Point3D {
    has $.x-axis;
    has $.y-axis;
    has $.z-axis;
    
    method set-coord($new-x, $new-y, $new-z) {
        $!x-axis = $new-x;
        $!y-axis = $new-y;
        $!z-axis = $new-z;
    }
    
    method print-point {
        say "("~$!x-axis~","~$!y-axis~","~$!z-axis~")";
    }
    
    # method using the self invocant
    method distance-to-center {
        return sqrt(self.x-axis ** 2 + self.y-axis ** 2);
    }
    
    # method using a custom invocant named $rect
    method polar-coordinates($rect:) {
        my $r = $rect.distance-to-center;
        my $theta = atan2($rect.y-axis, $rect.x-axis);
        return "("~$r~","~$theta~","~$rect.z-axis~")";
    }
}

Objects

[edit | edit source]

Objects are data items whose type is a given class. Objects contain any attributes that the class defines, and also has access to any methods in the class. Objects are created with the new keyword.

Using the class Point3D:

my $point01 = Point3D.new();

The class constructor, new() can take named methods used to initialize any of the class attributes:

# Either syntax would work for object initialization
my $point01 = Point3D.new(:x-axis(3), :y-axis(4), :z-axis(6));
my $point02 = Point3D.new(x-axis => 3, y-axis => 4, z-axis => 6);

Methods from that class are called using the dot notation. This is the object, a period, and the name of the method after that.

$point01.print-point();
say $point01.polar-coordinates();

When an object isn't provided for dot notation method calls, the default variable $_ is used instead:

$_ = Point3D.new(:x-axis(6), :y-axis(8), :z-axis(6));;
.print-point();
say .polar-coordinates();

Inheritance

[edit | edit source]

Basic class systems enable data and the code routines that operate on that data to be bundled together in a logical way. However, there are more advanced features of most class systems that enable inheritance too, which allows classes to build upon one another. Inheritance is the ability for classes to form logical hierarchies. Raku supports normal inheritance of classes and subclasses, but also supports special advanced features called mixins, and roles. We are going to have to reserve some of the more difficult of these features for later chapters, but we will introduce some of the basics here.

Basic Types

[edit | edit source]

We've talked about a few of Perl's basic types in earlier chapters. It may surprise you to know that all Raku data types are classes, and that all these values have built-in methods that can be used. Here we're going to talk about some of the methods that can be called on some of the various objects that we've seen so far.

.print and .say

[edit | edit source]

We've already seen the print and say builtin functions. All built-in classes have methods of the same name that print a stringified form of the object.

.perl and eval

[edit | edit source]

We're going to take a quick digression and talk about the eval function. eval lets us compile and execute a string of Raku code at runtime.

eval("say 'hello world!';");

All Raku objects have a method called .perl that returns a string of Raku code representing that object.

my Int $x = 5;
$x.perl.say;          # "5"

my @y = (1, 2, 3);
@y.perl.say;          # "[1, 2, 3]"

my %z = :first(1), :second(2), :third(3);
%z.perl.say;          # "{:first(1), :second(2), :third(3)}"

Context and Coercion methods

[edit | edit source]

There are a number of methods that can be called to explicitly change the given data item into a different form. This is like an explicit way to force the given data item to be taken in a different context. Here is a partial list:

.item
Returns the item in scalar context.
.iterator
Returns an iterator for the object. We'll talk about iterators in a later chapter.
.hash
Returns the object in hash context
.list
Returns the object in array or "list" context
.Bool
Returns the boolean value of the object
.Array
Returns an array containing the object data
.Hash
Returns a hash containing the object data
.Iterator
Returns an iterator for the object. We'll talk about iterators in a later chapter.
.Scalar
Returns a scalar reference to the object
.Str
Returns a string representation for the object

Introspection Methods

[edit | edit source]
.WHENCE
Returns a code reference for the object types autovivification closure. We'll talk about autovivification and closures later.
.WHERE
Returns the memory location address of the data object
.WHICH
Returns the objects identity value, which for most objects is just it's memory location (it's .WHERE)
.HOW
(HOW = Higher Order Workings) Returns the meta class which handles this object
.WHAT
Returns the type object of the current object
Next Page: Comments and POD | Previous Page: Blocks and Closures
Home: Raku Programming