113

I've been curious about the impact of not having an explicit primary constructor in Scala, just the contents of the class body.

In particular, I suspect that the private or protected constructor pattern, that is, controlling construction through the companion object or another class or object's methods might not have an obvious implementation.

Am I wrong? If so, how is it done?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Don Mackenzie
  • 7,953
  • 7
  • 31
  • 32
  • You could have a Scala singleton (with the object keyword, that is), and define your class as private within that singleton, and have methods of the singleton for constructing your objects. – Paggas Nov 13 '09 at 17:06
  • @Paggas, unfortunately when you return an instance of a class marked private out of it's scope it won't compile, even when returned from a method of it's in scope companion object. – Don Mackenzie Nov 13 '09 at 17:36
  • This is done quite profusely throughout the Scalaz source code. The concept is also known as an *abstract* algebraic data type. – Tony Morris Oct 28 '11 at 07:49

2 Answers2

197

You can declare the default constructor as private/protected by inserting the appropriate keyword between the class name and the parameter list, like this:

class Foo private () { 
  /* class body goes here... */
}
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Aleksander Kmetec
  • 3,287
  • 2
  • 24
  • 19
  • Thanks Aleksander, Can you please tell me whether this is presented in one of the scala books or in the language specification? Sorry I can't upvote yet. – Don Mackenzie Nov 13 '09 at 17:31
  • I just glanced over "Programming Scala"'s explanation of constructors (pages 92-95) and I don't see it mentioned there. I actually found the answer to your question in an old changelog, but I've never seen it mentioned anywhere else before. Link: http://www.scala-lang.org/node/43#2.4.0 – Aleksander Kmetec Nov 13 '09 at 17:36
  • 19
    Pag 414 of "Programming in Scala". Page 97 of Wampler's Programming Scala. Page 60 of Subramaniam's Programming Scala. I don't have a PDF of Beginning Scala with me right now to check it out. – Daniel C. Sobral Nov 13 '09 at 18:53
  • Oh, I see it now on page 97. Thanks. – Aleksander Kmetec Nov 13 '09 at 19:21
  • 1
    Thanks both for the further research, I've got the Wampler book, but only on my phone and clearly haven't read it thoroughly but I've found that it complements the Odersky book surprisingly well. – Don Mackenzie Nov 13 '09 at 20:53
  • then y this piece of code `class Person private (){} val p = new Person` is not throwing Compile time error – Aamir Apr 26 '16 at 05:34
66

Aleksander's answer is correct, but Programming in Scala offers an additional alternative:

sealed trait Foo {
 // interface
}

object Foo {
  def apply(...): Foo = // public constructor

  private class FooImpl(...) extends Foo { ... } // real class
}
Community
  • 1
  • 1
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • That's clever, needless to say I didn't realise traits could act as surrogates for classes in the construction paradigm. – Don Mackenzie Nov 13 '09 at 21:10
  • In this particular case, they are just an interface. Though you could put some code in it. Alas, there's a bug in my example, which I'm correcting right now... – Daniel C. Sobral Nov 13 '09 at 23:01
  • Just been giving this technique a bit of thought. The trait must convey the complete non private interface of the required implementation of a "Foo" but in return for this constraint you get a lot of freedom in how you provide the implementation while keeping with the spirit of what apply should return. – Don Mackenzie Nov 13 '09 at 23:37
  • 18
    Popping in years later to say: I think this is a good answer to the question but a bad solution to the problem. If some future programmer were to Aleksander's code, he would say "Ah, the primary constructor is private but other constructors are not." If that programmer were to look at Daniel's code, he would say, "Ah, they are using a Factory pattern to compensate for Scala's inability to mark the default constructors as private. Wait, Scala's *can* mark the default constructors as private! What is going on here?!?" In other words, a bad WTF/LOC ratio. – Michael Lorton Jul 23 '11 at 17:09
  • 20
    @Malvolio I do not quite agree. This pattern not only make the primary constructor private, but also the _implementation_, forcing the user to use the interface (trait). That has its own value. As for someone thinking something because he/she doesn't know the language -- piffle! To quote Kenny Tilton, [learn the damn language](http://smuglispweeny.blogspot.com/2008/07/fear-no-evil-ii-or-why-solar-power.html)! – Daniel C. Sobral Jul 25 '11 at 02:42
  • 7
    It should be mentioned somewhere that this approach means not using the `new` keyword. – Travis Parks Mar 14 '13 at 20:16
  • @TravisParks See the question... The whole point is to be able to control construction though the companion object. – aij Dec 19 '13 at 01:12
  • 1
    One caveat with this approach is that someone could still instantiate a Foo through their own implementation. That could be seen as an advantage or disadvantage depending on the reason for controlling construction. – aij Dec 19 '13 at 01:15
  • 1
    @aij True, so I just made it so that can't happen anymore. :) – Daniel C. Sobral Dec 19 '13 at 01:26
  • When applied to a case class, doesn't this approach filter away almost all the good parts of a case class; equals, hashcode, toString, pattern matching, etc? – chaotic3quilibrium Aug 21 '14 at 19:01
  • 1
    @chaotic3quilibrium td;lr: yes. An hierarchy of case classes is usually composed of very different case classes that belong together somehow. Often, the trait they all share doesn't even come with an implementation. As such, the use case for case classes inheriting from a trait and a private implementation of a trait are very different. – Daniel C. Sobral Aug 21 '14 at 23:12
  • What's "td;lr"? Is that a reference to "too long; didn't read" (tl;dr)? If not, I'm not up on my leet speak so I don't know the reference. :) – chaotic3quilibrium Aug 22 '14 at 00:28
  • @chaotic3quilibrium Yep, that's it. – Daniel C. Sobral Aug 25 '14 at 00:42
  • I _think_ it needs to read `private[Foo] class FooImpl`. Else you get "private class FooImpl escapes its defining scope as part of type rm.Foo.FooImpl" – Cpt. Senkfuss Nov 28 '16 at 21:50
  • @Cpt.Senkfuss Weird, that's new. I wonder what version of Scala started complaining about it. – Daniel C. Sobral Nov 30 '16 at 21:54
  • 1
    @Cpt.Senkfuss It happens when you leave out the result type. The compiler infers the concrete private type and hence the error. `def apply(...): Foo =` and it's ok. Personally I prefer the more restrictive `private[this] class FooImpl` to rule out the possibility that `trait Foo` may fiddle with `FooImpl`. – Ohashi Apr 25 '17 at 03:55
  • @Ohashi Good catch! I've added the return type to the code. – Daniel C. Sobral Apr 25 '17 at 21:16