1

Scala code:

trait Logger {
  def log(msg: String)
}

trait TimeLogger extends Logger {
  def log(msg: String) = super.log(new Date + ": " + msg)
}

class MyApp extends TimeLogger {
  override def log(msg: String): Unit = println(msg)

  log("Hello")
}

new MyApp()

When I compile it, it reports error:

Error:(12, 34) method log in trait Logger is accessed from super. It may not be abstract unless it is overridden by a member declared `abstract' and `override'
    def log(msg: String) = super.log(new Date + ": " + msg)
                                 ^

I'm not quite understand it, why should I declared an abstract and override log method? How to fix it?

Freewind
  • 193,756
  • 157
  • 432
  • 708
  • See also: http://stackoverflow.com/questions/23645172/why-is-abstract-override-required-not-override-alone-in-subtrait – Freewind Aug 07 '15 at 01:57

4 Answers4

3

Scala traits, in the manner you're using Log are essentially interfaces, i.e. specifications of behavior. So your types

trait Logger {
  def log(msg: String)
}

trait TimeLogger extends Logger {
  def log(msg: String) = super.log(new Date + ": " + msg)
}

are saying that an instance of a Logger will provide it's own implementation of log(msg: String). Since 'log' is not implemented in Logger, it's impossible to call it with super..

However, if you were to call super.log from MyApp then it would exercise the TimeLogger.log call.

Chris
  • 2,885
  • 18
  • 25
1

As far as I see, you don't have an implementation of log in your Logger trait. By calling super.log from TimeLogger, you are calling an unimplemented method.

It seems you are attempting to override a method, but not completely define it. You cannot call the method you are overriding from its own implementation (unless you want recursion). Instead of calling super.log, which is not implemented, I believe you actually want to call the implementation of the logging from a child class. You certainly cannot use the same function prototype for both.

Perhaps you could define TimeLogger and MyApp in the following way:

trait TimeLogger extends Logger {
  def logImpl(msg: String)
  def log(msg: String) = logImpl(new Date + ": " + msg)
}

class MyApp extends TimeLogger {
  override def logImpl(msg: String): Unit = println(msg)

  log("Hello")
}
Zoltán
  • 21,321
  • 14
  • 93
  • 134
1

Correct me if I'm wrong, but I think you are trying to decorate the log function of any logger implementation with a timestamp.

As a result you would like to use the TimeLogger trait as a Decorator for Logger implementations that delegate to say println, Log4j, maybe even android.Log.

There are two ways (I can think of) how you can achieve something like that:

1)

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

class PrintStreamLogger extends Logger {
  def log(msg: String): Unit = println(msg)
}

abstract class TimeLogger(loggerImpl: Logger) extends Logger {
  def log(msg: String): Unit = loggerImpl.log(new Date + ": " + msg)
}

class MyApp extends TimeLogger(new PrintStreamLogger) {
  log("Hello")
}

2)

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

  protected def logImpl(msg: String): Unit
}

trait TimeLogger {
  loggerImpl: Logger =>
  override def log(msg: String): Unit =
    loggerImpl.logImpl(s"${new Date}: $msg")
}

class MyApp extends Logger with TimeLogger {
  protected def logImpl(msg: String): Unit = println(msg)
  log("Hello")
}
Sascha Kolberg
  • 7,092
  • 1
  • 31
  • 37
0

I have another way to fix it by creating a trait PrintLogger which extends Logger, and then mix both of them in MyApp:

trait Logger {
  def log(msg: String)
}

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

trait TimeLogger extends Logger {
  abstract override def log(msg: String) = super.log(new Date + ": " + msg)
}

class MyApp extends PrintLogger with TimeLogger {
  log("Hello")
}

new MyApp()
Freewind
  • 193,756
  • 157
  • 432
  • 708
  • This solution is quite hacky. Your `TimeLogger` trait **requires** an intermediate parent which **implements** logger, even though its declaration does not specify so. The class `MyApp` wouldn't even compile had you reversed the order of the extended traits. When you require an implementation of a trait, it is much better to use the cake pattern in a similar way Sascha Kolberg does in his answer. – Zoltán Aug 05 '15 at 17:11