I'm a little confused about what is going on in Perl constructors. I found these two examples perldoc perlbot.
package Foo;
#In Perl, the constructor is just a subroutine called new.
sub new {
#I don't get what this line does at all, but I always see it. Do I need it?
my $type = shift;
#I'm turning the array of inputs into a hash, called parameters.
my %params = @_;
#I'm making a new hash called $self to store my instance variables?
my $self = {};
#I'm adding two values to the instance variables called "High" and "Low".
#But I'm not sure how $params{'High'} has any meaning, since it was an
#array, and I turned it into a hash.
$self->{'High'} = $params{'High'};
$self->{'Low'} = $params{'Low'};
#Even though I read the page on [bless][2], I still don't get what it does.
bless $self, $type;
}
And another example is:
package Bar;
sub new {
my $type = shift;
#I still don't see how I can just turn an array into a hash and expect things
#to work out for me.
my %params = @_;
my $self = [];
#Exactly where did params{'Left'} and params{'Right'} come from?
$self->[0] = $params{'Left'};
$self->[1] = $params{'Right'};
#and again with the bless.
bless $self, $type;
}
And here is the script that uses these objects:
package main;
$a = Foo->new( 'High' => 42, 'Low' => 11 );
print "High=$a->{'High'}\n";
print "Low=$a->{'Low'}\n";
$b = Bar->new( 'Left' => 78, 'Right' => 40 );
print "Left=$b->[0]\n";
print "Right=$b->[1]\n";
I've injected the questions/confusion that I've been having into the code as comments.
To answer the main thrust of your question, since a hash can be initialized as a list of
key => value
pairs, you can send such a list to a function and then assign@_
to a hash. This is the standard way of doing named parameters in Perl.For example,
This will result in
%stuff
in subroutinefoo
having a hash with two keys,beer
andvodka
, and the corresponding values.Now, in OO Perl, there's some additional wrinkles. Whenever you use the arrow (
->
) operator to call a method, whatever was on the left side of the arrow is stuck onto the beginning of the@_
array.So if you say
Foo->new( 1, 2, 3 )
;Then inside your constructor,
@_
will look like this:( 'Foo', 1, 2, 3 )
.So we use
shift
, which without an argument operates on@_
implicitly, to get that first item out of@_
, and assign it to$type
. After that,@_
has just our name/value pairs left, and we can assign it directly to a hash for convenience.We then use that
$type
value forbless
. Allbless
does is take a reference (in your first example a hash ref) and say "this reference is associated with a particular package." Alakazzam, you have an object.Remember that
$type
contains the string 'Foo', which is the name of our package. If you don't specify a second argument tobless
, it will use the name of the current package, which will also work in this example but will not work for inherited constructors.Your question is not about OO Perl. You are confused about data structures.
A hash can be initialized using a list or array:
When you invoke a method on a
bless
ed reference, the reference is prepended to the argument list the method receives:Output:
Yes, I know that I'm being a bit of a necromancer here, but...
While all of these answers are excellent, I thought I'd mention Moose. Moose makes constructors easy (
package Foo;use Moose;
automatically provides a constructor callednew
(although the name "new" can be overridden if you'd like)) but doesn't take away any configurability if you need it.Once I looked through the documentation for Moose (which is pretty good overall, and there are a lot more tutorial snippets around if you google appropriately), I never looked back.
Some points that haven't been dealt with yet:
Not quite. Calling the constructor new is just a convention. You can call it anything you like. There is nothing special about that name from perl's point of view.
Both of your examples don't return the result of bless explicitly. I hope that you know that they do so implicitly anyway.
If you assign an array to a hash, perl treats alternating elements in the array as keys and values. Your array is look at like
When you assign that to %hash, you get
Which is another way of saying that in perl list/hash construction syntax,
","
and"=>"
mean the same thing..1. In Perl, the constructor is just a subroutine called new.
Yes, by convention
new
is a constructor. It may also perform initialization or not.new
should return an object on success or throw an exception (die
/croak
) if an error has occurred that prevents object creation.You can name your constructor anything you like, have as many constructors as you like, and even build bless objects into any name space you desire (not that this is a good idea).
.2. I don't get what
my $type = shift;
does at all, but I always see it. Do I need it?shift
with no arguments takes an argument off the head of@_
and assigns it to$type
. The->
operator passes the invocant (left hand side) as the first argument to the subroutine. So this line gets the class name from the argument list. And, yes, you do need it..3. How does an array of inputs become the
%params
hash?my %params = @_;
Assignment into a hash is done in list context, with pairs of list items being grouped into as key/value pairs. So
%foo = 1, 2, 3, 4;
, creates a hash such that$foo{1} == 2
and$foo{3} == 4
. This is typically done to create named parameters for a subroutine. If the sub is passed an odd number of arguments, an warning will be generated if warnings are enabled..4. What does 'my $self = {};` do?
This line creates an anonymous hash reference and assigns it to the lexically scoped variable
$self
. The hash reference will store the data for the object. Typically, the keys in the hash have a one-to-one mapping to the object attributes. So if class Foo has attributes 'size' and 'color', if you inspect the contents of a Foo object, you will see something like$foo = { size => 'm', color => 'black' };
..5. Given
$self->{'High'} = $params{'High'};
where does$params{'High'}
come from?This code relies on the arguments passed to
new
. Ifnew
was called likeFoo->new( High => 46 )
, then the hash created as per question 3 will have a value for the keyHigh
(46). In this case it is equivalent to saying$self->{High} = 46
. But if the method is called likeFoo->new()
then no value will be available, and we have$self->{High} = undef
..6. What does
bless
do?bless
takes a reference and associates with a particular package, so that you can use it to make method calls. With one argument, the reference is assoicated with the current package. With two arguments, the second argument specifies the package to associate the reference with. It is best to always use the two argument form, so that your constructors can be inherited by a sub class and still function properly.Finally, I'll rewrite your hash based object accessor as I would write it using classical OO Perl.