1

I am currently creating a class in Perl that looks like this:

sub new{
   $class = shift;
   $self = {
     #Member Variables
     server => shift,
     type => shift,
     domains => shift
   };
   bless $self, $class;
   return $self;
}

I want the domains to be an array with multiple variables. How would I differentiate an array from a normal variable when using shift? I am trying to input the array like this:

 my $var = new class("server",1,(1,2,3));
 my $var = new class("server",1,[1,2,3]);

Neither of these work when trying to iterate through the array doing:

 for $i ($self->{domains}){
     print "$i\n";
 }
user081608
  • 1,093
  • 3
  • 22
  • 48
  • 1
    Especially when using object-oriented Perl, you ***must always*** `use strict` and `use warnings 'all'` at the top of every Perl source file, and declare each variable using `my`. – Borodin May 12 '17 at 18:51

2 Answers2

5

Arguments are passed to a function as a list of scalars, and your first invocation is just

my $var = new class("server",1,1,2,3);

A hash value need be a scalar, so you need an anonymous array there

domains => [ LIST ];

So either

  • shift off all single options as you do and then copy the rest into the arrayref

    domains => [ @_ ];
    
  • or pass an arrayref, which is a scalar, like in your second invocation and assign it

    domains => shift;
    

In both cases the $self->{domains} is going to be an arrayref.

On the other hand, consider nicely assigning arguments first

sub new { 
    my ($class, $server, $type, @domains) = @_;
    # ...
    my $self = { 
        # ...
        domains => \@domains
    };
    return bless $self, $class;
}

for the first invocation, or

sub new {
    my ($class, $server, $type, $rdomains) = @_;
    my $self = {
        # ...
        domains => $rdomains
    };
    return bless $self, $class;
}

for the second one. Since bless returns its first argument we can directly return (for brevity).

Finally, you use the indirect object notation for calling the constructor. In short, don't -- use

my $object = ClassName->new( ARGS );

See the link above for an official statement, and this post


Please always run with warnings, as that saves a lot of headaches. I also strongly suggest to always use strict as it promotes all manner of good practices

# At the beginning of every program
use warnings 'all';
use strict;
zdim
  • 64,580
  • 5
  • 52
  • 81
  • Hey zdim, would i still need to include `bless $self, $class;` and `return $self;` after I set `my $self = {...}` ? – user081608 May 16 '17 at 15:27
  • @user081608 Yes, by all means. Setting `$self` merely populates a hashref in the program. It is the `bless`-ing that makes `$self` an object of `$class`, and after that line `$self` "knows" what class it belongs to, you can call methods on it, etc. While `return`ing it is important for all kinds of uses. I've added that for completeness, thank you for asking. – zdim May 16 '17 at 17:19
3

If you want to specify domains as a list, you need to do this:

sub new {
   $class = shift;
   $self = {
     server => shift,
     type => shift,
     domains => [ @_ ],
   };
   bless $self, $class;
   return $self;
}

That's because hashes cannot have non-scalar keys or values.

Either way, you are going to have to dereference that array ref when iterating through domains:

for my $domain (@{ $self->{domains} }){
     print "$domain\n";
 }
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339