Grace 0.7 supports traits — reusable collections of methods that can be “mixed in” to class declarations. Classes (and object constructors) can easily use more than one trait. For example, an orderingFromCompare
trait could define a suite of ordering methods based on a compare
method:
123456 trait compareFromOrdering {method compare(other) { abstract }method < (other) { compare(other) < 0 }method == (other) { compare(other) == 0 }method > (other) { compare(other) > 0 }}
As you can see, a trait declaration looks pretty much like a class declaration, except that it uses the keyword trait rather than class. You can’t see the restrictions on traits: unlike a class, a trait may not contain var or def declarations, nor inline code. Classes can use multiple traits, but can inherit from at most a single superclass.
12345 class comparableCat(name) colour(colour') {inherit cat(aName) colour("Pedigree " ++ aColour)use compareFromOrderingmethod compare(other) { name.compare(other.name) }}
It is a truth universally acknowledged that any single inheritance language must want multiple inheritance
Bertrand “Jane Austen” Meyer
We found three reasons to include traits in Grace. First, most other languages to which students may move (including Java, Python, Ruby, and of course Scala, C++ and Eiffel) now support some form of trait or multiple inheritance, and even second year students studying design patterns (like Adapter or Iterator) can benefit from multiple inheritance. Second, we found traits helpful in designing our own libraries—the collections library in particular. Third, we found we needed more flexible forms of reuse when designing dialects. Grace’s dialects form a lattice, not a tree, so we needed some way of composing dialects from reusable components. All of these reasons are more important to library and dialect authors than to beginners: we don’t expect novice students to be taught about traits early on! Grace’s dialect mechanism can be used to remove traits from the language used for beginning students.
Advanced programmers may note that trait declarations can be though of as methods returning objects, in just the same way that class declarations are methods returning classes.
The key difference between classes and traits is that classes may declare variables and constants and contain inline code, while traits may not. Another difference is that objects created by classes are automatically furnished with a few default method, including asString
and ==
, whereas traits are not. Like classes, traits may have type parameters, parameters, and may have multi-part names (although stylistically we try to avoid them).
Any trait declaration can be turned into a class by changing the “trait” keyword to “class”.