score:11

Accepted answer

Whether this is indeed a design flaw is rather debatable. One would consider that complicating the syntax to allow this particular use case is not worthwhile.

Also, Scala is after all a predominantly functional language, so the presence of vars in your program should not be that frequent, again raising the question if this particular use case needs to be handled in a special way.

However, it seems that a simple solution to your problem would be to use an apply method in the companion object:

class Foo private(private var _x: Int) {
  def x = _x
}

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

Usage:

val f = Foo(x = 3)
println(f.x)

LATER EDIT:

Here is a solution similar to what you originally requested, but that changes the naming a bit:

class Foo(initialX: Int) {
  private var _x = initialX
  def x = _x
}

Usage:

val f = new Foo(initialX = 3)

score:0

The concept you are trying to express, which is an object whose state is mutable from within the object and yet immutable from the perspective of other objects ... that would probably be expressed as an Akka actor within the context of an actor system. Outside the context of an actor system, it would seem to be a Java conception of what it means to be an object, transplanted to Scala.

import akka.actor.Actor
class Foo(var x: Int) extends Actor {
  import Foo._
  def receive = {
    case WhatIsX => sender ! x
  } 
}
object Foo {
  object WhatIsX
}

score:0

Not sure about earlier versions, but In Scala 3 it can easily be implemented like follows:

// class with no argument constructor
class Foo {
  // prive field
  private var _x: Int = 0
    
  // public getter
  def x: Int = _x
  // public setter
  def x_=(newValue: Int): Unit =
    _x = newValue  
  
  //auxiliary constructor
  def this(value: Int) =
    this()
    _x = value
}

Note

  • Any definition within the primary constructor makes the definition public, unless you prepend it with private modifier
  • Append _= after a method name with Unit return type to make it a setter
  • Prepending a constructor parameter neither with val nor with var, makes it private

Then it follows:

val noArgFoo = Foo() // no argument case
println(noArgFoo.x) // the public getter prints 0
val withArgFoo = Foo(5) // with argument case
println(withArgFoo.x) // the public getter prints 5

noArgFoo.x = 100 // use the public setter to update x value
println(noArgFoo.x) // the public getter prints 100
withArgFoo.x = 1000 // use the public setter to update x value
println(withArgFoo.x) // the public getter prints 1000

This solution is exactly what you asked; in a principled way and without any ad hoc workaround e.g. using companion objects and the apply method.


Related Query

More Query from same tag