views:

80

answers:

3

Hi everyone,

So, i'm a bit of a perl newb. Although I had something much more complicated going, i all of a sudden hit a roadblock and cannot figure out wtf is wrong with the code. I've simplified it so greatly that it's only a very small fragment of code.

Test.pl

package Test;

sub new {
  my ($class) = shift;
  my $self = {
    _attr => "asdfa"
  };
  bless $self, $class;
  return $self;
}
sub log {
  print "\nAccessed via class: ".$self->{_attr};
}

process.pl

#!/usr/bin/perl
do "Test.pl";
use strict;
use warnings;
use diagnostics;

my($test) = new Test();
$test->log;
print "\nAccessed via main: ".$test->{_attr};

I run process.pl and I get the following output

Accessed via class:
Accessed via main: asdfa

I also get the warning

Use of uninitialized value in concatenation (.) or string at Test.pl line 12 (#1) (W uninitialized) An undefined value was used as if it were already defined. It was interpreted as a "" or a 0, but maybe it was a mistake. To suppress this warning assign a defined value to your variables.

So the problem is that $self is actually undefined. Why, I have no idea. Is this not the way to initialize an object?

+6  A: 

The object instance is passed as the first argument to the method. The usual thing to do is to store it in a variable called $self, but perl doesn't set this up for you, you must do it yourself:

sub log {
  my $self = shift;
  print "\nAccessed via class: ".$self->{_attr};
}

Note that although you have defined strict and warnings in your main code, you haven't in test.pl which means that $self was silently created with an undefined value rather than throwing a compile error for using an undeclared variable.

Furthermore, I would advise you to put package Test into a file called Test.pm, add a true statement 1; on its own at the end of the file, and call it by saying use Test; instead of do "test.pl". It's a much cleaner way to write modular code in Perl.

Philip Potter
Thank you sooo much!
Brad Goss
+1  A: 

in the sub log :

sub log{
    my $self = shift;
    print "\nAccessed via class: ".$self->{_attr};
}
M42
+3  A: 

I know you've already accepted an answer, but you've got some serious problems with your code.

  • Put your object definitions in files ending in .pm not .pl
  • use modules instead of doing libraries.
  • Indirect object notation can lead to bugs, it is best to avoid using it.

I took the liberty of rewriting your code with the small changes needed to fix the issues.

First in MyTest.pm:

package MyTest;  # Changed name to avoid name conflicts.
use strict;      # Always
use warnings;

sub new {
  my $class = shift;
  # Removed parens on $class, they put the assignment of shift's 
  # result into list context (which had no effect on the result, 
  # but it is also unnecessary).

  my %defaults = ( attr => 'asdfa' );
  my %args = %defaults, @_;  
  # Assigns arguments and default values to %args, actual named 
  # args will override keys in defaults where they match;      

  my $self = {};      

  bless $self, $class;

  while( my ($attr, $value) = each %args ) {
    $self->$attr($value); # Initialize each attribute in named arg hash.
  }

  return $self;
}

sub attr {
    my $self = shift;
    if( @_ ) {
      $self->{_attr} = shift;
    }

    return $self->{attr}
}    

sub log {
  my $self = shift;  # Get invocant
  print "Accessed via class: ", $self->attr, "\n";  
}

process.pl

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

use MyTest;

my $test = MyTest->new();  # Direct call of object constructor

$test->log;

print "Accessed via main: $test->{_attr}\n";  # Violating encapsulation 
                                              # is generally a bad idea.

If you are doing heavy OOP, consider learning to use Moose. Moose is a powerful, ultra-modern object system for Perl that adds powerful capabilities and reduces boilerplate code.

If you want to learn "classical" Perl OOP, the tutorials in the perldoc (perlboot, perltoot, perlobj, perlbot and perltooc) are pretty good. If you want to get really deep into it, Damian Conway's Object Oriented Perl is a fantastic book.

daotoad
thanks for taking the time to thoroughly explain everything daotoad. Very much appreciated.
Brad Goss