I'm sure it's a duplicate, but I couldn't find it.
Consider this class
class Test1(var param: Int)
Scala generates a getter and a setter, and makes the param private.
It can be shown using javap for example:
public class Test1 {
private int param;
public int param();
public void param_$eq(int);
public Test(int);
}
I was trying to write the desugared version of it with explicit getters / setters but couldn't do so 100% the same way as the private var had a naming collision with the getter.
class Test2(private[this] var param:Int) {
def param:Int = this.param
def param_= (param:Int) {this.param = param}
}
This is the error:
ambiguous reference to overloaded definition,
both method param in class Test2 of type => Int
and variable param in class Test2 of type Int
match expected type Int
def param:Int = param
^
This of course works (renaming private member to _param
)
class Test3(private[this] var _param:Int) {
def param:Int = this._param
def param_= (param:Int) {this._param = param}
}
But generates this slightly different bytecode of course (since we had to rename param
to _param
):
public class Test3 {
private int _param;
public int param();
public void param_$eq(int);
public Test3(int);
}
Is there any way to reach the same bytecode as the example in Test1
while using explicit getter / setters as in Test2
?
In Scala methods and fields share the same name space. This is a little confusing for converts coming from Java or other languages which have separate name space for each.
But it follows the Uniform Access Principle i.e. the user of a class can't tell if he is actually calling a def or a val (or a var) when used without parenthesis. This also means you can switch implementations between val an def without clients being affected. (I'm not sure if they'd have to get recompiled, but the source code can stay as it is.
Actually, you can!
Here is an answer that does exactly that to good effect.
There you will find a private var and an accessor with the same name.
private[this] var state
private final def state()
Note the parens on the definition of the accessor, which are not needed at the use site.
Under the covers, the local field has that LOCAL_SUFFIX_STRING, which is an evil space. See the Test3
members, below, which strips away the covers to bare all.
On the getter side, you can add parens. That breaks the saccharin setter, apparently. Can you live without sugary assignment syntax?
When you reference x.param
, the compiler will supply parens, see @alexiv 's comment elsewhere on uniform access or the SO answer mentioned above.
import reflect.runtime.currentMirror
import reflect.runtime.universe._
class Test2(private[this] var param: Int) {
def param(): Int = param
def param_=(param: Int) { this.param = param }
}
val x = new Test2(1)
Console println x.param
x.param_=(2)
Console println x.param
class Test3(var param: Int)
val ps = typeOf[Test3].members filter (m => m.name.toString.startsWith("param")) map (m => s"'${m.name.toString}'")
Console println ps
Console println (typeOf[Test3].members filter (_.name.toString.endsWith(nme.LOCAL_SUFFIX_STRING)))
Note that the other answers suggest that Scala only distinguishes terms and types, neglecting to mention that symbols (obviously) can be overloaded.
You may have read that overloading is evil! That may be so, but whatever you do in the privacy of your own private members is entirely your own affair.
(Updated to suggest that even if the question is somewhat duplicated somewhere, this is still a fun and informative answer.)
I think variable and method are treated the same, the variable param is like a method without parameters, and the method param is the same, so just like the error indicates: ambiguous reference to overloaded definition.