Duck Typing and "Roles" in Object Oriented Programming
Update: I have a more recent post on this subject here.
I recently read an article talking about the new “roles” system in Perl. Roles are classes of objects that perform the same set of functions. So, if you had an “Eagle” object, or a “Sparrow” object, perhaps both would have the field “feathers”, and the function “fly”. Each object might then differ in the size of the beak, or maybe only the Eagle has the method “swoop”. Perl roles would let you tag a collection of methods (in this case, “feathers” and “fly”) as performing a certain role (in this case, probably “flying_bird”). This is pretty useful, because if you wanted to write a (simple) bird watching simulator, you could handle any type of bird object as long as it handled that method and that property. If the method names are slightly different (for instance, perhaps the “Condor” object has the method “soar” instead of “fly”), but behave the same, Roles can resolve this.
Know Your Role
Perl’s role system is in contrast to duck typing that I use a lot in haXe. Duck typing skips the process of setting up explicit roles, and just tries to match the field/method names explicitly. So, any object that can “fly” and has “feathers” can be considered as a “flying bird” without the need of declaring roles in each object. The matching parameters for a duck type are typically given in a typedef, which is just a list of field names and types.
The article states that roles have the following advantages:
- Roles are explicitly given for classes… in their case they use the example of a field “bark”, which might belong to a “tree” or a “dog” object… duck typing perhaps could confuse them. Roles would not.
- Roles are more flexible… you have more fine grained control over what constitutes or is compatible with a role.
Better Examples
However, I’m not sold. The example they give (“bark” belonging to both “trees” and “dogs”) is not a good one. “Tree bark” seems like it would be a property, while “Dog bark” seems like it would be a method/action. This could easily be detected by most duck type checking languages, and would clear up a great deal of field naming confusion right away.
The “old cliché” that they reference (if it walks like a duck, and talks like a duck, then it is a duck) actually gives a better example. In this case, duck typing is occurring on two fields, rather than one. The chances that classes have two fields that are identically named, yet pertain to unrelated objects is much lower. In the article they say that “roles add context back”, but I would argue that context can get added back by being more specific with typedefs.
Using Natural Language Instincts
This ability to manage specificity through the selection and addition of representative symbols is an integral part of our natural language abilities. We use it every time we need to search the web (If I wanted to specify that I’m looking for dog-like bark things, I might query “bark woof”, rather than just “bark”. The specification is only as complex as it needs to be, and it relies on human knowledge to decide which terms best describe/discriminate the necessary object properties. It also doesn’t rely on specifically describing the roles beforehand, or explicitly indicate which objects perform which role. Duck typing does rely on programmers to differentiate their classes semantically through field names, which I consider good coding practice (i.e. don’t have two fundamentally different classes that have the same field names, and don’t have similar classes with completely different field names).
In the end, it boils down to managing complexity. Perl roles will force you to specify all of your roles explicitly, and require that appropriate object class code indicate a role behavior where necessary. This is “bad” complexity imho, since it involves a lot of boilerplate and class code markup. On the other hand, duck typing will force you to be very careful and specific with how you define a typedef, and occasionally force you to change how fields are named. In certain cases, it might keep you from treating certain classes as related when necessary, or it might confuse two unrelated classes… all on the basis of whether fields match or not.
Managing Type Context with Duck Typing
Certain duck type situations can cause false-negative or false-positive typing conflicts:
- Classes should have the same basic typedef, but have mismatched field names (false-negative typing): This is usually the result of bad coding style for the classes. Use this as an opportunity to rename the mismatched field names to something more consistent. Sometimes getter/setter mechanisms interfere with a field match. If one class uses a getter/setter for a property field, consider adopting the same behavior on the other class.
- Classes are not related, but the typedef selects both of them (false positive typing): See if there’s another field that can be added to the duck type check. Usually this will let you discriminate between the two classes.
There still could be certain situations where duck typing fails, and in these cases, I typically fall back on class reflection and other methods to get things working. However, these cases are very rare for me.
In conclusion, both approaches have drawbacks, but I find that duck typing allows me to handle complexity in more familiar natural language terms, while roles are more rigid and top-down. The former is better if I’m working on my own projects, but perhaps roles really shine when you have to work with larger classes that you don’t have control over or want to modify extensively.
I’m surprised that Perl went with such a strong top-down approach for determining object class types. It really seems to go against its loosely-styled ad-hoc nature. Perl has become somewhat stagnant in recent years, so perhaps this is an attempt to shake things up a bit. If so, I have doubts whether it’s a step in the right direction.





Trackbacks & Pingbacks