This file was automatically generated from http://svn.pugscode.org/pugs/docs/tutorial/ch06_objects.pod on Sat Aug 1 14:01:20 2009 GMT, revision 27701.
=head0 Objects
Objects are encapsulated chunks of data and functionality. Over the years a host of concepts have sprung up around objects, such as data abstraction, code reuse, encapsulation, single and multiple inheritance, composition, delegation, mixins, polymorphism, and multiple dispatch. Every language with object-oriented syntax selects a subset of these ideas and combines them in different ways. With Perl 6 we want to provide a cleaner and simpler syntax for working with objects, but we also want to support a larger set of object-oriented ideas. Does that sound impossible? The solution is a classically Perl-ish one: make the easy things easy and the hard things possible.
You can declare a class in one of two ways. The most familiar syntax
for class declaration ends in a semicolon. The rest of the file after
the declaration defines the class. With this syntax there can be only
one class or module declaration in a file.
class Heart::Gold; # class definition follows ...
The class declaration extends to the very end of the file, although in
Perl 6 the file doesn't need to return a 1 or a true to indicate
that the module loaded successfully.
The other syntax for class declaration wraps the definition in a block. You can have as many of these as you like in a file, and even embed one class within the block of another.
class Heart::Gold {
# class definition enclosed
...
}
And an embedded class:
class Heart::Gold {
# class definition here
class Heart::Gold::InfiniteImprobabilityDrive {
# sub-class definition here
}
class Heart::Gold::Ship {
# Another sub-class definition here
}
}
With a file definition, all code that follows the class declaration is
defined in the Heart::Gold namespace. With a block definition,
everything within the block is defined in the class's namespace.
To create a new object from a class, simply call its new method. The
default new method in the universal base class
Object creates and initializes an object.
Heart::Gold $ship; $ship = Heart::Gold.new(length => 150);
There's a shortcut for typed variables so you don't have to give the name of the class twice:
my Heart::Gold $ship .= new(length => 150);
The .= operator is like other assignment operators such as += and
-=. The two declarations are equivalent:
my Heart::Gold $ship; $ship = Heart::Gold.any_method() my Heart::Gold $ship .= any_method()
The . symbol is almost always associated with classes, their methods,
and their members, so anyplace you see it you can assume it has something
to do with a class.
Classes are the "cookie cutters" that build objects. Just as a
module groups subroutines in a package, a class groups methods
in a package. Classes can also contain subroutines, submethods, and
multimethods. Classes are significantly different than modules,
though, primarily because they construct objects. Objects don't just
define functionality, they also hold data. In Perl 5 objects were
simply hashes bestowed
with special powers by the bless built-in. Perl 6 objects can still
be simple blessed data structures, but the default is now an object
that hides the details of its internal representation--a true opaque
object.
Attributes are the data at the core of an opaque object. Other
languages have called them instance variables, data members, or
instance attributes. Attributes are declared with the has keyword,
and generally have a "." after the sigil:
class Heart::Gold {
has int $.length;
has int $.height is rw;
has @.cargo;
has %.crew;
...
}
Remember how we said above that the . symbol was used with classes?
This is another instance, the dot after the variable sigil indicates that
the variable is an attribute of the class. Attributes aren't
directly accessible outside the class, but inside the class they act just
like ordinary variables.
print $.length; $.length = 140;
Attributes also automatically generate their own accessor method with
the same name as the attribute. Accessor methods are accessible inside
or outside the class. By default, accessors are read-only, but the
is rw property marks an accessor as
read-write.
my Heart::Gold $obj .= new() $value = $obj.height; # returns the value of $.height $obj.height = 90; # sets the value of $.height $value = $obj.height # Okay, is readable $obj.length = 20 # WRONG! $.length is not rw
Methods are similar to subroutines, but different enough to merit
their own keyword, method. The most obvious differences are that
they're invoked on an object (or class), and they pass their invocant
(that is, the object or class on which they were invoked)
as an implicit argument. The invocant is marked off from the other
parameters in the list by a colon:
method initiate_drive ($self: $power, $tea) {
...
}
Methods topicalize their invocant, so it's always accessible as $_,
even if the method doesn't include it in the parameter list. This is
particularly handy since any method called without an explicit object
defaults to $_:
method shut_down ($drive) {
if .safe { # Same as $_.safe
.powerdown($drive); # Same as $_.powerdown($drive)
}
return .status; # Same as $_.status
}
Method declarations support the same syntax as subroutines for optional, named, variadic, and typed parameters, default values for parameters, properties on parameters, and return values. Method calls support positional and named argument passing just like subroutines. See Chapter 5 for more details on this syntax.
You can call a method in one of two ways. The standard method call is
connected to the object with the . operator. Like we said, The
. operator is like another way of saying "related to the class or
object".
$ship.shut_down($infinity);
An indirect object call is an alternative to the standard method call. This syntax looks like an ordinary subroutine call, except that the invocant is separated from the other arguments by a colon:
shut_down($ship: $infinity);
The parentheses are optional unless the method call is ambiguous without them.
shut_down $ship: $infinity;
Any class can inherit methods from another class using the is
keyword in the class declaration. You may have noticed that this is
the same keyword as compile-time properties. The fact that a class
inherits from some other class is really just a trait of the
inheriting class.
use Ship;
class Heart::Gold is Ship {
....
}
Any class can inherit from multiple parent classes.
class Heart::Gold is Ship is Improbable {
....
}
Within a derived class, inherited attributes are accessible only through their accessor methods:
class Ship {
has $.height;
has $.length;
...
}
class Heart::Gold is Ship {
method dimensions ($self:){
print "$self.length x $self.height \n";
}
}
The default new method provided by the Object base class
constructs and initializes opaque objects. It does this by calling
bless, which calls the CREATE and BUILDALL methods. The
CREATE method constructs an opaque object. The BUILDALL method
calls the initializers for all inherited classes and finally the
class's own initializer. BUILDALL actually calls the parent's
BUILDALL method, which calls its parent's BUILDALL method, etc.
The initializer for each class is BUILD. The default BUILD
initializes the attributes of the object with named arguments to
new, matching the name of the argument to the name of the
attribute.
There are a number of ways to change the default object construction
and initialization behavior. If you override new so that it passes
a data structure as the first argument to bless, it will construct
a traditional blessed hash object
instead of calling CREATE to construct an opaque object:
$class.bless({answer => '42'});
If you override the CREATE method you can alter the way objects are
constructed. If you override the BUILDALL method you can change how
the initializers for inherited classes are called. If you override the
BUILD method you can change how the current class initializes
objects and their attributes. Overriding BUILD will be common.
Overriding CREATE and BUILDALL will be rare, since their default
behavior is designed to handle everything from the simple opaque
object to inheriting from classes written in other languages.
Object destruction traverses the inheritance hierarchy in the reverse
order of object initialization. Objects are created from least derived
to most derived and destroyed from most derived to least derived. The
DESTROYALL method first calls the DESTROY method of the current
class, and then calls the DESTROYALL method of the parent class
(which calls its own DESTROY and then its own parent's
DESTROYALL, etc). You will rarely need to define a DESTROY
method, since the interpreter handles memory deallocation. It can be
useful for class-specific cleanup, like closing a socket or
filehandle.
Classes in Perl 6 are first class entities with entries in symbol tables or lexical scratchpads. This means classes can be lexically scoped, just like variables or subroutines:
my class Infinite::Improbablity {
...
}
$drive = Infinite::Improbability.new();
A lexical class works just like any other class, but is accessible by name only within the lexical scope where it's defined.
You can also define anonymous classes and create objects from them:
$class = class {
...
}
$object = $class.new();
A class's block is a closure, just like every other block, so it has access to variables from its defining scope, no matter where it's actually used.
A role is a reusable unit of class code. Much like a module exports
subroutines into your program or another module, a role exports
methods and attributes into a class. If your first thought on reading
this is "Isn't that just inheritance?", then welcome to a whole new
world. Inheritance is one way to reuse code, but many relationships
other than isa are possible. Various languages pick an alternative
and provide syntax for it: Ruby has mixins, Java has interfaces,
and some versions of Smalltalk have traits. Perl roles go a bit
beyond all of them.
You define a role using the role keyword:
role Hitchhiker {...}
You pull a role into a class using the does keyword:
class Arthur does Hitchhiker {...}
Roles cannot instantiate objects directly. To create an object that
makes use of a role, you make a new object from a class that uses
that role:
$person = Arthur.new(...);
Like classes, roles can define both attributes and methods:
role Hitchhiker {
has $.towel;
method thumb_ride ($self: $ship) {...}
...
}
Unlike classes, when you pull a role's methods and attributes into a
class they aren't maintained in an inheritance hierarchy to be
searched later. Instead, they are composed into the class almost as if
they had been defined in that class. All methods defined in the role
are accessible in the composed class, even if they wouldn't be
inherited. All attributes defined in the role are accessible in the
composed class by their direct $.name, not just by their accessor
method.
One advantage of composition is that classes can reuse behavior, even
if they have no connection that would justify an inheritance relation.
Let's say you want to define two classes: Arthur and Ford.
Arthur inherits from Human and has all the behaviors and
qualities of a human creature. Ford, on the other hand, has the
behaviors and qualities of a creature from Betelgeuse:
class Arthur is Human does Hitchhiker {...}
class Ford is Betelgeusian does Hitchhiker {...}
Inheritance makes sense in this case--the inherited classes are core,
defining characteristics of the resulting class. But the Hitchhiker
role isn't a defining part of Ford and Arthur--they weren't always
hitchhikers. The role just adds some useful behavior to the class.
In some situations you may want to add a role at run time instead of
at compile time. Perhaps you want to choose different roles based on
how the object is used, or perhaps the role's behavior shouldn't be
available until part-way through the life of an object. The same
does keyword adds roles at run time, but operates on
an object instead of a class. In this example, Arthur starts as an
ordinary human, and only adds the Hitchhiker role later in life:
class Arthur is Human {...}
$person = Arthur.new;
$person.live_quietly until $vogon_ship.arrive;
$person does Hitchhiker;
$person.thumb_ride($vogon_ship);
An interface is a reusable unit that defines what methods a class should support, but doesn't provide any implementations for those methods. In Perl 6, interfaces are just roles that define only method stubs and no attributes. This example defines an interface for products shipped by the Sirius Cybernetics corporation:
role Sirius::Cybernetics {
method share {...}
method enjoy {...}
}
No matter whether the product is an elevator, a nutrimatic machine, or
an automatic door, it must support the share and enjoy methods.
Now, since these products are so very different, none will implement
the methods in quite the same way, but you're guaranteed the products
will be able to "Share and Enjoy" in one way or another (generally an
irritating way).
Since a class pulls in roles by composition instead of inheritance, a
conflict results when two roles both have a method with the same name.
So, the Hitchhiker and Writer roles both define a lunch_break
method (lunch breaks being vitally important in both the publishing
and footslogging industries):
role Hitchhiker {
method lunch_break {
.suck($.towel);
.drink($old_janx);
}
...
}
role Writer {
method lunch_break {
my $restaurant = Jolly::Nice::Restaurant.new;
.dine($restaurant);
}
...
}
If the Ford class does the Writer role as well as the
Hitchhiker role, which kind of lunch break should he take? Since
roles are composed without hierarchy or priority, both methods are
equally valid choices. Rather than randomly selecting an
implementation for you, Perl 6 simply requires you to choose one.
There are several ways to do this. One is to define a method of the
same name in the class itself. This method might simply call the
method from one of the roles:
class Ford does Hitchhiker does Writer {
method lunch_break { .Writer::lunch_break(@_); }
}
Or the method might select between the possible implementations based
on one of the arguments or some condition in the object. This example
checks the string value returned by the .location method to find
out which lunch break is appropriate:
class Ford does Hitchhiker does Writer {
method lunch_break ($self: $arg) {
given (.location) {
when "Megadodo Office" { $self.Writer::lunch_break($arg); }
when "Ship Cargo Hold" { $self.Hitchhiker::lunch_break($arg); }
}
}
}
You can also get a finer-grained control over method conflict
resolution using delegation syntax (explained in the next section).
This example renames Hitchhiker's lunch_break method to snack
in the composed class:
class Ford does Hitchhiker handles :snackE<laquo>lunch_breakE<raquo> does Writer {...}
Delegation is yet another possible relationship between an object and
another body of code. Rather than pull methods into a class, you call
methods in another object as if they were methods of the class. In
Perl 6, delegation can be done in either a class or a role. A
delegated object is simply an attribute defined in the class or role.
The handles keyword specifies which methods of
the delegated object will act as methods of the class. This example
declares that any calls to the thumb_ride method on an object with
the Hitchhiker role, will actually call the method on its
$.thumb attribute:
role Hitchhiker {
...
has Electronic::Thumb $.thumb handles 'thumb_ride';
...
}
The handles keyword accepts many variations in the syntax to
delegate methods. You can pass it an array reference of multiple
method names:
has Electronic::Thumb $.thumb handles ['thumb_ride', 'sub_etha'];
Or a quoted list:
has Electronic::Thumb $.thumb handles E<laquo>thumb_ride sub_ethaE<raquo>;
A pair in place of a string method name gives the method a different
name in the class. This example declares a method named hitch in
the class, but any calls to it are delegated to the thumb_ride
method on the $.thumb object:
has Electronic::Thumb $.thumb handles :hitchE<laquo>thumb_rideE<raquo>;
If the method name is given as a pattern, it's a wildcard delegation
and all methods that match that pattern will be delegated to the
attribute. This example delegates all methods that start with "thumb"
to $.thumb:
has Electronic::Thumb $.thumb handles /^thumb/;
If the method name is a substitution, it does wildcard method
renaming. This example would delegate a method call to hitch_ride
to a method named thumb_ride in $.thumb:
has Electronic::Thumb $.thumb handles (s/^hitch/thumb/);
By default, all methods and attribute accessors are public methods,
so they can be called anywhere. You can also declare private
methods or accessors, which can be called only within the class where
they're defined, or from certain trusted classes. A private method is
declared with the my keyword at the start of the declaration.
my method inaccessible ($self: $value) {...}
A private attribute is declared with an exclamation markin place of the dot
(.) in the name:
has $!hidden;
You call a private method or accessor with an exclamation mark in the call:
$object.!hidden(42);
The attribute variable ($!name or $.name) is never accessible
outside the class, whether the attribute is public or private.
At first glance this might look like nothing more than the
"encapsulation by convention" of Perl 5. It's actually much more than
that. The exclamation mark implicitly sets a private trait on
the method or attribute. The encapsulation is enforced by the
interpreter. An external call to a private method will fail as if the
method simply didn't exist. External queries to the package symbol
table for private methods also fail.
Only public methods are inherited by a derived class, but inherited public methods can call private methods from their own class. Private methods and attributes in a role are private to the composed class, as if they were defined in that class.
The one loophole in private methods is that a class can declare that
it trusts certain other classes to allow those
classes to access its private methods. Roles cannot declare a trusted
class. In this example, the Friendly class declares that it trusts
the Zaphod class:
class Friendly {
trusts Zaphod; # probably a bad idea, really
}
You can define ordinary subroutines within a class or role. They
cannot be invoked on an object with the $object.methodname syntax
and will never pass an implicit invocant argument. They aren't
inherited but can be pulled in with role composition. They're mainly
useful for utility code internal to the class:
class Answer::Young;
has $.answer;
...
sub is_valid ($value) {
return 1 if 10 < $value < 42;
}
...
method set_answer ($new) {
$.answer = $new if is_valid($new);
}
Subroutines may be exported if the class also functions as a module.
A submethod is declared like a method, but behaves more like a
sub in that it's not inherited but can be pulled in with a role.
Submethods are useful for inheriting interface without inheriting
implementation--you can override a method from a parent class without
inflicting the changes on any child classes.
The Frogstar::A class defines a set of methods and attributes for
the Frogstar Scout robots:
class Frogstar::A {
has Laser::Beam $.beam;
has Antimatter::Ray $.ray;
has Electron::Ram $.ram;
...
method zap ($target) { $.beam.fire($target); }
method shoot ($target) { $.ray.fire($target); }
method smash ($target) { $.ram.fire($target); }
...
}
In addition to methods for navigation, propulsion, etc. the Frogstar
Scouts boast an astounding number of destructive methods (as is to be
expected). The Frogstar::B class inherits all of Frogstar::A's
methods and attributes, and also adds its own additional weaponry.
Instead of defining a new method for the Zenon Emitter, the Frogstar
Scout B overrides the smash method to use the emitter:
class Frogstar::B is Frogstar::A {
has Zenon::Emitter $.emitter;
submethod smash ($target) { $.emitter.fire($target); }
}
It still smashes the target, only faster, as you might expect from a
newer model. Since the overridden method was declared as a submethod,
it has no effect on the Frogstar Scout C which inherits from
Frogstar::B:
class Frogstar::C is Frogstar::B {...}
...
$fighter = Frogstar::C.new(...);
$fighter.smash($floor); # uses the Electron::Ram
In the previous chapter we mentioned multi subroutines. The multi
keyword actually applies to any code object:
subroutines, methods, or submethods. As we said before, multi
allows you to define multiple different routines all with the same
name but different signatures. This example dispatches to a variant
of the lunch method depending on the types of the arguments:
multi method lunch (Lunching::Friar $who, Megadodo::Office $location) {
print "Jolly nice restaurant.";
}
multi method lunch (Hitchhiker $who, Cargo::Hold $location) {
print "Towel again.";
}
A member of the Lunching Friars of Voondon must always eat at a nice restaurant when he visits the offices of Megadodo Publications. A hitchhiker in a cargo hold, however, will just have to settle for the nutrient solution soaked into the corner of his towel.
A call to a multimethod has the same syntax as a call to a subroutine--the name of the routine followed by a list of arguments:
lunch($zaphod, $where);
This call searches outward through its lexical, package, and
global scopes for a matching name. If it finds a non-multi sub it
makes an ordinary subroutine call. Otherwise it generates a list of
multi subs, methods, or submethods with that name and dispatches
to the closest matching signature.
You can also call a multimethod with an ordinary single-dispatch method call:
$zaphod.lunch($where);
In this case, the call will only failover to multiple dispatch if it
can't find a suitable method to call under single dispatch to
$zaphod.
Operator overloading makes use of multiple dispatch. An operator is
just a subroutine with special call syntax. Operators define the kind
of syntax they use as part of their name: prefix, postfix,
infix, circumfix, etc. This example overloads two operators that
use the + symbol--one prefix operator and one infix operator:
multi sub *prefix:+ (Time $a) {...} # $x = +$y;
multi sub *infix:+ (Time $a, Time $b) {...} # $x = $y + $z;
These operators are declared as multi subs with global scope, as most
operators will be in Perl 6 (global is specified by the leading *
in the name). They're multi so it's easy to add new behavior for new
types of operands. They're global so that any operation anywhere with
the defined operand types will find the right multi variant of the
operator.