ScalaTraits
The Gist
Traits and Mixin Class Composition cover the ways in which Scala models interfaces and abstract classes, allowing for multiple inheritance.
My Interpretation
Scala doesn’t have interfaces in the way that Java does; rather it uses Mixins (like Ruby), referred to as Traits.
A Trait is somewhat more similar to an abstract class in Java, except that in Scala, you can extend any number of traits that you wish.
Suppose our Circle class is getting refactored and enhanced. We wish to make the area
method part of an interface that other shape classes might use. Further, we wish to be able to compare circles based on their size. In Java, we would implement the Comparable
interface and a new interface called something like Area
.
Now, further suppose that we want our comparison interface to be a bit richer than a simple compareTo
method that returns an int; we want to clearly test for “less than”. In Java, we would need to extend the Comparable
interface as so:
public interface SuperComparable extends Comparable { | |
boolean lessThan(Object o); | |
boolean greaterThan(Object o); | |
boolean same(Object o); | |
} |
The problem is that the three new methods would have the exact same implementation in every case — they’d use the compareTo
method. If our class already extends another class, we’re SOL. Traits let us combine the concepts:
trait SuperComparable { | |
// extenders need only implement this method | |
// since it has no definition, it's abstract | |
// Also notice that the final colon and type indicate | |
// the return type of this method | |
def compareTo(x: Any): Int | |
// here we have a method that works in terms | |
// of the abstract one above, just as you | |
// would have in a Java abstract class | |
// Also note that we don't need to declare | |
// the return type; it's inferred by | |
// the compiler | |
def lessThan(x: Any) = compareTo(x) < 0 | |
def greaterThan(x: Any) = compareTo(x) > 0 | |
def same(x: Any) = compareTo(x) == 0 | |
} | |
// This is more like a traditional | |
// interface in Java, as the methods | |
// are all abstract | |
trait HasArea { | |
def area: Double | |
} | |
class Shape { | |
override def toString = "Some Shape" | |
} | |
// We can extend a proper superclass, but also | |
// mixin the two traits using the "with" | |
// keyword. Note that if we had no explicit superclass | |
// the first trait would follow the "extends" keyword. | |
class Circle(r:Int) extends Shape with SuperComparable with HasArea { | |
val radius = r; | |
def diameter = radius * 2 | |
def area = { | |
val pi = 3.14 | |
var area = pi * radius | |
area *= radius | |
area | |
} | |
override def toString = "Circle with radius " + radius | |
// note that we do not need to declare override | |
// here (although we can) | |
// asInstanceOf performs a cast; we probably wouldn't | |
// implement this method this way in the real | |
// world. | |
def compareTo(x: Any) = radius - x.asInstanceOf[Circle].radius | |
} | |
object SuperComparableDemo { | |
def main(args: Array[String]) { | |
val circle = new Circle(4) | |
val sameCircle = new Circle(4) | |
val smallCircle = new Circle(3) | |
val biggerCircle = new Circle(5) | |
println(circle.lessThan(biggerCircle)) | |
println(circle.same(sameCircle)) | |
println(circle.greaterThan(smallCircle)) | |
println(circle.lessThan(smallCircle)) | |
println(circle.area) | |
} | |
} |
There is a lot more that can be done with traits (and several no-doubt better implementations of the “super comparable” concept), but this should demonstrate what Traits can do and why they are useful.
My Thoughts on this Feature
I love mixins in Ruby and I love this feature. It does, however, make the scaladoc very hard to follow at times, and I just can’t for the life of me understand why you always extends
the first trait. It would be so much nicer to only extend
proper classes and instead with
Traits; this would make reading code a lot easier.