views:

123

answers:

4

I'm creating a new object like this:

TestObject->new(@array1, @array2)

My new method looks like this:

sub new {
  my $class = shift;
  my $self = {};

  my $self->{Array1} = shift;
  my $self->{Array2} = shift;

  bless($self, $class);

  return $self;
}

As a simple test to access the data, I'm trying this, and then once I get it working, I can build more meaningful logic:

sub mymethod {
  my $self = shift;
  my $param = shift;

  my $array1Value = shift(my $self->{Array1});
  my $array2Value = shift(my $self->{Array2});

  print $array1Value." ".$array2Value;
}

But when I call mymethod, I get this error:

Type of arg 1 to shift must be array (not hash element) at Tests/MyObject.pm line 21, near "})"

Suggestions? I read this page on Perl data structures, but they don't have examples for creating a hash of arrays using arguments to a method using shift. So my problem might be there.

+5  A: 

When you pass arrays as parameters, they are flattened. You can pass references to them. See perlsub

#!/usr/bin/env perl

package foo;

sub new {
    my $class = shift;
    my $self = {};

    $self->{Array1} = shift;
    $self->{Array2} = shift;

    bless($self, $class);

    return $self;
}

sub mymethod {
  my $self = shift;
  my $param = shift;

  my $array1Value = shift( @{$self->{Array1}} );
  my $array2Value = shift( @{$self->{Array2}} );

  print "$array1Value $array2Value\n";
}

package main;

my @a = ( 0, 1, 2);
my @b = ( 3, 4, 5);
my $o = new foo( \@a, \@b );;
$o->mymethod;
William Pursell
Minor nit: Do not use indirect object syntax in Perl (new Foo as opposed to the better Foo->new). Cf. http://perldoc.perl.org/perlobj.html#Indirect-Object-Syntax
tsee
See also http://stackoverflow.com/questions/429657/what-is-the-difference-between-new-someclass-and-someclass-new-in-perl
Ether
Don't use all lowercase package names either.
Sinan Ünür
A: 

you need to derefernece the array ref:

@{$self->{Array2}}

By the way if you are using OO I emphatically suggest you look into Moose. It will make your life much easier!

ennuikiller
I think you'd need to reference it in the first place though too, right? Like `->new(\@array1, \@array2)`?
Kev
That worked. When I tried that, I just tried @$self->{Array2}, forgetting the { and } around $self->{Array2}.
Thomas Owens
This answer completely ignores the problem of passing real arrays into a function, which means the code might compile but will DTWT.
darch
+4  A: 

you have to use pointers to arrays, not arrays in this case:

  TestObject->new([@array1], [@array2])

and then later

my $array1Value = shift(@{$self->{Array1}});
catwalk
new(\@array1, \@array2) will be much more efficient since [@foo] creates a new anonymous array and then (shallowly) copies the elements of @foo into that whereas \@foo creates a reference to the existing array. Also note that in Perl, we generally refer to this as a reference, not as a pointer. There are no C-like pointers in Perl.
tsee
this is exactly because I am generally using [] syntax instead of \@. The object is supposed to encapsulate data; it can not be responsible for whatever happens to those arrays outside of its context. The question of efficiency IMO will be raised only in rare cases where we have to handle HUGE volumes of data and fine-tune data copying
catwalk
catwalk: then you may want a deep copy (e.g. Storable::dclone); `[@foo]` will copy the values in @foo, but the new array will still be connected to the values accessible from the old if the values are themselves references.
ysth
[replacing previous, completely wrong-headed comment:]The encapsulation problem should be relegated to the callee, actually. Let the caller use whatever he wants; if you want to be insulated to changes in the arguments, make the copy in the callee.
darch
You guys have just come up with a very common test case: pass some data to a method and then alter that data in the caller; does the object's version of the data also get altered? It's surprising how often this is overlooked!
Ether
+1  A: 

You're shifting an arrayref instead of an actual array.

The syntax ytou're probably looking for is:

my $array1Value = shift @{ $self->{Array1} };
my $array2Value = shift @{ $self->{Array2} };

Note how the array is dereferenced using @.

JB
Also beware that this will be modifying the original array, not a copy of it.
Kev
I supposed that's what he wants, as he's using `shift` instead of subscripting, but it's still worth mentioning. +1
JB
It is indeed what I want.
Thomas Owens