In a previous post, I explained how Scala's use of singleton objects is better than Java's use of static members. I was asked for some sample code after that post, so I thought I would throw some together. Let's look at a simple Java class.
class Foo {
private static int number = 1;
public static Foo create(String a) {
return new Foo("Some " + a);
}
private String a;
private int id = number++;
public Foo(String a) {
this.a = a;
}
@Override
public String toString() {
return "Foo #" + id + " is " + a;
}
}
This class keeps track of how many instances have ever been created. You construct a Foo with a name, and the Foo's name and id are part of its string representation. In addition, there is a create method that has been defined on the Foo class itself.
Scala doesn't have a "static" keyword. Instead, members that would otherwise be static are placed onto the so-called companion object.
object Foo {
var number:Int = 1;
def create(a:String) = new Foo("Some " + a)
}
class Foo(a:String) {
private val id:Int = Foo.number
Foo.number = Foo.number + 1
override def toString() = {
"Foo #" + id + " is " + a
}
}
Because Foo is the name of both an object and a class in the same package, they are allowed to access each other's private members. Basically, this makes the instance members of a singleton object equivalent to static members of an ordinary Java class. However, since the singleton object is a fully fledged object, it can be passed around in a way that Java classes normally can't be.
def createList(f : Foo.type) = {
List(f.create("One"), f.create("Two"))
}
Have you ever wanted a Java class' static members to obey an interface? Well, the singleton object can mix in Scala traits (Scala traits seem to take the place of both interfaces and mixins from other languages).
trait Creatable[A] {
def create(a:String) : A
def createDefault() : A = {
return create("Default")
}
}
object Foo extends Creatable[Foo] {
var number:Int = 1;
override def create(a:String) = new Foo(a)
}
And here's a whole sample program:
trait Creatable[A] {
def create(a:String) : A
def createDefault() : A = {
return create("Default")
}
}
object Foo extends Creatable[Foo] {
var number:Int = 1;
override def create(a:String) = new Foo(a)
}
class Foo(a:String) {
private val id:Int = Foo.number
Foo.number = Foo.number + 1
override def toString() = {
"Foo #" + id + " is " + a
}
}
def createList(f : Creatable[Foo]) = {
List(f.create("Three"), f.create("Four"))
}
println(Foo.create("One"))
println(Foo.create("Two"))
println(createList(Foo))
println(Foo.createDefault())
----------
Foo #1 is One
Foo #2 is Two
List(Foo #3 is Three, Foo #4 is Four)
Foo #5 is Default
Why are singleton objects better than static members? To begin with, Scala's singleton objects are at least as expressive as static class members, so you're not losing anything from Java. You define a singleton object differently that you define static members in Java, but you access them using notation identical to Java (i.e. Foo.bar(5) in both languages). In addition, you get some other nice features - first class object status and the ability to participate in the normal class hierarchy. As an added bonus, Scala's simpler syntax actually made the class/singleton-object pair shorter than the equivalent Java solution. Not bad!