chromatic has Class::Roles on the CPAN. This is an attempt to implement traits in Perl. I think it's a great start,but there are a few features of traits that it doesn't implement yet. I've been thinking about the problem and I think I've got it licked. When all of the traits (roles) are used, a dynamically created interface is generated and it validates the integrity of the flattened class. It's a bit more complicated than it sounds, but I'll send chromatic some code when I'm done -- if it works.
I'm waiting to see what shakes out of A12 before I do much more work on it. Very few people really understand the point of roles; I hope that Larry will explain it far better than I've been able to do.
Re:The Wait
Ovid on 2004-02-15T02:36:41
I don't blame you. It looks like there's a lot of potential there, but how it integrates into Perl 6 will be interesting.
I just finished an alpha version of Class::Trait and I'm writing the docs now. I don't have a tarball uploaded, but the interface looks like this (borrowing heavily from your examples):
package Person;
# make them a lifeguard, but ensure that they use &Trait::Dog::swim and not
# &Trait::LifeGuard::swim
use Class::Trait 'Trait::LifeGuard';
use Class::Trait 'Trait::Dog' => { explicit => 'swim' };
# the dog will want a &doggie_treat, but since it's AUTOLOADed or inherited,
# we must explicitly promise that it will be available
Class::Trait->promise('doggie_treat');
Class::Trait->assemble;
1;
package Trait::LifeGuard;
sub swim {
return Trait::LifeGuard::_swim();
}
sub save_drowning_swimmer {
my (undef, $swimmer) = @_;
# save the swimmer
}
1;
package Trait::Dog;
Class::Trait->expects('doggie_treat');
sub swim {
my ($class, $target) = @_;
Trait::Dog::_eat($class->doggie_treat);
# swim to $target
}
sub _eat {
...
}
1;Essentially, it boils down to traits having expectations and the primary class making promises. If the primary class does not have a given method in its symbol table (due to AUTOLOAD or inheritance), then it promises that the method will be available when called (Class::Trait->promise('doggie_treat');). A trait is expected to not make promises at the current time (that may change).
A trait might need methods it doesn't provide, though, so it sets expectations
package Trait::Dog;
Class::Trait->expects('doggie_treat');As the primary class and traits are used, a tally of all promises, expectations, and actual methods is made. When the Class::Trait->assemble method is called, the interface is validated and flattened into the primary class.
To resolve conflicts, you must explicitly request a given method from a trait.
use Class::Trait 'Trait::Dog' => { explicit => 'swim' };All methods in a package that do not begin with an underscore (or the "import" method) are added to the list of traits to be flattened. If a trait wants a private helper method, it must call it via the fully qualified name (or a private subref).
So far, the tests pass, but it does have a few limitations. I worked hard to make the interface as self-explanatory as possible. If you or anyone else is interested, I can provide a download link for the tarball when it's ready.
Re:The Wait
Ovid on 2004-02-15T02:42:58
I forgot to mention that since I don't know how Perl 6 roles are to be implemented, my design goals were driven by my understanding of the original traits document. That's one of the reasons why I call them "traits" instead of "roles". I've thought about uploading this to the CPAN, but I have two concerns. First, I don't want to cause potential confusion when Perl 6 comes out. Second, since there are already beginning implementations of roles, I don't necessarily want to provide competing modules unless I am very confident in what mine can do.
Also, I've discovered that when I write weird stuff like this, I get very little feedback. Very few people understand what traits do (I'm not entirely sure that I've got it right), so I suspect that few, if any, would use my module. Further, I base my idea on the idea of composite runtime interfaces. That's a bizarre concept, so I don't know if it's a good idea.