Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I assign to var in Scala subclass?

Suppose I have the following abstract class:

abstract class A (var is_happy : Boolean) {
  def toggle_happiness();
}

And now I want to define a concrete class which implements the toggle_happiness() method:

class B (is_happy : Boolean) extends A (is_happy) {
  def toggle_happiness() = {
    is_happy = !is_happy
  }
}

Scala's compiler gives me:

error: reassignment to val
   is_happy = !is_happy
            ^

What's going on here? I thought that is_happy referred to a var in my class that is set by my constructor. Do I have a conflict with the name is_happy?

Thanks, Dan

like image 714
Dan Barowy Avatar asked Jul 11 '11 21:07

Dan Barowy


2 Answers

See this question. Essentially, Scala thinks that you're trying to assign to the constructor parameter, is_happy, rather than the var, is_happy, which just happens to have the same name. Some solutions are to:

  • Make the var abstract in the base class.
  • Rename the constructor parameter (e.g. _is_happy). Since parameter names are part of the public API of your constructors/methods, this may not be advisable.

You're fortunate that the problem was detected at compile time in your case. This issue can lead to very surprising runtime behavior when it goes undetected.

like image 178
Aaron Novstrup Avatar answered Nov 07 '22 14:11

Aaron Novstrup


There is another simple solution. One that only requires to modify B (no need to change the base class) and won't modify the interface (no parameter renaming). Just introduce a private method that returns this, and explicitly dereference this:

class B (var is_happy : Boolean) extends A {
  private def self = this
  def toggle_happiness() = {
    self.is_happy = !self.is_happy
  }
}

Note that this work around is localized to B. Everywhere else (included in derived classes) you can keep using just is_happy (no need for self.is_happy).


As a side note, we should really be able to directly dereference this, as in this.is_happy (instead of adding the self method and doing self.is_happy). But for some reason the compiler will blindly treat this.is_happy the same as is_happy, so we get back to square one and this.is_happy actually still point to B's parameter rather than A's variable. This very much looks like a compiler bug to me.

like image 1
Régis Jean-Gilles Avatar answered Nov 07 '22 13:11

Régis Jean-Gilles