Suppose you want to build a house. First, you would buy a piece of property located at a specific address. Then you would hire an architect or buy a program for your computer to help design the house. You would decide what type, style, how many rooms, doors, windows, etc. After you design the house, you will hire a contractor to build the house. Once it's built, you have access to your new house, you can go inside, set up housekeeping, paint it, clean it, furnish it, remove trash, landscape it, whatever. But before you can really do anything in or around your house, you must build it. Later you may want to add a new room, show it for sale, demolish it, etc. Since you have the blueprints, you could find another piece of property and build a house just like yours, maybe paint it a different color, change the landscaping, etc. In fact, you could build a whole development with houses like yours from the same design, each house identified by its unique address.
In an object-oriented language, the house would be the object, a noun. The style, number of rooms, type, etc., would be the properties that describe the object, like adjectives, and the verbs, such as paint the house, move into the house, show the house, describe the "behaviors" for the object.
All of this will become clearer as we examine a number of examples and discuss how Perl creates, maniuplates, and destroys objects.
This chapter will discuss a number of topics in detail. For the big picture, the following steps are necessary to create the new data type called object and define what it can do:
1. | Determine what your object is and what it is supposed to accomplish (design). |
2. | Create the new object (constructor) in a package, called a class. |
3. | Describe the object; i.e., give it properties, attributes (adjectives). |
4. | Bless the object (make the data type an object). |
5. | Define the functions (verbs), what it can do or what can be done to it (methods). |
6. | Use the object (define the user interface, call the methods). |
7. | Reuse the object (inheritance). |
8. | Destroy the object (remove the object from memory). |
A Perl class is just a package. The terms are interchangeable. A class is stored in a .pm module, and the class name is the same as the module (minus the .pm extension). If you want to distinguish between the two terms, a class is a package containing special subroutines called methods that manipulate objects. A Perl class normally consists of:
The data that describes the object.
A function, called "bless," that creates the object.
Special subroutines, called "methods," that know how to create, access, manipulate, and destroy the object.
Since a class is really just a package, it has its own symbol table, and the data or routines in one class can be accessed in another via the double colon (Perl 5) or the single apostrophe (Perl 4).
Unlike other languages, Perl does not strictly monitor public/private borders within its modules.[2] To keep variables private, the my function is used. The my variables exist only within the innermost enclosing block, subroutine, eval, or file. The my variables cannot be accessed from another package by using the double colon (or single apostrophe), because my variables are not related to any package; they are not stored in the symbol table of the package in which they are created.
[2] Wall, L., and Schwartz, R. L., Programming Perl, 2nd ed., O'Reilly & Associates: Sebastopol, CA, 1998, p. 287.
To begin with, an object in Perl is created by using a reference. A reference, if you recall, is a scalar that holds the address of some variable. It's a pointer. A reference might also point to a variable or subroutine that has no name, called an anonymous variable. For example, here is a reference, called $ref, to an anonymous hash consisting of two key/value pairs:
my $ref = { "Owner"=>"Tom", "Price"=>"25000" };
To access a value in the anonymous hash, the reference (pointer) $ref can be dereferenced by using the arrow operator as follows:
$ref->{"Owner"}
To make a Perl object, first a reference is created. The reference normally is assigned the address of an anonymous hash (although it could be assigned the address of an array or scalar or subroutine). The hash will contain the data members, properties, of the object. In addition to storing the address of the hash, the reference must know what package it belongs to. This is done by creating the reference and then "blessing" it into a package. The bless function acts on the "thing" being referenced in the package, not the reference itself. It creates an internal pointer to track what package the thing (object) belongs to. The object is the thing (usually a hash) that was blessed into the class (package). If the package is not listed as the second argument, the bless function assumes the current package. It returns a reference to the blessed object. (See "The bless Function" for a complete discussion of bless.)
my $ref = { Owner => "Tom", Price => 250000 }; # This is the object bless( $ref, Class); # The object is blessed into the package named Class return $ref; # A reference to the object is returned
Once an object has been blessed, you don't have to export symbols with the @EXPORT_OK or @EXPORT arrays. In fact, as a general rule, if the module is trying to be object-oriented, then export nothing.
Figure 14.2 demonstrates how you might visualize a House class. First you would create a package. This package is called House and is found in a file called House.pm. In OO lingo, the package will now be called a class. (Note the class name must be same as the filename without the .pm extension.) To illustrate encapsulation, the house object is enclosed around the data that describes it. The properties, or attributes, describe characteristics of the object, such as its owner, style, size, color, and so forth. In our example, the house properties are Owner, Style, and Price. In Perl, the object is often described with an anonymous hash, where the key/value pairs are the properties of the object. Outside of the house, subroutines are listed. In the OO world, these subroutines are called public methods, and they are the way you get access to the object. They can get access to the object but not until it exists. They often describe "behaviors" of the object; i.e., what it can do or what can be done to it. In fact, the methods should be the only way to get access to the object. For our house object, one method to access the house might be to move in, another to clean it, another to display it, and so on. Methods in Perl are just glorified subroutines.
There are no special Perl keywords called private, public, or protected as in other OO languages. Perl's package mechanism makes up the class where the data and subroutines, called methods, are stored. The my function keeps variables lexically scoped, and the bless function guarantees that when the object is created, it will know to which class it belongs. In summary, the object is usually a pointer to an anonymous hash, array, or scalar and is manipulated by special functions called methods that have access to the object via the pointer.
Think of the bless function as creating a new data type called an object. In Figure 14.2 the House object is created by first giving it properties with an anonymous hash and getting back a pointer, an address. Think of it as the address where the house is located, only in our program, the memory address. The bless goes to that address and creates a House object. Once you've blessed a scalar, array, hash, etc., it is transformed into an object. To be more technical, the first argument to the bless function must be pointer. The bless function internally tags whatever the pointer is pointing at (called the referent) with a reference to the package where it belongs. This is how an object is created. If the package (class) is not listed as the second argument, the bless function tags the object as belonging to the current package. The bless function uses the reference to find the object and returns a reference to the object. Since the blessing associates the object with a particular package (class), Perl will always know to what package the object belongs. An object can be blessed into one class and then reblessed into another and then another, and so on, but an object can belong to only one class at a time.
Formatbless REFERENCE, CLASSNAME bless REFERENCE Example 14.2.
|
Example 14.3 illustrates how to create an object. First we create an anonymous hash, then bless it into a package, and use the ref function to see if the object is truly in the package.
(The Script) 1 package House; # Package declaration 2 my $ref = { "Owner"=>"Tom", #Anonymous hash; data for the package "Price"=>"25000", # Properties/attributes }; 3 bless($ref, House); # The bless function creates the object. The hash referenced by # $ref is the object. It is blessed into # the package; i.e., an internal pointer is created to keep track # of the package where it belongs. 4 print "The bless function tags the hash with its package name.\n"; 5 print "The value of \$ref is: $ref.\n"; 6 print "The ref function returns the class (package) name:", ref($ref), ".\n"; (Output) 4 The bless function tags the hash with its package name. 5 The value of $ref is: House=HASH(0x5a08a8). 6 The ref function returns the class (package) name: House. Explanation
|
[a] It is recommended that the two-argument form for the bless function be used, especially with inheritance. (See "Inheritance" on page 460.)
A method is a subroutine that operates on an object. It is a special subroutine that belongs to a class and expects its first argument to be either a package name or a reference to an object. This argument is sent by Perl implicitly. Otherwise, it looks like any other subroutine. A method is used primarily to create an object, to assign or change the data in the object, or to retrieve data from an object.[3]
[3] Unlike C++, Perl doesn't provide any special syntax for a method definition.
There are two types of methods: class (or static) methods and instance (or virtual) methods.[4] The class method expects a class name as its first argument, and the instance method expects an object reference as its first argument.
[4] What you call a method type depends on what book you read. Larry Wall categorizes methods as class methods, instance methods, and dual-nature methods.
A class method is a subroutine that affects the class as a whole; for example, it can create an object or act on a group of objects. The class method expects a class name as its first argument. In object-oriented programs, a constructor function is a class method used to create an object. In Perl, this method is commonly called new, although you can call it anything you like. The creation of the object is often called the instantiation of the object, or instance, of the class.
Object-oriented programs use instance methods (also called access methods) to control the way the object's data is assigned, modified, and retrieved. You can't use an instance method until you have created the object. The method that creates the object is called a constructor. It returns a reference to the object. Once the reference to the newly created object is returned, the instance method uses that reference, often called $this or $self, to get at the object. The instance method expects a reference to the object as its first argument. It then manipulates an object by using the reference to it.
Perl provides a special syntax for invoking methods. Instead of using the package::function syntax, methods are invoked in one of two ways: class method invocation or instance method invocation. There are two types of syntax for each method call: object-oriented syntax and indirect syntax. If you are using objects, either syntax for these method calls is acceptable. The older way of calling methods with the double colons is not recommended.
Something to remember: A method, unlike an ordinary subroutine, is always sent one argument implicitly, either the name of the class or a reference to the object. If, for example, you call a method with three arguments, four arguments are really sent, the first one being the value found on the left-hand side of the arrow when using the object-oriented style.
Assume the method name is called new and the return value, $ref, is a pointer to the object.
1) $ref = class->new( list of arguments ); # object-oriented syntax 2) $ref = new class ( list of arguments ); # indirect syntax
If the class is called House, Perl translates
$ref = House->new();
to
$ref = House::new(House);
Assume the method name is called display and the reference to the object is called $ref.
1) $ref->display( list of arguments ); # object-oriented syntax 2) display $ref ( list of arguments ); # indirect syntax
The first example for each method is called the object-oriented; the second example, using the arrow operator, is called the indirect syntax syntax.
When Perl sees one of the preceding methods being invoked, it knows what class the object belongs to, because the object was blessed (an internal pointer is tracking where it is).[5]
[5] The capability of Perl to call the appropriate module's function is called runtime binding, according to Srinivasan, S., Advanced Perl Programming, O'Reilly & Associates: Sebastopol, CA, 1997.
display $ref (arguments...);
or
$ref->display(arguments...);
and $ref points to an object in a class called House, Perl translates that to
House::display($ref, arguments...);
Figure 14.3 illustrates the layout of a typical object-oriented module. The file where the module is created is a .pm file. In this example, the .pm file is House.pm. The file consists of one package declaration. The package will be called a class; so, this is the House class. The class consists of subroutines, now called methods. The first type of method, called new, is a constructor method. It is the method that will define and create (construct) the object. When a user of this module calls the method new, he will get back a reference to the newly created House object (the address of the house). The new method gets the name of the class as it first argument. This method not only creates the object but also blesses the object so that the object always knows what class (package) it belongs to. (See "The bless Function" on page 429.) The second two methods are called access, or instance, methods. These are the methods that store and fetch the data from the object. You can't use these methods until you have created an instance of the object. (You can't move into the house or show it off until you have built it.) Once you, the user, have a reference to the object, the reference is used to call the instance methods.
Continuing in Figure 14.3, we see that the object's data will be described in an empty anonymous hash (although any other data type might be used), and the address of the object will be assigned to a local (my) reference. (The object's data will be assigned later with an instance method called set_data.) The bless function will tag the object with the name of the class where it belongs and return a pointer to the object; i.e., when the user of the module calls the constructor, he gets back a pointer to the newly created object. The constructor is said to "instantiate" the object (create a new house). The user can create as many objects as he wants, and Perl will give him a unique address for each. Once an object is created, the instance methods (often called setters and getters) will be used to manipulate the object. The user calls the instance methods to store data in the object and to retrieve data from the object. The instance methods must have a reference to the object in order to access the right object. The instance methods always get a reference to the object as their first argument.
There are many ways the module can be designed. This is just one simple approach.
Constructor is an OOP term for a class method that creates and initializes an object into a class. There is no special syntax for a constructor. It is just a method that is used to get a reference blessed into a package. The first method in a Perl class (i.e., the first subroutine in a package) is normally the one that creates the reference (to the object) and blesses it into the package. This method is often called new, since it makes a new "thing," but could be called anything you want, such as create, construct, initiate, and so forth.
The object that is blessed into the new subroutine is usually an anonymous hash or anonymous array. The anonymous hash or array is assigned the data that describes the object. The data is often described as the properties, or attributes, of the object. When referred to collectively, the attributes define the state of the object.
To review: The class methods, also called static methods, are methods, or subroutines, that don't require the instance of an object in order to function. They are independent functions that act on behalf of the class. A function that calculates a paycheck or gets a list of names from a database is an example of a class method. The most common class method is called a constructor method, a method used to create the object. It takes a class (package) name as its first argument and functions for the entire class.
Object-oriented programs often use access, or instance, methods to control the way data is modified, retrieved, and displayed. In order to manipulate an object, the instance, or access, methods require an instance of an object; that is, a reference to an object that has already been created.
If the data need to be represented in a different way in one of the methods, the other methods needs not be affected, as long as the interface provided to the user remains the same. The instance methods in the following examples are used as access functions that display the data members of the class. Instance methods take an object reference as their first argument. Look at the value on the left-hand side of the -> where the method is being called. That value is the object, and it is implicitly sent as the first argument to the method being called. (If the value on the left-hand side of the -> is a class name, then the class name is sent as the first argument to the method; e.g., a constructor sends the class as its first argument.)
Instance variables are used to initialize the object when it is created. In this way, each time the object is created, it can be customized. The properties that describe the object may be passed as arguments to the constructor method and assigned to instance variables. They are called instance variables because they come into existence when the object is created, or instantiated. Either an anonymous hash or an anonymous array is commonly used to hold the instance variables. In the following example, the object "has a" or "contains a" owner and a price.
The first argument to an instance method is always a reference to the object. In the called method, this value is typically shifted from the @_ array and stored in a my variable called $self or $this, although it doesn't matter what you call the variable. The remaining arguments are then processed as they are in any regular subroutine.
All of the examples so far have used a House object. In the next example, we will create an Employee object. The Employee constructor will take parameters to be used as properties of an employee. If a constructor method is expecting a name, address, and salary to be passed in that order, it would be easy to send the parameters in the wrong order, causing the address to be assigned to the name, or the name to the salary, and so on. Using named parameters provides a method to ensure that parameters can be passed to a method in any order and still result in the values, getting assigned to the correct attributes. The arguments are passed by the calling, or driver, program as key/value pairs (hash) and received by the constructor as a hash. The following example demonstrates how named parameters are passed to a method and by a method.
Code View: #!/usr/bin/perl # User of Employee.pm--See Example 14.9 for module 1 use Employee; 2 use warnings; use strict; 3 my($name, $extension, $address, $basepay, $employee); 4 print "Enter the employee's name. "; chomp($name=<STDIN>); print "Enter the employee's phone extension. "; chomp($extension=<STDIN>); print "Enter the employee's address. "; chomp($address=<STDIN>); print "Enter the employee's basepay. "; chomp($basepay=<STDIN>); # Passing parameters as a hash 5 $employee = Employee->new( "Name"=>$name, "Address"=>$address, "Extension"=>$extension, "PayCheck"=>$basepay, ); print "\nThe statistics for $name are: \n"; 6 $employee->get_stats; (Output) Enter the employee's name. Daniel Savage Enter the employee's phone extension. 2534 Enter the employee's address. 999 Mission Ave, Somewhere, CA Enter the employee's basepay. 2200 The statistics for Daniel Savage are: Address = 999 Mission Ave, Somewhere, CA PayCheck = 2200 IdNum = Employee Id not provided! Extension = 2534 Name = Daniel Savage Explanation
|
Webster's Dictionary defines polymorphism as
polymorphism: n. 1. the state or condition of being polymorphous.[6]
[6] Webster's Encyclopedic Unabridged Dictionary of the English Language, Random House Value Publishing: Avenel, NJ, 1996, p. 1500. Reprinted by permission.
There, that should clear things up! Here's another definition:
Having many forms or the ability to take several forms . . . The same operation may behave differently on different classes.
Polymorphism can be described in many ways, and it's a word that is inherently part of the OO lingo. In Perl, it means that you can provide a method with the same name in different classes and when you call the method, it will do the right thing; in other words, when the reference to the object invokes the method, it will go to the class where the object belongs.
In Example 14.10, polymorphism is demonstrated. Two modules, Cat.pm and Dog.pm, each have three functions with the same names: new, set_attributes, and get_attributes. The driver, or user, program in Example 14.11 will use both of the modules. A reference to the cat or dog object is returned when it's respective class constructors are called. When the access methods are called with an object reference, Perl knows which method to call and to which class it belongs even though the methods have the same name. Perl determines which class the invoking object belongs to and looks in that class (package) for the method being called. The ability to call the right method demonstrates polymorphism. Dynamic, or runtime, binding allows the program to defer calling the correct method until the program is running and, along with polymorphism, to tie the correct method to its associated class without using if statements to determine which method to call. This provides a great deal of flexibility and is necessary for inheritance to work properly.
To take advantage of polymorphism and runtime binding, the object-oriented syntax must be used rather than the :: syntax. If, for example, you have two classes, Director and Rifleman, and both classes contain an access method called shoot, you can write $object–>shoot, and Perl will know which class the object belongs to. It determined the correct class at compile time. In this way, the Director will not shoot bullets at his cast, and the Rifleman will not try to take movies of the rifle range. It is also possible to add another class, such as a BasketballPlayer class, with a different shoot method and be sure that the appropriate method will be called for that class. Without runtime binding and polymorphism, the correct class will be determined based on the outcome of some condition, as shown here:
if ( ref($object1) eq "Director") { Director::shoot($object1); elsif ( ref($object2) eq "Rifleman" ){ Rifleman::shoot($object2); else{ BasketballPlayer::shoot($object3); }
With the object-oriented syntax, a reference to the object is implicitly passed to the method. Since Perl sends the object to the access method as its first argument and the object has been blessed into the proper class, Perl can implement polymorphism and do the right thing! Assume in Example 14.10 that $object1 was created as an object in the Director class, $object2 object in the Rifleman class, and $object3 in the BasketballPlayer class.
$object1->shoot;evaluates to Director::shoot($object1); $object2->shoot;evaluates to Rifleman::shoot($object2); $object3->shoot;evaluates to BasketballPlayer::shoot($object3)
Code View: (The Script: driver program for Example 14.10) #!/bin/perl 1 use Cat; # Use the Cat.pm module 2 use Dog; # Use the Dog.pm module 3 my $dogref = Dog->new; # Polymorphism 4 my $catref= Cat->new; 5 $dogref->set_attributes("Rover", "Mr. Jones", "Mutt"); 6 $catref->set_attributes; # Polymorphism 7 $dogref->get_attributes; 8 $catref->get_attributes; (Output) xxxxxxxxxxxxxxxxxxxx All about Rover Owner is Mr. Jones. Breed is Mutt. Name is Rover. xxxxxxxxxxxxxxxxxxxx -------------------- Stats for the Cat -------------------- Sex is Male. Type is Siamese. Owner is Mrs. Black. Name is Sylvester. -------------------- Explanation
|
[a] The new constructor could also be called by using the indirect method new Dog.
The –> arrow syntax is used in object-oriented programs that use polymorphism, dynamic binding, and inheritance. The :: syntax is allowed, but it is not flexible and can lead to problems unless conditional statements are used. The following example demonstrates how the :: syntax can be a disadvantage. With the object-oriented syntax, the problem would not occur.
Perl keeps track of the number of references to an object, and when the count reaches 0, the object is automatically destroyed. If a reference goes out of scope or your program exits, Perl handles the garbage collection by destroying every object associated with a reference and deallocating any memory that was used. So, you don't have to worry about cleaning up memory.[7] However, you can define a DESTROY method in your program to get control of the object just before it goes away.
[7] If you use self-referencing data structures, you will be responsible for destroying those references.