This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fill in some details about the release
[perl5.git] / pod / perlbot.pod
index fb94560..91723b7 100644 (file)
@@ -1,18 +1,80 @@
 =head1 NAME
 
-perlbot - Bag'o Object Tricks For Perl5 (the BOT)
+perlbot - Bag'o Object Tricks (the BOT)
 
-=head1 INTRODUCTION
+=head1 DESCRIPTION
 
 The following collection of tricks and hints is intended to whet curious
 appetites about such things as the use of instance variables and the
 mechanics of object and class relationships.  The reader is encouraged to
 consult relevant textbooks for discussion of Object Oriented definitions and
-methodology.  This is not intended as a comprehensive guide to Perl5's
-object oriented features, nor should it be construed as a style guide.
+methodology.  This is not intended as a tutorial for object-oriented
+programming or as a comprehensive guide to Perl's object oriented features,
+nor should it be construed as a style guide.  If you're looking for tutorials,
+be sure to read L<perlboot>, L<perltoot>, and L<perltooc>.
 
 The Perl motto still holds:  There's more than one way to do it.
 
+=head1 OO SCALING TIPS
+
+=over 5
+
+=item 1
+
+Do not attempt to verify the type of $self.  That'll break if the class is
+inherited, when the type of $self is valid but its package isn't what you
+expect.  See rule 5.
+
+=item 2
+
+If an object-oriented (OO) or indirect-object (IO) syntax was used, then the
+object is probably the correct type and there's no need to become paranoid
+about it.  Perl isn't a paranoid language anyway.  If people subvert the OO
+or IO syntax then they probably know what they're doing and you should let
+them do it.  See rule 1.
+
+=item 3
+
+Use the two-argument form of bless().  Let a subclass use your constructor.
+See L<INHERITING A CONSTRUCTOR>.
+
+=item 4
+
+The subclass is allowed to know things about its immediate superclass, the
+superclass is allowed to know nothing about a subclass.
+
+=item 5
+
+Don't be trigger happy with inheritance.  A "using", "containing", or
+"delegation" relationship (some sort of aggregation, at least) is often more
+appropriate.  See L<OBJECT RELATIONSHIPS>, L<USING RELATIONSHIP WITH SDBM>,
+and L<"DELEGATION">.
+
+=item 6
+
+The object is the namespace.  Make package globals accessible via the
+object.  This will remove the guess work about the symbol's home package.
+See L<CLASS CONTEXT AND THE OBJECT>.
+
+=item 7
+
+IO syntax is certainly less noisy, but it is also prone to ambiguities that
+can cause difficult-to-find bugs.  Allow people to use the sure-thing OO
+syntax, even if you don't like it.
+
+=item 8
+
+Do not use function-call syntax on a method.  You're going to be bitten
+someday.  Someone might move that method into a superclass and your code
+will be broken.  On top of that you're feeding the paranoia in rule 2.
+
+=item 9
+
+Don't assume you know the home package of a method.  You're making it
+difficult for someone to override that method.  See L<THINKING OF CODE REUSE>.
+
+=back
+
 =head1 INSTANCE VARIABLES
 
 An anonymous array or anonymous hash can be used to hold instance
@@ -26,7 +88,7 @@ variables.  Named parameters are also demonstrated.
                my $self = {};
                $self->{'High'} = $params{'High'};
                $self->{'Low'}  = $params{'Low'};
-               bless $self;
+               bless $self, $type;
        }
 
 
@@ -38,20 +100,19 @@ variables.  Named parameters are also demonstrated.
                my $self = [];
                $self->[0] = $params{'Left'};
                $self->[1] = $params{'Right'};
-               bless $self;
+               bless $self, $type;
        }
 
        package main;
 
-       $a = new Foo ( 'High' => 42, 'Low' => 11 );
+       $a = Foo->new( 'High' => 42, 'Low' => 11 );
        print "High=$a->{'High'}\n";
        print "Low=$a->{'Low'}\n";
 
-       $b = new Bar ( 'Left' => 78, 'Right' => 40 );
+       $b = Bar->new( 'Left' => 78, 'Right' => 40 );
        print "Left=$b->[0]\n";
        print "Right=$b->[1]\n";
 
-
 =head1 SCALAR INSTANCE VARIABLES
 
 An anonymous scalar can be used when only one instance variable is needed.
@@ -62,12 +123,12 @@ An anonymous scalar can be used when only one instance variable is needed.
                my $type = shift;
                my $self;
                $self = shift;
-               bless \$self;
+               bless \$self, $type;
        }
 
        package main;
 
-       $a = new Foo 42;
+       $a = Foo->new( 42 );
        print "a=$$a\n";
 
 
@@ -81,23 +142,25 @@ object.
        package Bar;
 
        sub new {
+               my $type = shift;
                my $self = {};
                $self->{'buz'} = 42;
-               bless $self;
+               bless $self, $type;
        }
 
        package Foo;
        @ISA = qw( Bar );
 
        sub new {
-               my $self = new Bar;
+               my $type = shift;
+               my $self = Bar->new;
                $self->{'biz'} = 11;
-               bless $self;
+               bless $self, $type;
        }
 
        package main;
 
-       $a = new Foo;
+       $a = Foo->new;
        print "buz = ", $a->{'buz'}, "\n";
        print "biz = ", $a->{'biz'}, "\n";
 
@@ -111,23 +174,25 @@ relationships between objects.
        package Bar;
 
        sub new {
+               my $type = shift;
                my $self = {};
                $self->{'buz'} = 42;
-               bless $self;
+               bless $self, $type;
        }
 
        package Foo;
 
        sub new {
+               my $type = shift;
                my $self = {};
-               $self->{'Bar'} = new Bar ();
+               $self->{'Bar'} = Bar->new;
                $self->{'biz'} = 11;
-               bless $self;
+               bless $self, $type;
        }
 
        package main;
 
-       $a = new Foo;
+       $a = Foo->new;
        print "buz = ", $a->{'Bar'}->{'buz'}, "\n";
        print "biz = ", $a->{'biz'}, "\n";
 
@@ -135,11 +200,10 @@ relationships between objects.
 
 =head1 OVERRIDING SUPERCLASS METHODS
 
-The following example demonstrates how one might override a superclass
-method and then call the method after it has been overridden.  The
-Foo::Inherit class allows the programmer to call an overridden superclass
-method without actually knowing where that method is defined.
-
+The following example demonstrates how to override a superclass method and
+then call the overridden method.  The B<SUPER> pseudo-class allows the
+programmer to call an overridden superclass method without actually knowing
+where that method is defined.
 
        package Buz;
        sub goo { print "here's the goo\n" }
@@ -152,46 +216,52 @@ method without actually knowing where that method is defined.
 
        package Foo;
        @ISA = qw( Bar Baz );
-       @Foo::Inherit::ISA = @ISA;  # Access to overridden methods.
 
-       sub new { bless [] }
+       sub new {
+               my $type = shift;
+               bless [], $type;
+       }
        sub grr { print "grumble\n" }
        sub goo {
                my $self = shift;
-               $self->Foo::Inherit::goo();
+               $self->SUPER::goo();
        }
        sub mumble {
                my $self = shift;
-               $self->Foo::Inherit::mumble();
+               $self->SUPER::mumble();
        }
        sub google {
                my $self = shift;
-               $self->Foo::Inherit::google();
+               $self->SUPER::google();
        }
 
        package main;
 
-       $foo = new Foo;
+       $foo = Foo->new;
        $foo->mumble;
        $foo->grr;
        $foo->goo;
        $foo->google;
 
+Note that C<SUPER> refers to the superclasses of the current package
+(C<Foo>), not to the superclasses of C<$self>.
+
 
-=head1 USING RELATIONSHIP WITH SDBM 
+=head1 USING RELATIONSHIP WITH SDBM
 
 This example demonstrates an interface for the SDBM class.  This creates a
 "using" relationship between the SDBM class and the new class Mydbm.
 
-       use SDBM_File;
-       use POSIX;
-
        package Mydbm;
 
+       require SDBM_File;
+       require Tie::Hash;
+       @ISA = qw( Tie::Hash );
+
        sub TIEHASH {
-           my $self = shift;
+           my $type = shift;
            my $ref  = SDBM_File->new(@_);
-           bless {'dbm' => $ref};
+           bless {'dbm' => $ref}, $type;
        }
        sub FETCH {
            my $self = shift;
@@ -199,7 +269,7 @@ This example demonstrates an interface for the SDBM class.  This creates a
            $ref->FETCH(@_);
        }
        sub STORE {
-           my $self = shift; 
+           my $self = shift;
            if (defined $_[0]){
                my $ref = $self->{'dbm'};
                $ref->STORE(@_);
@@ -209,12 +279,13 @@ This example demonstrates an interface for the SDBM class.  This creates a
        }
 
        package main;
+       use Fcntl qw( O_RDWR O_CREAT );
 
-       tie %foo, Mydbm, "Sdbm", O_RDWR|O_CREAT, 0640;
+       tie %foo, "Mydbm", "Sdbm", O_RDWR|O_CREAT, 0640;
        $foo{'bar'} = 123;
        print "foo-bar = $foo{'bar'}\n";
 
-       tie %bar, Mydbm, "Sdbm2", O_RDWR|O_CREAT, 0640;
+       tie %bar, "Mydbm", "Sdbm2", O_RDWR|O_CREAT, 0640;
        $bar{'Cathy'} = 456;
        print "bar-Cathy = $bar{'Cathy'}\n";
 
@@ -230,7 +301,10 @@ that it is impossible to override the BAZ() method.
 
        package FOO;
 
-       sub new { bless {} }
+       sub new {
+               my $type = shift;
+               bless {}, $type;
+       }
        sub bar {
                my $self = shift;
                $self->FOO::private::BAZ;
@@ -253,7 +327,10 @@ FOO::private::BAZ().
 
        package FOO;
 
-       sub new { bless {} }
+       sub new {
+               my $type = shift;
+               bless {}, $type;
+       }
        sub bar {
                my $self = shift;
                $self->FOO::private::BAZ;
@@ -267,7 +344,10 @@ FOO::private::BAZ().
 
        package GOOP;
        @ISA = qw( FOO );
-       sub new { bless {} }
+       sub new {
+               my $type = shift;
+               bless {}, $type;
+       }
 
        sub BAZ {
                print "in GOOP::BAZ\n";
@@ -284,7 +364,10 @@ method GOOP::BAZ() to be used in place of FOO::BAZ().
 
        package FOO;
 
-       sub new { bless {} }
+       sub new {
+               my $type = shift;
+               bless {}, $type;
+       }
        sub bar {
                my $self = shift;
                $self->BAZ;
@@ -297,7 +380,10 @@ method GOOP::BAZ() to be used in place of FOO::BAZ().
        package GOOP;
        @ISA = qw( FOO );
 
-       sub new { bless {} }
+       sub new {
+               my $type = shift;
+               bless {}, $type;
+       }
        sub BAZ {
                print "in GOOP::BAZ\n";
        }
@@ -322,7 +408,7 @@ This problem can be solved by using the object to define the context of the
 method.  Let the method look in the object for a reference to the data.  The
 alternative is to force the method to go hunting for the data ("Is it in my
 class, or in a subclass?  Which subclass?"), and this can be inconvenient
-and will lead to hackery.  It is better to just let the object tell the
+and will lead to hackery.  It is better just to let the object tell the
 method where that data is located.
 
        package Bar;
@@ -330,14 +416,15 @@ method where that data is located.
        %fizzle = ( 'Password' => 'XYZZY' );
 
        sub new {
+               my $type = shift;
                my $self = {};
                $self->{'fizzle'} = \%fizzle;
-               bless $self;
+               bless $self, $type;
        }
 
        sub enter {
                my $self = shift;
-       
+
                # Don't try to guess if we should use %Bar::fizzle
                # or %Foo::fizzle.  The object already knows which
                # we should use, so just ask it.
@@ -353,9 +440,10 @@ method where that data is located.
        %fizzle = ( 'Password' => 'Rumple' );
 
        sub new {
+               my $type = shift;
                my $self = Bar->new;
                $self->{'fizzle'} = \%fizzle;
-               bless $self;
+               bless $self, $type;
        }
 
        package main;
@@ -410,8 +498,8 @@ behavior by adding custom FETCH() and STORE() methods, if this is desired.
        package Mydbm;
 
        require SDBM_File;
-       require TieHash;
-       @ISA = qw(TieHash);
+       require Tie::Hash;
+       @ISA = qw(Tie::Hash);
 
        sub TIEHASH {
                my $type = shift;
@@ -438,6 +526,10 @@ behavior by adding custom FETCH() and STORE() methods, if this is desired.
        package main;
        use Fcntl qw( O_RDWR O_CREAT );
 
-       tie %foo, Mydbm, "adbm", O_RDWR|O_CREAT, 0640;
+       tie %foo, "Mydbm", "adbm", O_RDWR|O_CREAT, 0640;
        $foo{'bar'} = 123;
        print "foo-bar = $foo{'bar'}\n";
+
+=head1 SEE ALSO
+
+L<perlboot>, L<perltoot>, L<perltooc>.