Belmark Caday Belmark Caday - 4 months ago 7
Perl Question

How do object oriented concept works in Perl

I am reading a book on perl and so far I understand the concept of OOP until i encountered this code:

sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = {
color => "bay",
legs => 4,
owner => undef,
@_, # Override previous attributes
};
return bless $self, $class;
}
$ed = Horse->new; # A 4-legged bay horse
$stallion = Horse->new(color => "black"); # A 4-legged black horse


What I see in that code is that whatever is passed in the
new
subroutine is considered as the package name which will be converted into an object reference with this code:

my $invocant = shift; #this one just get the name of the package which is the argument passed


return bless $self, $class;



  1. Now what is the use of the pre-declaration of the hash (not empty hash)? and why is the
    @_
    supplied in the last part of the list? what for?



Next is this statement based on that code above:

This Horse constructor ignores its invocant's existing attributes when used as an instance method. You could create a second constructor designed to be called as an instance method, and if designed properly, you could use the values from the invoking object as defaults for the new one:

which 90% of that statement I dont understand.


  1. What is an instance method? or object method? can you provide an example?



I know that this one
my $class = ref($invocant) || $invocant;
are object and instance methods but Im not sure how they differ or how to use them differently.

The "second constructor" mentioned above is this:

$steed = Horse->new(color => "dun");
$foal = $steed->clone(owner => "EquuGen Guild, Ltd.");
sub clone {
my $model = shift;
my $self = $model->new(%$model, @_);
return $self; # Previously blessed by ->new
}


Which again, I have no idea what it does. So anyone can clarify this for me.

DVK DVK
Answer

Now what is the use of the pre-declaration of the hash (not empty hash)? and why is the @_ supplied in the last part of the list? what for?

This is a very clever approach which lets you achieve 2 things at once:

  1. Allow you to have default values for the constructor

  2. Allow you to override some (or all) of those defaults with a has passed in to the constructor call.


How does this work? Based on 3 things you need to know about hashes:

  • A hash can be treated as a list, by flattening out into a "key1", "value1", "key2", "value2" ... list. This happens if you pass a hash as a parameter to a subroutine: mySub(%hash1)

  • A list (with even # of elements) can be turned INTO a hash via a reverse process.

  • A hash, constructed from a list, where a certain key is encountered more than once, will ONLY have that key once, and - important here - the value of that key in the resulting hash will be the LAST instance among values associated with that key.

In other words, the following 4 assignments produce the same exact resulting data structure:


    my %hash1;
    $hash1{20} = 2;
    $hash1{40} = 4;

    my %hash2 = ( 20, 2, 40, 4); # Notice that "," is same as "=>"

    my %hash3 = ( 20 => 2, 40 => 4); # Notice that "," is same as "=>"

    my %hash4 = ( 40 => 1, 40 => 3, 20 => 2, 40 => 4); 
    # first 2 couples will be effectively ignored, due to same keys later on

Example:

  • If you pass in a hash that has no color key but legs: Horse->new(legs=>3)

    • @_ array will contain 2 elements, "legs" and "3" (obtained by flattening that hash).

    • Your new hash - to be assigned to $self - will then be constructed from the following list:

       ("color","bay", 
       "legs", "4", # Will get overwritten
       # more 
       "legs", "3")
      
    • Now, as per the third bullet above, "legs","4" pair is overwritten by later "legs","3" in a hash assignment; so the resulting hash will have a (default) value of "bay" for the color, and a passed-via-constructor-arguments value of "3" for legs.