1

I have something like below that I want to compile

trait T{
  def a: Int
}

class A private(val a: Int, a2: Int) extends T{
  def add(b: Int): A = new A(a + b, a2 + 2*b)
}

object T{
  def make(a: Int): A = {
    new A(a, 2*a) // doesn't compile
}

Here class A has a private constructor because I want the only way to construct a A is to pass through the constructor T.make or with the updated method A.add (which in this example both garantie that a2 = 2*a).

But because A constructor is private, it cannot be access by the parent trait T. Same goes for protected. Basically, I would need an inversed protected?

Note: A solution that is not satisfying is to lower (too much) the restriction on A constructor, maybe to package-private. But I don't want any other construction possible but the ones that were planned. I could lower the constraint to all code in the current file, but I don't know how to do that either.

Juh_
  • 14,628
  • 8
  • 59
  • 92
  • It should work. See [here](https://stackoverflow.com/questions/6919965/companion-object-cannot-access-private-variable-on-the-class). Also, for best-practice, see [here](https://stackoverflow.com/a/30836828/5599298) – slouc Sep 12 '17 at 10:43
  • @slouc Your first link is relevant for behavior in REPL (the second link is ok). – Dmytro Mitin Sep 12 '17 at 11:09
  • 2
    about best-practice, this is just a personal preferences to give explicit names to builder functions (make, build, ...). I keep apply() for case classes / pure definition classes with alternate constructors. Not my case here but I could have use it in the example – Juh_ Sep 12 '17 at 11:23

2 Answers2

4

A few options.

  • You can rename your object T to object A - then it will have access to A's private members

  • You can make class A inner to object T - then you can make the constructor private[T], and T will have access to it.

  • You can also make it package-private. You are mistaken when you say that it would be "lowering restriction too much". A package in scala doesn't have to be an entire directory. It doesn't even need to be the whole file. You have complete control over its content, and the purpose of that is to be able to do exactly what you are trying to do here.

Dima
  • 39,570
  • 6
  • 44
  • 70
3

Maybe you should put make(..) into companion object of class A rather than companion object of trait T.

  object A  {
    def make(a: Int): A = {
      new A(a, 2 * a) 
    }
  }
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • 1
    That works indeed. I (obviously) have a more complex case that make this not very practical (ex: I have another T subclasses and public constructors that share functionalities with A constructors). But I can find my way out of this – Juh_ Sep 12 '17 at 11:11