1

Given:

class Foo(x: Int) {}

object Foo {
  def apply(x: Int) = new Foo(x)
}

Besides marking Foo's constructor as private, how can I present a warning or compile-time failure when calling new Foo(...)?

In other words, I'd like to restrict (either by compile-time warning or error) construction of Foo to Foo.apply.

Is this possible?

Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384

1 Answers1

7

In scala there are two idiomatic ways how to achieve that.

  1. Constructor private to the class and companion object.

Factory has access to constructor, while anyone else doesn't:

class Foo private[Foo](val x: Int)

object Foo {
  def apply(x:Int) = new Foo(x)
}

val foo = new Foo(1)  // cannot compile
val foo1 = Foo(1) //compiles fine
  1. Sealed abstract class.

In scala sealed class can be extended only in the same source file it is defined. I suggest to make Foo sealed abstract class and return anonymous child of Foo in object's apply method.

sealed abstract class Foo(val x:Int)

object Foo {
  def apply(x:Int):Foo = new Foo(x) {}
}

In this case Foo can be created nowhere except the file where it is defined.

UPD: Actually, this question was already discussed on stackoverflow.

UPD2: Added brief overview of both methods.

Community
  • 1
  • 1
Aivean
  • 10,692
  • 25
  • 39
  • But an `abstract class` cannot be instantiated. – Kevin Meredith Sep 25 '15 at 14:26
  • 4
    @KevinMeredith, that's the point. In `object Foo` you can create object of anonymous classes that extend `Foo` (that's why there are curly braces after `new Foo`), while in other files you can't do that, because `Foo` is abstract and sealed, meaning you can't create it directly and you can't extend it in order to instantiate it's child. – Aivean Sep 25 '15 at 18:38