Skip Menu |

This queue is for tickets about the Moose CPAN distribution.

Report information
The Basics
Id: 117325
Status: rejected
Priority: 0/
Queue: Moose

People
Owner: Nobody in particular
Requestors: thomas.pansino [...] intel.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Nested roles not flagging conflicts
Date: Tue, 30 Aug 2016 06:34:42 +0000
To: "bug-Moose [...] rt.cpan.org" <bug-Moose [...] rt.cpan.org>
From: "Pansino, Thomas" <thomas.pansino [...] intel.com>
I have some code similar to the following: Show quoted text
> ls
BaseRole.pm ChildRoleA.pm ChildRoleB.pm MyClass.pm test.pl ====== BaseRole.pm ====== package BaseRole; use Moose::Role; sub foo { print("Calling BaseRole::foo\n"); } 1; ====== ChildRoleA.pm ====== package ChildRoleA; use Moose::Role; with 'BaseRole'; sub bar { print("Calling ChildRoleA::bar\n"); } 1; ====== ChildRoleB.pm ====== package ChildRoleB; use Moose::Role; with 'BaseRole'; requires 'bar'; sub foo { print("Calling ChildRoleB::foo\n"); } 1; ====== MyClass.pm ====== package MyClass; use Moose; with 'ChildRoleA'; with 'ChildRoleB'; __PACKAGE__->meta()->make_immutable(); 1; ====== test.pl ====== #!/usr/bin/env perl use v5.14.1; use strict; use warnings; use MyClass; my $class = MyClass->new(); $class->foo(); $class->bar(); Running test.pl produces the following output: Calling BaseRole::foo Calling ChildRoleA::bar When I originally wrote this, I was hoping that the definition of ChildRoleB::foo would override BaseRole::foo since the with call to ChildRoleB comes after the with call to ChildRoleA. After quite a bit of manual reading and Internet research, I realized Moose roles don't really have inheritance like that. The only overriding that's valid would have been a definition for foo in MyClass, therefore having two definitions for foo in two different roles should actually have been flagged as a conflict when MyClass was composed. So first thing - is my understanding correct? You can only override a method from a role with a definition in a composing class? All other conflicting definitions in roles needs to be dealt with via exclusion or aliasing? If so, then the real question is, why is this not being flagged as a conflict? I tested and it does flag correctly in version 2.08, but not in 2.16 if I do the with as two separate statements like it is in my example. If I change it to be a single with call though, it works as expected. My guess is something changed in Moose::Util::apply_all_roles between these two versions. Thoughts?
On Tue Aug 30 02:34:58 2016, thomas.pansino@intel.com wrote: Show quoted text
> with 'ChildRoleA'; > with 'ChildRoleB';
This is your problem. If you consume each role separately Moose cannot detect conflicts. You should always consume all of your roles in a single "with" call: with 'ChildRoleA', 'ChildRoleB'; Cheers, -dave
Subject: RE: [rt.cpan.org #117325] Nested roles not flagging conflicts
Date: Mon, 12 Sep 2016 17:14:58 +0000
To: "bug-Moose [...] rt.cpan.org" <bug-Moose [...] rt.cpan.org>
From: "Pansino, Thomas" <thomas.pansino [...] intel.com>
Thanks Dave. Shouldn't this be flagged though? As I mentioned it does flag correctly in 2.08, but as of 2.16 it accepts this silently and does the wrong thing. At the very least, the requirement to use only one with call per class is unclear from the documentation and should be updated. -Tom Show quoted text
-----Original Message----- From: Dave Rolsky via RT [mailto:bug-Moose@rt.cpan.org] Sent: Saturday, September 10, 2016 21:34 To: Pansino, Thomas <thomas.pansino@intel.com> Subject: [rt.cpan.org #117325] Nested roles not flagging conflicts <URL: https://rt.cpan.org/Ticket/Display.html?id=117325 > On Tue Aug 30 02:34:58 2016, thomas.pansino@intel.com wrote:
> with 'ChildRoleA'; > with 'ChildRoleB';
This is your problem. If you consume each role separately Moose cannot detect conflicts. You should always consume all of your roles in a single "with" call: with 'ChildRoleA', 'ChildRoleB'; Cheers, -dave
On 2016-09-12 12:15:15, thomas.pansino@intel.com wrote: Show quoted text
> Thanks Dave. > > Shouldn't this be flagged though? As I mentioned it does flag > correctly in 2.08, but as of 2.16 it accepts this silently and does > the wrong thing. > At the very least, the requirement to use only one with call per class > is unclear from the documentation and should be updated.
I'm surprised that this caused an error in 2.08. I'm guessing that maybe it was a _different_ error than the one you get when you consume both roles in a single with statement. I'm pretty surprised the docs don't make a point of mentioning that you should just use one with statement. I'll fix that.
Subject: RE: [rt.cpan.org #117325] Nested roles not flagging conflicts
Date: Mon, 12 Sep 2016 18:09:29 +0000
To: "bug-Moose [...] rt.cpan.org" <bug-Moose [...] rt.cpan.org>
From: "Pansino, Thomas" <thomas.pansino [...] intel.com>
That looks tremendously better, thanks! So follow up question - could this not be flagged? It seems like it would be beneficial to have a bit somewhere that tracks if apply_all_roles (and maybe ensure_all_roles too) was called, and die with an appropriate error if called more than once. That would cover my case with multiple with calls as well as anyone who is doing dynamic Role addition to individual classes (I think?) which would also be at risk for this masking behavior. Show quoted text
-----Original Message----- From: Dave Rolsky via RT [mailto:bug-Moose@rt.cpan.org] Sent: Monday, September 12, 2016 10:46 To: Pansino, Thomas <thomas.pansino@intel.com> Subject: [rt.cpan.org #117325] Nested roles not flagging conflicts <URL: https://rt.cpan.org/Ticket/Display.html?id=117325 > https://github.com/moose/Moose/pull/133
On 2016-09-12 13:09:54, thomas.pansino@intel.com wrote: Show quoted text
> That looks tremendously better, thanks! > > So follow up question - could this not be flagged? It seems like it > would be beneficial to have a bit somewhere that tracks if > apply_all_roles (and maybe ensure_all_roles too) was called, and die > with an appropriate error if called more than once. That would cover > my case with multiple with calls as well as anyone who is doing > dynamic Role addition to individual classes (I think?) which would > also be at risk for this masking behavior.
There are valid (corner) use cases for calling "with" more than once because of various limitations in how roles work. But generally speaking, unless you encounter such a case you should consume all your roles in one shot. To do what you're suggesting would require roles to work more like a compile-time thing, which would be very hard to do in Perl 5 as it stands now. But Perl 6 gets this right ;)
Subject: RE: [rt.cpan.org #117325] Nested roles not flagging conflicts
Date: Mon, 12 Sep 2016 18:29:38 +0000
To: "bug-Moose [...] rt.cpan.org" <bug-Moose [...] rt.cpan.org>
From: "Pansino, Thomas" <thomas.pansino [...] intel.com>
Show quoted text
> There are valid (corner) use cases for calling "with" more than once because of various limitations in how roles work.
Of course, it always breaks somebody ;) I guess what I'm more concerned with is Moose silently retaining the first sub definition despite other definitions being applied in later roles. It seems to go against Moose's mantra of requiring conflicts be explicitly resolved by the developer, which to me is one of the big safety features here. The documentation update will at least keep people on the fairway now and out of the rough patch I was in, but I think if the intention is to flag any duplicate definitions in roles, then this should be a case where it flags too. Thoughts? Thanks for all that you do btw, really appreciate your contributions as a whole. Show quoted text
-----Original Message----- From: Dave Rolsky via RT [mailto:bug-Moose@rt.cpan.org] Sent: Monday, September 12, 2016 11:13 To: Pansino, Thomas <thomas.pansino@intel.com> Subject: [rt.cpan.org #117325] Nested roles not flagging conflicts <URL: https://rt.cpan.org/Ticket/Display.html?id=117325 > On 2016-09-12 13:09:54, thomas.pansino@intel.com wrote:
> That looks tremendously better, thanks! > > So follow up question - could this not be flagged? It seems like it > would be beneficial to have a bit somewhere that tracks if > apply_all_roles (and maybe ensure_all_roles too) was called, and die > with an appropriate error if called more than once. That would cover > my case with multiple with calls as well as anyone who is doing > dynamic Role addition to individual classes (I think?) which would > also be at risk for this masking behavior.
There are valid (corner) use cases for calling "with" more than once because of various limitations in how roles work. But generally speaking, unless you encounter such a case you should consume all your roles in one shot. To do what you're suggesting would require roles to work more like a compile-time thing, which would be very hard to do in Perl 5 as it stands now. But Perl 6 gets this right ;)
On 2016-09-12 13:29:55, thomas.pansino@intel.com wrote: Show quoted text
> > There are valid (corner) use cases for calling "with" more than once > > because of various limitations in how roles work.
> Of course, it always breaks somebody ;) > > I guess what I'm more concerned with is Moose silently retaining the > first sub definition despite other definitions being applied in later > roles. It seems to go against Moose's mantra of requiring conflicts be > explicitly resolved by the developer, which to me is one of the big > safety features here. The documentation update will at least keep > people on the fairway now and out of the rough patch I was in, but I > think if the intention is to flag any duplicate definitions in roles, > then this should be a case where it flags too. > > Thoughts? Thanks for all that you do btw, really appreciate your > contributions as a whole.
Patches welcome, but this could be really challenging. Keep in mind that when a class consumes a role with a method of the same name, it is _intentional_ that the class's version silently wins. This allow classes to override roles, which is a feature. In the two-with situation, the second with sees the methods from the first role as being part of the class, not as being role methods. Now we _do_ keep track of where methods came from, so in theory we could check that and die, _but_ there are all sorts of corner cases I could imagine here. Only dying when necessary while still allowing meta-fun trickery could range from difficult to impossible. That said, it has _always_ been the intention that you only call with just once, which is why I was so surprised it wasn't mentioned in the docs. It's been "common" knowledge among Moose users for a really long time, but obviously explicit is better.
Subject: RE: [rt.cpan.org #117325] Nested roles not flagging conflicts
Date: Tue, 13 Sep 2016 21:07:17 +0000
To: "bug-Moose [...] rt.cpan.org" <bug-Moose [...] rt.cpan.org>
From: "Pansino, Thomas" <thomas.pansino [...] intel.com>
Show quoted text
> Keep in mind that when a class consumes a role with a method of the same name, it is _intentional_ that the class's version silently wins.
Right, but actually I originally expected that the second role would override methods from the first role, kind of like how inheritance works. I think that was where I went wrong - treating roles like they would inherit, which is why having a safeguard to flag if someone _else_ tries to do that would be useful I think. But I'm not familiar enough with Moose internals to pull that off yet, and you all are busy doing other things, so documentation is probably enough for now. If I ever decide to go after this I'll reach out to you, get a feel for some of those corner cases you're thinking of that I might not know about. Show quoted text
> It's been "common" knowledge among Moose users for a really long time, but obviously explicit is better.
I think that was the missing part - I don't know many other Moose users and am just getting into using Moose heavily on a project. The documentation so far has been excellent, kudos to you all for that, it just needed that missing part. Thanks! Show quoted text
-----Original Message----- From: Dave Rolsky via RT [mailto:bug-Moose@rt.cpan.org] Sent: Monday, September 12, 2016 11:42 To: Pansino, Thomas <thomas.pansino@intel.com> Subject: [rt.cpan.org #117325] Nested roles not flagging conflicts <URL: https://rt.cpan.org/Ticket/Display.html?id=117325 > On 2016-09-12 13:29:55, thomas.pansino@intel.com wrote:
> > There are valid (corner) use cases for calling "with" more than once > > because of various limitations in how roles work.
> Of course, it always breaks somebody ;) > > I guess what I'm more concerned with is Moose silently retaining the > first sub definition despite other definitions being applied in later > roles. It seems to go against Moose's mantra of requiring conflicts be > explicitly resolved by the developer, which to me is one of the big > safety features here. The documentation update will at least keep > people on the fairway now and out of the rough patch I was in, but I > think if the intention is to flag any duplicate definitions in roles, > then this should be a case where it flags too. > > Thoughts? Thanks for all that you do btw, really appreciate your > contributions as a whole.
Patches welcome, but this could be really challenging. Keep in mind that when a class consumes a role with a method of the same name, it is _intentional_ that the class's version silently wins. This allow classes to override roles, which is a feature. In the two-with situation, the second with sees the methods from the first role as being part of the class, not as being role methods. Now we _do_ keep track of where methods came from, so in theory we could check that and die, _but_ there are all sorts of corner cases I could imagine here. Only dying when necessary while still allowing meta-fun trickery could range from difficult to impossible. That said, it has _always_ been the intention that you only call with just once, which is why I was so surprised it wasn't mentioned in the docs. It's been "common" knowledge among Moose users for a really long time, but obviously explicit is better.