1

So far I always relied on the order of variables in a class, but now I'm trying to initialize those variables in a shuffled order.

For example, this is what I normally do while creating an object.

my $person1 = Person->new ('Fernando', 'Alonso', 36);

And this is what I'm trying to achieve.

my $person2 = Person->new (Age => 36, FistName => 'Fernando', LastName => 'Alonso');

I tried => regarding to several documents (e.g. perldoc) I saw, but they didn't return a complete example to me. However I don't actually work on the following script, it's a fair MCVE with the 'cliché' package Person.

use strict;
use warnings;

package Person;
sub new {
  my $class = shift;
  my $self = {
    FirstName => shift,
    LastName  => shift,
    Age       => shift,
  };
  print "First name : $self->{FirstName}\n";
  print "Last name  : $self->{LastName}\n";
  print "Age        : $self->{Age}\n\n";
  bless  $self, $class;
  return $self;
}

# Works well
my $person1 = Person->new ('Fernando', 'Alonso', 36);

# (?) How to assign 36 directly to $self->{Age}
my $person2 = Person->new (Age => 36, '', '');

The output is as follows.

First name : Fernando
Last name  : Alonso
Age        : 36

First name : Age
Last name  : 36
Age        : 

So, how should I create the object to make explicit assignments to the class variables? If necessary, how should I modify package Person?

P.S. I avoid changing the variables after the object is created.

1 Answer 1

4

The original Person class constructor expects the arguments to contain values in a specific order, but you want to specify key-value pairs. This is easy enough by representing the input as a hash reference.

package Person;
sub new {
  my $class = shift;

  # read @_ as list of key-value pairs; 
  # set $self as reference to hash of these pairs
  my $self = { @_ };       
  #my $self = { my %args = @_ };   # if you like your abstractions unbroken 

  bless  $self, $class;
  return $self;
}

If you want to restrict the keys that can be set to FirstName, LastName, and Age, you could do something like this.

package Person;
sub new {
  my $class = shift;
  my %args = @_;
  my $self = {
    FirstName => $args{FirstName},
    LastName  => $args{LastName},
    Age       => $args{Age},
  };
  bless  $self, $class;
  return $self;
}

and as a further enhancement, you could provide default values where the caller has not specified all of the expected keys

package Person;
sub new {
  my $class = shift;
  my %args = @_;
  my $self = {
    FirstName => $args{FirstName} // "Fred",
    LastName  => $args{LastName} // "Flinstone",
    Age       => $args{Age} // 42,
  };
  bless  $self, $class;
  return $self;
}
Sign up to request clarification or add additional context in comments.

2 Comments

… and if you want to be resilient against typos you can delete $args{$key} each argument so that you can afterwards check for unused args like if (my @unknown = sort keys %args) { croak "Unknown named arguments: @unknown"; }
my $self = { @_ } breaks abstraction. I think you should mark it as being undesirable at least.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.