Daniel Ruoso wrote: > Jon Lang wrote: >> The key to understanding roles is to note that roles don't implement >> methods; classes implement methods. > > Er, while I see your point, Roles are not just interfaces... they are OO > components that can be plugged into other classes. They often are used > for type identity exactly because of that attribute, since you won't be > enforcing any hierarchy.
Right. But as they were originally conceived, they were interfaces that could also handle code reuse, rather than units of code reuse that could also be used as interfaces. From this perspective, it makes perfect sense that a role's methods can be overridden as easily as they are. But you make a good point: there are some (a few? most?) programmers who are going to want to use roles primarily for code reuse, and who will want it to be a little more difficult to override the code provided by a role (e.g., requiring the use of supersede and perhaps augment in order to replace the definition with a new one). First and foremost, this distinction between suggested ans mandatory implementation is what I was trying to make a little more explicit in my proposal: a suggested method can be overridden by the class with no extra effort; a mandatory method requires that the class be explicit about the override. The next question is which of these approaches Perl 6 should use with roles. Currently, it's using suggested implementations; what I'm hearing you say is that you'd rather have mandatory implementations. IMHO, there's a time ans place for both; so I was trying to come up with a compromise of sorts: a way of letting the programmer select the approach that most suits his needs. >> Roles define which methods must be implemented, and suggest ways that >> they might be implemented; classes decide which implementation to use. >> Anything that breaks this paradigm is a Bad Thing. > > That's not the common conception in Roles usage, specially in Moose. As > I said, Roles are not just interfaces, they are OO reuseable components. FWIW, I never said that they're "just" interfaces. Also, I question whether that is or is not the common conception of role usage. I readily admit that it isn't so in the programming circles that you travel in; but are you typical of the perl community in this regard? This is not a rhetorical question; the way that we end up addressing this issue hinges on this question: should roles provide suggested implementations by default, or should they provide mandatory implementations by default? Even if Perl is rich enough to provide for both, the decision of which way to go when no explicit decision has been made is an important one. > The spec itself says: > > Classes are primarily for instance management, not code reuse. > Consider using C<roles> when you simply want to factor out > common code. Right: roles are preferable to classes when it comes to code reuse. That doesn't necessarily mean that roles are _primarily_ intended for code reuse. They _might_ be; but if so, it's because they've grown beyond their original concept. > The key issue here is Perl 6 wasn't yet used to the extent that > Moose::Roles are, and Moose people have identified that the use of Roles > as reusable components raised the issue when the class inadvertedly > overrides one of the methods that are implemented by one of the composed > roles. You know what? Until Moose was mentioned in this conversation, I had never heard of it. > I did think that this should be the expected behavior, but when the > people that is heavily using it says "it took me a lot of time to > debug", it indicates that there's something wrong with the behavior. > > So now I changed my mind, inheritance is about overriding behavior, so > when you implement a method in the subclass it is a natural thinking > that this should override the superclass, but when you think about it > really carefully this logic doesn't really map well to Roles > (considering roles as OO reuseable components). That may indeed be the case. It's entirely possible that we may want to change things so that roles define mandated methods, and possibly introduce interfaces as a variation of roles that define suggested methods. But we may instead want to keep roles as they are, and define some other variation that works just like a role except that it mandates its methods. And its also possible that I'm fundamentally wrong about this, and that we _don't_ need both approaches available for roles. > That being said, I'd think the following as an interesting solution: > > role R1 { > method foo() {...} # degenerates to interface > } > role R2 does R1 { > method bar() { > # some implementation > } > method baz() { > # some implementation > } > } > > class Bla does R2 { > method foo { > # implementing here is natural, since the role only > # declared a stub, it's even a warning not to implement it > } > supersede method bar { > # explicitly tells that I want to ignore the implementation > # in the role. nextsame wouldn't find the role implementation. > } > augment method baz { > # explicitly tells that I want to provide an additional > # implementation besides the one in the role. nextsame would find > # the role implementation. > } > } > > In the above example, declaring a method without either "supersede" or > "augment" would result in a compile-time warning, while using "augment" > semantics by default. I'm not sure I follow the bit about "augment"; but I agree that something like this would work well when the desired behavior for a role is to provide mandatory implementations for its methods (or, more specifically, when the desired behavior for a method is to resist being implicitly overridden). -- Jonathan "Dataweaver" Lang