This is a bit of a trick problem, because you can’t override the
getter and setter methods Scala generates for you, at least not if you
want to stick with the Scala naming conventions. For instance, if you
have a class named Person
with a
constructor parameter named name
, and
attempt to create getter and setter methods according to the Scala
conventions, your code won’t compile:
// error: this won't work
class
Person
(
private
var
name
:
String
)
{
// this line essentially creates a circular reference
def
name
=
name
def
name_=
(
aName
:
String
)
{
name
=
aName
}
}
Attempting to compile this code generates three errors:
Person.scala:3: error: overloaded method name needs result type def name = name ^ Person.scala:4: error: ambiguous reference to overloaded definition, both method name_= in class Person of type (aName: String)Unit and method name_= in class Person of type (x$1: String)Unit match argument types (String) def name_=(aName: String) { name = aName } ^ Person.scala:4: error: method name_= is defined twice def name_=(aName: String) { name = aName } ^ three errors found
I’ll examine these problems more in the Discussion, but the short
answer is that both the constructor parameter and the getter method are
named name
, and Scala won’t allow
that.
To solve this problem, change the name of the field you use in the
class constructor so it won’t collide with the name of the getter method
you want to use. A common approach is to add a leading underscore to the
parameter name, so if you want to manually create a getter method called
name
, use the parameter name _name
in the constructor, then declare your
getter and setter methods according to the Scala conventions:
class
Person
(
private
var
_name
:
String
)
{
def
name
=
_name
// accessor
def
name_=
(
aName
:
String
)
{
_name
=
aName
}
// mutator
}
Notice the constructor parameter is declared private
and var
. The private
keyword keeps Scala from exposing that
field to other classes, and the var
lets the value of the field be changed.
Creating a getter method named name
and a setter method named name_=
conforms to the Scala convention and
lets a consumer of your class write code like this:
val
p
=
new
Person
(
"Jonathan"
)
p
.
name
=
"Jony"
// setter
println
(
p
.
name
)
// getter
If you don’t want to follow this Scala naming convention for
getters and setters, you can use any other approach you want. For
instance, you can name your methods getName
and setName
, following the JavaBean style.
(However, if JavaBeans are what you really want, you may be better off
using the @BeanProperty
annotation,
as described in Recipe 17.6.)
When you define a constructor parameter to be a var
field, Scala makes the field private to
the class and automatically generates getter and setter methods that
other classes can use to access the field. For instance, given a simple
class like this:
class
Stock
(
var
symbol
:
String
)
after the class is compiled with scalac
, you’ll see this signature when you
disassemble it with javap
:
$ javap Stock
public class Stock extends java.lang.Object{
public java.lang.String symbol();
public void symbol_$eq(java.lang.String);
public Stock(java.lang.String);
}
You can see that the Scala compiler generated two methods: a
getter named symbol
and a setter
named symbol_$eq
. This second method
is the same as a method you’d name symbol_=
, but Scala needs to translate the
=
symbol to $eq
to work with the JVM.
That second method name is a little unusual, but it follows a
Scala convention, and when it’s mixed with some syntactic sugar, it lets
you set the symbol
field on a
Stock
instance like this:
stock
.
symbol
=
"GOOG"
The way this works is that behind the scenes, Scala converts that line of code into this line of code:
stock
.
symbol_$eq
(
"GOOG"
)
You generally never have to think about this, unless you want to override the mutator method.
As shown in the Solution, the recipe for overriding default getter and setter methods is:
Create a
private var
constructor parameter with a name you want to reference from within your class. In the example in the Solution, the field is named_name
.Define getter and setter names that you want other classes to use. In the Solution the getter name is
name
, and the setter name isname_=
(which, combined with Scala’s syntactic sugar, lets users writep.name = "Jony"
).Modify the body of the getter and setter methods as desired.
It’s important to remember the private
setting on your field. If you forget
to control the access with private
(or private[this]
), you’ll end up
with getter/setter methods for the field you meant to hide. For
example, in the following code, I intentionally left the private
modifier off of the _symbol
constructor parameter:
// intentionally left the 'private' modifier off _symbol
class
Stock
(
var
_symbol
:
String
)
{
// getter
def
symbol
=
_symbol
// setter
def
symbol_=
(
s
:
String
)
{
this
.
symbol
=
s
println
(
s
"symbol was updated, new value is $symbol"
)
}
}
Compiling and disassembling this code shows the following class signature, including two methods I “accidentally” made visible:
public
class
Stock
extends
java
.
lang
.
Object
{
public
java
.
lang
.
String
_symbol
();
// error
public
void
_symbol_$eq
(
java
.
lang
.
String
);
// error
public
java
.
lang
.
String
symbol
();
public
void
symbol_$eq
(
java
.
lang
.
String
);
public
Stock
(
java
.
lang
.
String
);
}
Correctly adding private
to
the _symbol
field results in the
correct signature in the disassembled code:
public
class
Stock
extends
java
.
lang
.
Object
{
public
java
.
lang
.
String
symbol
();
// println(stock.symbol)
public
void
symbol_$eq
(
java
.
lang
.
String
);
// stock.symbol = "AAPL"
public
Stock
(
java
.
lang
.
String
);
}
Note that while these examples used fields in a class constructor, the same principles hold true for fields defined inside a class.
Get Scala Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.