Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala case class private constructor isn't private

Tags:

scala

Today I encountered a strange problem with case class constructors. I wanted to make a constructor private and it seems that it isn't problem. So I've tried it in one of my projects and it works. But in another project I can invoke private constructor and it compiles. I thought it is something with my ide, so I made a standalone class and compile it with scalac. And it compiles. Here is the code:

package com.test

object Main {

  def main(args: Array[String]) {
    val bar = Bar("12345")
//    bar.doStuff()
    println(bar)
  }
}

case class Bar private(foo: String){
  private def doStuff():Unit = println("stuff")
}

The funny thing is that if I uncomment bar.doStuff() it won't compile. So I assume private works in this case, but somehow doesn't work for constructor. What am I doing wrong? Scalac is 2.11.8

like image 259
Artem Malinko Avatar asked Jun 29 '16 10:06

Artem Malinko


People also ask

Can a constructor be private in what cases?

Yes, we can declare a constructor as private. If we declare a constructor as private we are not able to create an object of a class. We can use this private constructor in the Singleton Design Pattern.

Can a constructor of a class be private?

A private constructor in Java is used in restricting object creation. It is a special instance constructor used in static member-only classes. If a constructor is declared as private, then its objects are only accessible from within the declared class. You cannot access its objects from outside the constructor class.

Is constructor always private?

No, Constructors can be public , private , protected or default (no access modifier at all).

What happens if I make class constructor private?

Private constructors allow us to restrict the instantiation of a class. Simply put, they prevent the creation of class instances in any place other than the class itself.


2 Answers

The notation val bar = Bar("12345") is shorthand for val bar = Bar.apply("12345"), in other words, it calls the apply method of the (automatically generated) companion object of the case class.

The companion object has access to the private constructor, so that's why it works.

(Why do you want to make the constructor of a case class private? That doesn't sound like a good idea).

like image 147
Jesper Avatar answered Oct 10 '22 15:10

Jesper


If you want Bar("abc") to not compile, here's a simple workaround.

Quickly tested in 2.12.3. Doesn't work in 2.11.8

case class Bar private (value: String)
object Bar {
  private def apply(v: String) = new Bar(v) // makes the method private
  def create(value: String): Bar = ... // your own implementation
}

val bar = Bar("abc") // compile error
val bar = new Bar("abc") // compile error
val bar = Bar.create("abc") // ok
like image 36
tamatama Avatar answered Oct 10 '22 16:10

tamatama