11

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?

Mifeet
  • 12,949
  • 5
  • 60
  • 108
  • 5
    Because using `new` is like wearing a top hat or suspenders. It's stylish for a certain style, but not very contemporary. The companion factory is a pair of casual fit jeans. – som-snytt Aug 29 '15 at 00:09

2 Answers2

6

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.

Kulu Limpa
  • 3,501
  • 1
  • 21
  • 31
  • 1
    I like the idea with value caching. The lesson learned is that you can easily change the implementation of apply() to do whatever you want but when you use `new`, you must always end up with a new instance. – Mifeet Aug 29 '15 at 10:13
3

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.

Community
  • 1
  • 1
Shadowlands
  • 14,994
  • 4
  • 45
  • 43
  • 1
    As an impl detail, `private[A]` results in a public ctor. More usual just to `private` since it means the same to Scala but has a private ctor for Java. – som-snytt Aug 29 '15 at 00:06
  • I don't have that much experience with Scala, but doesn't it become bothersome having to write the extra companion for every object? – Mifeet Aug 29 '15 at 10:15
  • @Mifeet Case classes provide a (usually) suitable companion object for free, so generally it isn't a bother at all. – Shadowlands Aug 29 '15 at 22:47
  • Yup, but I wouldn't want a case class for a service with several dependencies. Perhaps we could draw the line between implementation classes wired by DI management (`new`), and other classes dynamically created after startup (factory)? – Mifeet Aug 30 '15 at 08:02
  • Sure, sounds like a reasonable division. I'd say whatever feels right for a given project/team. – Shadowlands Aug 30 '15 at 08:06