package in main file : careful with initializations!

dami on 2008-02-27T19:23:48

A colleague of mine came with a program looking more or less like this. What do you think is the output ?

  use strict;
  use warnings;

  my $obj = Obj->new(11);
  print $obj->meth, "\n";

  #-----------
  package Obj;
  #-----------
  use strict;
  use warnings;

  my $foo = 22;
  my $bar = 33;

  sub new {
    my ($class, $arg) = @_;
    my $self = bless {arg => $arg}, $class;
  }

  sub meth {
    my ($self) = @_;
    return "$self->{arg} / $foo / $bar";
  }

It looks so obvious : the answer must be 11 / 22 / 33. But this is wrong! We get trapped by being so used to external packages, where everything is initialized at load time.

Here, everything is in the same file. So the main program starts, new and meth get called before $foo and $bar are initialized, and the result is 11 / / , with a warning about uninitialized values!


Deja vu

runrig on 2008-02-27T22:40:04

There was a similar issue just the other day on perlmonks.

Remember what `use Foo` means?

Aristotle on 2008-02-27T23:31:36

It means BEGIN { require Foo; Foo->import; }.

Note the BEGIN block!

If you’re going to inline a package into another file that would normally use it, don’t forget to wrap the whole thing in BEGIN.

Sounds like a job for Perl::Critic

Alias on 2008-02-28T04:44:37

That looks like a really good candidate for a Perl::Critic policy, both because it's probably a common gotcha, and it should be relatively easy to write the policy code.