4
trait Base {
  def someMethod: Unit
}

trait SomeTrait extends Base {
  abstract override def someMethod: Unit = ???
}

class SomeTraitImp extends SomeTrait with Base {
  override def someMethod: Unit = ???
}

Error message states:

Error: overriding method someMethod in trait SomeTrait of type => Unit; method someMethod needs `abstract override' modifiers override def someMethod: Unit = ???

Why Scala compiler restricts me from overriding this method without marking it as an abstract?

Edit:

I checked this answer and it explains why abstract keyword required on method when we reference to super which may not have implementation yet.

In my case I'm just trying to override someMethod in SomeTrait by brand new implementation and not trying to call super.someMethod.

Is this override can break something at runtime?

Bogdan Vakulenko
  • 3,380
  • 1
  • 10
  • 25
  • 1
    Possible duplicate of [Why is "abstract override" required not "override" alone in subtrait?](https://stackoverflow.com/questions/23645172/why-is-abstract-override-required-not-override-alone-in-subtrait) – Dmytro Mitin Apr 12 '19 at 07:49
  • Can you let us know which Scala version you are using, and give some real code that shows this error? – Tim Apr 12 '19 at 08:19
  • @Tim scala 2.12.7. this is the real code that shows the error. – Bogdan Vakulenko Apr 12 '19 at 08:21

1 Answers1

6

If you have abstract override, it must override a concrete implementation for the whole thing to become concrete.

This works:

trait Foo extends Base { def someMethod: Unit = ??? }
class SomeTraitImp extends Foo with SomeTrait 

Because SomeTrait.someMethod overrides a concrete implementation in Foo. This does not:

class SomeTraitImp extends SomeTrait with Foo

Because a concrete method in Foo is trying to override an abstract override in SomeTraitImpl.

Your example is essentially the same as last snippet, except your override is in the class itself rather than in Foo.

And to answer your last question, yes, this would break at runtime if it was allowed. Consider this:

 trait Foo { def foo: String }
 trait Bar extends Foo { abstract override def foo = super.foo + "bar" }
 class Baz extends Foo with Bar { override def foo = super.foo + "baz" }

 println(new Baz().foo)

If this compiled, it would trow an exception at runtime, because super.foo in Baz calls Bar's foo, which calls super.foo, which refers to Foo.foo, which is abstract.

Bogdan Vakulenko
  • 3,380
  • 1
  • 10
  • 25
Dima
  • 39,570
  • 6
  • 44
  • 70
  • The question is why override _without a `super` call_ is unsafe. – Alexey Romanov Apr 12 '19 at 11:36
  • @Dima and what if we don't have `super.foo` call in Baz. Only `def foo = "baz" ` ? Is it still unsafe? – Bogdan Vakulenko Apr 12 '19 at 12:58
  • @Dima and also question abut this `class SomeTraitImp extends SomeTrait with Foo`. Here we have `SomeTrait` containing abstract implementation overriding concrete implementation in `Foo` so I supposed that as we have concrete implementation we can say that whole `SomeTraitImp` is concrete because abstract method can call non-abstract code if needed. – Bogdan Vakulenko Apr 12 '19 at 14:19
  • 1
    @BogdanVakulenko It is not _actually_ unsafe without the `super` call, but the idea is that you _declare_ a method as `abstract override` to say "this trait must be overriding a concrete implementation". Just like you cannot instantiate an abstract class, even if it has no actual abstract members. – Dima Apr 12 '19 at 15:07
  • 1
    In `class SomeTraitImp extends SomeTrait with Foo`, `SomeTrait` does _not_ override implementation of `Foo` (it goes left to right, so `Foo` overrides `SomeTrait`, the other way around), `SomeTrait`'s super in this case is `Base`. – Dima Apr 12 '19 at 15:11
  • @Dima just last question. Let's say I have traits `A` and `B`. And I'm creating `val` like this `val v = new A with B { ... } `. Can I say that this block `{ ... }` is the same as if I could write something like this `val v = new A with B with { ... } ` . Kind of anonymous class or trait with all linerization/overriding rules applied as if I create this trait separately and then join it as regular trait? – Bogdan Vakulenko Apr 12 '19 at 15:47
  • `A with B { ... }` is the same as `class C extends A with B { ... }`, if that's what you are asking. – Dima Apr 12 '19 at 17:38