Consider the following base and derived classes in Scala:
abstract class Base( val x : String )
final class Derived( x : String ) extends Base( "Base's " + x )
{
override def toString = x
}
Here, the identifier ‘x’ of the Derived class parameter overrides the field of the Base class, so invoking toString like this:
println( new Derived( "string" ).toString )
returns the Derived value and gives the result “string”.
So a reference to the ‘x’ parameter prompts the compiler to automatically generate a field on Derived, which is served up in the call to toString. This is very convenient usually, but leads to a replication of the field (I’m now storing the field on both Base and Derived), which may be undesirable. To avoid this replication, I can rename the Derived class parameter from ‘x’ to something else, like ‘_x’:
abstract class Base( val x : String )
final class Derived( _x : String ) extends Base( "Base's " + _x )
{
override def toString = x
}
Now a call to toString returns “Base’s string”, which is what I want. Unfortunately, the code now looks somewhat ugly, and using named parameters to initialize the class also becomes less elegant:
new Derived( _x = "string" )
There is also a risk of forgetting to give the derived classes’ initialization parameters different names and inadvertently referring to the wrong field (undesirable since the Base class might actually hold a different value).
Is there a better way?
Edit 1: To clarify, I really only want the Base values; the Derived ones just appear to be necessary for initializing the fields of the base class. The example only references them to illustrate the ensuing issues.
Edit 2: Actually, the example would have been clearer if I had used vars instead of vals, since that highlights the problem with values getting changed later on in the base class:
class Base( var x : Int ) { def increment() { x = x + 1 } }
class Derived( x : Int ) extends Base( x ) { override def toString = x.toString }
val derived = new Derived( 1 )
println( derived.toString ) // yields '1', as expected
derived.increment()
println( derived.toString ) // still '1', probably unexpected
Edit 3: It might be nice to have a way to suppress automatic field generation if the derived class would otherwise end up hiding a base class field. It would appear that the Scala compiler could actually have been designed to do this for you, but of course this contradicts the more general rule of “nearer” identifiers (the Derived class’ ‘x’) hiding more remote ones (the Base class’ ‘x’). It seems like a reasonably nice solution would be a modifier like ‘noval’, maybe like this:
class Base( var x : Int ) { def increment() { x = x + 1 } }
class Derived( noval x : Int ) extends Base( x ) { override def toString = x.toString }
val derived = new Derived( 1 )
println( derived.toString ) // yields '1', as expected
derived.increment()
println( derived.toString ) // still '2', as expected
The idiomatic way to avoid duplicating the field would be to write
However, in your version it looks like you actually want a second field, since you have two distinct values. As you correctly point out, giving these fields the same name is likely to lead to confusion.
Since you don’t actually need the constructor argument outside of the constructor, you could use this approach (a private constructor with a companion module that acts as a factory):