Categories
Posts in this category
- Introduction
- Strings, Arrays, Hashes;
- Types
- Basic Control Structures
- Subroutines and Signatures
- Objects and Classes
- Contexts
- Regexes (also called "rules")
- Junctions
- Comparing and Matching
- Containers and Values
- Where we are now - an update
- Changes to Perl 5 Operators
- Laziness
- Custom Operators
- The MAIN sub
- Twigils
- Enums
- Unicode
- Scoping
- Regexes strike back
- A grammar for (pseudo) XML
- Subset Types
- The State of the implementations
- Quoting and Parsing
- The Reduction Meta Operator
- The Cross Meta Operator
- Exceptions and control exceptions
- Common Perl 6 data processing idioms
- Currying
Wed, 24 Sep 2008
Objects and Classes
Permanent link
NAME
"Perl 5 to 6" Lesson 05 - Objects and Classes
LAST UPDATED
2015-02-25
SYNOPSIS
class Shape { method area { ... } # literal '...' has $.colour is rw; } class Rectangle is Shape { has $.width; has $.height; method area { $!width * $!height; } } my $x = Rectangle.new( width => 30.0, height => 20.0, colour => 'black', ); say $x.area; # 600 say $x.colour; # black $x.colour = 'blue';
DESCRIPTION
Perl 6 has an object model that is much more fleshed out than the Perl 5 one. It has keywords for creating classes, roles, attributes and methods, and has encapsulated private attributes and methods. In fact it's much closer to the Moose
Perl 5 module (which was inspired by the Perl 6 object system).
There are two ways to declare classes
class ClassName; # class definition goes here
The first one begins with class ClassName;
and stretches to the end of the file. In the second one the class name is followed by a block, and all that is inside the block is considered to be the class definition.
class YourClass { # class definition goes here } # more classes or other code here
Methods
Methods are declared with the method
keyword. Inside the method you can use the term self
to refer to the object on which the method is called (the invocant).
You can also give the invocant a different name by adding a first parameter to the signature list and appending a colon :
to it.
Public methods can be called with the syntax $object.method
if it takes no arguments, and $object.method($arg, $foo)
or $object.method: $arg, $foo
if it takes arguments.
class SomeClass { # these two methods do nothing but return the invocant method foo { return self; } method bar(SomeClass $s: ) { return $s; } } my SomeClass $x .= new; $x.foo.bar # same as $x
(The my SomeClass $x .= new
is actually a shorthand for my SomeClass $x = SomeClass.new
. It works because the type declaration fills the variable with a "type object" of SomeClass
, which is an object representing the class.)
Methods can also take additional arguments just like subs.
Private methods can be declared with method !methodname
, and called with self!method_name
.
class Foo { method !private($frob) { return "Frobbed $frob"; } method public { say self!private("foo"); } }
Private methods can't be called from outside the class and private methods are only looked up in the current class, not its parent classes.
Attributes
Attributes are declared with the has
keyword, and have a "twigil", that is a special character after the sigil. For private attributes that's a bang !
, for public attributes it's the dot .
. Public attributes are just private attributes with a public accessor. So if you want to modify the attribute, you need to use the !
sigil to access the actual attribute, and not the accessor (unless the accessor is marked is rw
).
class SomeClass { has $!a; has $.b; has $.c is rw; method set_stuff { $!a = 1; # ok, writing to attribute from within the class $!b = 2; # same $.b = 3; # ERROR, can't write to ro-accessor $.c = 4; # ok, the accessor is rw } method do_stuff { # you can use the private name instead of the public one # $!b and $.b do the same thing by default return $!a + $!b + $!c; } } my $x = SomeClass.new; say $x.a; # ERROR! a is private say $x.b; # ok $x.b = 2; # ERROR! b is not declared "rw" $x.c = 3; # ok
Inheritance
Inheritance is done through an is
trait.
class Foo is Bar { # class Foo inherits from class Bar ... }
All the usual inheritance rules apply - public methods are first looked up on the direct type, and if that fails, on the parent class (recursively). Likewise the type of a child class is conforming to that of a parent class:
class Bar { } class Foo is Bar { } my Bar $x = Foo.new(); # ok, since Foo ~~ Bar
In this example the type of $x
is Bar
, and it is allowed to assign an object of type Foo
to it, because "every Foo
is a Bar
".
Classes can inherit from multiple other classes:
class ArrayHash is Hash is Array { ... }
Though multiple inheritance also comes with multiple problems, and people usually advise against it. Roles are often a safer choice.
Roles and Composition
In general the world isn't hierarchical, and thus sometimes it's hard to press everything into an inheritance hierarchy. Which is one of the reasons why Perl 6 has Roles. Roles are quite similar to classes, except you can't create objects directly from them, and that composition of multiple roles with the same method names generate conflicts, instead of silently resolving to one of them, like multiple inheritance would do.
While classes are intended primarily for type conformance and instance management, roles are the primary means for code reuse in Perl 6.
role Paintable { has $.colour is rw; method paint { ... } # literal ... } class Shape { method area { ... } } class Rectangle is Shape does Paintable { has $.width; has $.height; method area { $!width * $!height; } method paint() { for 1..$.height { say 'x' x $.width; } } } Rectangle.new(width => 8, height => 3).paint;
SEE ALSO
http://doc.perl6.org/language/objects http://design.perl6.org/S12.html http://design.perl6.org/S14.html http://www.jnthn.net/papers/2009-yapc-eu-roles-slides.pdf http://en.wikipedia.org/wiki/Perl_6#Roles