0

The following pattern seems to be idiomatic scala:

class Foo() {}
object Foo { def apply() = new Foo() }
val x = Foo()

What is the motivation for the idiomatic approach? In which cases should I not provide the factory method, forcing client to use val y = new Foo()? Should all cases with companion objects provide a factory method?

jwvh
  • 50,871
  • 7
  • 38
  • 64
  • This is, amongst other things, what `case` classes are for. `case class Foo() {}` will generate automatically the `object Foo` with the same `apply` method (in fact it will generate even more than that). – Alec Aug 22 '17 at 16:22
  • [This answer](https://stackoverflow.com/questions/45751212/is-apply-and-unapply-a-constructor-in-scala/45752243#45752243) to a previous question addresses most of your questions. – jwvh Aug 22 '17 at 16:29
  • Two [additional](https://stackoverflow.com/questions/609744/what-is-the-rationale-behind-having-companion-objects-in-scala) [answers](https://stackoverflow.com/questions/9806029/scala-companion-object-purpose) of almost same question. – user6296589 Aug 24 '17 at 19:45

2 Answers2

1

Case class apply is normally rewritten by the compiler to new. That's not done if you write a custom apply, even a trivial one.

There are probably similar edge cases around implicit value classes.

$ scala
Welcome to Scala 2.12.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.

scala> case class K(i: Int)
defined class K

scala> K(42)
res0: K = K(42)

scala> :javap -c res0
Compiled from "<console>"
public class $line4.$read$$iw$$iw$ {
  public static $line4.$read$$iw$$iw$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class $line4/$read$$iw$$iw$
       3: invokespecial #28                 // Method "<init>":()V
       6: return

  public $line3.$read$$iw$$iw$K res0();
    Code:
       0: aload_0
       1: getfield      #31                 // Field res0:L$line3/$read$$iw$$iw$K;
       4: areturn

  public $line4.$read$$iw$$iw$();
    Code:
       0: aload_0
       1: invokespecial #33                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: putstatic     #35                 // Field MODULE$:L$line4/$read$$iw$$iw$;
       8: aload_0
       9: new           #14                 // class $line3/$read$$iw$$iw$K
      12: dup
      13: bipush        42
      15: invokespecial #38                 // Method $line3/$read$$iw$$iw$K."<init>":(I)V
      18: putfield      #31                 // Field res0:L$line3/$read$$iw$$iw$K;
      21: return
}

scala> case class K(i: Int) ; object K { def apply(j: Int) = new K(j) }
defined class K
defined object K

scala> K(42)
res1: K = K(42)

scala> :javap -c res1
Compiled from "<console>"
public class $line6.$read$$iw$$iw$ {
  public static $line6.$read$$iw$$iw$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class $line6/$read$$iw$$iw$
       3: invokespecial #31                 // Method "<init>":()V
       6: return

  public $line5.$read$$iw$$iw$K res1();
    Code:
       0: aload_0
       1: getfield      #34                 // Field res1:L$line5/$read$$iw$$iw$K;
       4: areturn

  public $line6.$read$$iw$$iw$();
    Code:
       0: aload_0
       1: invokespecial #36                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: putstatic     #38                 // Field MODULE$:L$line6/$read$$iw$$iw$;
       8: aload_0
       9: getstatic     #41                 // Field $line5/$read$$iw$$iw$K$.MODULE$:L$line5/$read$$iw$$iw$K$;
      12: bipush        42
      14: invokevirtual #45                 // Method $line5/$read$$iw$$iw$K$.apply:(I)L$line5/$read$$iw$$iw$K;
      17: putfield      #34                 // Field res1:L$line5/$read$$iw$$iw$K;
      20: return
}
som-snytt
  • 39,429
  • 2
  • 47
  • 129
0

A class does not need a companion object if none of the following apply:

  • There is functionality in the class that is not tied to an instance (what is called "static" in Java)
  • There is a desire to provide a constructor that avoids the need to call new. This is accomplished in Scala by having SomeClass.apply(params)

If none of the above are of interest, there is no need for the companion object. A companion object is a useful structure - if you have those needs. If not, there is no reason to have it. I am not aware of any reason to categorically not have a companion object. It's a tool that you don't write if you don't need to.

radumanolescu
  • 4,059
  • 2
  • 31
  • 44
  • I think the question might be rephrased to "*For which classes do we desire a constructor without the need for `new`*"? Is there a convention? – Bergi Aug 22 '17 at 17:28
  • 1
    @Bergi -- Indeed, this is what I am getting at. I also saw [this answer](https://stackoverflow.com/a/630015/6296589). I understand that in many cases it is not really needed. – user6296589 Aug 23 '17 at 15:17