|
Perl 6 FAQ - Object Orientation
This FAQ is part of the Programmer's Heaven Perl 6 FAQ. It answers questions about the new object system in Perl 6, which is a vast improvement on that of Perl 5.How does object orientation in Perl 6 differ from Perl 5?
Perl 6 makes vast improvements over Perl 5 when it comes to object oriented programming. The main differences are:- The "->" for method calling and attribute access has been replaced with "." (as used in Java, C# and many other languages)
- A new opaque type has been added so real encapsulation is trivial
- The "class" keyword has been introduced to distinguish real classes that can be instantiated from modules of subroutines. If you are familiar with Perl 5, a consequence of this is that you will no longer have to write your own constructor that blesses a hash and so on.
- The "has" keyword has been introduced for specifying attributes rather than just storing them in a hash or array (thus giving much better compile time checking)
- The "method" keyword has been introduced to indicate that something is really a method, not just a subroutine.
- The introduction of roles to aid code re-use. In Perl 6, classes are primarily for instance management rather than code re-use. Many object oriented languages use classes to do both of these; Perl 6 won't stop you doing this, but roles may well allow for better re-use.
Does Perl 6 force me to write in an object oriented fashion?
No. Perl 6 is a multi-paradigm programming language. If using OOP suits a situation, use it. If it doesn't, program in a procedural style, or a functional style, or a programming with contracts style, or whatever style you feel like.How do you define classes?
Perl 6 has added a new "class" keyword for declaring a class, partially replacing the "package" keyword in Perl 5.class Dog {
...
}You may also use a class declaration without a block:
class Dog; ...
However, if you do this then it must be the first declaration in the file, and the rest of the file will be taken to be part of the implementation of the class "Dog".
How do you define the attributes/fields/properties for a class?
The new "has" keyword is used to specify the attributes for the class. These will exist per instance of the class.class Dog {
has $.tail;
has @.paws;
}Here the secondary "." sigil is used to indicate that an accessor ("get" method) for the attribute should be automatically inserted when the program is being compiled. To get a mutator ("set" method) too, add the "rw" trait.
class Dog {
has $.tail; # Automatic get
has @.paws; # Automatic get
has $.toy is rw; # Automatic get/set
}Note that this is not like making a public attribute in languages like Java and C#, which may be considered a breach of encapsulation by some. The attributes are still private and accessed through methods, it's just that you do not have to write these methods yourself.
You may omit the dot to avoid generating any accessors or mutators, meaning that the attribute is not accessible from outside of the class (just like a private attribute).
class Dog {
has $.tail;
has @.paws;
has $.toy is rw;
has $brain; # Invisible outside the class
}The "!" sigil can be used to make it explicit that an attribute is private, and more importantly can be used to access it if there happens to be a lexical variable of the same name as the attribute that hides it.
class Dog {
has $.tail;
has @.paws;
has $.toy is rw;
has $!brain; # Invisible outside the class
method brain_transplant($brain) {
# $brain parameter hides $brain attribute. Use $!brain.
$!brain = $brain;
}
}Note that, even when accessors/mutators are generated, you can still write your own, which will automatically override the default ones.
How do you define methods?
Use the new "method" keyword to define a method. A method takes a parameter list somewhat like a "sub" does.class Dog {
has $.treats_eaten;
method give_treats($how_many) {
$.treats_eaten += $how_many;
}
}The invocant (object that the method was invoked on) need not be specified explicitly in the parameter list, unlike in Perl 5. It is available using the self keyword. We can use this to call a method on the instance of the object that this method was invoked on:
class Dog {
has $.treats_eaten;
method give_treats($how_many) {
$.treats_eaten += $how_many;
self.wag_tail();
}
method wag_tail() {
...
}
}It is also possible to give an explicit name to the invocant. To do this, put the variable you would like to hold the invocant at the start of the parameter list and then place a colon after it to denote that it is the invocant, not just an ordinary parameter.
class Dog {
has $.treats_eaten;
method give_treats($this_dog: $how_many) {
$.treats_eaten += $how_many;
$this_dog.wag_tail();
}
method wag_tail() {
...
}
}One reason you may wish to do this is to provide a more descriptive name for the invocant. (There are other reasons why you may wish to do this too, but they are beyond the scope of this answer.)
How do you inherit from another class?
Perl 6, like Perl 5, supports multiple inheritance. Many languages (Java, C#) support only single inheritance of classes. To inherit from a class, use the "is" keyword.class Dog is Animal {
...
}Or for multiple inheritance, use "is" several times.
class Dog is Animal is Pet {
...
}How do you instantiate a class?
In Perl 6, every class automatically comes with a new method, which is essentially its constructor. This means that you can instantiate a class in the C#-ish, Java-ish way:my Dog $spot = new Dog();
However, you can use the ".=" operator (call method and assign) to avoid writing the name of the class twice:
my Dog $spot .= new();
This works because "new" is a class (or static) method in the Dog class. It can be better understood by breaking it into two lines:
my Dog $spot; $spot .= new()
At this point you may be thinking "hang on, Spot is not instantiated yet so how can a method be called on it?" This can be done because, unlike in some other languages, methods of the class (also known as static methods) can be called just like instance methods, and the type of $spot is known from its declaration.
The default constructor can also be used to initialize attributes:
my Dog $spot .= new(name => 'Spot');
How do you call a method?
Use the "." operator to call a method on an object. For example, to call the give_treats method on the object $dog, you would write:my Dog $spot .= new(name => 'Spot'); # Instantiate $dog $dog.give_treats(4); # Call method
How do I translate a typical Perl 5 class into Perl 6?
The Perl 5 support for object orientation makes it hard to define a "typical class" in Perl 5. However, here is an example of a Ball class, which stores details about a ball, including how bouncy it is. There is a method to calculate the velocity a ball will bounce back at if it hits a surface at a given velocity.############
## Perl 5 ##
############
package Ball;
# Constructor.
# ############
sub new {
# Get the invocant
$invocant = shift;
# Create a reference to an anonymous hash.
my $self = {
restitution => 0.8
};
# Bless the reference.
bless $self, $invocant;
# Return the newly created object.
return $self;
}
# Calculate bounce velocity of the ball.
# ######################################
sub calculate_bounce_velocity {
#Get the invocant and impact velocity.
$self = shift;
my $impact_velocity = shift;
#Do the calculation.
my $bounce_velocity = $self->{'restitution'} * -$impact_velocity;
#Return bounce velocity.
return $bounce_velocity;
}
1;We start by replacing the package declaration with the new class keyword.
############class Ball { }
- # Perl 6 ##
- ###########
We then notice that there appears to be an attribute "restitution" that is presumably set from outside of the object. We will make this a real instance variable, set the default value and use "." and "is rw" to have an accessor and a mutator generated automatically.
############class Ball { has $.restitution is rw = 0.8; }
- # Perl 6 ##
- ###########
At this point, knowing we get an automatically generated new method that covers the functionality the existing new method in the Perl 5 code has, we can decide not to translate the new method at all. That just leaves the velocity method. It can be shorter and simpler, since:
- We can use the new parameter list syntax
- We can use the new attribute access code
############class Ball { has $.restitution is rw = 0.8;
- # Perl 6 ##
- ###########
method calculate_bounce_velocity($impact_velocity) { #Do the calculation. my $bounce_velocity = $.restitution * -$impact_velocity; #Return bounce velocity. return $bounce_velocity; } }
- Calculate bounce velocity of the ball.
- ######################################
This is about a third of the length of the original code, and much more readable.
What is a role?
Roles are a new idea in Perl 6. A role, like a class, can have methods and attributes. However, it cannot be instantiated on its own. Instead, it must be somehow "joined" with another class or object in order to be used. This can be done at compile time, in which case the process is known as role composition or at runtime, in which case we say the role has been mixed in.
There are many ways to think of roles, and the one that is easiest for you depends on what languages you have worked in before. If you are familiar with interfaces, think of roles as interfaces where the methods are allowed to come with a default implementation. If you are familiar with mix-ins, think of roles a bit like those, but you can also compose them at compile time. If parametric polymorphism (or generics) is more comfortable to you, think of a role as a set of generic methods and, optionally, some associated attributes. You may also think of roles as being somewhat like aspects in Aspect Oriented Programming.
When should I use roles rather than classes?
When deciding whether to implement something as a role or a class, consider whether it is something that an object can be said to do rather than to be. For example, a dog clearly is an animal. However, it does eat. If there are a set of common methods associated with eating, for example Bite and Chew, then placing these methods into an "Eat" role is probably a good idea. This way, eating functionality can be shared by both the Cat and the Dog classes.role Eat {
method Bite() { ... }
method Chew() { ... }
}Another angle to approach this from is to ask, "is this something that just one class does, or something done by many classes?" For example, if you were considering implementing a Log class with a write_message_to_log method, it may be better to implement this as a role and then compose the role into all classes that need to do logging.
How do I compose roles at compile time?
Composing a role into a class involves taking the role's methods and "adding them" to the methods of that class. Composing a role into a class at compile time is achieved using the "does" keyword.class Dog is Animal does Eat {
...
}You can compose multiple roles by using the "does" keyword many times.
class Dog is Animal does Eat does Fetch {
...
}The "does" keyword can also be placed inside the class body.
class Dog is Animal {
does Eat;
does PlayFetch;
does MakeTooMuchNoise; # Well, mine does anyway...
...
}Can I use a role like an interface?
An interface can be seen as a role where none of the methods are implemented. To specify that a method is not implemented, use the "..." operator (yes, that really is part of Perl 6 syntax).role Meal {
method prepare(:$style) { ... }
method cook() { ... }
}Method bodies must be provided by another role or the class (or one of its superclasses) that the role is being composed or mixed in to. For roles composed at compile time, this can be checked at compile time.
Can I use a role like a mix-in?
In Perl 6, mixing in a role involves adding its methods to a class or object at runtime. Composing a new role into an existing class using the "does" keyword will not modify an existing class, but instead will create a new anonymous class with the role composed into it and bind it to the given name. This means that any new objects instantiated from the class will have the role composed in, but existing objects will not gain the methods from the role.If instead of "does" you use "but", a copy will be made of the existing class or object before the role is mixed in, and the expression will evaluate to the copy of that class or object with the role mixed in.
Runtime mixing in is not implemented in Pugs at the time of writing; the FAQ will be updated with some code examples once this functionality is available to play with.
Back To FAQ List | Next Section
What's next?
Join our Perl 6 Newsletter
Visit our Perl Resources
- Perl 6 Forum
- Perl, PHP & Python zone
- Perl Programming Forum
- Beginners Guide to Perl
- Regex tutorial
- 20 Perl Tips And Tricks
|
|
riya
From India (Report as abusive) |
"Very Useful" this faqs made to know about many things unknown and it helped me a lot |
| View all Rate and comment this article |
Sponsored links
Build IT Knowledge with Current & Trusted Content
Helps Employees Develop & Hone New Technical Programming Skills. Sign Up & Get Full Access.
Helps Employees Develop & Hone New Technical Programming Skills. Sign Up & Get Full Access.
Check Out IT Certification Preparation Materials
Sign Up With SkillSoft & Get Access to Training Materials for Over 50 Professional Certifications.
Sign Up With SkillSoft & Get Access to Training Materials for Over 50 Professional Certifications.
PureCM Software Configuration Management
Version control and integrated issue tracking - powerful and easy to use. Get your FREE trial now!
Version control and integrated issue tracking - powerful and easy to use. Get your FREE trial now!
CSTSOFT Instrumentation .NET & ActiveX Components
A collection of 13 instrumentation .NET/ActiveX/VCL components including Gauge,Knob,LED,Trend etc.
A collection of 13 instrumentation .NET/ActiveX/VCL components including Gauge,Knob,LED,Trend etc.
Software Localization Tool Sisulizer
Localize DotNet, C++ Builder, Delphi, C/C++, Visual Basic & Java apps & html help. Try Sisulizer now
Localize DotNet, C++ Builder, Delphi, C/C++, Visual Basic & Java apps & html help. Try Sisulizer now