22

I need to define multiple modules in the same file. I would like to do something like the following:

package FooObj {
    sub new { ... }
    sub add_data { ... }
}

package BarObj {
    use FooObj;
    sub new { 
        ... 
        # BarObj "has a" FooObj
        my $self = ( myFoo => FooObj->new() );
        ...
    }
    sub some_method { ... }
}

my $bar = BarObj->new();

However, this results in the message:

Can't locate FooObj.pm in @INC ...
BEGIN failed...

How do I get this to work?

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
Robert S. Barnes
  • 39,711
  • 30
  • 131
  • 179

3 Answers3

27

Drop the use. Seriously.

use tells perl to read in the code from another file, which you don't need to do because the code is in the same file.

Dave Sherohman
  • 45,363
  • 14
  • 64
  • 102
  • 1
    And how to import anything exported by `Exporter` without the use of `use`? – ceving Nov 10 '15 at 15:31
  • @ceving Call `import` directly. e.g., `FooObj->import(@params)` in the case of this question's code (if it used `Exporter`). – Dave Sherohman Nov 11 '15 at 08:22
  • No I had a different question in mind: http://stackoverflow.com/q/33634898/402322 – ceving Nov 11 '15 at 08:25
  • How do I accomplish `use parent 'FooObj';` in the same case? – Jean Jun 22 '18 at 20:46
  • @Jean - Perl inheritance is implemented by way of the package-level `@ISA` array. `use parent` combines `use` and setting `@ISA` into a single operation, so, if you don't need the `use`, you can just set `our @ISA = qw(FooObj);` for yourself. – Dave Sherohman Jun 23 '18 at 08:13
  • Thanks for clarifying. I was trying to stay away from modifying `@ISA` according to latest Perl recommendation. So in this case I will have to or resort to putting each package in its on file? – Jean Jun 25 '18 at 13:39
  • @Jean - I stand corrected. I checked `perldoc parent` (http://perldoc.perl.org/parent.html) so I could give you a reference showing that it's the same thing, but spotted a sentence I'd never noticed before: "_If you want to have a subclass and its parent class in the same file, you can tell `parent` not to load any modules by using the `-norequire` switch_" So there you go - you _can_ `use parent` for modules within a single file after all! – Dave Sherohman Jun 26 '18 at 07:58
17

Unless I'm trying to create a private package that no one should know about, I put one package per file. That solves the problem. But, let's put them in the same file.

The use loads a file and calls the import method in that package. It's really only incidently that its argument looks like a module name. It's looking for the file. If the file is not there, it barfs.

You can do this, where BarObj assumes that FooObj is already there:

{
    package FooObj;
    sub new      { bless { _count => 0 }, $_[0] }
    sub add_data { $_[0]->{_count}++ }
}

{
    package BarObj;
    use Data::Dumper;

    sub new {
        bless { myFoo => FooObj->new }, $_[0];
        }

    sub foo         { $_[0]->{myFoo} }
    sub some_method { print Dumper( $_[0] ) }
}

my $bar = BarObj->new;
$bar->some_method;

If you need to interact with a package (and that's all it is: not a module or an object), you just need to have it defined before you want to use it. If you need to import something, you can call the import directly:

FooObj->import( ... );

Suppose there's something from FooObj that you want to import (but not inherit!), you call import directly with no loading;

{
    package FooObj;
    use Data::Dumper;
    sub new      { bless { _count => 0 }, $_[0] }
    sub add_data { $_[0]->{_count}++ }

    use Exporter qw(import);
    our @EXPORT = qw(dumper);
    sub dumper   { print Dumper( $_[0] ) }
}

{
    package BarObj;
    FooObj->import;

    sub new {
        bless { myFoo => FooObj->new }, $_[0];
        }

    sub foo         { $_[0]->{myFoo} }

    # dumper mixin, not inherited.
    sub some_method { dumper( $_[0] ) }
}

my $bar = BarObj->new;
$bar->some_method;
brian d foy
  • 129,424
  • 31
  • 207
  • 592
12

By convention we put one package in one file and name them the same thing, but that is just for convenience. You can put multiple packages in a single file. Since they are already loaded, you do not need to use use.

You also do not need to create special scoping for the packages, as the package keyword takes care of that. Using the braces does help with scoping of our variables. So you don't strictly need those brace blocks, but they're a good idea.

use uses a package naming convention to find the appropriate file to load. The package keyword inside the module defines the namespace. And the import functions handle the package loading (generally inherited from Exporter).

#!/usr/bin/perl

use strict;
use warnings;

package FooObj;

sub new
{
        my $this  = shift;
        my $class = ref($this) || $this;
        my $self  = {};
        bless $self, $class;
        $self->initialize();
        return $self;
}

sub initialize { }
sub add_data   { }

package BarObj;

#use FooObj; <-- not needed.

sub new
{
        my $this  = shift;
        my $class = ref($this) || $this;
        my $self  = { myFoo => FooObj->new() };
        bless $self, $class;
        $self->initialize();
        return $self;
}
sub initialize  { }
sub some_method { }
sub myFoo       { return $_[0]->{myFoo} }

package main;
use Test::More;
my $bar = BarObj->new();
isa_ok( $bar,        'BarObj', "bar is a BarObj" );
isa_ok( $bar->myFoo, 'FooObj', "bar->myFoo is a FooObj" );
done_testing();

__DATA__

ok 1 - bar is a BarObj isa BarObj
ok 2 - bar->myFoo is a FooObj isa FooObj
1..2
spazm
  • 4,399
  • 31
  • 30
  • 2
    +1 For interesting info, however I still prefer using the braces as I think it adds visual clarity. – Robert S. Barnes Apr 12 '10 at 17:24
  • Robert, I see your point. I often use (named) bare braces for visual clarity -- usually just before I decide that a given section needs to be refactored into its own routine or that a driver script needs to move more functionality back to the module. I don't often put multiple packages in a single file, so haven't really considered the need to brace or not to brace. – spazm Apr 12 '10 at 17:30
  • 6
    It's not only clarity, but it's a scoping issue. Packages do not create a scope, so that my() variable you have there is file scoped without the braces that would limit it otherwise. – brian d foy Apr 12 '10 at 21:22
  • 1
    `our` variables will also become file scoped without braces around the package. `package A; our $DEBUG = 'A'; package B; print $DEBUG;` prints 'A' – Eric Strom Apr 30 '10 at 21:09