1nickt has asked for the wisdom of the Perl Monks concerning the following question:
Edit: Please see below for the solution.
O monks,
My program has a loop in which it instantiates a Moo object and composes in one or another role based on some condition.
Debugging shows that each time through the loop a new object is instantiated, and the correct role is composed in, but when I call a method on the object, the first object's method gets the call! Even though it is a new instance of the object and the old one has gone out of scope since we are in the next iteration of the loop.
It's acting as if the method is compiled into memory. I feel like this is so weird it *must* be something simple I'm overlooking, but I can't for the life of me see what. Any help to understand would be greatly appreciated.
Here's code that demonstrates the issue: MyClass.pm :
Odd.pm :package MyClass; use Moo; sub BUILD { my ( $self, $args ) = @_; my $module = $args->{'number'} % 2 ? 'Odd' : 'Even'; warn "$args->{'number'} $self loading $module"; eval "with '$module'; 1;" or die $@; } 1;
Even.pm :package Odd; use Moo::Role; warn "Loaded ", __PACKAGE__; sub bar { my ( $self, $foo ) = @_; warn "$foo $self I am Odd"; } 1;
test.pl :package Even; use Moo::Role; warn "Loaded ", __PACKAGE__; sub bar { my ( $self, $foo ) = @_; warn "$foo $self I am Even"; } 1;
Output, NOT as expected. Note the object memory address is different second time through, and the correct module is loaded, but the sub that gets called is from the other package!#!usr/bin/perl use strict; use warnings; use MyClass; foreach my $foo ( 1 .. 2 ) { print "\n"; my $o = MyClass->new({ number => $foo }); warn "$foo $o->bar"; $o->bar( $foo ); print "\n"; } __END__
$ perl test.pl 1 MyClass=HASH(0x118df00) loading Odd at MyClass.pm line 8. Loaded Odd at Odd.pm line 4. 1 MyClass=HASH(0x118df00)->bar at test.pl line 13. 1 MyClass=HASH(0x118df00) I am Odd at Odd.pm line 7. 2 MyClass=HASH(0x11b68e8) loading Even at MyClass.pm line 8. Loaded Even at Even.pm line 4. 2 MyClass=HASH(0x11b68e8)->bar at test.pl line 13. 2 MyClass=HASH(0x11b68e8) I am Odd at Odd.pm line 7.
Thank you!
Note: this post was edited, including title, to remove extraneous references to Parallel::ForkManager which I thought was the issue. Thanks to Athanasius for pointing out that that was unrelated. )
EDIT: thanks to a push from Athanasius and a giant assist from mst on IRC, I figured out the correct way to do what I want, which is to use Role::Tiny->create_class_with_roles to compose the Role into an anonymous class before calling new().
So now MyClass.pm looks like:
and the caller looks like:package MyClass; use Moo; 1;
Output:#!usr/bin/perl use strict; use warnings; use MyClass; use Role::Tiny(); foreach my $foo ( 1 .. 2 ) { my $module = $foo % 2 ? 'Odd' : 'Even'; my $class = Role::Tiny->create_class_with_roles( 'MyClass', $modul +e ); my $o = $class->new(); $o->bar( $foo ); } __END__
$ perl test.pl 1 MyClass__WITH__Odd=HASH(0x23f5f80) I am Odd at Odd.pm line 8. 2 MyClass__WITH__Even=HASH(0x2442db0) I am Even at Even.pm line 7.
|
|---|