tags:

views:

57

answers:

2

Trying to get the hang of using OOP in Perl. My problem is that I'm setting a variable in the class, but the value is lost when I try and retrieve it. I'm sure the issue is glaring, but I need some extra eyes.

Constructor:

sub new
{
    my ($class, $name) = @_;
    my $self = {
        _name => $name,
        _times => []
    };
    bless ($self, $class);
    return $self;
}

accessor/mutator method:

sub times {
    my ($self) = shift;
    if (@_) { @{$self->{_times}} = shift }
    print "times size: " . @{$self->{_times}} . "\n";
    return @{$self->{_times}};
}

call from the main program:

$js->addRun($duration, $curStartTime);
print "Times size: " . @{$js->times()} . "\n";

relevant code from addRun() subroutine:

sub addRun {
    my ($self, $duration, $runDateTime) = @_;
    if (!defined($duration) || !defined($runDateTime)) { return 0; }
    push(@{$self->{_times}},$duration);
}

When I run this code, it enters the addRun subroutine and pushes the value to the _times variable. Then I print the value by calling the accessor/mutator. But the accessor/mutator has its own print command, so I can check the value before I return it.

The accessor prints the correct value, but when I print what was returned, it's undefined. Is my syntax messed up somewhere? Am I just an idiot?

Thanks

+8  A: 

The problem is in your times() subroutine you are returning an array, not an array reference.

Then in your main program you are trying to dereference the call to times() but you don't need to.

So in your main program just call it as follows:-

print "Times size: " . $js->times() . "\n";
dalton
+1. Should you be returning an array? You might want to read up on wantarray to make your code more context-aware.
Konerak
Awesome, fixed it right up. That's what I get for using syntax without fully understanding it. I think I ran into one problem where it needed to be dereferenced, so I must have gone crazy with the idea.Thanks
brydgesk
@Konerak, why bother with wantarray? Why not just return the array and let context do what it should? For example if `times` returns the array, it will get the size in scalar context and the contents in list. Just like a normal array. If you want an array ref, you can do `my $bar = [$foo->times];`, which is pretty much what you'd need to do with `wantarray`, unless you want to break encapsulation on your object.
daotoad
The perl OOP tutorial uses the syntax I was using (returning arrays, not array references) http://perldoc.perl.org/perltoot.html
brydgesk
+3  A: 

I tried your code with use strict; enabled and got Can't use string ("1") as an ARRAY ref while "strict refs" in use.

It was referring to the line: print "Times size: " . @{$js->times()} . "\n";

The times method returns an array of values. When you dereference the return value of times, you are giving it a scalar context. So the array is evaluated to give the number of members in the array, ie 1. So you are trying to access @'1', which does not exist.

Here's a cleaned up version of your code. You had a couple errors (it was impossible to ever have an array of length > 1 when setting via the times method.

#!/usr/bin/perl 

use strict;
use warnings;

my $foo = Foo->new('Pogo');

$foo->addRun( 10, time );
$foo->addRun( 20, time );
print "Times: ", join( ' ', $foo->times ), "\n";
print "Times length: " . $foo->times . "\n";


BEGIN {
    package Foo;

    sub new {
        my ($class, $name) = @_;
        my $self = {
            _name => $name,
            _times => [],
        };
        bless $self, $class;
        return $self;
    }

    sub times {
        my $self = shift;
        if (@_) { 
            my $time_array = shift;
            @{$self->{_times}} = @{$time_array};
        }
        return @{$self->{_times}};
    }

    sub add_times {
        my $self = shift;
        return push @{$self->{_times}}, @_;
    }

    sub addRun {
        my ($self, $duration, $runDateTime) = @_;

        return 0 unless defined($duration) and defined($runDateTime);

        $self->add_times($duration);
    }

}
daotoad
You mean to tell me that `use strict` would have made this bug impossible? AMAZING!
friedo