Search code examples
perlmoose

Compile time issue with MooseX::Aliases, immutable and circular 'use'


I get a compile time error (Moose complains about modifying an immutable instance) running 'perl -c' on a package but code using the package runs error-free. Example Code:

File Pa_1.pm (immutable Moose class using MooseX::Aliases and package Pa_2.pm):

package Pa_1;

use Pa_2;

use Moose;

# uncommenting either this line ...
use MooseX::Aliases;

# ... or this line to make 'perl -c' work
__PACKAGE__->meta->make_immutable;

1;

File Pa_2.pm (just using Pa_1.pm which uses Pa_2.pm):

package Pa_2;

use Pa_1;
1;

File run_pa_1.pl :

#!/usr/bin/env perl

use Pa_1;

my $pa1 = Pa_1->new();
print "Done !\n";

Executing run_pa_1.pl works, but 'perl -c Pa_1.pm' gives

The 'add_method' method cannot be called on an immutable instance at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Class/MOP/Class/Immutable/Trait.pm line 32.
        Class::MOP::Class::Immutable::Trait::_immutable_cannot_call('add_method') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Class/MOP/Class/Immutable/Trait.pm line 47
        Class::MOP::Class:::around('CODE(0xc10158)', 'Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'DESTROY', 'Moose::Meta::Method::Destructor=HASH(0x14af4f8)') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Class/MOP/Method/Wrapped.pm line 162
        Class::MOP::Method::Wrapped::__ANON__('Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'DESTROY', 'Moose::Meta::Method::Destructor=HASH(0x14af4f8)') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Class/MOP/Method/Wrapped.pm line 91
        Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::SERIAL::1::add_method('Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'DESTROY', 'Moose::Meta::Method::Destructor=HASH(0x14af4f8)') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Class/MOP/Mixin/HasMethods.pm line 181
        Class::MOP::Mixin::HasMethods::_restore_metamethods_from('Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Class/MOP/Class.pm line 405
        Class::MOP::Class::_restore_metaobjects_from('Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Moose/Meta/Class.pm line 728
        Moose::Meta::Class::_restore_metaobjects_from('Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Class/MOP/Class.pm line 65
        Class::MOP::Class::reinitialize('Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'error_class', 'Moose::Error::Default', 'wrapped_method_metaclass', 'Class::MOP::Method::Wrapped', 'instance_metaclass', 'Moose::Meta::Instance', 'method_metaclass', ...) called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Moose/Meta/Class.pm line 188            Moose::Meta::Class::reinitialize('Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'attribute_metaclass', 'Moose::Meta::Class::__ANON__::SERIAL::2') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Moose/Util/MetaRole.pm line 99            Moose::Util::MetaRole::_make_new_metaclass('Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'HASH(0x144f868)', 'class') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Moose/Util/MetaRole.pm line 28            Moose::Util::MetaRole::apply_metaroles('for', 'Class::MOP::Class::Immutable::Moose::Meta::Class::__ANON__::S...', 'class_metaroles', 'HASH(0x144f868)', 'role_metaroles', 'HASH(0x144f838)') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Moose/Exporter.pm line 543
        Moose::Exporter::_apply_metaroles('Pa_1', 'ARRAY(0x93c630)', 'CODE(0xddccc8)') called at /home/pecho/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/x86_64-linux/Moose/Exporter.pm line 460
        Moose::Exporter::__ANON__('MooseX::Aliases') called at Pa_1.pm line 6
        Pa_1::BEGIN() called at Pa_1.pm line 6
        eval {...} called at Pa_1.pm line 6
BEGIN failed--compilation aborted at Pa_1.pm line 6.

I am a little confused because an error is emitted starting perl on Pa_2.pm with compile switch but run time seems to be ok.

  • In debugger and doing 'use Pa_2' there is no error too.
  • Executing 'perl -c run_pa_1.pl' no error too.
  • Not using MooseX::Aliases or not making Pa_1.pm immutable let 'perl -c Pa_1.pm' compile without error.

Is there a bug in the code, in MooseX::Aliases or is it something internal to Moose ?

Versions used : perl 5.16.1; Moose 2.0604; MooseX::Aliases 0.10;


Solution

  • Never execute a module directly. You end up compiling and executing it twice.

    Similarly, never compile a module directly. You end up compiling it twice.

    perl -c Pa_1.pm
    

    should

    perl -c -e'use Pa_1;'
    

    perl -c Pa_1.pm executes the following (ignoring require and import that do nothing):

    package Pa_1;
    require Pa_2;
    
    package Pa_2;
    require Pa_1;
    
    package Pa_1;
    require Moose;
    import Moose;
    require MooseX::Aliases;
    import MooseX::Aliases;
    __PACKAGE__->meta->make_immutable;
    1;
    
    package Pa_2;
    1;
    
    package Pa_1;
    import Moose;
    import MooseX::Aliases;
    

    perl -c -e'use Pa_1; executes the following (ignoring require and import that do nothing):

    package Pa_1;
    require Pa_2;
    
    package Pa_2;
    1;
    
    package Pa_1;
    require Moose;
    import Moose;
    require MooseX::Aliases;
    import MooseX::Aliases;
    __PACKAGE__->meta->make_immutable;
    1;
    

    Notice how you end up doing

    import Moose;
    import MooseX::Aliases;
    

    after doing

    __PACKAGE__->meta->make_immutable;
    

    when you do it wrong?