An email I wrote to the Perl 6 language list.
(OK, the subject sucked, but I tried :)
From Synopsis 14, the Perl 6 Role Spec:
You can, however, say$fido does Sentry; $fido does Tricks; $fido does TailChasing; $fido does Scratch;...Unlike the compile-time role composition, each of these layers on a new mixin with a new level of inheritance, creating a new anonymous class for dear old Fido, so that a .chase method from TailChasing hides a .chase method from Sentry.
Recently I reported a bug in Moose's runtime role application. The bug was caused by repeated runtime role application causing recursive inheritance warnings. The problem was very hard to track down because I was effectively doing something like this:
$object->meta->apply('Some::Role') while 1;
(The reality is that we had a singleton with a role applied to it multiple times).
Eventually, the code broke and this was real fun to debug, but I can imagine a scenario for this being natural. Imagine that tour REST interface returns XML, but sometimes someone wants YAML. So you have:
$resultset does Role::Serializable::XML;
But sometimes:
$resultset does Role::Serializable::YAML;
Since you cache resultsets if they've not changed, you could easily have the XML and YAML roles getting reapplied at runtime multiple times.
I don't see anything in the spec addressing this. Aside from "don't do that", is this something which can be addressed in perl instead of Perl? This problem is closely related to the "ordering problem" with mixins and multiple inheritance that roles were designed to avoid!
I think this issue could be mitigated by allowing runtime role application to be lexically scoped:
{ temp $resultset does Role::Serializable::YAML; print $resultset.as_string; }
I think that would work, but I'm unsure.
I really think that doing anything that is equivalent the following is an incorrect usage of the feature more then it is a bug.
Some::Role->meta->apply($object) while 1;
You can simply modify this line slightly and avoid all your warnings by doing this
while (1) {
Some::Role->meta->apply($object) unless $object->does('Some::Role');
}
Sure it would be nice if Moose prevented you from shooting yourself in the foot like this, but what if you really wanted to shoot yourself in the foot? Who is Moose to say you can't? I think this type of thing is more a case of "your probably doing something stupid, but in case your not, and it is actually something clever, we will allow it" then it is a case of "your doing something stupid and we wont let you".
This problem is closely related to the "ordering problem" with mixins and multiple inheritance that roles were designed to avoid!
Yes, this is true, but that is because you are re-applying the role at different times. The ordering problem is only solved when you apply all your roles at once and they can be merged. For instance
package Foo;
with 'Bar', 'Baz';
... is not the same as
package Foo;
with 'Bar';
with 'Baz';
They can potentially create two very different classes because the former merges the Bar and Baz roles first (doing all the conflict detection and role merging goodness), whereas the later will first apply the Bar role, then apply the Baz role and not do any conflict detection between the two roles.
- Stevan
Re:Incorrect Usage
Ovid on 2009-03-15T17:25:13
I do see your point and I think you're right (I've some issues with implementation, but that's OK
:). At the very least, though, I would like to see Moose::Role be able to generate a sane error message to make it easier to track bugs like this down. Re:Incorrect Usage
Stevan on 2009-03-17T22:08:22
The problem is that we are not considering it an error. The particular errors you were getting were tricky not because of something Moose::Role did as much as your repeated application of the role to the class caused really odd side effects to happen. How would I tell the difference between a error borne from side-effects and one that I could directly trace back to a mis-use of the feature?
- Stevan
Re:Incorrect Usage
Ovid on 2009-03-18T12:20:14
I'm not saying that Moose::Role is behaving in error here. I'm saying there's a detectable error condition and a better error message would help.
How would I tell the difference between a error borne from side-effects and one that I could directly trace back to a mis-use of the feature?
When applying a role at runtime, by noting Perl's recursive inheritance limit (98 role applications on my Solaris box) and issuing a reasonable error reporting the package/file/line number of role application, it would have been trivial for me to find the source error. Currently this error wins my personal "most obscure error message" award
:) Deep recursion on subroutine "MRO::Compat::__get_linear_isa_dfs" at
/home/poec01/branches/tagging/deps/lib/perl5/MRO/Compat.pm line 123.
Deep recursion on subroutine "Class::MOP::Class::class_precedence_list" at/home/poec01/branches/tagging/deps/lib/perl5/i86pc-solaris-thread-multi/Class/M O P/Class.pm line 602.
Deep recursion on subroutine "MRO::Compat::__get_linear_isa_dfs" at/home/poec01/branches/tagging/deps/lib/perl5/MRO/Compat.pm line 123.
Deep recursion on subroutine "MRO::Compat::__get_linear_isa_dfs" at/home/poec01/branches/tagging/deps/lib/perl5/MRO/Compat.pm line 123.
Deep recursion on subroutine "MRO::Compat::__get_linear_isa_dfs" at/home/poec01/branches/tagging/deps/lib/perl5/MRO/Compat.pm line 123.
Deep recursion on subroutine "MRO::Compat::__get_linear_isa_dfs" at/home/poec01/branches/tagging/deps/lib/perl5/MRO/Compat.pm line 123.
Deep recursion on subroutine "Class::MOP::Class::class_precedence_list" at/home/poec01/branches/tagging/deps/lib/perl5/i86pc-solaris-thread-multi/Class/M O P/Class.pm line 602.
Deep recursion on subroutine "MRO::Compat::__get_linear_isa_dfs" at/home/poec01/branches/tagging/deps/lib/perl5/MRO/Compat.pm line 123.
Recursive inheritance detected while looking for method '()' in package 'Moose::Object' at/home/poec01/branches/tagging/deps/lib/perl5/i86pc-solaris-thread-multi/Class/M O P/Instance.pm line 157.
Recursive inheritance detected while looking for method '()' in package 'Moose::Object'.Re:Incorrect Usage
Stevan on 2009-03-20T00:47:40
Okay, I will agree that is could be detected, but how simple it is to do is another thing entirely. You are always invited to fork the Moose git repo and patch this if you like.
- Stevan