Let's say we have a class with a 'name' property:
class SuperFoo(var name: String)
If I wish to override this, to eg add some locking around the calls:
class SubFoo(n: String) extends SuperFoo(n) {
val lock = new ReentrantLock
override def name(): String =
{
lock.lock
try {
super.name
} finally {
lock.unlock
}
}
override def name_=(arg: String): Unit = {
lock.lock
try {
super.name = arg
} finally {
lock.unlock
}
}
}
The above produces a compilation error:
super may be not be used on variable name
Any ideas how to correctly implement this? (i.e. override the getter & setter to add locking around them). Thanks!
Here you need to refer directly to the super class setter/getter. Normally you should write something like:
class SubFoo(n: String) extends SuperFoo(n) {
val lock = new ReentrantLock
override def name(): String =
{
lock.lock
try {
super.name()
} finally {
lock.unlock
}
}
override def name_=(arg: String): Unit = {
lock.lock
try {
super.name_=(arg)
} finally {
lock.unlock
}
}
}
However, if the setter will compile without any problem, the getter won't because the compiler will view it as super.name.apply()
(Strings can get this method through implicit conversions).
I see several options:
- Favor composition over inheritance (a classic).
- Change the variable name, make it private and write accessor in the super-class (see below).
- Resort to reflection/manual name umangling voodoo.
I'll go for option #1, but here is code for option #2:
class SuperFoo( private var nameVar: String) {
def name: String = nameVar
def name_=(arg: String): Unit = nameVar = arg
}
class SubFoo(n: String) extends SuperFoo(n) {
val lock = new ReentrantLock
override def name(): String =
{
lock.lock
try {
super.name
} finally {
lock.unlock
}
}
override def name_=(arg: String): Unit = {
lock.lock
try {
super.name = arg
} finally {
lock.unlock
}
}
}
EDIT: Here is a workable implementation of option #1:
trait Foo {
def name: String
def name_=(arg: String): Unit
}
class SimpleFoo( var name: String) extends Foo
class LockedFoo(foo: Foo) extends Foo {
val lock = new ReentrantLock
def name(): String =
{
lock.lock
try {
foo.name
} finally {
lock.unlock
}
}
def name_=(arg: String): Unit = {
lock.lock
try {
foo.name = arg
} finally {
lock.unlock
}
}
}