Many classes in the Scala standard library use apply()
of their companion object as factory. This is often convenient when chaining calls like List(List(1))
. On the other hand, it's still possible to create objects directly with new
(new HashMap[Int, Int]()
).
That's standard library. Now, in my own code, which approach is better to use: companion factory or creating objects with new
?
Is there any convention on when to create companion object factory and when to do with the new
keyword?
What are the advantages of using one over the other?
A companion object and its class can access each other's private members. A companion object's apply method lets you create new instances of a class without using the new keyword. A companion object's unapply method lets you de-construct an instance of a class into its individual components.
Solution: companion objectThe ability to extend interfaces and classes is one of the features that sets the companion objects apart from Java's static functionality. Also, companions are objects, we can pass them around to the functions and assign them to variables just like all the other objects in Kotlin.
Answer: Companion object is not a Singleton object or Pattern in Kotlin – It's primarily used to define class level variables and methods called static variables. This is common across all instances of the class.
Object expressions are executed (and initialized) immediately, where they are used. Object declarations are initialized lazily, when accessed for the first time. A companion object is initialized when the corresponding class is loaded (resolved) that matches the semantics of a Java static initializer.
In most cases I use the companion object's apply
method, because the code looks less cluttered. However, there is at least one benefit of using a static factory. Consider the unimaginative type MyInt
which just wraps an Int
:
class MyInt(val i: Int)
I can obtain instances of MyInt
calling the constructor which will instantiate a new object each time the constructor is called. If my program relies heavy on MyInt
this results in a lot of instances created. Assuming most of the MyInt
I use are -1
, 0
, and 1
, since MyInt
is immutable I can reuse the same instances:
class MyInt(val i: Int)
object MyInt {
val one = new MyInt(1)
val zero = new MyInt(0)
val minusOne = new MyInt(-1)
def apply(i: Int) = i match {
case -1 => minusOne
case 0 => zero
case 1 => one
case _ => new MyInt(i)
}
}
So at least for immutable values there can be a technical advantage of using the static factory over calling the constructor. As an implication, if you want to express in code that a new instance is created, then use the new
keyword. Personally, I use the new
-keyword when creating objects, and the apply
-method when creating values, though I don't know if there is an official convention.
I don't know that there is a general recommendation of one approach over the other, usually it is just a convenience not to have to type new
.
There are occasions, though, where the factory method option can be better. For example, if your class has a String field that must be uppercase, you can make the standard constructor private, forcing instantiation via the factory method which ensures the field is always uppercase:
class A private[A] (s: String)
object A {
def apply(s: String): A = new A(s.toUpperCase)
}
Note: if your class is a case class, there are a couple of other tweaks to get this to work fully - see here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With