Programming in Scala Gist 12

Vinu Charanya
vTechNotes
Published in
6 min readMay 29, 2016

These are the key points from the Programming in Scala, Second Edition by Martin Odersky, Lex Spoon, Bill Venners. I wanted to make note of some key points. They may seem broken and not make much sense, if you have not read the book. This is for personal reference. Feel free to correct me if I have interpreted anything wrong in this post.

Chapter 12— Traits

Traits are a fundamental unit of code reuse in Scala. Trait encapsulates method and field definition, which can then be reused by mixing them into classes. A class can mix in any number of traits. Traits are useful for 1. widening thin interface to rich ones 2. Defining stackable modifications.

12.1 How traits work

  • Trait definition looks very similar to class definition except for the trait modifier.
  • Trait can be mixed in either using extends or with keywords. “Mix in” is preferred over inheritance.
  • Using extends to mix in a trait implicitly inherit the trait’s superclass. Trait also defines a type similar to class.
  • More with clause can be used to mix in multiple traits
  • Traits are like Java interfaces with concrete methods. However, traits can declare fields ad maintain state.
  • Two things that Traits differ from class definition —1. “Class parameters” 2. super calls are statically bound in a class whereas, it is dynamically bound in a trait (This is to enable stackable modifications).

12.2 Thin versus rich interfaces

  • Traits can enrich a thin interface to a rich interface.
  • Having a thin interface makes it easy on the implementers, hard on clients as they have to write more code and rich interface makes it easy on clients and more work for implementers.
  • In Java if the interfaces are rich, the client has to implement them all. Ability to add concrete method in Scala tilts the thin-rich trade-off heavily towards rich interfaces.

12.3 Example: Rectangular objects

  • An example on how traits can be used to make code reuse easier was explained.
  • Repetitions can be eliminated with an enrichment trait.
  • Trait can have abstract methods.

12.4 The Ordered trait

  • Scala provides a trait called Ordered that helps with comparison operations.
  • Ordered trait allows enrichment of a class with comparison methods such as <, > , <=, >= etc., by implementing only one method, compare
  • Ordered requires a type parameter to extend it with another class Ordered[C], where C is the class whose elements you compare.
  • When Ordered trait is mixed in, a compare method should be defined. The method should compare the receiver, this , with the object passed as an argument to the method and return 0, +ve or -ve integer to denote whether the receiver is = or > or < respectively.
  • Ordered trait is good to consider for classes implemented with some comparison. Ordered does not define equals for you because of type erasure and this needs to be done by the implementer.

12.5 Traits as stackable modifications

Traits allows modifications of the methods of a class in a stackable way. Given a class that implement an Integer Queue, define traits that perform modifications such as Doubling, increment and Filtering. These modifications are stackable in the sense, the ability to mix them into a class and obtain new class that has all those modifications.

An Abstract IntQueue class and a BasicIntQueue extending IntQueue
  • Traits can extend another class which becomes its superclass. When this happens, the trait can only be mixed into classes that extend the same superclass
This trait can only be mixed into BasicIntQueue or other subclasses of IntQueue
  • The super call on a method declared abstract is illegal for normal classes. However, since the super calls in a trait are dynamically bound, the super call in trait Doubling will work so long as the trait is mixed in after another trait or class that gives a concrete definition to the method. To make this possible such methods must use the modifier abstract override.

We would have gotten the same result with

scala> val queue = new BasicIntQueue with Doubling
scala> queue.put(10)
scala> queue.get()
Int = 20
scala> val queue = (new BasicIntQueue with Incrementing with Filtering)
scala> queue.put(-1);queue.put(0); queue.put(1)
scala> queue.get() //Int = 1
scala> queue.get() // Int = 2
  • The order of the mixins is significant. (Roughly speaking, traits to the right take effect first)
  • On a method call on a class with mixins, the method in the trait furthest to the right is called first. If the method calls super, it invokes the method in the next trait to its left and so on…
Changing the order of traits has different output.
  • Overall, stackable modifications gives a lot of flexibility.

12.6 Why not multiple inheritance?

  • Traits are way to inherit from multiple-class like constructs. They differ by the interpretation of super which is determined by a linearization as discussed above.
  • Without trait, multiple-inheritance would raise concerns around which super to be invoked. If we apply linearization one of the major issues is, there is no way to achieve incremented and doubled value.
Problems with multiple inheritance
  • In Scala, a class is always linearized before all of its superclasses and mixed in traits.

Scala’s Linearization illustration

Arrows with white triangular head — Inheritance with heads pointing to the super type. Darkened heads depict linearization. dark heads points in direction in which super calls will be resolved.
The invocation of super will be the first one to the right

12.7 To trait, or not to trait?

How to decide between trait or an abstract class? Here are a few guidelines:

  • If the behavior will not be reused, then make it a concrete class.
  • If it might be reused in multiple, unrelated classes, make it a trait.
  • If you want to inherit from it in Java code, use an abstract class.
  • If you plan to distribute it in compiled form, and expectation for outside groups to write classes inheriting from it, lean towards abstract class.
  • If efficiency is important, lean towards using a class. If you still do not know, after considering the above, then start by making it as a trait.

Conclusion

Traits are similar to multiple inheritance, but they interpret super using linearization, they both avoid some of the difficulties of traditional multiple inheritance, and allow you to stack behaviors. Traits are fundamental unit of code that is reusable through inheritance.

Previous:

Next:

--

--