Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala overriding a non-abstract def with a var

In Scala I can do this:

trait SomeTrait {
  protected def foo: String
}

class Wibble extends SomeTrait {
  protected var foo = "Hello"
}

But I cannot do the same thing where I provide a default definition for foo

trait SomeTrait {
  protected def foo: String = "World"
}

class Wibble extends SomeTrait {
  protected var foo = "Hello" //complains about lack of override modifier

  override protected var foo = "Hello" //complains "method foo_ overrides nothing"
}

Why can't I do this?

EDIT: After a conversation on the scala-users mailing list, I have raised this in trac

like image 336
oxbow_lakes Avatar asked Sep 08 '09 09:09

oxbow_lakes


People also ask

When to use override scala?

Scala overriding method provides your own implementation of it. When a class inherits from another, it may want to modify the definition for a method of the superclass or provide a new version of it. This is the concept of Scala method overriding and we use the 'override' modifier to implement this.

How does override work in Scala?

In Scala, method overriding uses override modifier in order to override a method defined in the super class whereas, method overloading does not requires any keyword or modifier, we just need to change, the order of the parameters used or the number of the parameters of the method or the data types of the parameters ...


1 Answers

In Scala, when you write a var foo, the Scala compiler automatically generates a setter (called foo_=) and a getter (called foo) for it, and sets the field as private (you'll see it as private if you decompile a class having 'public' Scala fields with javap). That's what the 'method foo_= overrides nothing' error means. In your trait you haven't defined a foo_= method, and for a public field setter and getters always come in pairs.

If you do not provide a default value in the trait (i.e. abstract method), then the override keyword is not necessary. Therefore, in your first example, the getter overrides the abstract method and the setter... it just is there. The compiler doesn't complain. But when you provide an actual implementation of the method in the trait, you need to specifically write the override keyword when overriding. When writing protected var foo, you haven't specified the override keyword for the getter and when writing override protected var foo, you have also indicated to the compiler that method foo_= is to be overridden, but the trait has no such method.

Also, logically you cannot really override a def with a var (considering a strict view of overriding, like in the previous paragraph). A def is logically a function (you give it some input, it produces an output). A var is similar to a no-arg function, but also supports setting its value to something else, an operation which is not supported by a function. Instead, if you would change it to a val, it would be OK. It's like a function that always produces the same (cached) result.

If you want to have similar behaviour to a var you could do something like this (by having explicit setter and getters):

class Wibble extends SomeTrait {
  private var bar = "Hello"
  override protected def foo = bar
  protected def foo_=(v: String) { bar = v}
}

Now you can do anything you could do with a var :).

val x = new Wibble
println(x.foo) // yields "Hello"
x.foo = "Hello again"
println(x.foo) // yields "Hello again"
like image 149
Flaviu Cipcigan Avatar answered Sep 30 '22 11:09

Flaviu Cipcigan