Scala let you mix-in different related traits.
By “non-functional,” I mean of course the programmer who is not looking to jump into the world of functional programming. ;-)
Scala is often portrayed as a solution for the multi-core scalability problems that come with Java’s approach to multithreading, but it offers so much more.
The Usual Reason to Consider Scala
Java multithreading requires you to protect any variables that might be accessed from multiple threads. This is often referred to as “synchronize and suffer” because you must manually add synchronization to protect your variables—and then suffer because it’s so easy to get it wrong. And there are lots of ways to get it wrong:
assuming you only have to synchronize setters and ignoring getters
forgetting that synchronized methods exhibit fairness while synchronized blocks do not
forgetting to protect related variables, exposing the code to data corruption and/or deadlock
Scala has certainly made a name for itself in offering ways to avoid these problems via immutable variables, functional programming, actors, and libraries like Akka. But there is a whole other side to the language. So even if you’re not ready to drink the mutability-is-bad Koolaid, Scala still has lots to offer.
This article discusses one of those “non-functional” features: traits.
The Java [Anti]Pattern
One of the common development patterns in Java is to create an interface, then create an abstract base class that implements that interface and provides some base implementation, and then create several concrete classes derived from the base class. Some might call this an antipattern because of the number of files it creates. On the other hand, Java doesn’t give you much choice. Interfaces cannot have implementations, so there is no place to put common method instantiations except in classes.
Listing 1: The Java [Anti]Pattern
Scala, on the other hand, offers traits, which are like interfaces with a little implementation thrown in. (A trait can also be like a mini-strategy pattern, as you can mix-in one of several different related traits depending on your need). A class can use a single trait, multiple traits, and/or can extend another class.
Here’s all the syntax you should need to be able to read the Scala in this article:
def starts a method,
variables are started with var or val,
variables are defined with [name] [type] rather than Java style [type] [name], and
semicolons are not required.
That covered, let’s look at some Scala:
Scala does not have an interface keyword, so traits do double duty. An abstract method in a trait is just like a Java interface method in that all classes using the trait must define it. Trait methods with an implementation do not need to be implemented by classes using them.
This may seem like a small saving but it’s just the tip of the iceberg with traits.
While java interfaces are applied on an all-or-nothing basis—your class either implements the interface or it does not—Scala lets you use traits on a per-instance basis. So you can say “this instance of class Foo that normally does not extend trait Bar, does in fact extend it!”
MySpecialContent defined here is an instance of the Content class, but for this particular instance object we mix in the OtherTrait:
This capability may not be universally viewed as a Good Thing by all Java programmers, as it is a step towards dynamic languages where classes can be modified after the fact. While it is true that Traits and Open Classes are different parts of the language, they do accomplish the same thing: they change the behavior of an existing class, and that is something odd to many traditional Java programmers.
While many view open classes as a boon it is also true that they add complexity. An instance of the class created without the trait can be assigned an instance of the class with the trait, but not the reverse. On the other hand, you still have the option to mark a class as final which prevents instance-based trait mixing. On the other other hand, marking a class as final also means you cannot derive other classes from it, so it’s at best an imperfect solution.
Given all this, why would you want to use instance-specific trait mix-ins?
There’s a Pattern for That
Think strategy pattern. The strategy pattern says that a class performs a type of action where there can be several related implementations of that action.
An example from my field of Video On Demand might be obtainTheContent. We might have a class called Movie that corresponds to playing a movie on a customer device. In order to do so it would presumably have to get the bits to play; i.e., it would obtainTheContent. It might do that differently if the customer device was a plasma TV, a tablet, or a smartphone.
In Java we might declare an obtainTheContent method that accepted a device type parameter and performed different actions based on it. Or, we could declare a set of related classes that each implemented an obtainTheContent interface. We could then instantiate the appropriate class and call the method on it. Or we could use Spring (or Guice) and declare the interface as a required bean and create the correct type on the fly.
In Scala we could simply say:
This would create a movie that exposes methods from the TableContent trait. We could also create an object new Movie with BitPlasmaContent.
I hope this brief exposure to one of the the non-functional aspects of Scala has piqued your curiosity. To learn more you can explore Programming Scala by Venkat Subramaniam or Programming in Scala2 by Martin Odersky, Lex Spoon, and Bill Venners, all of whom know far more about Scala than I ever will.
Brian Tarbox is a Distinguished Member of Technical Staff at Motorola where he designs server-side solutions in the Video On Demand space. He writes a blog on the intersection of software design, cognition, and Tai Chi at briantarbox.blogspot.com. His primary contact point is about.me/BrianTarbox.