in reply to SOLVED [ create_class_with_roles() ]: Moo[se] namespace weirdness with conditionally composed-in Roles

Hello 1nickt,

This behaviour does not appear to be due to Parallel::ForkManager. I can reproduce it with just the following test script:

#! perl use strict; use warnings; use MyClass; for my $foo (1 .. 2) { my $o = MyClass->new({ number => $foo }); $o->bar($foo); }

Output:

16:56 >perl 1576a_SoPW.pl 6052 1 MyClass=HASH(0x4b4ca8) loading Odd at MyClass.pm line 8. 6052 Loaded Odd at Odd.pm line 4. 6052 1 MyClass=HASH(0x4b4ca8) I am Odd at Odd.pm line 7. 6052 2 MyClass=HASH(0x2274048) loading Even at MyClass.pm line 8. 6052 Loaded Even at Even.pm line 4. 6052 2 MyClass=HASH(0x2274048) I am Odd at Odd.pm line 7. 16:56 >

Changing from Moo to Moose makes no difference to the result.

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Replies are listed 'Best First'.
Re^2: Namespace weirdness with Parallel::ForkManager using 0 children
by 1nickt (Canon) on Mar 21, 2016 at 07:21 UTC

    Thanks Athanasius, I should have thought of testing that, was so sure it was P::M-related. I'm going to edit the post and the title to try to draw in some Moo experts. Thanks again.

    The way forward always starts with a minimal test.

      Adding the following line at the end of sub BUILD in “MyClass.pm” seems to fix the problem:

      Role::Tiny->apply_roles_to_object($self, $module);

      So my guess is: roles are, by default, class-based, rather than object-based, so that once a role has been added to a class, the definition of that class doesn’t change. But with multiple threads, the problem doesn’t arise as the class definition is re-created for each new thread.

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        Ha, that's actually what I suspected, that the package was being permanently altered in Perl's brain the first time through. I just didn't think that with() operated on the package level, as does apply_roles_to_package (which I was eschewing because of that).

        But it gets back to what I mentioned in an earlier discussion, which is that using apply_roles_to_object seems to break the whole point of Roles, in that using it in sub BUILD in the parent causes the child's method to be loaded *before* the parent's of the same name. Notably, placing the conditional code inside an after BUILD => sub { ... }; block makes no difference to the outcome.

        package MyClass; use Moo; use Moo::Role(); sub BUILD { my ( $self, $args ) = @_; my $module = $args->{'num'} % 2 ? 'Odd' : 'Even'; warn "$args->{'num'} $self loading $module"; Moo::Role->apply_roles_to_object( $self, $module); return $self; }; sub baz { return 'qux'; } 1;
        And in each of the Roles:
        sub baz { die "Died in ", __PACKAGE__; }
        Output:
        1 MyClass=HASH(0x19c12c0) loading Odd at MyClass.pm line 14. Loaded Odd at Odd.pm line 4. 1 MyClass__WITH__Odd=HASH(0x19c12c0)->bar at test.pl line 11. Died in Odd at Odd.pm line 11.

        I guess I will just code around that; indeed I don't reuse method names anywhere as a practise ... but it seems odd. Oh well. ++Athanasius for helping me figure out that I was just seeing another symptom of the same issue I was dealing with earlier!


        The way forward always starts with a minimal test.