How to create a Scala class with private field with public getter, and primary constructor taking a parameter of the same name
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)
Related videos on Youtube
Comments
-
Erik Kaplun over 1 year
Search results so far have led me to believe this is impossible without either a non-primary constructor
class Foo { // NOT OK: 2 extra lines--doesn't leverage Scala's conciseness private var _x = 0 def this(x: Int) { this(); _x = x } def x = _x } val f = new Foo(x = 123) // OK: named parameter is 'x'
or sacrificing the name of the parameter in the primary constructor (making calls using named parameters ugly)
class Foo(private var _x: Int) { // OK: concise def x = _x } val f = new Foo(_x = 123) // NOT OK: named parameter should be 'x' not '_x'
ideally, one could do something like this:
class Foo(private var x: Int) { // OK: concise // make just the getter public public x } val f = new Foo(x = 123) // OK: named parameter is 'x'
I know named parameters are a new thing in the Java world, so it's probably not that important to most, but coming from a language where named parameters are more popular (Python), this issue immediately pops up.
So my question is: is this possible? (probably not), and if not, why is such an (in my opinion) important use case left uncovered by the language design? By that, I mean that the code either has to sacrifice clean naming or concise definitions, which is a hallmark of Scala.
P.S. Consider the case where a public field needs suddenly to be made private, while keeping the getter public, in which case the developer has to change 1 line and add 3 lines to achieve the effect while keeping the interface identical:
class Foo(var x: Int) {} // no boilerplate
->
class Foo { // lots of boilerplate private var _x: Int = 0 def this(x: Int) { this(); _x = x } def x = _x }
-
Erik Kaplun over 10 yearsI do appreciate your answer, but ... regarding "this particular use case", I'd humbly argue that this is not such a special use case but rather quite a common one—correct me if I'm wrong ... As to the companion object approach—it changes the interface when going from public to private (not to mention it's another 2 lines of boilerplate).
-
Marius Danila over 10 yearsI didn't see this pattern a lot in the libraries I've inspected. Admittedly, this is based on my own experience. I've updated my answer for a solution with less boilerplate. Since in Scala variables & methods share the same namespace in a class I don't think it can get better than this
-
Vladimir Matveev over 10 years@ErikAllik, no, this is not common use case in idiomatic Scala code at all, mostly because it is related to mutability. And idiomatic Scala code limits use of mutable state to the absolute minimum. BTW, when your code presents a
var
as a part of its interface, and then you change it todef
you are potentially breaking clients of your code, so it is highly arguable whether such refactoring should take place at all. -
Erik Kaplun over 8 years@VladimirMatveev: agreed — I updated my question accordingly already some time ago :)