Dirk80 has asked for the wisdom of the Perl Monks concerning the following question:

I have a big object oriented module based on a hash. There's one list inside this module. I would like to have this list also as an object. But I wanted to try it without a separate module. So I want to have two packages in one module.

It is working if I specify the name directly. But if I want to have the name of the subpackage dependent on the name of the main package, I get an error. My code looks like this.

use strict; use warnings; package My; my $pkg_sub; BEGIN { $pkg_sub = __PACKAGE__ . '::A'; } # some methods package $pkg_sub; # My::A # some methods 1;

What am I doing wrong?

Replies are listed 'Best First'.
Re: Name of subpackage dependent on main package
by davido (Cardinal) on Dec 29, 2019 at 23:34 UTC

    It obviously doesn't work quite how you're thinking. One of the problems is that package does not accept the namespace as a dynamic argument. The namespace must be a hard-coded string of characters. However, all is not lost. You can have everything you want, just not the way you're doing it:

    package My; use strict; use warnings; my $pkg_sub = __PACKAGE__ . '::A'; # some methods for package My... { no strict 'refs'; *{$pkg_sub . '::new'} = sub { my $class = shift; return bless {ref($_[0]) ? %{$_[0]} : @_}, $class; }; *{$pkg_sub . '::greet' } = sub { print 'Hello ' . shift()->{'name' +} . ".\n"; }; } 1; package main; my $mya = My::A->new({name => 'Dave'}); $mya->greet();

    You can bless a reference into any string you want. And in this case, you can assign a subroutine reference to any typeglob you want. In the example above I'm creating My::A::new, and My::A::greet. Yes, it's a little more work, but where there's work, there's a need for automation:

    my %subs = ( new => sub { # constructor goes here... }, greet => sub { # Greeter goes here... }, ); while (my ($name, $code) = each %subs) { no strict 'refs'; *{$pkg_sub . '::' . $name} = $code; }

    This hash based method has the advantage of releasing strict 'refs' in a much smaller scope. To be clear, you don't need a package My::A; statement to be able to create subroutines and methods in the My::A namespace; you just have to do without the conveniences package provides, crafting the subroutine namespaces manually.

    And, in fact, this method is how Class:Builder works (snippet from Class::Builder):

    { # ... no strict 'refs'; # ... while (my ($name, $code) = each %methods){ *{"$class"."::"."$name"} = $code; } }

    Dave

Re: Name of subpackage dependent on main package
by haj (Curate) on Dec 29, 2019 at 23:40 UTC
    Well, package just doesn't take variables. You could wrap the package declaration and the methods therein into a string eval. However, apart from demonstrating that it can be done I can not imagine a problem which can't be solved in an other, more reasonable way.
    use strict; use warnings; package My; use Data::Dump qw(dump); my $pkg_sub = __PACKAGE__ . '::A'; my $package_declaration = "package $pkg_sub;"; eval $package_declaration . <<'EndOfPackage'; sub new { my $class = shift; bless [@_], $class; } # some more methods EndOfPackage my $new_object = $pkg_sub->new( qw( a b c) ); dump $new_object; # prints: bless(["a", "b", "c"], "My::A") 1;
    No. Don't do this.
Re: Name of subpackage dependent on main package
by Tanktalus (Canon) on Dec 29, 2019 at 23:37 UTC

    If you conform to perl's conventions, that is, to have each package in its own file in the proper directory and file names, you may find autopackage to your liking instead of trying to build it yourself. It probably could be extended to include a sub-package name, too, which would give you something like:

    use autopackage 'A'; # == package My::A;
    I'm not entirely sure that's a great idea, but that doesn't mean I wouldn't do it. PRs accepted :)

Re: Name of subpackage dependent on main package
by tobyink (Canon) on Dec 30, 2019 at 07:49 UTC

    Having package names calculated dynamically is kind of what I wanted to achieve with MooX::Press, though that's probably not really what you want in your case.

Re: Name of subpackage dependent on main package
by Anonymous Monk on Dec 29, 2019 at 21:31 UTC