Perl Module Review: Class::Trait

by chromatic

Object-oriented design has faltered somewhat on the overuse of inheritance and class hierarchies at the expense of polymorphism and true typed genericity. Traits and roles form one great approach to solving those problems in an efficient, resuable, and powerful way. They're available in Perl 6, of course -- but they're also available in Perl 5.

Curtis Poe's and Stevan Little's Class::Trait is the most complete implementation of traits (or roles in Perl 6) available on the CPAN today. I recently explored it for an afternoon. Here's what I found.


Stefan Lukas
2006-08-08 04:19:59
now I've got a clue what this Role stuff in perl6 is about. It seems to be worth considering not to inherit but to mix in and thats a good way. Thanks.
2006-08-11 19:55:03
is traits like a kind interface from the java world?
2006-08-12 13:06:16
michel: traits are considerably different from Java interfaces. One of the serious problems with interfaces is that they specify and interface by no implementation. Thus, you need to rewrite the implementation every time for every class heirarchy which uses the interface. You can get around this by trying to create small delegation classes, but then you have to write more code again and anythin which forces you to write more code is kind of missing the point.

With traits, the implementation is already provided. And unlike multiple inheritance or mixins, you have no ordering problems, so you can simply declare that your class provides certain traits and either include, exclude, or rename trait methods on the fly to provide the behaviors you need.

2006-08-18 23:22:26
Could one just import the serializable method (really just a sub) into one's package using the conventional import techniques and have it work the same way as a 'trait'? I've never tried that but it seems like it would accomplish what you;re doing, unless perl's OO system purposely overlooks imported subs when scanning for methods.
2006-08-18 23:42:51
Ryan, if you do it that way, you cannot use does() to see if an object or class performs a given trait.

You don't always get the right answer by using can() either, because of homophonic methods. Dog and Tree objects both can bark(), but it's unlikely both methods have the same semantic meaning.

Think of a trait as a named, cohesive collection of behaviors. Without the name or without the behavior, it's not a trait. That doesn't mean that whatever it is is useless, only that it's not a trait.

Peter Scott
2006-08-20 07:56:51
Let me play devil's advocate for a bit here so I can learn this better. Traits make sense to me but I can't come up with a solid reason why, yet. Let's take the above example. What advantage does it have over inheritance? If the modules used inheritance instead of traits as far as I can tell everything would work the same except that you wouldn't need the @REQUIRES lines. And ref() on an object would return a different answer.

I can see why a trait shouldn't be a full-blown class, because it doesn't need a constructor; you're never going to instantiate an instance from it. Like a Java interface. But Perl classes are incomplete to begin with; if you don't write a constructor, there isn't one. There's the usual bad taste in the mouth of multiple inheritance, but that's mainly due to diamond pattern problems with attributes, and Perl classes don't have instance attributes, only methods.

So if someone asks me why traits are better than multiple inheritance, I don't have a good answer besides, "it's considered a best practice" at the moment. Can someone help me out?

2006-08-22 11:39:19
Ovid, michel: true, traits are "considerably different from Java interfaces", but, Java interfaces aren't supposed to allow for code reuse. That's what composition is for. Java interfaces only tell the runtime that certain objects provide certain methods. This is by design, not a shortcoming.

Seems like traits are interfaces + default implementation - headache of multiple inheritance.