Reputation: 3741
I have an existing perl script which I have to modify. For this, I need some struct-like container for my data. I do not have any 'outside' modules, nor do I possess the capability to obtain them, and my perl is 5.8.8. I've written a package containing one var and two arrays for my needs, however I cannot get it to work and I am not sure why. Here it is:
{
package TestData;
sub new
{
my $class = shift;
my $self = {
_id => shift,
_genUsers => [],
_testSymbols => [],
};
return bless ($self, $class);
}
sub setId
{
my ($self, $id) = @_;
$self->{_id} = $id if defined($id);
}
sub addGenUser
{
my ($self, $user) = @_;
push @{$self->{_genUsers}}, $user;
}
sub addTestSymbol
{
my ($self, $sym) = @_;
push @{$self->{_testSymbols}}, $sym;
}
sub getId
{
my $self = @_;
return $self->{_id};
}
sub getGenUserList
{
my $self = @_;
return @{$self->{_genUsers}};
}
sub getTestSymbolList
{
my $self = @_;
return @{$self->{_testSymbols}};
}
}
use strict;
use POSIX;
my $id = "test";
my @a;
push @a, "this";
my @b;
push @b, "that";
my $obj = new TestData($id, @a, @b);
print "DEBUG: " . $obj->getId() . "\n";
Last line always throws "use of uninitialized value". What's going on?
Also would it be possible to do something like this:
my @c;
push @c, $obj;
foreach(@c){
print "DEBUG2: " . $_->getId() . "\n";
}
Thank you.
EDIT: Thank you everyone for your replies. This is what the fully working end result looked like:
{
use strict;
use POSIX;
package TestData;
sub new
{
my $class = shift;
my $self = {
_alpha => shift,
_beta => shift,
_gamma => shift,
_delta => shift,
_theta => shift
};
return bless ($self, $class);
}
sub getAlpha
{
my $self = shift;
return $self->{_alpha};
}
sub getBeta
{
my $self = shift;
return $self->{_beta};
}
sub getGamma
{
my $self = shift;
return $self->{_gamma};
}
sub getDelta
{
my $self = shift;
return $self->{_delta};
}
sub getTheta
{
my $self = shift;
return $self->{_theta};
}
}
Upvotes: 0
Views: 116
Reputation: 50338
The bug is in the line(s) that read:
my $self = @_;
This is a scalar assignment, and so assigns the length on @_
to $self
. Trying to use the length as a hash reference then gives the "use of uninitialized value" warning you see, and returns undef
.
By the way, in addition to enabling warnings, you should get into the habit of starting all your scripts and modules with use strict;
. If you'd done that, it would've caught this bug, and you would've received a runtime error saying something like:
Can't use string ("1") as a HASH ref while "strict refs" in use at foo.pl line 36.
Anyway, to fix your code, you should replace the line above with either:
my ($self) = @_;
or:
my $self = shift;
or even:
my $self = $_[0];
With my ($self) = @_
the parentheses turn it into a list assignment; with my $self = shift
it's still a scalar assignment, but shift
(which, inside a sub
, is shorthand for shift @_
) pulls the first scalar out of @_
.
The choice of which style to prefer basically comes down to personal taste and consistency; if you're used to pulling all your method args out of @_
with a single assignment like:
my ($self, $foo, $bar, $baz) = @_;
then, for methods that take no arguments other than $self
, a single-element list assignment seems more consistent. On the other hand, if you prefer to pick your args out of @_
one at a time, as in:
my $self = shift;
my $foo = shift;
my $bar = shift;
my $baz = shift;
the you obviously should follow that pattern for single-arg methods too.
Upvotes: 2
Reputation: 5805
Change
my $self = @_;
to
my $self = shift;
in your methods that only expect one argument and especifically the called one (i.e.):
sub getId
{
my $self = shift;
return $self->{_id};
}
You can also wrap the $self around parentheses to change context and do the same thing as commented
Output:
DEBUG: test
Upvotes: 2
Reputation: 2320
Rather than roll your own, you might want to check out Class::Struct
, which has been part of Perl's core since 5.4.
Upvotes: 1