Monday, December 22nd, 2008

Towards Better Reuse: Traits in JavaScript

Category: JavaScript

<>p>From way back in 1987 comes a quote that summarizes how many feel about the state of object-oriented programming:

Multiple inheritance is good, but there is no good way to do it.

Joey Hurst wrote in to point us to his pet project–JSTraits–which aims to address this issue in JavaScript by providing an implementation of “traits”. He defines traits in the following way:

Despite the undisputed prominence of inheritance as the fundamental reuse mechanism in object-oriented programming languages, the main variants — single inheritance, multiple inheritance, prototype inheritance and mixin inheritance — all suffer from conceptual and practical problems. This project provides a Javascript implementation of traits, a simple compositional model for structuring object-oriented programs. A trait is essentially a group of pure methods that serves as a building block for classes and is a primitive unit of code reuse. In this model, classes are composed from a set of traits by specifying glue code that connects the traits together and accesses the necessary state.

And now, the code. Here’s an example of defining a trait using JSTrait:

javascript
< view plain text >
  1. var TComparable = Trait.define({
  2.  
  3.   uses: [TEquality], // requires equalTo, provides notEqualTo
  4.  
  5.   requires: ['lessThan'],
  6.   methods: {
  7.  
  8.     lessThanOrEqualTo: function(other) {
  9.  
  10.       return this.lessThan(other) || this.equalTo(other);
  11.  
  12.     },
  13.     greaterThan: function(other) {
  14.  
  15.       return !this.lessThenOrEqualTo(other);
  16.  
  17.     },
  18.     greaterThanOrEqualTo: function(other) {
  19.  
  20.       return !this.lessThan(other);
  21.  
  22.     },
  23.     compare: function(other) {
  24.  
  25.       if (this.lessThan(other)) return -1;
  26.  
  27.       if (this.equalTo(other)) return 0;
  28.  
  29.       return 1;
  30.     }
  31.   }
  32.  
  33. });

And here’s an example of using the trait in a class:

javascript
< view plain text >
  1. var GardenGnome = Class.define({
  2.  
  3.   superclass: LawnOrnament,
  4.   uses: TComparable,
  5.  
  6.   members: {
  7.     init: function(girth) {
  8.  
  9.       // use the natural unit of measurement for garden gnomes, girth
  10.       this.girth = girth;
  11.  
  12.     },
  13.     equalTo: function(other) {
  14.  
  15.       return this.girth === other.girth;
  16.  
  17.     },
  18.     lessThan: function(other) {
  19.  
  20.       return this.girth < other.girth;
  21.  
  22.     }
  23.   }
  24. });

What do you think of traits? The project page has a bit more documentation, including more info on the project’s motivation, a synopsis of traits, and more information on traits themselves.

Related Content:

  • Making gains in software development through open standards
    Learn how open standards can augment software development projects by enabling reuse, improving requirements management and facilitating automated...
  • JavaOne2006 - Day4
    Learn why programmers are trained from the very beginning to value simplicity through encapsulation and reuse and to value performance through...
  • Ajax after the hype
    Yes, there was exuberance when Ajax burst on the scene in 2005, but by now it appears that the hype was justified by the benefits of the technology,...
  • Insourcing beyond outsourcing
    In this article, we'll take a brief look at the value, risks and issues of offshore outsourcing for iSeries Java Web development...
  • TheServerSide at JavaOne 2005 - Day 3
    Read how IBM is committed more than ever to Java after fears that the two might part...

Posted by Ben Galbraith at 11:42 am
12 Comments

+++--
3.4 rating from 18 votes

12 Comments »

Comments feed TrackBack URI

Well, without going too deep about this traits concept, I’d just like to leave a note about a potential confusion with the traits concept of SVG Mobile 1.2:

A trait is the typed value (e.g. a number, not just a string), associated with an element by an XML attribute or a CSS property. The trait facilities in the SVG uDOM allow for strongly-typed access to certain attribute and property values.

Comment by HelderMagalhaes — December 22, 2008

Traits are called Roles in Joose. Here is the same example using Joose roles:
http://code.google.com/p/joose-js/wiki/CookbookRecipe6

Comment by Malde — December 22, 2008

Malde: It does indeed look like Joose and JSTraits provide very similar traits/roles functionality. I’ll do a deeper comparison sometime this week to see if either project could benefit from the inclusion of the other’s code. Thanks for the pointer.

Comment by jhurstus — December 22, 2008

Traits are also built into Scala :)

Comment by cromwellian — December 22, 2008

I would be a lot happier with this approach if it leveraged the existing JavaScript semantics for creating objects and prototypes. I think that Doug Crockford has sufficiently docuemented the “JavaScript Way” to objects from which you can create new objects. Yet another code framework that abuses JavaScript into a classical inheritance model is not a good thing.

However, I suspect that this represents some very useful syntax sugar that could easily be adapted to the approaches that Douglas recommends.

Comment by littlefyr — December 22, 2008

littlefyr: I definitely understand your concern.

I somewhat agree with your comments re pseudo-classical inheritance in JS. For this reason, JSTraits was designed to be easily plugged into just about any existing inheritance mechanism, including Crockford’s parasitic/beget inheritance to which you allude. As noted in the JSTrait’s documentation, the ‘Class.define’ method is included mostly for testing convenience. The core traits functionality could be (and I hope will be) added to just about any existing JS inheritance mechanism, not just the thin pseudo-classical one I’ve included in JSTraits for examples/testing.

I’d also argue that traits fit very well with prototype based inheritance. Self, the language from which JS pretty much stole its prototype OO model, actually has a feature also known as “traits” that is very similar to what JSTraits provides. The two were a natural fit in Self, and I suspect, just as you do, that the same will be true of JS and JSTraits.

It’s both a blessing and a curse to work in a language that is flexible enough to easily accommodate changes to something as fundamental as the OO system. On the one hand, programmers can easily adapt the language to their own tastes or to better fit the problem at hand. On the flip side, these same customizations can lead to nasty compatibility issues when you try to pull in outside libraries that do not use the same idioms and language extensions of the rest of your code base. I’ve noticed that there is a continuum in this regard with extremely flexible languages like Lisp (defmacro…) populating one end, and more locked down languages like Java populating the other end. JavaScript seems to fall somewhere near the Lisp side.

Comment by jhurstus — December 22, 2008

This looks a lot like MooTools, which uses the Java-like “Extends” and “Implements”. It is very useful.

Comment by MattCoz — December 22, 2008

Congrats, looks like you’ve re-invented the “Design by Contract” concept from Eiffel … ;)
Still, probably great innovation – though just needed to say this…
.
Anyway, you can pull this *way* further also (by reading the specifications on “Design by Contract”) which also includes stuff like pre and post conditions on variables, return values etc…?
Though Eiffel I think does this (to some extend) compile time, which obviously is impossible in JS…
.
Anyway, doesn’t Cappuccino have these mechanisms too…?

Comment by ThomasHansen — December 22, 2008

@ThomasHansenI don’t think Joey claims to have invented anything. Traits are a (well) known term in object oriented programming and there are implementation for most dynamic programming languages. THe original impl. was in Smalltalk.

@Joey Does your library implement correct semantics for Trade composition. For example if one trade composes another and both implement the same method, does this method become a required method of the trait? Joose does not fully hit the required hehavior here. Moose::Role does.

Comment by Malde — December 22, 2008

@ThomasHansen: I’d echo Malde’s comment. I’ll pass along your Eiffel observation to the people who did invent traits to see what they have to say. Now that you mention it, it seems a little arbitrary that they limited the ‘requires’ feature to method names as opposed to method signatures or full on contracts like Eiffel. I suspect that this may have to do with the environment in which traits were first implemented (SmallTalk/Squeak).

@Malde I think it does. I got in touch with one of the authors of the original traits research paper who said he would take a look at my implementation to make sure it matches their conception of traits, so we should know for sure soon. My implementation does handle the specific case you mentioned correctly (unless one of the conflicting methods is excluded, of course, in which case there is no conflict to resolve).

Comment by jhurstus — December 22, 2008

@ThomasHansen: Also, to follow up on Cappuccino it does appear that Objective-J has a somewhat similar concept called ‘Categories’. However traits differ in some notable ways: (1) traits unlike categories can be composed from multiple traits to build up new traits from existing traits (2) the rules for injecting trait methods into a class are slightly different (3) traits provide more control on how they are added into other traits or classes (via aliasing and excluding exported method names). Thanks for the feedback!

Comment by jhurstus — December 22, 2008

@ThomasHansen
I followed up with the inventors of Traits about why the trait composition validation mechanism stops at an existence check (“does class Foo implement required methods x, y, z?”) and doesn’t do something more flexible like Eiffel contracts. Their answer, as I suspected, was that checking method names was easy to implement in the first language to be augmented with Traits (Smalltalk/Squeak). There is no conceptual reason that traits couldn’t be extended to support different composition validation mechanisms like contracts.

Comment by jhurstus — January 4, 2009

Leave a comment

You must be logged in to post a comment.