X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=pod%2Fperlobj.pod;h=81c6c962468b67fa87f32cd3fc5e2cf1f7adc1c5;hb=4d9142afa100a96f07b67cd4b087273df8c60543;hp=6bbaab47044c76337f1a577dcedaa9b35086a4b2;hpb=748a93069b3d16374a9859d1456065dd3ae11394;p=p5sagit%2Fp5-mst-13.2.git diff --git a/pod/perlobj.pod b/pod/perlobj.pod index 6bbaab4..81c6c96 100644 --- a/pod/perlobj.pod +++ b/pod/perlobj.pod @@ -34,7 +34,7 @@ We'll cover these points now in more depth. Unlike say C++, Perl doesn't provide any special syntax for constructors. A constructor is merely a subroutine that returns a -reference that has been "blessed" into a class, generally the +reference to something "blessed" into a class, generally the class that the subroutine is defined in. Here is a typical constructor: @@ -61,7 +61,33 @@ that wish to call methods in the class as part of the construction: my $self = {} bless $self; $self->initialize(); - $self; + return $self; + } + +If you care about inheritance (and you should; see L), then you want to use the two-arg form of bless +so that your constructors may be inherited: + + sub new { + my $class = shift; + my $self = {}; + bless $self, $class + $self->initialize(); + return $self; + } + +Or if you expect people to call not just Cnew()> but also +C<$obj-Enew()>, then use something like this. The initialize() +method used will be of whatever $class we blessed the +object into: + + sub new { + my $this = shift; + my $class = ref($this) || $this; + my $self = {}; + bless $self, $class + $self->initialize(); + return $self; } Within the class package, the methods will typically deal with the @@ -100,7 +126,7 @@ package. This is how Perl implements inheritance. Each element of the @ISA array is just the name of another package that happens to be a class package. The classes are searched (depth first) for missing methods in the order that they occur in @ISA. The classes accessible -through @ISA are known as base classes of the current class. +through @ISA are known as base classes of the current class. If a missing method is found in one of the base classes, it is cached in the current class for efficiency. Changing @ISA or defining new @@ -177,7 +203,7 @@ indirect object slot: display {find Critter "Fred"} 'Height', 'Weight'; -For C++ fans, there's also a syntax using -> notation that does exactly +For C++ fans, there's also a syntax using -E notation that does exactly the same thing. The parentheses are required if there are any arguments. $fred = Critter->find("Fred"); @@ -224,6 +250,16 @@ name with the package like this: $fred = Critter->MyCritter::find("Fred"); $fred->MyCritter::display('Height', 'Weight'); +If you're trying to control where the method search begins I you're +executing in the class itself, then you may use the SUPER pseudoclass, +which says to start looking in your base class's @ISA list without having +to explicitly name it: + + $self->SUPER::display('Height', 'Weight'); + +Please note that the C construct is I meaningful within the +class. + Sometimes you want to call a method when you don't know the method name ahead of time. You can use the arrow form, replacing the method name with a simple scalar variable containing the method name: @@ -251,7 +287,7 @@ automatically when the current object is freed. An indirect object is limited to a name, a scalar variable, or a block, because it would have to do too much lookahead otherwise, just like any -other postfix dereference in the language. The left side of -> is not so +other postfix dereference in the language. The left side of -E is not so limited, because it's an infix operator, not a postfix operator. That means that below, A and B are equivalent to each other, and C and D @@ -268,6 +304,107 @@ That's about all there is to it. Now you just need to go off and buy a book about object-oriented design methodology, and bang your forehead with it for the next six months or so. +=head2 Two-Phased Garbage Collection + +For most purposes, Perl uses a fast and simple reference-based +garbage collection system. For this reason, there's an extra +dereference going on at some level, so if you haven't built +your Perl executable using your C compiler's C<-O> flag, performance +will suffer. If you I built Perl with C, then this +probably won't matter. + +A more serious concern is that unreachable memory with a non-zero +reference count will not normally get freed. Therefore, this is a bad +idea: + + { + my $a; + $a = \$a; + } + +Even thought $a I go away, it can't. When building recursive data +structures, you'll have to break the self-reference yourself explicitly +if you don't care to leak. For example, here's a self-referential +node such as one might use in a sophisticated tree structure: + + sub new_node { + my $self = shift; + my $class = ref($self) || $self; + my $node = {}; + $node->{LEFT} = $node->{RIGHT} = $node; + $node->{DATA} = [ @_ ]; + return bless $node => $class; + } + +If you create nodes like that, they (currently) won't go away unless you +break their self reference yourself. (In other words, this is not to be +construed as a feature, and you shouldn't depend on it.) + +Almost. + +When an interpreter thread finally shuts down (usually when your program +exits), then a rather costly but complete mark-and-sweep style of garbage +collection is performed, and everything allocated by that thread gets +destroyed. This is essential to support Perl as an embedded or a +multithreadable language. For example, this program demonstrates Perl's +two-phased garbage collection: + + #!/usr/bin/perl + package Subtle; + + sub new { + my $test; + $test = \$test; + warn "CREATING " . \$test; + return bless \$test; + } + + sub DESTROY { + my $self = shift; + warn "DESTROYING $self"; + } + + package main; + + warn "starting program"; + { + my $a = Subtle->new; + my $b = Subtle->new; + $$a = 0; # break selfref + warn "leaving block"; + } + + warn "just exited block"; + warn "time to die..."; + exit; + +When run as F, the following output is produced: + + starting program at /tmp/test line 18. + CREATING SCALAR(0x8e5b8) at /tmp/test line 7. + CREATING SCALAR(0x8e57c) at /tmp/test line 7. + leaving block at /tmp/test line 23. + DESTROYING Subtle=SCALAR(0x8e5b8) at /tmp/test line 13. + just exited block at /tmp/test line 26. + time to die... at /tmp/test line 27. + DESTROYING Subtle=SCALAR(0x8e57c) during global destruction. + +Notice that "global destruction" bit there? That's the thread +garbage collector reaching the unreachable. + +Objects are always destructed, even when regular refs aren't and in fact +are destructed in a separate pass before ordinary refs just to try to +prevent object destructors from using refs that have been themselves +destructed. Plain refs are only garbage collected if the destruct level +is greater than 0. You can test the higher levels of global destruction +by setting the PERL_DESTRUCT_LEVEL environment variable, presuming +C<-DDEBUGGING> was enabled during perl build time. + +A more complete garbage collection strategy will be implemented +at a future date. + =head1 SEE ALSO -You should also check out L for other object tricks, traps, and tips. +You should also check out L for other object tricks, traps, and tips, +as well as L for some style guides on constructing both modules +and classes.