30

I'm pretty sure that I read somewhere that it's possible, but there are a few gotchas that you need to be aware of. Unfortunately, I can't find the tutorial or page that described what you need to do. I looked through the Perl tutorials, and didn't find the one that I remember reading. Could someone point me to a page or document that describes how to put multiple packages into a single .pm file?

Thomas Owens
  • 114,398
  • 98
  • 311
  • 431

4 Answers4

41

This is how I normally do it:

use strict;
use warnings;
use 5.010;

{
    package A;
    sub new   { my $class = shift; bless \$class => $class }
    sub hello { say 'hello from A' }
}

{
    package B;
    use Data::Dumper;
    sub new   { my $class = shift; bless { @_ } => $class }
    sub hello { say 'Hello from B + ' . shift->dump       }
    sub dump  { Dumper $_[0] }
}

$_->hello for A->new, B->new( foo => 'bar' );
AndyG
  • 39,700
  • 8
  • 109
  • 143
draegtun
  • 22,441
  • 5
  • 48
  • 71
  • What is the block scope good for if the package defines already its own scope? – ceving Oct 29 '15 at 10:14
  • 7
    @ceving - For the same reason that `package` was changed at perl 5.14 to now allow the following syntax: `package A { ... }`. NB. This is the same as `{ package A; ... }`). This avoid *gotchas* you may get with things like `my` & `our`. ref: http://perldoc.perl.org/5.14.0/functions/package.html – draegtun Nov 01 '15 at 21:01
  • 1
    What about exports, imports and inheritance? – U. Windl Mar 07 '19 at 12:47
19

You simply start off the new package with another package statement:

package PackageOne;

# ...... code

package PackageTwo;

# .... more code

Problems with this approach (archived on 2009)

Denilson Sá Maia
  • 47,466
  • 33
  • 109
  • 111
ennuikiller
  • 46,381
  • 14
  • 112
  • 137
  • I'm pretty sure in the article that I read, there were a few other things that you had to do or problems that might appear with scoping. – Thomas Owens Nov 17 '09 at 13:36
  • 1
    of course there will be scoping problems and thats why its not recommended, See the link I added. – ennuikiller Nov 17 '09 at 13:38
  • 4
    You can only `use` a package with a name that corresponds to the filename, and you can only (easily) `use` a file that contains a package corresponding to its name. Other than that and the fact that file-scoped lexicals will "leak" into the next package (avoidable by adding braces) there isn't a lot to know. – hobbs Nov 17 '09 at 17:35
  • 7
    The problems link is dead – steve May 25 '15 at 20:08
  • You can access that link through the "archives": https://web.archive.org/web/20090417065554/http://oreilly.com/catalog/prkunix/excerpt/PWPMch01.html – lepe May 29 '16 at 11:33
  • What about exports, imports and `@ISA`? – U. Windl Mar 07 '19 at 12:46
8

This is what worked for me:

#!/usr/bin/perl

use strict;
use warnings;

{
   package A;
   use Exporter;
   our @ISA = qw(Exporter);
   our @EXPORT_OK = qw(a_sub);
   our @EXPORT = qw(a_sub);

   sub a_sub {
       # your code ...
   }
}
{
   package B;
   use Exporter;
   our @ISA = qw(Exporter);
   our @EXPORT_OK = qw(b_sub);
   our @EXPORT = qw(b_sub);

   sub b_sub {
       # your code ...
   }
}

# Main code starts here ##############

use boolean;
use Data::Dumper;

import A qw(a_sub);
import B qw(b_sub);

a_sub();
b_sub();

The important point is that instead of using "use", you change it for "import" (that way it won't go and try to look for the file).

lepe
  • 24,677
  • 9
  • 99
  • 108
  • My approach was similar, I just changed `{ package A; ... }` to `package A { ... }`. – Denilson Sá Maia Jun 12 '17 at 11:36
  • 2
    Very good point about `use`. The same is true for `require`. If you need to `use` or `require` package `A`, set `$INC{'A.pm'}=1` before the `use` or `require`. That tells perl the module is already loaded, and it doesn't need to look on disk. For `use`, that assignment will need to be in a `BEGIN` block, e.g., `BEGIN { $INC{'A.pm'}=1; }`. – cxw Dec 12 '18 at 13:54
  • Is it possible to import a constant (`use constant`) that way? With `use strict` I'm seeing `Can't use bareword ...`. – U. Windl Mar 07 '19 at 12:54
  • @U.Windl : it would be good if you ask that question (own post) with an example of what are you trying to do and link this question or answer for reference. – lepe Mar 08 '19 at 08:03
  • 1
    @lepe: See https://stackoverflow.com/questions/55046430/how-to-import-a-constant-with-use-strict-avoiding-cant-use-bareword-as?noredirect=1#comment96861990_55046430 – U. Windl Mar 10 '19 at 15:01
3

How to do it: just issue multiple package instructions.

Gotchas I can think of: my-variables aren't package-localized, so they're shared anyway. Before you issue any, you're in package main by default.

JB.
  • 40,344
  • 12
  • 79
  • 106