Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

scala

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
}
like image 756
Erik Kaplun Avatar asked Sep 10 '13 21:09

Erik Kaplun


People also ask

When a class is instantiated its primary constructor is?

The primary constructor consists of the constructor parameters, the methods called in the class body, and the statements executed in the body of the class. This time, instead of a no-argument constructor provided by Scala, this class has a two-argument constructor we defined by listing them next to the class name.

What is constructor parameter in Scala?

Scala constructor is used for creating an instance of a class. There are two types of constructor in Scala – Primary and Auxiliary. Not a special method, a constructor is different in Scala than in Java constructors. The class' body is the primary constructor and the parameter list follows the class name.

What is primary and auxiliary constructor in Scala?

The auxiliary constructor in Scala is used for constructor overloading and defined as a method using this name. The auxiliary constructor must call either previously defined auxiliary constructor or primary constructor in the first line of its body.

What is primary constructor in Scala?

The primary constructor of a Scala class is a combination of: The constructor parameters. Methods that are called in the body of the class. Statements and expressions that are executed in the body of the class.


1 Answers

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)
like image 180
Marius Danila Avatar answered Oct 14 '22 10:10

Marius Danila