From d4dd1527c6782533fa5381d5ad2ece9c567a8a4a Mon Sep 17 00:00:00 2001 From: chromatic Date: Wed, 28 Sep 2011 15:14:00 -0700 Subject: [PATCH] Edited objects chapter. --- sections/advanced_oo.pod | 120 +++--- sections/blessed_references.pod | 274 ++++++------- sections/chapter_07.pod | 21 +- sections/moose.pod | 689 +++++++++++++++----------------- sections/reflection.pod | 137 +++---- 5 files changed, 590 insertions(+), 651 deletions(-) diff --git a/sections/advanced_oo.pod b/sections/advanced_oo.pod index f3b64258..b5d81137 100644 --- a/sections/advanced_oo.pod +++ b/sections/advanced_oo.pod @@ -3,36 +3,32 @@ Z Creating and using objects in Perl 5 with Moose (L) is easy. -I good object systems is not. Additional capabilities for -abstraction also offer possibilities for obfuscation. Only practical -experience can help you understand the most important design techniques... but -several principles can guide you. +I good programs is not. You must balance between designing too +little and too much. Only practical experience can help you understand the +most important design techniques, but several principles can guide you. =head2 Favor Composition Over Inheritance X X -Novice OO designs often overuse inheritance for two reasons: to reuse as much -code as possible and to exploit as much polymorphism as possible. It's common -to see class hierarchies which try to model all of the behavior for entities -within the system in a single class. This adds a conceptual overhead to -understanding the system, because you have to understand the hierarchy. It -adds technical weight to every class, because conflicting responsibilities and -methods may obstruct necessary behaviors or future modifications. +Novice OO designs often overuse inheritance to reuse code and to exploit +polymorphism. The result is a deep class hierarchy with responsibilities +scattered in the wrong places. Maintaining this code is difficult--who knows +where to add or edit behavior? What happens when code in one place conflicts +with code declared elsewhere? X X -The encapsulation provided by classes offers better ways to organize code. You -don't have to inherit from superclasses to provide behavior to users of -objects. A C object does not have to inherit from a C -object (an I); it can contain several C objects as -instance attributes (a I). +Inheritance is one tool. It's not the only tool. Although C may extend +C (an I), it's likely better for C to +I contain several C objects as instance attributes (a I). Decomposing complex classes into smaller, focused entities (whether classes or roles) improves encapsulation and reduces the possibility that any one class or -role will grow to do too much. Smaller, simpler, and better encapsulated +role will grow to do too much. Smaller, simpler, and better encapsulated entities are easier to understand, test, and maintain. =head2 Single Responsibility Principle @@ -40,29 +36,28 @@ entities are easier to understand, test, and maintain. X When you design your object system, model the problem in terms of -responsibilities, or reasons why each specific entity may need to change. For -example, an C object may represent specific information about a -person's name, contact information, and other personal data, while a C -object may represent business responsibilities. A simple design might conflate -the two into a single entity, but separating them allows the C class -to consider only the problem of managing information specific to who the person -is and the C class to represent what the person does. (Two C -may have a C-sharing arrangement, for example.) - -When each class has a single responsibility, you can improve the encapsulation -of class-specific data and behaviors and reduce coupling between classes. +responsibilities--the behavior each entity must provide. For example, an +C object may represent specific information about a person's name, +contact information, and other personal data, while a C object may +represent business responsibilities. Separating these entities in terms of +their responsibilities allows the C class to consider only the +problem of managing information specific to who the person is and the C +class to represent what the person does. (Two C may have a +C-sharing arrangement, for example.) + +When each class has a single responsibility, you improve the encapsulation of +class-specific data and behaviors and reduce coupling between classes. =head2 Don't Repeat Yourself X -Complexity and duplication complicate development and maintenance activities. -The DRY principle (Don't Repeat Yourself) is a reminder to seek out and to -eliminate duplication within the system. Duplication exists in many forms, in -data as well as in code. Instead of repeating configuration information, user -data, and other artifacts within your system, find a single, canonical -representation of that information from which you can generate all of the other -artifacts. +Complexity and duplication complicate development and maintenance. The DRY +principle (Don't Repeat Yourself) is a reminder to seek out and to eliminate +duplication within the system. Duplication exists in data as well as in code. +Instead of repeating configuration information, user data, and other artifacts +within your system, create a single, canonical representation of that +information from which you can generate the other artifacts. This principle helps to reduce the possibility that important parts of your system can get unsynchronized, and helps you to find the optimal representation @@ -72,18 +67,17 @@ of the system and its data. X -The Liskov substitution principle suggests that subtypes of a given type -(specializations of a class or role or subclasses of a class) should be -substitutable for the parent type without narrowing the types of data they -receive or expanding the types of data they produce. In other words, they -should be as general as or more general at what they expect and as specific as -or more specific about what they produce. - -Imagine two classes, C and C. The latter subclasses the -former. If the classes follow the Liskov substitution principle, you can -replace every use of C objects with C objects in the test -suite, and everything should passN and its child class C. If the +classes follow the Liskov substitution principle, you can replace every use of +C objects with C objects in the test suite, and everything +should passN.>. =head2 Subtypes and Coercions @@ -96,9 +90,9 @@ X Moose allows you to declare and use types and extend them through subtypes to form ever more specialized descriptions of what your data represents and how it -behaves. You can use these type annotations to verify that the data on which -you want to work in specific functions or methods is appropriate and even to -specify mechanisms by which to coerce data of one type to data of another type. +behaves. These type annotations help verify that the data on which you want to +work in specific functions or methods is appropriate and even to specify +mechanisms by which to coerce data of one type to data of another type. X> X> @@ -111,21 +105,23 @@ Z X -A common pattern among programmers new to object orientation is to treat -objects as if they were bundles of records which use methods to get and set -internal values. While this is simple to implement and easy to understand, it -can lead to the unfortunate temptation to spread the behavioral -responsibilities among individual classes throughout the system. +OO novices often treat objects as if they were bundles of records which use +methods to get and set internal values. This simple technique leads to the +unfortunate temptation to spread the object's responsibilities throughout the +entire system. -The most useful technique to working with objects effectively is to tell them -what to do, not how to do it. If you find yourself accessing the instance data -of objects (even through accessor methods), you may have too much access to the -responsibilities of the class. +With a well designed object, you tell it what to do and not how to do it. As a +rule of thumb, if you find yourself accessing object instance data (even +through accessor methods), you may have too much access to an object's +internals. One approach to preventing this behavior is to consider objects as immutable. -Pass in all of the relevant configuration data to their constructors, then -disallow any modifications of this information from outside the class. Do not -expose any methods to mutate instance data. +Provide the necessary data to their constructors, then disallow any +modifications of this information from outside the class. Expose no methods to +mutate instance data. The objects so constructed are always valid after their +construction and cannot become invalid through external manipulation. This +takes tremendous discipline to achieve, but the resulting systems are robust, +testable, and maintainable. Some designs go as far as to prohibit the modification of instance data I the class itself, though this is much more difficult to achieve. diff --git a/sections/blessed_references.pod b/sections/blessed_references.pod index e46f5aed..d390c387 100644 --- a/sections/blessed_references.pod +++ b/sections/blessed_references.pod @@ -2,8 +2,7 @@ Z -Perl 5's default object system is deliberately minimal. Three simple rules -combine to form the simple--though effective--basic object system: +Perl 5's core object system is deliberately minimal. It has only three rules: =over 4 @@ -15,28 +14,34 @@ combine to form the simple--though effective--basic object system: =back +You can build anything else out of those three rules, but that's all you get by +default. This minimalism can be impractical for larger projects--in particular, +the possibilities for greater abstraction through metaprogramming +(L) are awkward and limited. Moose (L) is a better +choice for modern programs larger than a couple of hundred lines, although +plenty of legacy code still uses Perl 5's default OO. + X> X> -You've already seen the first two rules (L). The third rule is new. -The C builtin associates the name of a class with a reference, such that -any method invocation performed on that reference uses the associated class for -resolution. That sounds more complicated than it is. - -The result is a minimal but working system, though its minimalism can be -impractical for larger projects. In particular, the default object system -offers only partial and awkward facilities for metaprogramming -(L). Moose is a better choice for serious, modern Perl -programs larger than a couple of hundred lines, but you will likely encounter -bare-bones Perl 5 OO in existing code. +The final piece of Perl 5 core OO is the blessed reference. The C +builtin associates the name of a class with a reference. That reference is now +a valid invocant, and Perl will perform method dispatch on it, using the +associated class. X X X -The default Perl 5 object constructor is a method which creates and blesses a -reference. By convention, constructors have the name C, but this is not -a requirement. Constructors are also almost always I: +A constructor is a method which creates and blesses a reference. By convention, +constructors have the name C, but this is not a requirement. +Constructors are also almost always I. + +C takes two arguments, a reference and a class name. It evaluates to the +reference. The reference may be empty. The class does not have to exist yet. +You may even use C outside of a constructor or a class (though all but +the simplest programs should use real constructors). The canonical constructor +resembles: =begin programlisting @@ -48,22 +53,16 @@ a requirement. Constructors are also almost always I: =end programlisting -C takes two arguments, the reference to associate with a class and the -name of a class. You may use C outside of a constructor or a -class--though abstraction recommends the use of the method. The class name -does not have to exist yet. - By design, this constructor receives the class name as the method's invocant. -It's possible, but inadvisable, to hard-code the name of a class directly. The -parametric constructor allows reuse of the method through inheritance, -delegation, or exporting. +You may also hard-code the name of a class, at the expense of flexibility. +Parametric constructor allows reuse through inheritance, delegation, or +exporting. X -The type of reference makes no difference when invoking methods on the object. -It only governs how the object stores I--the object's own -information. Hash references are most common, but you can bless any type of -reference: +The type of reference used is relevant only to how the object stores its own +I. It has no other effect on the resulting object. Hash +references are most common, but you can bless any type of reference: =begin programlisting @@ -74,18 +73,19 @@ reference: =end programlisting Whereas classes built with Moose define their own object attributes -declaratively, Perl 5's default OO is lax. A class representing basketball +declaratively, Perl 5's default OO is lax. A class representing basketball players which stores jersey number and position might use a constructor like: =begin programlisting - package Player; - - sub new + package Player { - my ($class, %attrs) = @_; + sub new + { + my ($class, %attrs) = @_; - bless \%attrs, $class; + bless \%attrs, $class; + } } =end programlisting @@ -99,14 +99,14 @@ players which stores jersey number and position might use a constructor like: position => 'center', ); - my $jerryd = Player->new( - number => 4, - position => 'guard', + my $dante = Player->new( + number => 33, + position => 'forward', ); =end programlisting -Within the body of the class, methods can access hash elements directly: +The object's methods can access hash elements directly: =begin programlisting @@ -118,10 +118,9 @@ Within the body of the class, methods can access hash elements directly: =end programlisting -Yet so can any code outside of the class. This violates encapsulation--in -particular, it means that you can never change the object's internal -representation without breaking external code or perpetuating ugly hacks--so -it's safer to provide accessor methods: +... but so can any other code. If external code violates attribute +encapsulation, you can never change the object's internal representation +without breaking external code. Accessor methods are safer: =begin programlisting @@ -130,13 +129,12 @@ it's safer to provide accessor methods: =end programlisting -Even with two attributes, Moose is much more appealing in terms of code you -don't have to write. +... and now you're starting to write manually what Moose gives you for free. =begin sidebar -Moose's default behavior of accessor generation encourages you to do the right -thing with regard to encapsulation as well as genericity. +Moose encourages you to write better code by using accessors instead of +accessing attributes directly. =end sidebar @@ -145,8 +143,7 @@ thing with regard to encapsulation as well as genericity. X X -Besides instance data, the other part of objects is method dispatch. Given an -object (a blessed reference), a method call of the form: +Given a blessed reference, a method call of the form: =begin programlisting @@ -155,55 +152,59 @@ object (a blessed reference), a method call of the form: =end programlisting ... looks up the name of the class associated with the blessed reference -C<$joel>. In this case, the class is C. Next, Perl looks for a -function named C in the C package. If the C class -inherits from another class, Perl looks in the parent class (and so on and so -on) until it finds a C method. If one exists, Perl calls it with +C<$joel>--C, in this case. Next, Perl looks for a functionN +named C in C. If no such function exists and if C +extends class, Perl looks in the parent class (and so on and so on) until it +finds a C. If Perl finds C, it calls that method with C<$joel> as an invocant. +=begin sidebar + +X> + +The C CPAN module can help avoid unintentional collisions between imported functions and methods. + +=end sidebar + X> X> -Moose classes store their inheritance information in a metamodel which provides -additional abilities on top of Perl 5's default OO system. - -In the default system, every class stores information about its parents in a -package global variable named C<@ISA>. The method dispatcher looks in a -class's C<@ISA> to find the names of parent classes in which to search for the -appropriate method. Thus, an C class might contain C in -its C<@ISA>. You could write this relationship as: +Moose provides C to track inheritance relationships, but Perl 5 uses a +package global variable named C<@ISA>. The method dispatcher looks in each +class's C<@ISA> to find the names of its parent classes. If C +extends C, you might write: =begin programlisting - package InjuredPlayer; - - @InjuredPlayer::ISA = 'Player'; + package InjuredPlayer + { + @InjuredPlayer::ISA = 'Player'; + } =end programlisting X pragma> X> -Many existing Perl 5 projects do this, but it's easier and simpler to use the -C pragma instead: +The C pragma (L) is cleanerN +pragma, but C superseded C in Perl 5.10.>: =begin programlisting - package InjuredPlayer; - - use parent 'Player'; + package InjuredPlayer + { + use parent 'Player'; + } =end programlisting -X pragma> -X> - -=begin sidebar +=begin programlisting -Perl 5.10 added C to supersede the C pragma. If you can't use -Moose, use C. +Moose has its own metamodel which stores extended inheritance information; this +offers additional features. -=end sidebar +=end programlisting X X @@ -213,40 +214,14 @@ You may inherit from multiple parent classes: =begin programlisting package InjuredPlayer; - - use parent qw( Player Hospital::Patient ); - -=end programlisting - -Perl 5 has traditionally preferred a depth-first search of parents when -resolving method dispatch. That is to say, if C inherits from -both C and C, a method call on an C -instance will dispatch first to C, then C, then any of -C's parents before dispatching in C. - -X pragma> -X> - -Perl 5.10 also added a pragma called C which allows you to use a different -method resolution scheme called C3. While the specific details can get complex -in the case of complex multiple inheritance hierarchies, the important -difference is that method resolution will visit all children of a parent before -visiting the parent. - -While other techniques such as roles (L) and Moose method modifiers -allow you to avoid multiple inheritance, the C pragma can help avoid -surprising behavior with method dispatch. Enable it in your class with: - -=begin programlisting - - package InjuredPlayer; - - use mro 'c3'; + { + use parent qw( Player Hospital::Patient ); + } =end programlisting -Unless you're writing a complex framework with multiple interoperable plugins, -you likely never need to use this. +... though the caveats about multiple inheritance and method dispatch +complexity apply. Consider instead roles (L) or Moose method modifiers. =head2 AUTOLOAD @@ -255,25 +230,25 @@ X> X> If there is no applicable method in the invocant's class or any of its -superclasses, Perl 5 will next look for an C function in every class -according to the selected method resolution order. Perl will invoke any -C (L) it finds to provide or decline the desired method. +superclasses, Perl 5 will next look for an C function (L) +in every class according to the selected method resolution order. Perl will +invoke any C it finds to provide or decline the desired method. -As you might expect, this can get quite complex in the face of multiple -inheritance and multiple potential C targets. +C makes multiple inheritance much more difficult to understand. =head2 Method Overriding and SUPER -You may override methods in the default Perl 5 OO system as well as in Moose. -Unfortunately, core Perl 5 provides no mechanism for indicating your I -to override a parent's method. Worse yet, any function you predeclare, -declare, or import into the child class may override a method in the parent -class simply by existing and having the same name. While you may forget to use -the C system of Moose, you have no such protection (even optional) in -the default Perl 5 OO system. +As with Moose, you may override methods in the core Perl 5 OO. Unlike Moose, +core Perl 5 provides no mechanism for indicating your I to override a +parent's method. Worse yet, any function you predeclare, declare, or import +into the child class may override a method in the parent class by having the +same name. Even if you forget to use the C system of Moose, at least +it exists. Core Perl 5 OO offers no such protection. + +X> To override a method in a child class, declare a method of the same name as the -method in the parent. Within an overridden method, call the parent method with +method in the parent. Within an overridden method, call the parent method with the C dispatch hint: =begin programlisting @@ -288,47 +263,52 @@ the C dispatch hint: =end programlisting The C prefix to the method name tells the method dispatcher to -dispatch to the named method in a I implementation. You may pass any -arguments to it you like, but it's safest to reuse C<@_>. +dispatch to an overridden method of the appropriate name. You can provide your +own arguments to the overridden method, but most code reuses C<@_>. Be careful +to C off the invocant if you do. =begin sidebar -X> +X> -Beware that this dispatcher relies on the package into which the overridden -method was originally compiled when redispatching to a parent method. This is -a long-standing misfeature retained for the sake of backwards compatibility. -If you export methods into other classes or compose roles into classes -manually, you may run afoul of this feature. The C module on the CPAN -can work around this for you. Moose handles it nicely as well. +C has a confusing misfeature: it dispatches to the parent of the +package into which the overridden method was I. If you've imported +this method from another package, Perl will happily dispatch to the I +parent. The desire for backwards compatibility has kept this misfeature in +place. The C module from the CPAN offers a workaround. Moose's +C does not suffer the same problem. =end sidebar =head2 Strategies for Coping with Blessed References -Avoid C where possible. If you I use it, use forward -declarations of your functions (L) to help Perl know which -C will provide the method implementation. +If blessed references seem minimal and tricky and confusing, they are. Moose is +a tremendous improvement. Use it whenever possible. If you do find yourself +maintaining code which uses blessed references, or if you can't convince your +team to use Moose in full yet, you can work around some of the problems of +blessed references with discipline. + +X> -Use accessor methods rather than accessing instance data directly through the -reference. This applies even within the bodies of methods within the class -itself. Generating these yourself can be tedious; if you can't use Moose, -consider using a module such as C to avoid repetitive +=over 4 + +=item * Use accessor methods pervasively, even within methods in your class. +Consider using a module such as C to avoid repetitive boilerplate. -Expect that someone, somewhere will eventually need to subclass (or delegate to -or reimplement the interface of) your classes. Make it easier for them by not -assuming details of the internals of your code, by using the two-argument form -of C, and by breaking your classes into the smallest responsible units -of code. +=item * Avoid C where possible. If you I use it, use forward +declarations of your functions (L) to help Perl know which +C will provide the method implementation. + +=item * Expect that someone, somewhere will eventually need to subclass (or +delegate to or reimplement the interface of) your classes. Make it easier for +them by not assuming details of the internals of your code, by using the +two-argument form of C, and by breaking your classes into the smallest +responsible units of code. -Do not mix functions and methods in the same class. +=item * Do not mix functions and methods in the same class. -Use a single F<.pm> file for each class, unless the class is a small, +=item * Use a single F<.pm> file for each class, unless the class is a small, self-contained helper used from a single place. -X> - -Consider using Moose and C instead of bare-bones Perl 5 OO; they -can interact with vanilla classes and objects with ease, alleviate almost of -the tedium of declaring classes, and provide more and better features. +=back diff --git a/sections/chapter_07.pod b/sections/chapter_07.pod index 1a6357b2..25554ab8 100644 --- a/sections/chapter_07.pod +++ b/sections/chapter_07.pod @@ -1,18 +1,15 @@ =head0 Objects -Writing large programs requires more discipline than writing small programs, -due to the difficulty of managing all of the details of your program -simultaneously. Abstraction (finding and exploiting similarities and -near-similarities) and encapsulation (grouping specific details together and -accessing them where they belong) are essential to managing this complexity. +Programming is a management activity. The larger the program, the more details +you must manage. Our only hope to manage this complexity is to exploit +abstraction (treating similar things similarly) and encapsulation (grouping +related details together). -Functions help, but functions by themselves aren't sufficient for the largest -programs. Object orientation is a popular technique for grouping functions -together into classes of related behaviors. - -Perl 5's default object system is minimal. It's very flexible--you can build -almost any other object system you want on top of it--but it provides little -assistance for the most common tasks. +Functions alone are insufficient for large problems. Several techniques group +functions into units of related behaviors--one popular technique is object +orientation. Perl 5's default object system is flexible, but minimal. You can +build great things on top of it, but it provides little assistance for some +basic tasks. L diff --git a/sections/moose.pod b/sections/moose.pod index 8657723f..3adaf651 100644 --- a/sections/moose.pod +++ b/sections/moose.pod @@ -1,39 +1,39 @@ =head1 Moose Z -X - -Moose is a powerful and complete object system for Perl 5. It builds on the -existing Perl 5 system to provide simpler defaults, better integration, and -advanced features from languages such as Smalltalk, Common Lisp, and Perl 6. -It's still worth learning the default Perl 5 object system--especially when you -have existing code to maintain--but Moose is the best way to write object -oriented code in modern Perl 5. X X X X -I (OO), or I (OOP), is a way -of managing programs by categorizing their components into discrete, unique -entities. These are I. In Moose terms, each object is an instance of -a I, which serves as a template to describe any data the object contains -as well as its specific behaviors. +In I (OO), or I (OOP), +programs work with I--discrete, unique entities with their own +identities. + +X + +I is a complete object system for Perl 5N +for more information.>. It provides simpler defaults, and advanced features +borrowed from languages such as Smalltalk, Common Lisp, and Perl 6. Moose code +interoperates with the default object system and is currently the best way to +write object oriented code in modern Perl 5. + +A Moose object is a concrete instance of a I, which is a template +describing data and behavior specific to the object. =head2 Classes X X> -A class in Perl 5 stores class data. By default, Perl 5 classes use packages -to provide namespaces: +If an object is a concrete thing, its class is its abstract definition. Perl 5 +classes use packages (L) to provide namespaces: =begin programlisting + package Cat { - package Cat; - use Moose; } @@ -41,9 +41,8 @@ to provide namespaces: X -This C class appears to do nothing, but Moose does a lot of work to define -the class and register it with Perl. With that done, you can create objects -(or I) of the C class: +This C class I to do nothing, but that's all Moose needs to make +a class. Create objects (or I) of the C class with the syntax: =begin programlisting @@ -52,25 +51,25 @@ the class and register it with Perl. With that done, you can create objects =end programlisting -The arrow syntax should look familiar. Just as an arrow dereferences a -reference, an arrow calls a method on an object or class. +Just as an arrow dereferences a reference, an arrow calls a method on an object +or class. =head2 Methods X X -A I is a function associated with a class. It resembles a -fully-qualified function call in a superficial sense, but it differs in two -important ways. First, a method call always has an I on which the -method operates. When you create an object, the I of the class is the -invocant. When you call a method on an instance, that instance is the +A I is a function associated with a class. Just as functions belong to +namespaces, so do methods belong to classes, with two differences. First, a +method always operates on an I. Calling C on C +effectively sends the C class a message. The name of the class, C, is +C's invocant. When you call a method on an object, that object is the invocant: =begin programlisting - my $fuzzy = B->new(); - B<$fuzzy>->sleep_on_keyboard(); + my $choco = B->new(); + B<$choco>->sleep_on_keyboard(); =end programlisting @@ -79,19 +78,17 @@ X X X -Second, a method call always involves a I strategy. The dispatch -strategy describes how the object system decides I method to call. This -may seem obvious when there's only a C, but method dispatch is fundamental -to the design of object systems. +Second, a method call always involves a I strategy, where the object +system selects the appropriate method. Given the simplicity of C, the +dispatch strategy is obvious, but much of the power of OO comes from this idea. -The invocant of a method in Perl 5 is its first argument. For example, the -C class could have a C method: +Inside a method, its first argument is the invocant. Idiomatic Perl 5 uses +C<$self> as its name. Suppose a C can C: =begin programlisting + package Cat { - package Cat; - use Moose; B @@ -108,10 +105,8 @@ eaten yet: =begin programlisting - my $alarm = Cat->new(); - $alarm->meow(); - $alarm->meow(); - $alarm->meow(); + my $fuzzy_alarm = Cat->new(); + $fuzzy_alarm->meow() for 1 .. 3; =end programlisting @@ -122,23 +117,20 @@ X X X -By pervasive convention, methods store their invocants in lexical variables -named C<$self>. Methods which access invocant data are I, -because they depend on the presence of an appropriate invocant to work -correctly. Methods (such as C) which do not access instance data are -I, as you can use the name of the class as an invocant. -Constructors are also class methods. For example: +Methods which access invocant data are I, because they depend +on the presence of an appropriate invocant to work correctly. Methods (such as +C) which do not access instance data are I. You may +invoke class methods on classes and class and instance methods on instances, +but you cannot invoke instance methods on classes. -=begin programlisting +X - Cat->meow() for 1 .. 3; +I, which I instances, are obviously class methods. Moose +provides a default constructor for you. -=end programlisting - -Class methods can help you organize your code into namespaces without requiring -you to import (L) functions, but a design which relies heavily on -class methods for anything other than constructors may be the sign of muddled -thinking. +Class methods are effectively namespaced global functions. Without access to +instance data, they have few advantages over namespaced functions. Most OO code +rightly uses instance methods, as they have access to instance data. =head2 Attributes @@ -146,20 +138,19 @@ X X X -Every object in Perl 5 is unique. Objects can contain I, or -private data associated with each object. You may also hear this described as -I or I. +Every object in Perl 5 is unique. Objects can contain private data associated +with each unique object--these are I, I, or object +I. X X (read only)> -To define object attributes, describe them as part of the class: +Define an attribute by declaring it as part of the class: =begin programlisting + package Cat { - package Cat; - use Moose; B<< has 'name', is => 'ro', isa => 'Str'; >> @@ -167,18 +158,21 @@ To define object attributes, describe them as part of the class: =end programlisting -In English, that line of code means "C objects have a C attribute. -It's readable but not writable, and it's a string." +In English, that reads "C objects have a C attribute. It's +read-only, and is a string." + +Moose provides the C function, which declares an attribute. The first +argument, C<'name'> here, is the attribute's name. The C<< is => 'ro' >> pair +of arguments declares that this attribute is Cead Cnly, so you cannot +modify it after you've set it. Finally, the C<< isa => 'Str' >> pair declares +that the value of this attribute can only be a Cing. -In Perl and Moose terms, C is a function which declares an attribute. -The first argument is the name of the attribute, in this case C<'name'>. The -C<< is => 'ro' >> pair of arguments declares that this attribute is Cead -Cnly, so you cannot modify it after you've set it. Finally, the C<< isa => -'Str' >> pair declares that the value of this attribute can only be a -Cing. This will all become clear soon. +X +X -That single line of code creates an accessor method (C) and allows you -to pass a C parameter to the constructor: +As a result of C, Moose creates an I method named C, +from which you can retrieve an instance's name, and allows you to pass a +C parameter to C's constructor: =begin programlisting @@ -194,14 +188,13 @@ to pass a C parameter to the constructor: X -Attributes do not I to have types, in which case Moose will skip all of -the verification and validation for you: +If you pass a non-string, Moose will complain. Attributes do not I to +have types. In that case, anything goes: =begin programlisting + package Cat { - package Cat; - use Moose; has 'name', is => 'ro', isa => 'Str'; @@ -212,10 +205,8 @@ the verification and validation for you: =end programlisting -This can be more flexible, but it can also lead to strange errors if someone -tries to provide invalid data for an attribute. The balance between -flexibility and correctness depends on your local coding standards and the type -of errors you want to catch. +Specifying a type allows Moose to perform some data validations for you. +Sometimes this strictness is invaluable. =begin sidebar @@ -228,8 +219,7 @@ characteristics: =end programlisting -Perl parses both that form and the form used in this book the same way. You -I achieve the same effect by writing either: +The form used in this book is equivalent, as are: =begin programlisting @@ -238,8 +228,8 @@ I achieve the same effect by writing either: =end programlisting -... but in this case, extra punctuation adds clarity. The approach of the -Moose documentation is most useful when dealing with multiple characteristics: +Choose the punctuation which offers you the most clarity. Moose's approach +works nicely for complex declarations: =begin programlisting @@ -254,9 +244,7 @@ Moose documentation is most useful when dealing with multiple characteristics: =end programlisting -... but for the sake of simplicity of introduction, this book prefers to use -less punctuation. Perl gives you the flexibility to choose whichever approach -makes the intent of your code most clear. +... while this book prefers a low-punctuation approach for simple declarations. =end sidebar @@ -265,14 +253,12 @@ X X If you mark an attribute as readable I writable (with C<< is => rw >>), -Moose will create a I method--a method you can use to change the value -of an attribute: +Moose will create a I method which can change that attribute's value: =begin programlisting + package Cat { - package Cat; - use Moose; has 'name', is => 'ro', isa => 'Str'; @@ -288,23 +274,20 @@ of an attribute: =end programlisting -Trying to use a C accessor as a mutator will throw the exception C. +An C accessor used as a mutator will throw the exception C. -Using C or C is a matter of design, convenience, and purity. Moose -does not enforce any particular philosophy in this area. One school of thought -suggests making all instance data C and passing all relevant data into the -constructor (L). In the C example, C might still be -an accessor, but the constructor could take the I of the cat's birth and -calculate the age itself based on the current year, rather than relying on -someone to update the age of all cats manually. This approach helps to -consolidate all validation code and helps to ensure that all created objects -have valid data. +Using C or C is a matter of design, convenience, and purity. Moose +enforces no particular philosophy in this area. Some people suggest making all +instance data C such that you must pass instance data into the constructor +(L). In the C example, C might still be an accessor, +but the constructor could take the I of the cat's birth and calculate the +age itself based on the current year. This approach consolidates validation +code and ensure that all created objects have valid data. -Now that individual objects can have their own instance data, the value of -object orientation may be more obvious. An object is a group of related data -as well as behaviors appropriate for that data. A class is the description of -the data and behaviors that instances of that class possess. +Instance data begins to demonstrate the value of object orientation. An object +contains related data and can perform behaviors with that data. A class +describes that data and those behaviors. =head2 Encapsulation @@ -313,102 +296,95 @@ X Moose allows you to declare I attributes class instances possess (a cat has a name) as well as the attributes of those attributes (you cannot change a -cat's name). By default, Moose does not permit you to describe how an object -I its attributes; Moose decides that for you. This information is -available if you really need it, but the declarative approach can actually -improve your programs. In this way, Moose encourages I: hiding -the internal details of an object from external users of that object. +cat's name). Moose itself decides how to I those attributes. You can +change that if you like, but allowing Moose to manage your storage encourages +I: hiding the internal details of an object from external users +of that object. -Consider how you might change the way C handles ages. Instead of -requiring a static value for an age passed to the constructor, pass in the year -of the cat's birth and calculate the age as needed: +Consider a change to how Cs manage their ages. Instead of passing a value +for an age to the constructor, pass in the year of the cat's birth and +calculate the age as needed: =begin programlisting - package Cat; - - use Moose; + package Cat + { + use Moose; - has 'name', is => 'ro', isa => 'Str'; - has 'diet', is => 'rw'; - B<< has 'birth_year', is => 'ro', isa => 'Int'; >> + has 'name', is => 'ro', isa => 'Str'; + has 'diet', is => 'rw'; + B<< has 'birth_year', is => 'ro', isa => 'Int'; >> - B - B<{> - B - B + B + B<{> + B + B - B<< return $year - $self->birth_year(); >> - B<}> + B<< return $year - $self->birth_year(); >> + B<}> + } =end programlisting While the syntax for I C objects has changed, the syntax for -I C objects has not. The C method does the same thing it -has always done, at least as far as all code outside of the C class -understands. I it does that has changed, but that is a detail internal to -the C class and encapsulated within that class itself. +I C objects has not. Outside of C, C behaves as it +always has. I it works internally is a detail to the C class. =begin sidebar Retain the old syntax for I C objects by customizing the -generated C constructor to allow passing an C parameter. Calculate -C from that. See C. +generated C constructor to allow passing an C parameter. Calculate +C from that. See C. =end sidebar X -This new approach to calculating C ages has another advantage; you can use -I to reduce the code necessary to create a C -object: +Calculating ages has another advantage. A I will do +the right thing when someone creates a new C object without passing a +birth year: =begin programlisting - package Cat; - - use Moose; + package Cat + { + use Moose; - has 'name', is => 'ro', isa => 'Str'; - has 'diet', is => 'rw', isa => 'Str'; - B<< has 'birth_year', is => 'ro', isa => 'Int', >> - B<< default => sub { (localtime)[5] + 1900 }; >> + has 'name', is => 'ro', isa => 'Str'; + has 'diet', is => 'rw', isa => 'Str'; + B<< has 'birth_year', is => 'ro', isa => 'Int', >> + B<< default => sub { (localtime)[5] + 1900 }; >> + } =end programlisting -The C keyword on an attribute takes a function reference which returns -the default value for that attribute when constructing a new object. If the -constructor does not receive an appropriate value for that attribute, the -object gets that default value instead. Now you can create a kitten: +The C keyword on an attribute takes a function referenceN which returns the default value for that +attribute when constructing a new object. If the code creating an object passes +no constructor value for that attribute, the object gets the default value: =begin programlisting - my $kitten = Cat->new( name => 'Bitey' ); + my $kitten = Cat->new( name => 'Choco' ); =end programlisting -... and that kitten will have an age of C<0> until next year. You can also use -a simple value, such as a number or string, as a default value. Use a function -reference when you need to calculate something unique for each object, -including a hash or array reference. +... and that kitten will have an age of C<0> until next year. =head3 Polymorphism -A program which deals with one type of data and one type of behavior on that -data receives few benefits from the use of object. Encapsulation is useful, to -be sure--but the real power of object orientation is not solely in -encapsulation. A well designed OO program can manage many types of data. When -well designed classes encapsulate specific details of objects into the -appropriate places, something curious happens to the rest of the program: it -has the opportunity to become I specific. +Encapsulation is useful, but the real power of object orientation is much +broader. A well designed OO program can manage many types of data. When well +designed classes encapsulate specific details of objects into the appropriate +places, something curious happens: the code often becomes I specific. -In other words, moving the specifics of the details of what the program knows -about individual Cs (the attributes) and what the program knows that -Cs can do (the methods) into the C class means that code that deals -with C instances can happily ignore I C does what it does. +Moving the details of what the program knows about individual Cs (the +attributes) and what the program knows that Cs can do (the methods) into +the C class means that code that deals with C instances can happily +ignore I C does what it does. -This is clearer with an example. Consider a function which describes an -object: +Consider a function which displays details of an object: =begin programlisting @@ -423,21 +399,22 @@ object: =end programlisting -X -X - -It's obvious (in context) that you can pass a C object to this function -and get sane results. You can do the same with other types of objects. This -is an important object orientation property called I, where you -can substitute an object of one class for an object of another class if they -provide the same external interface. - X X -Any object of any class which provides the C, C, and C -accessors will work with this function. The function is sufficiently generic -that any object which respects this interface is a valid parameter. +It's obvious (in context) that this function works if you pass it a C +object. In fact, it will do the right thing for any object with the appropriate +three accessors, no matter I that object provides those accessors and no +matter I of object it is: C, C, or C. The +function is sufficiently generic that any object which respects this interface +is a valid parameter. + +X +X + +This property of I means that you can substitute an object of one +class for an object of another class if they provide the same external +interface. =begin sidebar @@ -445,36 +422,33 @@ X X Some languages and environments require a formal relationship between two -classes before allowing a program to substitute instances of one class for -another. Perl 5 provides ways to enforce these checks, but it does not require -them. Its default ad-hoc system lets you treat any two instances with methods -of the same name as equivalent enough. Some people call this I, -arguing that any object which can C is sufficiently duck-like that you -can treat it as a duck. +classes before allowing a program to substitute instances for each other. Perl +5 provides ways to enforce these checks, but it does not require them. Its +default ad-hoc system lets you treat any two instances with methods of the same +name as equivalent enough. Some people call this I, arguing that +any object which can C is sufficiently duck-like that you can treat it +as a duck. =end sidebar -The benefit of the genericity in C is that neither the -specific type nor the implementation of the object provided matters. Any -invocant is valid if it supports three methods, C, C, and -C which take no arguments and each return something which can -concatenate in a string context. You may have a hundred different classes in -your code, none of which have any obvious relationships, but they will work -with this method if they conform to this expected behavior. - -This is an improvement over writing specific functions to extract and display -this information for even a fraction of those hundred classes. This genericity -requires less code, and using a well-defined interface as the mechanism to -access this information means that any of those hundred classes can calculate -that information in any way possible. The details of those calculations is -where it matters most: in the bodies of the methods in the classes themselves. +C cares that an invocant is valid only in that it supports +three methods, C, C, and C which take no arguments and +each return something which can concatenate in a string context. You may have a +hundred different classes in your code, none of which have any obvious +relationships, but they will work with this method if they conform to this +expected behavior. + +Consider how you might enumerate a zoo's worth of animals without this +polymorphic function. The benefit of genericity should be obvious. As well, any +specific details about how to calculate the age of an ocelot or octopus can +belong in the relevant class--where it matters most. Of course, the mere existence of a method called C or C does not -by itself imply the behavior of that object. A C object may have an -C which is an accessor such that you can discover C<$rodney> is 8 but -C<$lucky> is 3. A C object may have an C method that lets you -control how long to stow C<$cheddar> to sharpen it. In other words, C -may be an accessor in one class but not in another: +by itself imply the behavior of that object. A C object may have an +C which is an accessor such that you can discover C<$rodney> is 9 but +C<$lucky> is 4. A C object may have an C method that lets you +control how long to stow C<$cheddar> to sharpen it. C may be an accessor +in one class but not in another: =begin programlisting @@ -486,8 +460,8 @@ may be an accessor in one class but not in another: =end programlisting -Sometimes it's useful to know I an object does. You need to understand -its type. +Sometimes it's useful to know I an object does. For that, you must +understand its type. =head2 Roles @@ -496,29 +470,20 @@ X A I is a named collection of behavior and stateN and research on -traits in Smalltalk at U for copious -details.>. A class is like a role, with the vital difference that you can -instantiate a class, but not a role. While a class is primarily a mechanism -for organizing behaviors and state into a template for objects, a role is -primarily a mechanism for organizing behaviors and state into a named -collection. - -A role is something a class does. +Smalltalk traits at U for copious +details.>. While a class organizes behaviors and state into a template for +objects, a role organizes a named collection of behaviors and state. -The difference between some sort of C--with a C, an C, -and a preferred C--and C--which can C in storage--may be -that the C does the C role, while the C does the -C role. +You can instantiate a class, but not a role. A role is something a class does. -While you I check that every object passed into C is -an instance of C, you lose some genericity that way. Instead, check -that the object I the C role: +Given an C which has an age and a C which can age, one +difference may be that C does the C role, while the +C does the C role: =begin programlisting + package LivingBeing { - package LivingBeing; - use Moose::Role; requires qw( name age diet ); @@ -527,35 +492,36 @@ that the object I the C role: =end programlisting Anything which does this role must supply the C, C, and -C methods. This does not happen automatically; the C class must -explicitly mark that it does the role: +C methods. The C class must explicitly mark that it does the role: =begin programlisting - package Cat; - - use Moose; + package Cat + { + use Moose; - has 'name', is => 'ro', isa => 'Str'; - has 'diet', is => 'rw', isa => 'Str'; - has 'birth_year', is => 'ro', isa => 'Int', - default => sub { (localtime)[5] + 1900 }; + has 'name', is => 'ro', isa => 'Str'; + has 'diet', is => 'rw', isa => 'Str'; + has 'birth_year', is => 'ro', isa => 'Int', + default => sub { (localtime)[5] + 1900 }; - B + B - sub age { ... } + sub age { ... } + } =end programlisting X -That single line has two functions. First, it tells Moose that the class does -the named role. Second, it I the role into the class. This process -checks that the class I provides all of the required methods and all -of the required attributes without potential collisions. +The C line causes Moose to I the C role into the +C class. Composition ensures all of the attributes and methods of the role +part of the class. C requires any composing class to provide +methods named C, C, and C. C satisfies these +constraints. -The C class provides C and C methods as accessors to named -attributes. It also declares its own C method. +If C were composed into a class which did not provide those +methods, Moose would throw an exception. =begin sidebar @@ -566,7 +532,7 @@ methods. =end sidebar Now all C instances will return a true value when queried if they provide -the C role and C objects should not: +the C role. C objects should not: =begin programlisting @@ -575,20 +541,19 @@ the C role and C objects should not: =end programlisting -This design approach may seem like extra bookkeeping, but it separates the -I of classes and objects from the I of those -classes and objects. The special behavior of the C class, where it stores -the birth year of the animal and calculates the age directly, could itself be a -role: +This design technique separates the I of classes and objects from +the I of those classes and objects. The special behavior of the +C class, where it stores the birth year of the animal and calculates the +age directly, could itself be a role: =begin programlisting + package CalculateAge::From::BirthYear { - package CalculateAge::From::BirthYear; - use Moose::Role; - has 'birth_year', is => 'ro', isa => 'Int', + has 'birth_year', is => 'ro', + isa => 'Int', default => sub { (localtime)[5] + 1900 }; sub age @@ -602,45 +567,49 @@ role: =end programlisting -Moving this code out of the C class into a separate role makes it -available to other classes. Now C can compose both roles: +Extracting this role from C makes the useful behavior available to other +classes. Now C can compose both roles: =begin programlisting - package Cat; - - use Moose; + package Cat + { + use Moose; - has 'name', is => 'ro', isa => 'Str'; - has 'diet', is => 'rw'; + has 'name', is => 'ro', isa => 'Str'; + has 'diet', is => 'rw'; - B + B + } =end programlisting +Notice how the C method of C satisfies +the requirement of the C role. Notice also that any check that +C performs C returns a true value. Extracting C into a +role has only changed the details of I C calculates an age. It's +still a C. C can choose to implement its own age or get it +from somewhere else. All that matters is that it provides an C which +satisfies the C constraint. + X X -The implementation of the C method supplied by the -C satisfies the requirement of the C -role, and the composition succeeds. Checking that objects do the -C role remains unchanged, regardless of I objects do this -role. A class could choose to provide its own C method or obtain it -from another role; that doesn't matter. All that matters is that it contains -one. This is I. - -Pervasive use of allomorphism in your designs can reduce the size of your -classes and allow you to share more code between classes. It also allows more -flexibility in your design by naming specific collections of behaviors so that -you can test the capabilities of objects and classes and not their +Just as polymorphism means that you can treat multiple objects with the same +behavior in the same way, this I means that an object may +implement the same behavior in multiple ways. + +Pervasive allomorphism can reduce the size of your classes and increase the +code shared between them. It also allows you to name specific and discrete +collections of behaviors--very useful for testing for capabilities instead of implementations. X X X -For a lengthy comparison of roles and other design techniques such as mixins, -multiple inheritance, and monkeypatching, see +To compare roles to other design techniques such as mixins, multiple +inheritance, and monkeypatching, see U. =head3 Roles and DOES() @@ -648,8 +617,8 @@ U. X> X> -Applying a role to a class means that the class and its instances will return -true when you call the C method on them: +When you compose a role into a class, the class and its instances will return a +true value when you call C on them: =begin programlisting @@ -665,23 +634,22 @@ X X X -Another feature of Perl 5's object system is I, where one class -specializes another. This establishes a relationship between the two classes, -where the child inherits attributes and behavior of the parent. As with two -classes which provide the same role, you may substitute a child class for its -parent. In one sense, a subclass provides the role implied by the existence of +Perl 5's object system supports I, which establishes a +relationship between two classes such that one specializes the other. The child +class behaves the same way as its parent--it has the same number and types of +attributes and can use the same methods. It may have additional data and +behavior, but you may substitute any instance of a child where code expects its +parent. In one sense, a subclass provides the role implied by the existence of its parent class. =begin sidebar -Recent experiments in role-based systems in Perl 5 demonstrate that you can -replace almost every use of inheritance in a system with roles. The decision -to use either one is largely a matter of familiarity. Roles provide -composition-time safety, better type checking, better-factored and less coupled -code, and finer-grained control over names and behaviors, but inheritance is -more familiar to users of other languages. The design question is whether one -class truly I another or whether it provides additional (or, at least, -I) behavior. +Should you use roles or inheritance? Roles provide composition-time safety, +better type checking, better factoring of code, and finer-grained control over +names and behaviors, but inheritance is more familiar to experienced developers +of other languages. Use inheritance when one class truly I another. +Use a role when a class needs additional behavior, and when you can give that +behavior a meaningful name. =end sidebar @@ -690,9 +658,8 @@ Consider a C class which provides two public attributes =begin programlisting + package LightSource { - package LightSource; - use Moose; has 'candle_power', is => 'ro', isa => 'Int', @@ -724,15 +691,13 @@ usable within the class to set the value. =head3 Inheritance and Attributes -Subclassing C makes it possible to define a super candle which -behaves the same way as C but provides a hundred times the amount -of light: +A subclass of C could define a super candle which provides a +hundred times the amount of light: =begin programlisting + package SuperCandle { - package LightSource::SuperCandle; - use Moose; B; @@ -744,20 +709,25 @@ of light: X> -The C function takes a list of class names to use as parents of the -current class. The C<+> at the start of the C attribute name -indicates that the current class extends or overrides the declaration of the -attribute. In this case, the super candle overrides the default value of the -light source, so any new C created has a light value of 100 -candles. The other attribute and both methods are available on C -instances; when you invoke C or C on such an instance, Perl -will look in C for the method, then in the list of -parents of the class. Ultimately it finds them in C. +C takes a list of class names to use as parents of the current class. +If that were the only line in this class, C objects would behave +the same as C objects. It would have both the C and +C attributes as well as the C and C methods. + +The C<+> at the start of an attribute name (such as C) indicates +that the current class does something special with that attribute. Here the +super candle overrides the default value of the light source, so any new +C created has a light value of 100 candles. + +When you invoke C or C on a C object, Perl +will look in the C class for the method, then in each parent. In +this case, those methods are in the C class. X -Attribute inheritance works in a similar way (see C for -details). +Attribute inheritance works similarly (see C). + +=begin sidebar X X @@ -767,29 +737,35 @@ X X X -I (sometimes written I or -I) is easy to understand in the case of single-parent inheritance. When a -class has multiple parents (I), dispatch is less obvious. -By default, Perl 5 provides a depth-first strategy of method resolution. It -searches the class of the I named parent and all of its parents -recursively before searching the classes of the subsequent named parents. This -behavior is often confusing; avoid using multiple inheritance until you -understand it and have exhausted all other alternatives. See C -for more details about method resolution and dispatch strategies. +I (or I or I) is obvious +for single-parent classes. Look in the object's class, then its parent, and so +on until you find the method or run out of parents. Classes which inherit from +multiple parents (I)--suppose your C extends +both C and C--require trickier dispatch. Reasoning about multiple +inheritance is complex. Avoid multiple inheritance when possible. + +Perl 5 uses a depth-first method resolution strategy. It searches the class of +the I named parent and all of that parent's parents recursively before +searching the classes of subsequent parents. The C pragma (L) +provides alternate strategies, including the C3 MRO strategy which searches a +given class's immediate parents before searching any of their parents. + +See C for more details. + +=end sidebar =head3 Inheritance and Methods X X> -You may override methods in subclasses. Imagine a light that you cannot -extinguish: +As with attributes, subclasses may override methods. Imagine a light that you +cannot extinguish: =begin programlisting + package Glowstick { - package LightSource::Glowstick; - use Moose; extends 'LightSource'; @@ -799,20 +775,18 @@ extinguish: =end programlisting -All calls to the C method for objects of this class will do -nothing. Perl's method dispatch system will find this method and will not look -for any methods of this name in any of the parent classes. +Calling C on a glowstick does nothing, even though +C's method does something. Method dispatch will find the +subclass's method. You may not have meant to do this. When you do, use Moose's +C to express your intention clearly. -Sometimes an overridden method needs behavior from its parent as well. The -C command tells Moose (and everyone else reading the code) that the -subclass deliberately overrides the named method. The C function is -available to dispatch from the overriding method to the overridden method: +Within an overridden method, Moose's C allows you to call the +overridden method: =begin programlisting + package LightSource::Cranky { - package LightSource::Cranky; - use Carp; use Moose; @@ -842,14 +816,14 @@ available to dispatch from the overriding method to the overridden method: =end programlisting This subclass adds a warning when trying to light or extinguish a light source -that already has the current state. The C function dispatches to the +that already has the current state. The C function dispatches to the nearest parent's implementation of the current method, per the normal Perl 5 method resolution order. =begin sidebar -You can achieve the same behavior by using Moose method modifiers. See -C. +Moose's method modifiers can do similar things--and more. See C. =end sidebar @@ -858,8 +832,8 @@ C. X> X> -Inheriting from a parent class means that the child class and all of its -instances will return a true value when you call the C method on them: +Perl's C method returns true if its invocant is or extends a named +class. That invocant may be the name of a class or an instance of an object: =begin programlisting @@ -872,12 +846,11 @@ instances will return a true value when you call the C method on them: X -Moose provides many features you'd otherwise have to build for yourself with -the default object orientation of Perl 5. While you I build everything -you get with Moose yourself (L), or cobble it together with -a series of CPAN distributions, Moose is a coherent package which just works, -includes good documentation, is part of many successful projects, and is under -active development by an attentive and talented community. +Moose provides many features beyond Perl 5's default OO. While you I +build everything you get with Moose yourself (L), or cobble +it together with a series of CPAN distributions, Moose is worth using. It is a +coherent whole, with good documentation. Many important projects use it +successfully. Its development community is mature and attentive. X X @@ -885,13 +858,14 @@ X X> X> -By default, with Moose objects you do not have to worry about constructors and -destructors, accessors, and encapsulation. Moose objects can extend and -work with objects from the vanilla Perl 5 system. You also get -I--a way of accessing the implementation of the system through -the system itself--and the concomitant extensibility. If you've ever wondered -which methods are available on a class or an object or which attributes an -object supports, this metaprogramming information is available with Moose: +Moose takes care of constructors, destructors, accessors, and encapsulation. +You must do the work of declaring what you want, but what you get back is safe +and easy to use. Moose objects can extend and work with objects from the +vanilla Perl 5 system. + +Moose also allows I--manipulating your objects through Moose +itself. If you've ever wondered which methods are available on a class or an +object or which attributes an object supports, this information is available: =begin programlisting @@ -951,27 +925,26 @@ This is valid Perl 5 code: =end programlisting -X> -X> +X> +X> -The C extension from the CPAN uses a clever module called -C to add new syntax to Perl 5, specifically for Moose. The -C, C, and C keywords reduce the amount of boilerplate -necessary to write good object oriented code in Perl 5. Note specifically the -declarative nature of this example, as well as the now unnecessary C line at the start of the C method. +The C CPAN distribution uses the CPAN distribution +C to add new Moose-specific syntax. The C, C, and +C keywords reduce the amount of boilerplate necessary to write good +object oriented code in Perl 5. Note specifically the declarative nature of +this example, as well as the lack of C in C. -=begin sidebar +While Moose is not a part of the Perl 5 core, its popularity ensures that it's +available on many OS distributions. Perl 5 distributions such as Strawberry +Perl and ActivePerl also include it. Even though Moose is a CPAN module and not +a core library, its cleanliness and simplicity make it essential to modern Perl +programming. -As of Perl 5.12, the Perl 5 core explicitly supports C, but the -module is not a core module and it works with earlier versions of Perl 5. +=begin sidebar -=end sidebar +X> -One drawback of this approach is that you must be able to install CPAN modules -(or a custom Perl 5 distribution such as Strawberry Perl or Strawberry Perl -Professional which may include them for you), but in comparison to Perl 5's -core object orientation, the advantage in cleanliness and simplicity of Moose -should be obvious. +Moose programs do use more memory than non-Moose programs, but the +C CPAN module helps reduce the cost of features you don't use. -See C for more information on using Moose. +=end sidebar diff --git a/sections/reflection.pod b/sections/reflection.pod index 0591c50d..cd9de547 100644 --- a/sections/reflection.pod +++ b/sections/reflection.pod @@ -6,23 +6,24 @@ X X I (or I) is the process of asking a program about -itself as it runs. Even though you can write many useful programs without ever -having to use reflection, techniques such as metaprogramming -(L) benefit from a deeper understanding of which entities are -in the system. +itself as it runs. By treating code as data you can manage code in the same way +that you manage data. This is a principle behind code generation +(L). -C (L) simplifies many reflection tasks for object -systems, but many useful programs do not use objects pervasively, and many -useful programs do not use C. Several idioms exist for using -reflection effectively in the absence of such a formal system. These are the -most common. +X> + +Moose's C (L) simplifies many reflection tasks for +object systems. If you use Moose, its metaprogramming system will help you. If +not, several other core Perl 5 idioms help you inspect and manipulate running +programs. =head2 Checking that a Package Exists -To check that a package exists somewhere in the system--that is, if some code +To check that a package exists somewhere in your program--if some code somewhere has executed a C directive with a given name--check that the -package inherits from C by testing that the package somehow provides -the C method: +package inherits from C. Anything which extends C must +somehow provide the C method. If no such package exists, Perl will throw +an exception about an invalid invocant, so wrap this call in an C block: =begin programlisting @@ -30,33 +31,25 @@ the C method: =end programlisting -Although you I use packages with the names C<0> and C<''>N<... only if -you define them symbolically, as these are I identifiers forbidden by the -Perl 5 parser.>, the C method will throw a method invocation exception -if you use them as invocants. The C block catches such an exception. - -You I also grovel through the symbol table, but this approach is quicker -and easier to understand. +An alternate approach is groveling through Perl's symbol tables. =head2 Checking that a Class Exists Because Perl 5 makes no strong distinction between packages and classes, the -same technique for checking the existence of a package works for checking that -a class exists. There is no generic way for determining if a package is a -class. You I check that the package C provide C, but there -is no guarantee that any C found is a method, nor a constructor. +best you can do without Moose is to check that a package of the expected class +name exists. You I check that the package C provide C, but +there is no guarantee that any C found is either a method or a +constructor. =head2 Checking that a Module Has Loaded X> -X> If you know the name of a module, you can check that Perl believes it has -loaded that module from disk by looking in the C<%INC> hash. This hash -corresponds to C<@INC>; when Perl 5 loads code with C or C, it -stores an entry in C<%INC> where the key is the file path of the module to load -and the value is the full path on disk to that module. In other words, loading -C effectively does: +loaded that module by looking in the C<%INC> hash. When Perl 5 loads code with +C or C, it stores an entry in C<%INC> where the key is the file +path of the module to load and the value is the full path on disk to that +module. In other words, loading C effectively does: =begin programlisting @@ -65,10 +58,9 @@ C effectively does: =end programlisting -The details of the path will vary depending on your installation, but for the -purpose of testing that Perl has successfully loaded a module, you can convert -the name of the module into the canonical file form and test for existence -within C<%INC>: +The details of the path will vary depending on your installation. To test that +Perl has successfully loaded a module, convert the name of the module into the +canonical file form and test for that key's existence within C<%INC>: =begin programlisting @@ -80,23 +72,24 @@ within C<%INC>: =end programlisting -Nothing prevents other code from manipulating C<%INC> itself. Depending on -your paranoia level, you may check the path and the expected contents of the -package yourself. Some modules (such as C or -C) manipulate C<%INC> for good reasons. Code which -manipulates C<%INC> for poor reasons deserves replacing. +X> +X> +X> + +As with C<@INC>, any code anywhere may manipulate C<%INC>. Some modules (such +as C or C) manipulate C<%INC> for good +reasons. Depending on your paranoia level, you may check the path and the +expected contents of the package yourself. -X> +X> -The C module from the CPAN provides a function named -C which can give better answers than checking C<%INC> -directly. +The C CPAN module's C function encapsulates +this C<%INC> check. -=head2 Checking the Version of a Module +=head2 Checking a Module Version Number -There is no guarantee that a given module provides a version. Even so, all -modules inherit from C (L), so they all have a -C method available: +Modules do not have to provide version numbers, but all package extend +C (L) and respond to its C method: =begin programlisting @@ -104,14 +97,14 @@ C method available: =end programlisting -If the given module does not override C or contain a package -variable C<$VERSION>, the method will return an undefined value. Likewise, if -the module does not exist, the method call will fail. +C returns the given module's version number, if defined. Otherwise +it returns C. If the module does not exist, the method will likewise +return C. =head2 Checking that a Function Exists -The simplest mechanism by which to determine if a function exists is to use the -C method on the package name: +To check whether a function exists in a package, call C as a class +method on the package name: =begin programlisting @@ -122,11 +115,11 @@ C method on the package name: Perl will throw an exception unless C<$pkg> is a valid invocant; wrap the method call in an C block if you have any doubts about its validity. Beware that a function implemented in terms of C (L) may -report the wrong answer if the function's package does not also override -C correctly. This is a bug in the other package. +report the wrong answer if the function's package has not predeclared the +function or overridden C correctly. This is a bug in the other package. -You may use this technique to determine if a module's C has imported -a function into the current namespace: +Use this technique to determine if a module's C has imported a +function into the current namespace: =begin programlisting @@ -134,14 +127,13 @@ a function into the current namespace: =end programlisting -You may also root around in the symbol table and typeglobs to determine if a -function exists, but this mechanism is simpler and easier to explain. +As with checking for the existence of a package, you I root around in +symbol tables yourself, if you have the patience for it. =head2 Checking that a Method Exists -There is no generic way to determine whether a given function is a function or -a method. Some functions behave as both functions and methods; though this is -overly complex and usually a mistake, it is an allowed feature. +There is no foolproof way for reflection to distinguish between a function or a +method. =head2 Rooting Around in Symbol Tables @@ -149,21 +141,22 @@ X X A Perl 5 symbol table is a special type of hash, where the keys are the names -of package global symbols and the values are typeglobs. A I is a -core data structure which can contain any or all of a scalar, an array, a hash, -a filehandle, and a function. Perl 5 uses typeglobs internally when it looks -up these variables. +of package global symbols and the values are typeglobs. A I is an +internal data structure which can contain any or all of a scalar, an array, a +hash, a filehandle, and a function. -You can access a symbol table as a hash by appending double-colons to the name -of the package. For example, the symbol table for the C package -is available as C<%MonkeyGrinder::>. +Access a symbol table as a hash by appending double-colons to the name of the +package. For example, the symbol table for the C package is +available as C<%MonkeyGrinder::>. You I test the existence of specific symbol names within a symbol table with the C operator (or manipulate the symbol table to I or -I symbols, if you like). Yet be aware that certain changes to the Perl -5 core have modified what exists by default in each typeglob entry. In -particular, earlier versions of Perl 5 have always provided a default scalar -variable for every typeglob created, while modern versions of Perl 5 do not. +I symbols, if you like). Yet be aware that certain changes to the Perl +5 core have modified the details of what typeglobs store and when and why. + +X> See the "Symbol Tables" section in C for more details, then -prefer the other techniques in this section for reflection. +prefer the other techniques in this section for reflection. If you really must +manipulate symbol tables and typeglobs, consider using the C +CPAN module instead.