Raphael Descamps wrote: > In the original traits paper the aliasing is not "deep": to respect the > flattening property, the semantic of the role must not change, so > aliasing a recursive method will call the original method. It's a known > theoretical weakness of the traits paper and "freezing roles" try to > solve this problem.
It's a problem that doesn't exist if you don't alias. However, you run into another problem; namely, what to do if two roles provide semantically incompatible definitions for the same method. To be fair, ailasing doesn't solve the problem either, for the reasons that I outlined in my last post (i.e., aliasing breaks the interface). And "freezing roles" doesn't solve the problem either; it just specifies which role is broken in the combined interface. As far as I can tell, there are only two solutions that actually solve the problem: don't compose two roles that have incompatible methods, or find a way for the incompatible definitions to coexist under the same name. The former approach works off of the theory that if the names are the same, the semantics ought to be compatible; and thus incompatible semantics are a sign of poor design of the base roles. In an environment where the programmer has the ability to rewrite everything with which he's dealing, this makes a great deal of sense. But as Richard pointed out, CPAN is a counterexample to this: it is unreasonable to assume that two modules imported from CPAN, written in isolation by different authors, will never provide conflicting roles due to nothing more than conflicting naming conventions - roles that, in concept, ought to be able to be used together. As I understand things, Richard's proposed solution is to alias one of the offending methods during the import, effectively rewriting the source module to use a different name for the offending method, for the sole purpose of exporting to the target application. IMHO, this only works if you follow the chain of compositions all the way and alias everything. That is: role Foo { method x; } role Bar does Foo { method x; } role Baz does Foo { method x; } If you want to alias Bar.x on import, there should be an implicit aliasing of Foo.x as well, which would lead to the implicit aliasing of Baz.x too. It's the only way to avoid broken interfaces: you need to change all related interfaces to remain compatible with the one that you change, both up and down the composition chain. Needless to say, this strikes me as impractical, due to the effort involved in figuring out what needs to be aliased and what doesn't. Another possibility would be to borrow a page from XML Namespaces, which addressed a similar problem: allow the programmer to require imported elements to be referenced in terms of the module from which they were imported. E.g.: use Kennel prefix Foo; # imports role Dog use Forest prefix Bar; # imports role Tree class Dogwood does Foo-Dog does Bar-Tree { ... } my $dogwood is Dogwood; $dogwood.Foo-bark; $dogwood.Bar-bark; The idea here is that "prefix Foo" and "prefix Bar" cause every name that gets imported from that module to be prefixed with that string. So class Dogwood wouldn't have a "bark" method: it would have a "Foo-bark" method and a "Bar-bark" method. IOW, the above would be equivalent to: role Foo-Dog { ... method Foo-bark { ... } ... } role Bar-Tree { ... method Bar-bark { ... } ... } class Dogwood does Foo-Dog does Bar-Tree { ... } my $dogwood is Dogwood; $dogwood.Foo-bark; $dogwood.Bar-bark; -- Jonathan "Dataweaver" Lang