tags:

views:

588

answers:

1

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

+7  A: 

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"

-- Flaviu Cipcigan

Flaviu Cipcigan
Sorry - I made an error - the original trait method should have been protected also. I'm not sure I agree with you about logically being unable to override a `def` with a `var`. All my `def` is saying is that I expect there to be an accessor called `foo` which returns a String - declaring a `var` is an implementation of this
oxbow_lakes
I think I agree with you. I was thinking of overriding as a stricter notion when I wrote the answer. I'll edit the answer, and provide a workable solution :).
Flaviu Cipcigan
It's a shame there's not an `override def as var` syntax
oxbow_lakes