Item 49: Consider using Perl's object-oriented programming features.Perl contains all the features needed to support object-oriented programming, including the following:
In addition, it is possible to approximate many other quasi-object-oriented featureslike templatesin Perl. An object-oriented exampleThe easiest way to approach object-oriented programming in Perl is to see an example of it. Here is a minimalist Perl class called Timer : Writing a simple class in Perl
Here is an example of how the Timer class could be used: Using a class in Perl
Although this is a very short example, it covers all of the most important aspects of object-oriented programming in Perl (except for inheritance, which is covered in Item 50). Bear this example in mind as I launch into a somewhat long-winded discussion of it below. A class in Perl is a package (see Item 42). The concept of class in other object-oriented languages is similar, in that a separate namespace is one of the most important facilities provided by a class. A Perl object is data that has been blessed into a package. The bless operator takes a reference (usually, but not necessarily , a hash reference) and a package name as arguments. The package name is optionalthe current package is used if it is omitted. When blessed, data " knows " to which package it belongs. In PEGS, blessed data is topped off with a rounded-corner rectangle containing the package name:
The ref operator (see Item 30) returns the package name rather than the type of data when it is applied to a blessed reference: [1]
The ref operator returns the package name of a blessed object.
This can be handy information but it should not be overused , because a major goal of object-oriented programming is to avoid explicitly testing the type of an object. It is important to realize that although the bless operator takes a reference as an argument, it is not blessing the reference. It is blessing the data to which the reference points : The bless operator blesses data, not references.
In PEGS, this looks like:
Returning to the example, the first subroutine that we define is a constructor. A constructor is a subroutine that creates and initializes a new object. In general, Perl constructors return references to anonymous hashes. This is a convention, and a convenient one, because hashes are a natural way to express "structs" or "records" in Perl (see Item 33). Another convention is that constructors are generally named new . Unlike some other object-oriented languages, Perl has no special object-constructing or memory-allocating operator. A constructor could be named something entirely different, for example, gimme_a_new , and it would still work in the same way. Naming a constructor new makes object-oriented Perl look familiar to programmers who have worked in other object-oriented languages. Constructors are methods. You will remember, from the discussion of object-oriented Perl above, that methods are ordinary subroutines that are invoked with a special method call syntax. The line $timer = new Timer; is an example of "indirect object" method call syntax. Perl interprets a subroutine name followed immediately by a package name in a special way as a call to a subroutine in that package, with the package name as the first argument. So the above line is equivalent to: $timer = Timer::new('Timer'); Methods invoked by package name are referred to as " static," " class," or " package" methods, according to your preference of nomenclature . The second subroutine that we define, Elapsed , is also a method. Unlike the constructor, it is designed to be called via an object rather than a package. Although you can use indirect object syntax, the more common technique is to call it using the other type of method call syntax, the " arrow": $elapsed = $timer->Elapsed(); Here, Perl uses the class of the $timer object to the left of the arrow to determine in which package to look for the subroutine Elapsed . [2] Because $timer has been blessed into package Timer , Perl calls the subroutine Timer::Elapsed . Perl also automatically uses the value to the left of the arrow as the first argument to the subroutine, that is:
$elapsed = Timer::Elapsed($timer); Methods invoked via an object rather than a package name are referred to as " object" or " dynamic" methods. Finally, let's look more closely at the Elapsed method itself. Most object-oriented languages have an automatically created variable called this or self that you can use inside methods. This "self" variable contains a pointer to the object that was used to invoke the method. Perl does not create a $self variable for you automatically. However, as you just saw in our discussion of new and Elapsed , Perl does supply an object or a package name as the first argument to a method. In the case of an object method like Elapsed , it is customary to shift this value off the argument list and name it $self . This is exactly what happens behind the scenes in other object-oriented languages. In the case of the Elapsed method, $self is a reference to a Timer object. This object is an anonymous hash created by the Timer constructor, and therefore $self is a reference to a hash (see Item 30). DestructorsWhen the last reference to an object is gone, or the object goes out of scope, the object is destroyed and its space is reclaimed for later use by Perl. For ordinary, non-blessed data, that is the end of the story. Blessed objects, however, can go out with a little more fanfare. If a package contains a subroutine named DESTROY , this subroutine, called a destructor , will be invoked just before a blessed object belonging to that package is destroyed:
Destruction occurs when an object is no longer referencedeither because the last reference to it was overwritten (as is the case with the second assignment to $a , above) or the last reference to it has gone out of scope (as is the case with $b ). Objects still in existence at program termination are destroyed in a final mark-sweep garbage collection pass, as is the case with the final contents of $a . (For more about memory allocation and garbage collection in Perl, see Item 34.) Destructors are useful for ensuring that shareable resources like semaphores, locks, and files are released properly when the life of an object that uses them is over. For example: Use destructors to "clean up."
|