wen
wen

Reputation: 3848

What am I doing wrong? (With Scala's superclass parameters)

I have an parent class, and several child classes. What I want is when specific setter methods are called on instances of the child classes, a boolean value for "is synchronized" in the parent class is set to false. It should be possible to create child classes in either a synchronized or an unsynchronized state.

This is what I came up with:

class A(protected var isSync: Boolean) {
}
class B(var value:String, isSync: Boolean) extends A(isSync) {
  override def value_=(value:String): Unit = {
    this.isSync = false
    this.value = value
  }
}

Now, this doesn't compile for a number of reasons: the assignment of value to this.value is ambiguous; the var annotation already defines value_=; and this.isSync references the local constructor field isSync, instead of the (writable) parent field.

This question on Stack Overflow pointed out that I should use __value (or any name that isn't value) as a private var in the constructor, and define the setter myself. After some more tinkering, I came up with the following code that compiles and works:

class A(protected var isSync: Boolean) {
}
class B(private var __value: String, private val __isSync: Boolean)
    extends A(__isSync) {
  def value = __value
  def value_=(value: String) = {
    this.isSync  = false
    this.__value = value
  }
}

However, this code feels so rancid that by now I suspect I'm making a (if not more) fundamental mistake. Could anyone please correct me?

Thus the concrete questions are:

  1. Are there (and if, which) fundamental flaws in what I'm trying to implement? For some context: the objects, when changed, can (and probably have to) be synchronized with a server.
  2. What is the right/best way to pass parameters to a class you extend?
  3. What is the right/best way to override the setter generated by var (or generally provide your own setter implementation)?

Upvotes: 1

Views: 520

Answers (1)

Blaisorblade
Blaisorblade

Reputation: 6488

About question 1: I guess that you want to track whether the object has been changed since last time it was copied to the server, don't you? That's sensible, as long as the copy on the server cannot be modified: otherwise ensuring consistency of the replica is more complex (replica consistency is the keyword for googling, but I wouldn't recommend it). For clarity, I would talking about being clean or dirty - synchronized reminds me too closely of the synchronized Java statement.

About question 2, you don't need to make __isSync a private val (which will be stored in the class), you can leave it as a constructor parameter. As long as it is not used (other than in the invocation of A's constructor) __isSync should not take additional space in instances of B. I removed the private val annotation there, obtaining this code which compiles correctly as expected.

class A(protected var isSync: Boolean) {
}
class B(private var __value: String, __isSync: Boolean)
    extends A(__isSync) {
  def value = __value
  def value_=(value: String) = {
    this.isSync  = false
    this.__value = value
  }
}

About aesthetics and question 3: I would simply avoid the double underscore. Similar examples from Programming in Scala (Sec 18.2) simply use shorter names. They also use private[this] to prevent access to the member from other instances of the same class. Finally, you can remove {} after the class decl. in this example (even if maybe not in your code).

Thus we'd get code like this, which is close to the examples I already mentioned:

class A(protected var isSync: Boolean)
class B(private[this] var v: String, sync: Boolean)
    extends A(sync) {
  def value = v
  def value_=(value: String) = {
    isSync  = false
    v = value
  }
}

Upvotes: 3

Related Questions