Search code examples
scalaencapsulation

Why not mark val or var variables as private?


Coming from a java background I always mark instance variables as private. I'm learning scala and almost all of the code I have viewed the val/var instances have default (public) access. Why is this the access ? Does it not break information hiding/encapsulation principle ?


Solution

  • It would help it you specified which code, but keep in mind that some example code is in a simplified form to highlight whatever it is that the example is supposed to show you. Since the default access is public, that means that you often get the modifiers left off for simplicity.

    That said, since a val is immutable, there's not much harm in leaving it public as long as you recognize that this is now part of the API for your class. That can be perfectly okay:

    class DataThingy(data: Array[Double) {
      val sum = data.sum
    }
    

    Or it can be an implementation detail that you shouldn't expose:

    class Statistics(data: Array[Double]) {
      val sum = data.sum
      val sumOfSquares = data.map(x => x*x).sum
      val expectationSquared = (sum * sum)/(data.length*data.length)
      val expectationOfSquare = sumOfSquares/data.length 
      val varianceOfSample = expectationOfSquare - expectationSquared
      val standardDeviation = math.sqrt(data.length*varianceOfSample/(data.length-1))
    }
    

    Here, we've littered our class with all of the intermediate steps for calculating standard deviation. And this is especially foolish given that this is not the most numerically stable way to calculate standard deviation with floating point numbers.

    Rather than merely making all of these private, it is better style, if possible, to use local blocks or private[this] defs to perform the intermediate computations:

    val sum = data.sum
    val standardDeviation = {
      val sumOfSquares = ...
      ...
      math.sqrt(...)
    }
    

    or

    val sum = data.sum
    private[this] def findSdFromSquares(s: Double, ssq: Double) = { ... }
    val standardDeviation = findMySD(sum, data.map(x => x*x).sum)
    

    If you need to store a calculation for later use, then private val or private[this] val is the way to go, but if it's just an intermediate step on the computation, the options above are better.

    Likewise, there's no harm in exposing a var if it is a part of the interface--a vector coordinate on a mutable vector for instance. But you should make them private (better yet: private[this], if you can!) when it's an implementation detail.