How to create a Scala class with private field with public getter, and primary constructor taking a parameter of the same name

17,418

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)
Share:
17,418

Related videos on Youtube

Erik Kaplun
Author by

Erik Kaplun

github.com/erikkaplun

Updated on September 15, 2022

Comments

  • Erik Kaplun
    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
    Erik Kaplun over 10 years
    I 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
    Marius Danila over 10 years
    I 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
    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 to def you are potentially breaking clients of your code, so it is highly arguable whether such refactoring should take place at all.
  • Erik Kaplun
    Erik Kaplun over 8 years
    @VladimirMatveev: agreed — I updated my question accordingly already some time ago :)