Polymorphism, although a big word, is a simple concept. It means that methods defined in the base class will override methods defined in the parent classes. The following small example clarifies this concept polymorph.pl:
package A; sub foo { print("Inside A::foo\n"); } package B; @ISA = (A); sub foo { print("Inside B::foo\n"); } package main; B->foo();
This program displays
Inside B::foo
The foo() defined in class B overrides the definition that was inherited from class A.
Polymorphism is mainly used to add or extend the functionality of an existing class without reprogramming the whole class.
The prgram below uses polymorphism to override the qtyChange() function inherited from Inventory_item. In addition, it shows how to call a method in a parent class when the specific parent class name (also known as the SUPER class) is unknown.
The Perl program is as follows (polymorph2.pl):
package Inventory_item; sub new { my($class) = shift; my(%params) = @_; bless { "PART_NUM" => $params{"PART_NUM"}, "QTY_ON_HAND" => $params{"QTY_ON_HAND"} }, $class; } sub qtyChange { my($self) = shift; my($delta) = $_[0] ? $_[0] : 1; $self->{"QTY_ON_HAND"} += $delta; } package Pen; @ISA = ("Inventory_item"); @PARENT::ISA = @ISA; sub new { my($class) = shift; my(%params) = @_; my($self) = $class->PARENT::new(@_); $self->{"INK_COLOR"} = $params{"INK_COLOR"}; return($self); } sub qtyChange { my($self) = shift; my($delta) = $_[0] ? $_[0] : 100; $self->PARENT::qtyChange($delta); } package main; $pen = Pen->new( "PART_NUM"=>"12A-34", "QTY_ON_HAND"=>340, "INK_COLOR" => "blue"); print("The data type is " . ref($pen) . "\n"); print("The part number is " . %{$pen}->{'PART_NUM'} . "\n"); print("The quantity is " . %{$pen}->{'QTY_ON_HAND'} . "\n"); print("The ink color is " . %{$pen}->{'INK_COLOR'} . "\n"); $pen->qtyChange(); print("\n"); print("The quantity is " . %{$pen}->{'QTY_ON_HAND'} . "\n");
This program displays:
The data type is Pen The part number is 12A-34 The quantity is 340 The ink color is blue The quantity is 440
The first interesting line in the preceding example is my($delta) = $_[0] ? $_[0] : 1;. This line checks to see if a parameter was passed to Inventory_item::qtychange() and if not, assigns a value of 1 to $delta. This line of code uses the ternary operator to determine if $_[0] has a value or not. A zero is used as the subscript because the class reference was shifted out of the parameter array and into $self.
The next interesting line is @PARENT::ISA = @ISA;. This assignment lets you refer to a method defined in the parent class. Perl searches the parent hierarchy (the @ISA array) until a definition is found for the requested function.
The Pen::new() function uses the @PARENT::ISA to find the parent constructor using this line: my($self) = $class->PARENT::new(@_);. I don't really recommend calling parent constructors in this manner because the constructor that gets called will depend on the order of classes in the @ISA array. Having code that is dependent on an array keeping a specific order is a recipe for disaster; you might forget about the dependency and spend hours trying to find the problem. However, I thought you should see how it works. Because the $class variable (which is equal to Pen) is used to locate the parent constructor, the hash will be blessed with the name of the base Pen class-one small advantage of this technique. This is shown by the program's output. This technique avoids having to call the bless() function in the base class constructor.
By now, you must be wondering where polymorphism fits into this example. Well, the simple fact that both the Pen and Inventory_item classes have the qtyChange() method means that polymorphism is being used. While the Inventory_item::qtyChange() method defaults to changing the quantity by one, the Pen::qtyChange() method defaults to changing the quantity by 100. Because the Pen::qtyChange() method simply modifies the behavior of Inventory_item::qtyChange(), it does not need to know any details about how the quantity is actually changed. This capability to change functionality without knowing the details is a sign that abstraction is taking place.
Tip The Inventory_item::qtychange() notation refers to the qtyChange() function in the Inventory_item class, and Pen::qtyChange() refers to the qtyChange() function in the Pen class. This notation lets you uniquely identify any method in your script.