How do you provide overloaded constructors in Scala?
Scala constructor overload
scala
Related Solutions
This answer uses the
Manifest
-API, which is deprecated as of Scala 2.10. Please see answers below for more current solutions.
Scala was defined with Type Erasure because the Java Virtual Machine (JVM), unlike Java, did not get generics. This means that, at run time, only the class exists, not its type parameters. In the example, JVM knows it is handling a scala.collection.immutable.List
, but not that this list is parameterized with Int
.
Fortunately, there's a feature in Scala that lets you get around that. It’s the Manifest. A Manifest is class whose instances are objects representing types. Since these instances are objects, you can pass them around, store them, and generally call methods on them. With the support of implicit parameters, it becomes a very powerful tool. Take the following example, for instance:
object Registry {
import scala.reflect.Manifest
private var map= Map.empty[Any,(Manifest[_], Any)]
def register[T](name: Any, item: T)(implicit m: Manifest[T]) {
map = map.updated(name, m -> item)
}
def get[T](key:Any)(implicit m : Manifest[T]): Option[T] = {
map get key flatMap {
case (om, s) => if (om <:< m) Some(s.asInstanceOf[T]) else None
}
}
}
scala> Registry.register("a", List(1,2,3))
scala> Registry.get[List[Int]]("a")
res6: Option[List[Int]] = Some(List(1, 2, 3))
scala> Registry.get[List[String]]("a")
res7: Option[List[String]] = None
When storing an element, we store a "Manifest" of it too. A Manifest is a class whose instances represent Scala types. These objects have more information than JVM does, which enable us to test for the full, parameterized type.
Note, however, that a Manifest
is still an evolving feature. As an example of its limitations, it presently doesn't know anything about variance, and assumes everything is co-variant. I expect it will get more stable and solid once the Scala reflection library, presently under development, gets finished.
tl;dr
class C
defines a class, just as in Java or C++.object O
creates a singleton objectO
as instance of some anonymous class; it can be used to hold static members that are not associated with instances of some class.object O extends T
makes the objectO
an instance oftrait T
; you can then passO
anywhere, aT
is expected.- if there is a
class C
, thenobject C
is the companion object of classC
; note that the companion object is not automatically an instance ofC
.
Also see Scala documentation for object and class.
object
as host of static members
Most often, you need an object
to hold methods and values/variables that shall be available without having to first instantiate an instance of some class.
This use is closely related to static
members in Java.
object A {
def twice(i: Int): Int = 2*i
}
You can then call above method using A.twice(2)
.
If twice
were a member of some class A
, then you would need to make an instance first:
class A() {
def twice(i: Int): Int = 2 * i
}
val a = new A()
a.twice(2)
You can see how redundant this is, as twice
does not require any instance-specific data.
object
as a special named instance
You can also use the object
itself as some special instance of a class or trait.
When you do this, your object needs to extend some trait
in order to become an instance of a subclass of it.
Consider the following code:
object A extends B with C {
...
}
This declaration first declares an anonymous (inaccessible) class that extends both B
and C
, and instantiates a single instance of this class named A
.
This means A
can be passed to functions expecting objects of type B
or C
, or B with C
.
Additional Features of object
There also exist some special features of objects in Scala. I recommend to read the official documentation.
def apply(...)
enables the usual method name-less syntax ofA(...)
def unapply(...)
allows to create custom pattern matching extractors- if accompanying a class of the same name, the object assumes a special role when resolving implicit parameters
Best Solution
It's worth explicitly mentioning that Auxiliary Constructors in Scala must either call the primary constructor (as in landon9720's) answer, or another auxiliary constructor from the same class, as their first action. They cannot simply call the superclass's constructor explicitly or implicitly as they can in Java. This ensures that the primary constructor is the sole point of entry to the class.