10

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!

1
  • The compiler seems to think I'm overriding a variable: if I remove the super.name statement from the getter, I get this error message: "overriding variable name in class SuperFoo of type String; method name cannot override a mutable" Commented Dec 28, 2012 at 12:23

1 Answer 1

6

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:

  1. Favor composition over inheritance (a classic).
  2. Change the variable name, make it private and write accessor in the super-class (see below).
  3. 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 } } } 
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks- I was trying to avoid option 2 and use your option 1 somehow (option 3 is out of the question due to reflection). However, option 1 does not compile even if the property is not a string, try with Int and you'll see what I mean. Scalac thinks that you're trying to override the 'name' field for some reason... Any ideas how to get option 1 working with eg an Int?
I added option 1 solution. Following GoF guidelines, the decorator design pattern allows to add a behavior to an existing implementation.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.