diff options
author | Dave Rolsky <autarch@urth.org> | 2011-07-07 11:36:37 -0500 |
---|---|---|
committer | Dave Rolsky <autarch@urth.org> | 2011-09-08 21:47:22 -0500 |
commit | dbfe29416ae22f393039d7e661b8a11632e590a0 (patch) | |
tree | dc29adb51c80e4f6786bf6a37f4d0ced0219ac6e /pod/perlootut.pod | |
parent | 935647290357b277a54366c3caf2ddc89bfbd3eb (diff) | |
download | perl-dbfe29416ae22f393039d7e661b8a11632e590a0.tar.gz |
Check in new OO tutorial - perlootut
Diffstat (limited to 'pod/perlootut.pod')
-rw-r--r-- | pod/perlootut.pod | 677 |
1 files changed, 677 insertions, 0 deletions
diff --git a/pod/perlootut.pod b/pod/perlootut.pod new file mode 100644 index 0000000000..e1cfedbbca --- /dev/null +++ b/pod/perlootut.pod @@ -0,0 +1,677 @@ +=encoding utf8 + +=for comment +Consistent formatting of this file is achieved with: + perl ./Porting/podtidy pod/perlootut.pod + +=head1 NAME + +perlootut - Object-Oriented Programming in Perl Tutorial + +=head1 DATE + +This document was created in February, 2011. + +=head1 DESCRIPTION + +This document provides an introduction to object-oriented programming +in Perl. It begins with a brief overview of the concepts behind object +oriented design. Then it introduces several different OO systems from +L<CPAN|http://search.cpan.org> which build on top of what Perl +provides. + +By default, Perl's built-in OO system is very minimal, leaving you to +do most of the work. This minimalism made a lot of sense in 1994, but +in the years since Perl 5.0 we've seen a number of common patterns +emerge in Perl OO. Fortunately, Perl's flexibility has allowed a rich +ecosystem of Perl OO systems to flourish. + +If you want to know how Perl OO works under the hood, the L<perlobj> +document explains the nitty gritty details. + +This document assumes that you already understand the basics of Perl +syntax, variable types, operators, and subroutine calls. If you don't +understand these concepts yet, please read L<perlintro> first. You +should also read the L<perlsyn>, L<perlop>, and L<perlsub> documents. + +=head1 OBJECT-ORIENTED FUNDAMENTALS + +Most object systems share a number of common concepts. You've probably +heard terms like "class", "object, "method", and "attribute" before. +Understanding the concepts will make it much easier to read and write +object-oriented code. If you're already familiar with these terms, you +should still skim this section, since it explains each concept in terms +of Perl's OO implementation. + +Perl's OO system is class-based. Class-based OO is fairly common. It's +used by Java, C++, C#, Python, Ruby, and many other languages. There +are other object orientation paradigms as well. JavaScript is the most +popular language to use another paradigm. JavaScript's OO system is +prototype-based. + +=head2 Object + +An B<object> is a data structure that bundles together data and +subroutines which operate on that data. An object's data is called +B<attributes>, and its subroutines are called B<methods>. An object can +be thought of as a noun (a person, a web service, a computer). + +An object represents a single discrete thing. For example, an +object might represent a person. The attributes for a person object +might include name, birth date, and country of residence. If we created +an object to represent Larry Wall, Perl's creator, that object's name +would be "Larry Wall", born on "September 27, 1954", and living in +"USA". + +The methods associated with a person might include C<print_greeting()> +and C<calculate_age()>. + +In Perl most objects are hash references, but the OO systems we +recommend keep you from having to worry about this. In practice, it's +best to consider an object's internal data structure opaque. + +=head2 Class + +A B<class> defines the behavior of a category of objects. A class is a +name for a category (like "Person"), and a class also defines the +behavior of objects in that category. + +All objects belong to a specific class. For example, our Larry Wall +object belongs to the C<Person> class. When we want to create a +specific object, we start with its class, and B<construct> or +B<instantiate> an object. A specific object is often referred to as an +B<instance> of a class. + +In Perl, any package can be a class. The difference between a package +which is a class and one which isn't is based on how the package is +used. Here's our "class declaration" for the Person class: + + package Person; + +In Perl, there is no special keyword for constructing an object. +However, most OO modules on CPAN use a method named C<new()> to +construct a new object: + + my $larry = Person->new( + name => 'Larry Wall', + birth_date => '1954-09-27', + country_code => 'us', + ); + +(Don't worry about that C<< -> >> operator, it will be explained +later.) + +=head3 Blessing + +As we said earlier, most Perl objects are hash references, but an +object can be a reference to any Perl data type (scalar, array, etc.). +Turning a plain reference into an object is done by B<blessing> that +reference using Perl's C<bless> function. + +While we strongly suggest you don't build your objects from scratch, +you should know the term B<bless>. A B<blessed> reference is an object. +We sometimes say that an object has been "blessed into a class". + +Once a reference has been blessed, the C<blessed> function from the +L<Scalar::Util> core module can tell us its class name. This subroutine +returns an object's class when passed an object, and false otherwise. + + use Scalar::Util 'blessed'; + + print blessed($hash); # undef + print blessed($larry); # Person + +=head3 Constructor + +A B<constructor> creates a new object. In Perl, a class's constructor +is just another method, unlike some other languages, which provide +syntax for constructors. Most Perl classes use C<new> as the name for +their constructor: + + my $file = File->new(); + +=head2 Methods + +You already learned that a B<method> is a subroutine that operates on +an object's data. You can think of a method as the things that an +object can I<do>. + +In Perl, methods are simply subroutines that live in a class's package. +Methods are always written to receive the object as their first +argument: + + sub print_greeting { + my $self = shift; + + print "Hello, ", $self->name, "\n"; + } + + $larry->print_greeting; # Hello, Larry Wall + +What makes a method special is I<how it's called>. The arrow operator +(C<< -> >>) tells Perl that we are calling a method. + +When we make a method call, Perl arranges for the method's B<invocant> +to be passed as the first argument. B<Invocant> is a fancy name for the +thing on the left side of the arrow. The invocant can either be a class +name or an object. We can also pass additional arguments to the method: + + sub print_greeting { + my $self = shift; + my $greeting = shift // "Hello"; + + print $greeting, ", ", $self->name, "\n"; + } + + $larry->print_greeting("Yo, Wassup"); # Yo, Wassup, Larry Wall + +=head2 Attributes + +Each class can define its B<attributes>. When we instantiate an object, +we assign values to those attributes. For example, every C<Person> +object has a name. Attributes are sometimes called B<properties>. + +Perl has no special syntax for attributes. Under the hood, attributes +are often stored as keys in the object's hash reference, but don't +worry about this. + +We recommend that you only access attributes via B<accessor> methods. +These are methods that can get or set the value of each attribute. We +saw this earlier in the C<print_greeting()> example, which calls C<< +$self->name >>. + +You might also see the terms B<getter> and B<setter>. These are two +types of accessors. A getter gets the attribute's value, while a setter +sets it. + +Attributes are typically defined as read-only or read-write. Read-only +attributes can only be set when the object is first created, while +read-write attributes can be altered at any time. + +The value of an attribute may itself be another object. For example, +instead of returning its birth date as a string, the C<Person> class +could return a L<DateTime> object representing that date. + +It's possible to have a class that does not expose any publicly +settable attributes. Not every class has attributes and methods. + +=head2 Polymorphism + +B<Polymorphism> is a fancy way of saying that objects from two +different classes share an API. For example, we could have C<Person> +and C<Animal> classes which both have a C<speak()> method. This method +might produce different output for each class, but the basic API is the +same. + +While the two classes may differ in many ways, when it comes to the +C<speak()> method, they are the same. This means that we can try to +call the C<speak()> method on an object of either class, and B<we don't +have to know what class the object belongs to!> + +Polymorphism is one of the key concepts of object-oriented design. + +=head2 Inheritance + +B<Inheritance> is a way to specialize an existing class. It allows one +class to reuse the methods and attributes of another class. + +We often refer to inheritance relationships as B<parent-child> or +C<superclass/subclass> relationships. Sometimes this is called an +B<is-a> relationship. + +Inheritance is best used to create a specialized version of a class. +For example, we could create an C<Employee> class which B<inherits> +from C<Person>. An C<Employee> B<is-a> I<more specific> type of +C<Person>. All employees are persons, but not all persons are +employees. + +C<Person> is a B<superclass> of C<Employee>, and C<Employee> is a +B<subclass> of C<Person>. + + package Employee; + + use parent 'Person'; + +The L<parent> module is one of several ways that Perl lets you define +inheritance relationships. + +Perl allows multiple inheritance, which means that a class can inherit +from multiple parents. While this is possible, we strongly recommend +against it. Generally, you can use B<roles> to do everything you can do +with multiple inheritance in a cleaner way. + +Note that there's nothing wrong with defining multiple subclasses of a +given class. This is both common and safe. For example, we might define +C<Employee::Permanent> and C<Employee::Temporary> classes to +distinguish between different types of employees. + +=head3 Overriding methods and method resolution + +Inheritance allows two classes to share code. By default, every method +in the parent class is also available in the child. The child can +explicitly B<override> a parent's method to provide its own +implementation. For example, if we have an C<Employee> object, it has +the C<print_greeting()> method from person: + + my $larry = Employee->new( + name => 'Larry Wall', + birth_date => '1954-09-27', + country_code => 'us', + job_title => 'Hacker Extraordinaire', + ); + + $larry->print_greeting; # Hello, Larry Wall + +If we wanted to include the employee's job title in the greeting, we +could override the method: + + package Employee; + + use parent 'Person'; + + sub print_greeting { + my $self = shift; + + print "Hello, ", $self->name, " - ", $self->job_title, "\n"; + } + + $larry->print_greeting; # Hello, Larry Wall - Hacker Extraordinaire + +The process of determining what method should be used is called +B<method resolution>. What Perl does is look at the object's class +first (C<Employee> in this case). If that class defines the method, +then that class's version of the method is called. If not, Perl looks +at each parent class in turn. For C<Employee>, its only parent is +C<Person>. If C<Employee> does not define the method, but C<Person> +does, then Perl calls the method in C<Person>. + +If C<Person> inherited from C<Animal>, which inherited from C<Thing>, +then Perl would keep looking "up the chain" if necessary. + +It is possible to explicitly call a parent method from a child: + + package Employee; + + use parent 'Person'; + + sub print_greeting { + my $self = shift; + + $self->SUPER::print_greeting(); + + print "Your job is ", $self->job_title, "\n"; + } + +The C<SUPER::> bit tells Perl to look for the C<print_greeting()> in +the C<Employee> class's inheritance chain. When it finds the parent +class that implements this method, the method is called. + +We mentioned multiple inheritance earlier. The main problem with +multiple inheritance is that it greatly complicates method resolution. +See L<perlobj> for more details. + +=head2 Encapsulation + +B<Encapsulation> is the idea that an object is opaque. When another +developer uses your class, they don't need to know I<how> it is +implemented, they just need to know I<what> it does. + +Encapsulation is important for several reasons. First, it allows you to +separate the public API from the private implementation. This means you +can change that implementation without breaking the API. + +Second, when classes are well encapsulated, they become easier to +subclass. Ideally, a subclass uses the same APIs to access object data +that its parent class uses. In reality, subclassing sometimes involves +violating encapsulation, but a good API can minimize the need to do +this. + +We mentioned earlier that most Perl objects are implemented as hash +references under the hood. The principle of encapsulation tells us that +we should not rely on this. Instead, we should use accessor methods to +access the data in that hash reference. The object systems that we +recommend below all automate the generation of accessor methods. If you +use one of them, you should never have to access the object as a hash +reference directly. + +=head2 Composition + +In object-oriented code, we often find that one object references +another object. This is called B<composition>, or a B<has-a> +relationship. + +Earlier, we mentioned that the C<Person> class's C<birth_date> accessor +could return a L<DateTime> object. This is a perfect example of +composition. We could go even further, and make objects for name and +country as well. The C<Person> class would then be B<composed> of +several other objects. + +=head2 Roles + +B<Roles> are something that a class I<does>, rather than something that +it I<is>. Roles are relatively new to Perl, but have become rather +popular. Roles are B<applied> to classes. Sometimes we say that classes +B<consume> roles. + +Roles are an alternative to inheritance for providing polymorphism. +Let's assume we have two classes, C<Radio> and C<Computer>. Both of +these things have on/off switches. We want to model that in our class +definitions. + +We could have both classes inherit from a common parent, like +C<Machine>, but not all machines have on/off switches. We could create +a parent class called C<HasOnOffSwitch>, but that is very artificial. +Radios and computers are not specializations of this parent. This +parent is really a rather ridiculous creation. + +This is where roles come in. It makes a lot of sense to create a +C<HasOnOffSwitch> role and apply it to both classes. This role would +define a known API like providing C<turn_on()> and C<turn_off()> +methods. + +Perl does not have any built-in way to express roles. In the past, +people just bit the bullet and used multiple inheritance. Nowadays, +there are several good choices on CPAN for using roles. + +=head1 PERL OO SYSTEMS + +As we mentioned before, Perl's built-in OO system is very minimal, but +also quite flexible. Over the years, many people have developed systems +which build on top of Perl's built-in system to provide more features +and convenience. + +We strongly recommend that you use one of these systems. Even the most +minimal of them eliminates a lot of repetitive boilerplate. There's +really no good reason to write your classes from scratch in Perl. + +If you are interested in the guts underlying these systems, check out +L<perlobj>. + +=head2 Moose + +L<Moose> bills itself as a "postmodern object system for Perl 5". Don't +be scared, the "postmodern" label is a callback to Larry's description +of Perl as "the first postmodern computer language". + +C<Moose> provides a complete, modern OO system. Its biggest influence +is the Common Lisp Object System, but it also borrows ideas from +Smalltalk and several other languages. C<Moose> was created by Stevan +Little, and draws heavily from his work on the Perl 6 OO design. + +C<Moose> provides a number of features: + +=over 4 + +=item * Declarative sugar + +C<Moose> provides a layer of declarative "sugar" for defining classes. +That sugar is just a set of exported functions that make declaring how +your class works simpler and more palatable. This lets you describe +I<what> your class is, rather than having to tell Perl I<how> to +implement your class. + +Here's a simple but complete C<Moose> class: + + package Person; + use Moose; + + has name => ( is => 'ro' ); + has birth_date => ( is => 'ro' ); + has country_code => ( is => 'ro' ); + + sub print_greeting { + my $self = shift; + + print "Hello, ", $self->name, "\n"; + } + +The C<has()> subroutine declares an attribute, and C<Moose> +automatically creates accessors for these attributes. It also takes +care of creating a C<new()> method for you. This constructor knows +about the attributes you declared, so you can set them when creating a +new C<Person>. + +=item * Roles built-in + +C<Moose> lets you define roles the same way you define classes: + + package HasOnOfSwitch; + use Moose::Role; + + has is_on => ( + is => 'rw', + isa => 'Bool', + ); + + sub turn_on { + my $self = shift; + $self->is_on(1); + } + + sub turn_off { + my $self = shift; + $self->is_on(0); + } + +=item * A miniature type system + +In the example above, you can see that we passed C<< isa => 'Bool' >> +to C<has()> when creating our C<is_on> attribute. This tells C<Moose> +that this attribute must be a boolean value. If we try to set it to an +invalid value, our code will throw an error. + +=item * Full introspection and manipulation + +Perl's built-in introspection features are fairly minimal. C<Moose> +builds on top of them and creates a full introspection layer for your +classes. This lets you ask questions like "what methods does the Person +class implement?" It also lets you modify your classes +programmatically. + +=item * Self-hosted and extensible + +C<Moose> describes itself using its own introspection API. Besides +being a cool trick, this means that you can extend C<Moose> using +C<Moose> itself. + +=item * Rich ecosystem + +There is a rich ecosystem of C<Moose> extensions on CPAN under the +L<MooseX|http://search.cpan.org/search?query=MooseX&mode=dist> +namespace. In addition, many modules on CPAN already use C<Moose>, +providing you with lots of examples to learn from. + +=item * Many more features + +C<Moose> is a very powerful tool, and we can't cover all of its +features here. We encourage you to learn more by reading the C<Moose> +documentation, starting with +L<Moose::Manual|http://search.cpan.org/perldoc?Moose::Manual>. + +=back + +Of course, C<Moose> isn't perfect. + +C<Moose> can make your code slower to load. C<Moose> itself is not +small, and it does a I<lot> of code generation when you define your +class. This code generation means that your runtime code is as fast as +it can be, but you pay for this when your modules are first loaded. + +This load time hit can be a problem when startup speed is important, +such as with a command-line script or a "plain vanilla" CGI script that +must be loaded each time it is executed. + +Before you panic, know that many people do use C<Moose> for +command-line tools and other startup-sensitive code. We encourage you +to try C<Moose> out first before worrying about startup speed. + +C<Moose> also has several dependencies on other modules. Most of these +are small stand-alone modules, a number of which have been spun off +from C<Moose>. C<Moose> itself, and some of its dependencies, require a +compiler. If you need to install your software on a system without a +compiler, or if having I<any> dependencies is a problem, then C<Moose> +may not be right for you. + +=head3 Mouse + +If you try C<Moose> and find that one of these issues is preventing you +from using C<Moose>, we encourage you to consider L<Mouse> next. +C<Mouse> implements a subset of C<Moose>'s functionality in a simpler +package. For all features that it does implement, the end-user API is +I<identical> to C<Moose>, meaning you can switch from C<Mouse> to +C<Moose> quite easily. + +C<Mouse> does not implement most of C<Moose>'s introspection API, so +it's often faster when loading your modules. Additionally, it has no +I<required> non-core dependencies and can run without a compiler. If +you do have a compiler, C<Mouse> will use it to compile some of its +code for a speed boost. + +Finally, it ships with a C<C<Mouse>::Tiny> module that takes most of +C<Mouse>'s features and bundles them up in a single module file. You +can copy this module file into your application's library directory for +easy bundling. + +The C<Moose> authors hope that one day C<Mouse> can be made obsolete by +improving C<Moose> enough, but for now it provides a worthwhile +alternative to C<Moose>. + +=head2 Class::Accessor + +L<Class::Accessor> is the polar opposite of C<Moose>. It provides very +few features, nor is it self-hosting. + +It is, however, very simple, pure Perl, and it has no non-core +dependencies. It also provides a "Moose-like" API on demand for the +features it supports. + +Even though it doesn't do much, it is still preferable to writing your +own classes from scratch. + +Here's our C<Person> class with C<Class::Accessor>: + + package Person; + use Class::Accessor 'antlers'; + + has name => ( is => 'ro' ); + has birth_date => ( is => 'ro' ); + has country_code => ( is => 'ro' ); + + sub print_greeting { + my $self = shift; + + print "Hello, ", $self->name, "\n"; + } + +The C<antlers> import flag tells C<Class::Accessor> that you want to +define your attributes using C<Moose>-like syntax. The only parameter +that you can pass to C<has> is C<is>. We recommend that you use this +Moose-like syntax if you choose C<Class::Accessor> since it means you +will have a smoother upgrade path if you later decide to move to +C<Moose>. + +Like C<Moose>, C<Class::Accessor> generates accessor methods and a +constructor for your class. + +=head2 Object::Tiny + +Finally, we have L<Object::Tiny>. This module truly lives up to its +name. It has an incredibly minimal API and absolutely no dependencies +(core or not). Still, we think it's a lot easier to use than writing +your own OO code from scratch. + +Here's our C<Person> class once more: + + package Person; + use Object::Tiny qw( name birth_date country_code ); + + sub print_greeting { + my $self = shift; + + print "Hello, ", $self->name, "\n"; + } + +That's it! + +With C<Object::Tiny>, all accessors are read-only. It generates a +constructor for you, as well as the accessors you define. + +=head2 Role::Tiny + +As we mentioned before, roles provide an alternative to inheritance, +but Perl does not have any built-in role support. If you choose to use +Moose, it comes with a full-fledged role implementation. However, if +you use one of our other recommended OO modules, you can still use +roles with L<Role::Tiny> + +C<Role::Tiny> provides some of the same features as Moose's role +system, but in a much smaller package. Most notably, it doesn't support +any sort of attribute declaration, so you have to do that by hand. +Still, it's useful, and works well with C<Class::Accessor> and +C<Object::Tiny> + +=head2 OO System Summary + +Here's a brief recap of the options we covered: + +=over 4 + +=item * L<Moose> + +C<Moose> is the maximal option. It has a lot of features, a big +ecosystem, and a thriving user base. We also covered L<Mouse> briefly. +C<Mouse> is C<Moose> lite, and a reasonable alternative when Moose +doesn't work for your application. + +=item * L<Class::Accessor> + +C<Class::Accessor> does a lot less than C<Moose>, and is a nice +alternative if you find C<Moose> overwhelming. It's been around a long +time and is well battle-tested. It also has a minimal C<Moose> +compatibility mode which makes moving from C<Class::Accessor> to +C<Moose> easy. + +=item * L<Object::Tiny> + +C<Object::Tiny> is the absolute minimal option. It has no dependencies, +and almost no syntax to learn. It's a good option for a super minimal +environment and for throwing something together quickly without having +to worry about details. + +=item * L<Role::Tiny> + +Use C<Role::Tiny> with C<Class::Accessor> or C<Object::Tiny> if you +find yourself considering multiple inheritance. If you go with +C<Moose>, it comes with its own role implementation. + +=back + +=head2 Other OO Systems + +There are literally dozens of other OO-related modules on CPAN besides +those covered here, and you're likely to run across one or more of them +if you work with other people's code. + +In addition, plenty of code in the wild does all of its OO "by hand", +using just the Perl built-in OO features. If you need to maintain such +code, you should read L<perlobj> to understand exactly how Perl's +built-in OO works. + +=head1 CONCLUSION + +As we said before, Perl's minimal OO system has lead to a flourishing +of OO systems on CPAN. While you can still drop down to the bare metal +and write your classes by hand, there's really no reason to do that in +2011. + +For small systems, L<Object::Tiny> and L<Class::Accessor> both provide +minimal object systems that take care of basic boilerplate for you. + +For bigger projects, L<Moose> provides a rich set of features that will +let you focus on implementing your business logic. + +We encourage you to play with and evaluate L<Moose>, +L<Class::Accessor>, and L<Object::Tiny> to see which OO system is right +for you. + +=cut |