You can read about allomorphism here. Don't. You'll hurt yourself.
I read and reread that article until I hurt myself. I couldn't get it. However, chromatic and others talk about the raw power of allomophism so it must be important, right?
After doing a fair amount of reading and thinking about it, I think I can safely describe allomorphism as follows (please correct me if I'm wrong): allomorphism in programming is the property whereby objects not related by inheritance still present the same set or subset of behaviors. In Ruby, this is "duck typing". If I call $object->save, I really don't care what class that object is. I just want to know that I've somehow persisted the object (I probably shouldn't care how, either) and that I can retrieve it again later. That's allomorphism.
In traits we can say that a particular class does something and it magically can do it. Traits are powerful but not well understood. In fact, while I've wanted to have a chance to use them, I've deliberately not done so as I haven't wanted to use them unless I really saw a clear need for it. Now I have.
I have three unrelated classes. We'll call them XSLT, REST (Representational State Transfer) and REST::Dispatch. The XSLT class is the repository of all things XSLT for the system I'm working on. The REST class knows how to communicate with a Web server and the Dispatch class. The latter class knows how to talk to the REST class and how to talk to our data store.
While the REST and Dispatch classes are somewhat tightly coupled, it's via a "has-a" relationship. Unfortunately, they both have to know how to talk to the XSLT class. The Dispatch class has to know how ask the XSLT class for the location of the XSLT files so it can insert this as the stylesheet link in the XML it outputs. That is the only way it talks to XSLT. However, the client may not know how to process the XSLT so it can request that the XML be transformed on the server. Thus, the REST class needs to to ask the XSLT class to do the transformation. That's the only way the rest class talks to XSLT.
Server <--> E <-----> s <--> Data store
So far, so good. We have three classes that need to communicate, but the communication is fairly lightweight. How does allomorphism come into play? And traits?
This system is getting fairly large. We use Test::Class to create a set of test classes that mirror the actual classes. Now, however, I have a problem. Unit testing is fine, but I also need integration testing. Because the user agent can request that the server handle the XSLT transformation, I not only need to know that the XSLT class can produce the correct XHTML, I also need to know that the REST class can do the same thing via its request to the XSLT class. I also need to know that the Dispatch class serves the correct XML and that the REST class can send that along unchanged.
In short, I have three test classes which need to test very similar things but none of them are related via inheritance. The solution? Traits. I've now created traits that provide the shared behavior of these classes. Steven Little has produced a new version of Class::Trait which eliminates some of the difficulties I've encountered and I hope to incorporate this soon. (Currently, I've hacked around the problem with export trickery.)
The win here is that all of my shared behavior is in one spot. I don't need to dispatch to special handler classes. I don't need to duplicate code. I don't need to worry that I might have an inheritance nightmare. I just use the traits. Each of the three classes must provide a method that specifies which data store classes and fields we'll be working with at any given time and a proper trait can verify at compile time that this method is available. Thus, I've leveraged allomorphism to make my code simpler and if anything I need is missing, it blows up at compile time, not run time. This has the added benefit of making sure that I haven't corrupted my data store by failing at runtime. I've been forced to commit data at one point because I have to run a web server in my tests. Yuck.
It seems a bit strange at first and some will object that others will not understand, but that should never stand in the way of using a superior technical solution. Are traits truly that solution? We'll see.