For starters I've chosen our old friend - Singleton. Let's go then!
object Singleton
// Usage:
val singleton = Singleton
Done! Thx for reading..
..just kidding, let's dig a little deeper into that.
You are probably curious about thread safety of this solution. The actual code generated in bytecode and decompiled with JAD looks like that:
public final class Singleton$
implements ScalaObject
{
public Singleton$()
{
}
public int $tag()
throws RemoteException
{
return scala.ScalaObject.class.$tag(this);
}
public static final Singleton$ MODULE$ = this;
static
{
new Singleton$();
}
}
There are 3 things to consider:
- Singleton object is initialized in static block so thread safety is guaranteed by JVM
- Every time you reference Singleton object in your code, Scala compiler translates this call into 'Singleton$.MODULE$',
- This implemention has also quite cool semantics of access modifiers (which is a bit more advanced topic; search for 'companion module' to learn more).
An important thing to notice is that Singleton is eagerly initialized so if you try:
java.lang.Class.forName("Singleton$")it'll cause initialization to be performed. For now I have no idea how to force 'object' in Scala to be lazy initialized. The only solution I came up with would be:
// Incorrect (see the bottom of article)class LazySingleton private () {
def apply() = this
}
// Correct
class LazySingleton private () {
}
object LazySingleton {
lazy val INSTANCE = new LazySingleton();
def apply() = INSTANCE
}
// Usage:
val singleton = Singleton()
The trick is to make default constructor private and have apply method of 'object' class type return the only instance of LazySingleton class.
Disadvantage of second implementation is a small but noticable difference in usage. First - requires '()' [apply[ operator to be used. Second - it returns different type of class depending on whether '()' is used (class LazySingleton) or not (object LazySingleton):
scala> C()
res1: C = C@304648
scala> C
res2: C.type = C$@1b9e7fc
Modified 2009-06-23: Previous implemention of lazy singleton was incorrect and led to wrong conclusions.
Thanks for the post. I was looking for a solution and yours gave me this idea...
ReplyDeleteRename 'INSTANCE' to 'singleton' and the usage becomes an import statement. Then a 'var' is no longer needed.
Your information is more than 4 years outdated.
ReplyDeleteConsidering the date article was written your argument is very solid
ReplyDelete