1

Scala Compiler giving error where trying to run following program.

Error:(19, 8) class Logging inherits conflicting members:
  method log in trait TimestampLogger of type (msg: String)Unit  and
  method log in trait ShortLogger of type (msg: String)Unit
(Note: this can be resolved by declaring an override in class Logging.)
class Logging extends   TimestampLogger with ShortLogger
      ^
trait ShortLogger  {
  def log (msg: String) {println(msg)}


trait TimestampLogger  {
   def log (msg: String) {
    println("We are in Timestamp Logger")
    println(new java.util.Date() )
  }
}
class Logging extends   TimestampLogger with ShortLogger
val a = new Logging
a.log("Log Message")

Why Stackable Modification in scala traits not suggesting the correct log method? Why are we getting compilation error?

Koterpillar
  • 7,883
  • 2
  • 25
  • 41
Deepak Garg
  • 149
  • 1
  • 10
  • Why do you need `TimestampLogger` if it isn't going to do anything? Why not just `Logging extends ShortLogger`? – Tim Feb 13 '21 at 09:27
  • Hi @Tim This is just example to understand multiple inheritance – Deepak Garg Feb 13 '21 at 09:31
  • Scala does not support multiple inheritance, it supports a linear inheritance hierarchy. Have a look at some of the tutorials on this if you want to understand it better. – Tim Feb 13 '21 at 09:34
  • Not quite. Scala support inheriting multiple `trait`s, it performs trait linearization, but it _is_ considered a multiple inheritance. Scala (2) doesn't support inheriting from multiple `class`es. Then if you have a `trait` extend a class you can mix it in. – Mateusz Kubuszok Feb 13 '21 at 09:45
  • @MateuszKubuszok Each class has a single superclass so I would call that single inheritance. And a class does not inherit from multiple traits; each trait inherits from the previous one. – Tim Feb 13 '21 at 10:18
  • 1
    Correction: each _runtime_ bytecode class has a single superclass because that's a JVM limitation. In compile time each class might have at most one class and several trait parent. Trait linearization only affects the diamond problem (how conflicts are resolved). Type system doesn't distinct `A with B` from `B with A`. You can have multiple parents in the definition and that fulfills the definition of multiple inheritance. – Mateusz Kubuszok Feb 13 '21 at 11:22

1 Answers1

2

The error here is as message says lack of overrides.

You cannot have 2 different implementations of a method with the same signature. You have to resolve it. With traits you can have one implementation override another - this is actually required to perform trait linearization. But to be able to override you have to prove that overrides are about the same method. One way to fix it is to let methods override some base member. It always picks the "last" implementation.

trait Logger { def log(msg: String): Unit = () }

trait ShortLogger extends Logger {
  override def log(msg: String) = println(msg)
}

trait TimestampLogger extends Logger {
  override def log(msg: String): Unit = {
    println("We are in Timestamp Logger")
    println(new java.util.Date() )
  }
}

// last override "wins" => ShortLogger implementation will be used
class Logging1 extends TimestampLogger with ShortLogger

// last override "wins" => TimestampLogger implementation will be used
class Logging2 extends ShortLogger with TimestampLogger

If you don't want to use last-wins, you have to reimplement the method in the place where they are conflicting:

class Logging extends TimestampLogger with ShortLogger {
  override def log(msg: String) = ...
}

If you wanted to have both functionalities you would have to use a former approach + super

trait Logger { def log(msg: String): Unit = () }

trait ShortLogger extends Logger {
  override def log(msg: String) = {
    super.log(msg)
    println(msg)
  }
}

trait TimestampLogger extends Logger {
  override def log(msg: String): Unit = {
    super.log(msg)
    println("We are in Timestamp Logger")
    println(new java.util.Date())
  }
}

// both will perform both loggings, but in a different order
class Logging1 extends TimestampLogger with ShortLogger
class Logging2 extends ShortLogger with TimestampLogger
Mateusz Kubuszok
  • 24,995
  • 4
  • 42
  • 64
  • Interestingly, it you make the base method abstract and remove the `override` specifier (which is perfectly legal) you get the same error message... – Tim Feb 13 '21 at 10:23
  • I have raised a [separate question](https://stackoverflow.com/questions/66184225/why-is-override-sometimes-required-for-an-abstract-method) about the need to specify `override` even if it is not normally required. – Tim Feb 13 '21 at 10:48