Navigation Menu

Skip to content

Commit

Permalink
Applied edits from John Bokma.
Browse files Browse the repository at this point in the history
  • Loading branch information
chromatic committed Oct 8, 2010
1 parent 4421a9e commit 6d5d188
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 73 deletions.
3 changes: 3 additions & 0 deletions CREDITS
Expand Up @@ -200,3 +200,6 @@ E: spazm@cpan.org

N: Mark Hindess
E: soft-cpan@temporalanomaly.com

N: John Bokma
E: contact@johnbokma.com
19 changes: 12 additions & 7 deletions sections/advanced_oo.pod
Expand Up @@ -10,17 +10,22 @@ several principles can guide you.

=head2 Favor Composition Over Inheritance

Novice OO designs often overuse inheritance. 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, and it adds technical
weight to every class, because conflicting responsibilities and methods may get
in the way of necessary behaviors or future modifications.
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.

X<OO; is-a>
X<OO; has-a>

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<Car> object does not have to inherit from a C<Vehicle::Wheeled>
object; it can contain several C<Wheel> objects as instance attributes.
object (an I<is-a relationship>); it can contain several C<Wheel> objects as
instance attributes (a I<has-a relationship>).

Decomposing complex classes into smaller, focused entities (whether classes or
roles) improves encapsulation and reduces the possibility that any one class or
Expand Down
9 changes: 6 additions & 3 deletions sections/barewords.pod
Expand Up @@ -27,12 +27,15 @@ Even so, barewords are permissible in several places in Perl 5 for good reason.

X<barewords; pros>
X<hashes; bareword keys>
X<C<+>; unary operator>

Hash keys in Perl 5 are barewords. These are usually not ambiguous because
their use as keys is sufficient for the parser to identify them as the
equivalent of single-quoted strings. Yet be aware that attempting to evaluate
a function call or a built-in operator (such as C<shift>) to I<produce> a hash
key may not do what you expect, unless you disambiguate.
a function call or a builtin operator (such as C<shift>) to I<produce> a hash
key may not do what you expect, unless you disambiguate by providing arguments,
using function argument parentheses, or prepending unary plus to force the
evaluation of the builtin rather than its interpretation as a string:

=begin programlisting

Expand All @@ -42,7 +45,7 @@ key may not do what you expect, unless you disambiguate.
# the value produced by shift is the key
my $value = $items{B<shift @_>}

# unary plus is also sufficient to disambiguate
# unary plus uses the keyword shift
my $value = $items{B<+>shift};

=end programlisting
Expand Down
8 changes: 4 additions & 4 deletions sections/blessed_references.pod
Expand Up @@ -27,8 +27,8 @@ resolution. That sounds more complicated than it is.

Though these rules explain Perl 5's underlying object system, they are somewhat
more minimal in practice than may be practical, especially for larger projects.
In particular, they offer few facilities for metaprogramming (using APIs to
manipulate the program itself).
In particular, they offer few facilities for metaprogramming
(L<code_generation>).

Moose (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
Expand Down Expand Up @@ -209,8 +209,8 @@ X<pragmas; base>

=begin sidebar

Perl 5.10 added C<parent> to supersede the C<base> pragma added in Perl
5.004_4. If you can't use Moose, use C<parent>.
Perl 5.10 added C<parent> to supersede the C<base> pragma. If you can't use
Moose, use C<parent>.

=end sidebar

Expand Down
3 changes: 2 additions & 1 deletion sections/handling_warnings.pod
Expand Up @@ -66,7 +66,8 @@ C<Carp>'s verbose mode throughout the entire program:
=end programlisting

This changes all C<carp()> (and C<croak()>--L<reporting_errors>) calls to
include a backtrace.
include a backtrace. When you organize your code into modules (L<modules>),
use Carp instead of C<warn> or C<die> to save debugging time.

=head2 Enabling and Disabling Warnings

Expand Down
3 changes: 1 addition & 2 deletions sections/hashes.pod
Expand Up @@ -108,8 +108,7 @@ function:
=end programlisting

The key of the hash will be C<name> and not C<Leonardo>. If you intend to call
the function to get the key, disambiguate your intent by making the call
explicit:
the function to get the key, make the function call explicit:

=begin programlisting

Expand Down
8 changes: 8 additions & 0 deletions sections/missing_defaults.pod
Expand Up @@ -10,6 +10,14 @@ clean, maintainable, powerful, and succinct Perl 5 code is very different from
Perl 5.000. The default behaviors sometimes get in the way; fortunately,
better behaviors are available.

X<Task::Kensho>

The CPAN (L<cpan>) contains many modules and pragmas designed to make your work
simpler, more correct, and more enjoyableN<See C<Task::Kensho> to start.>. As
you improve as a Perl programmer, you will have many opportunities to use (and
even to create) such code in the right circumstances. For now, use these
pragmas and modules regularly in your own code.

=head2 The strict Pragma

X<strict>
Expand Down
125 changes: 73 additions & 52 deletions sections/moose.pod
Expand Up @@ -3,13 +3,12 @@
Z<moose>
X<moose>

Moose is a more complete object system for Perl 5. It builds on the existing
Perl 5 system, and provides simpler defaults, better integration, and advanced
features from several other languages, including Smalltalk, Common Lisp, and
Perl 6. It's still worth learning the default Perl 5 object system, if only to
write very simple programs where Moose is inappropriate or to maintain legacy
code, but Moose is currently the best way to write object-oriented code in
modern Perl 5.
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<object orientation>
X<object oriented programming>
Expand All @@ -18,19 +17,19 @@ X<OOP>
X<objects>
X<classes>

I<Object orientation>, or I<object oriented programming>, is a way of managing
programs by categorizing their components into discrete, unique entities.
These are I<objects>. In Moose terms, each object is an instance of a
I<class>, which serves as a template to describe any data the object contains
I<Object orientation> (OO), or I<object oriented programming> (OOP), is a way
of managing programs by categorizing their components into discrete, unique
entities. These are I<objects>. In Moose terms, each object is an instance of
a I<class>, which serves as a template to describe any data the object contains
as well as its specific behaviors.

=head2 Classes

X<classes>
X<package>

A class in Perl 5 stores class data. It may have a name. By default, Perl 5
classes use packages to provide namespaces:
A class in Perl 5 stores class data. By default, Perl 5 classes use packages
to provide namespaces:

=begin programlisting

Expand Down Expand Up @@ -67,12 +66,14 @@ X<invocant>
A I<method> 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<invocant> on which the
method operates. In the case of creating the two C<Cat> objects, the name of
the class (C<Cat>) is the invocant:
method operates. When you create an object, the I<name> of the class is the
invocant. When you call a method on an instance, that instance is the
invocant:

=begin programlisting

my $fuzzy = B<Cat>->new();
B<$fuzzy>->sleep_on_keyboard();

=end programlisting

Expand Down Expand Up @@ -115,21 +116,29 @@ eaten yet:

=end programlisting

X<instance method>
X<methods; instance>
X<class method>
X<methods; class>

By convention, invocants in Perl methods are lexical variables named C<$self>,
but this is merely pervasive convention. The example implementation of
C<meow()> does not use the invocant, so it's irrelevant once method dispatch
has completed. In that sense, C<meow()> is like C<new()>; you can safely use
the name of the class (C<Cat>) as its invocant. This is a I<class method>:
By pervasive convention, methods store their invocants in lexical variables
named C<$self>. Methods which access invocant data are I<instance methods>,
because they depend on the presence of an appropriate invocant to work
correctly. Methods (such as C<meow()>) which do not access instance data are
I<class methods>, as you can use the name of the class as an invocant.
Constructors are also class methods. For example:

=begin programlisting

Cat->meow() for 1 .. 3;

=end programlisting

Class methods can help you organize your code into namespaces without requiring
you to import (L<importing>) functions, but a design which relies heavily on
class methods for anything other than constructors may be the sign of muddled
thinking.

=head2 Attributes

X<attributes (objects)>
Expand Down Expand Up @@ -327,9 +336,9 @@ available if you really need it, but the declarative approach can actually
improve your programs. In this way, Moose encourages I<encapsulation>: hiding
the internal details of an object from external users of that object.

Consider a change to the age of a C<Cat>; instead of requesting that directly
from the constructor, calculate the age of a C<Cat> based on the year of its
birth:
Consider how you might change the way C<Cat> 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:

=begin programlisting

Expand Down Expand Up @@ -409,11 +418,12 @@ for each object, including a hash or array reference.
=head3 Polymorphism

A program which deals with one type of data and one type of behavior on that
data benefits little from the use of objects. A well-designed object-oriented
program should be capable of managing 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<less> specific.
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<less> specific.

In other words, moving the specifics of the details of what the program knows
about individual C<Cat>s (the attributes) and what the program knows that
Expand Down Expand Up @@ -502,11 +512,14 @@ Sometimes it's useful to know I<what> an object does. In other words, you need

Z<roles>

A I<role> is a named collection of behavior and state. 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 I<role> is a named collection of behavior and stateN<See the Perl 6 design
documents on roles at U<http://feather.perl6.nl/syn/S14.html> and research on
traits in Smalltalk at U<http://scg.unibe.ch/research/traits> 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.

Expand Down Expand Up @@ -640,6 +653,14 @@ flexibility in your design by naming specific collections of behaviors so that
you can test the capabilities of objects and classes and not their
implementations.

=begin sidebar

For details about roles versus other design techniques such as mixins, multiple
inheritance, and monkeypatching, see
U<http://www.modernperlbooks.com/mt/2009/04/the-why-of-perl-roles.html>.

=end sidebar

=head3 Roles and DOES()

X<DOES()>
Expand Down Expand Up @@ -742,31 +763,31 @@ X<Moose; extends>

The C<extends> syntax takes a list of class names to use as parents of the
current class. The C<+> at the start of the C<candle_power> attribute name
indicates that the current class extends the declaration of the attribute. In
this case, the super candle overrides the default value of the light source, so
any new C<SuperCandle> created has a light value of 100 candles. The other
attribute and both methods are available on C<SuperCandle> instances; when you
invoke C<light> or C<extinguish> on such an instance, Perl will look in
C<LightSource::SuperCandle> for the method, then in the list of parents of the
class. Ultimately it finds them in C<LightSource>.
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<SuperCandle> created has a light value of 100
candles. The other attribute and both methods are available on C<SuperCandle>
instances; when you invoke C<light> or C<extinguish> on such an instance, Perl
will look in C<LightSource::SuperCandle> for the method, then in the list of
parents of the class. Ultimately it finds them in C<LightSource>.

X<Moose; attribute inheritance>

Attribute inheritance works in a similar fashion, except that the act of
I<constructing> the instance makes all of the appropriate attributes available
in the proper fashion (see C<perldoc Class::MOP>).
Attribute inheritance works in a similar way (see C<perldoc Class::MOP> for
details).

X<methods; resolution>
X<method resolution order>
X<methods; dispatch order>
X<multiple inheritance>
X<objects; inheritance>
X<objects; multiple inheritance>
X<MRO>

I<Method dispatch order> (sometimes written I<method resolution order>) is easy
to understand in the case of single-parent inheritance. When a class has
multiple parents (I<multiple inheritance>), dispatch is less obvious. By
default, Perl 5 provides a depth-first strategy of method resolution. It
I<Method dispatch order> (sometimes written I<method resolution order> or
I<MRO>) is easy to understand in the case of single-parent inheritance. When a
class has multiple parents (I<multiple inheritance>), dispatch is less obvious.
By default, Perl 5 provides a depth-first strategy of method resolution. It
searches the class of the I<first> 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
Expand Down Expand Up @@ -799,9 +820,9 @@ 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.

Sometimes an overridden method needs behavior from its parent as well. The
C<override> command tells Moose that the subclass deliberately overrides the
named method. The C<super()> function is available to dispatch from the
overriding method to the overridden method:
C<override> command tells Moose (and everyone else reading the code) that the
subclass deliberately overrides the named method. The C<super()> function is
available to dispatch from the overriding method to the overridden method:

=begin programlisting

Expand Down Expand Up @@ -961,8 +982,8 @@ shift;> line at the start of the C<age> method.

=begin sidebar

The Perl 5 core provides support for C<Devel::Declare> as of Perl 5.12, but the
module is not a core module.
As of Perl 5.12, the Perl 5 core explicitly supports C<Devel::Declare>, but the
module is not a core module and it works with earlier versions of Perl 5.

=end sidebar

Expand Down
9 changes: 5 additions & 4 deletions sections/reflection.pod
Expand Up @@ -13,8 +13,9 @@ in the system.

C<Class::MOP> (L<class_mop>) simplifies many reflection tasks for object
systems, but many useful programs do not use objects pervasively, and many
useful programs do not use C<Class::MOP>. Several idioms (L<idioms>) exist for
using reflection effectively in the absence of such a formal system.
useful programs do not use C<Class::MOP>. Several idioms exist for using
reflection effectively in the absence of such a formal system. These are the
most common.

=head2 Checking that a Package Exists

Expand Down Expand Up @@ -81,8 +82,8 @@ within C<%INC>:

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, but modules with good reasons for manipulating this variable
(such as C<Test::MockObject> or C<Test::MockModule>) may do so. Code which
package yourself. Some modules (such as C<Test::MockObject> or
C<Test::MockModule>) manipulate C<%INC> for good reasons. Code which
manipulates C<%INC> for poor reasons deserves replacing.

=head2 Checking the Version of a Module
Expand Down

0 comments on commit 6d5d188

Please sign in to comment.