2
votes

I have following structure:

trait Runner {
  def run: Unit
}

trait LoggableRunner extends Runner {
  abstract override def run {
    println("logging enter")
    super.run
    println("logging exit")
  }
}

class RealRunner extends Runner {
  def run = println("running...")
}

This way I can enrich my class with logging in the following way:

val a = new RealRunner with LoggableRunner

Which adds log info before and after running the run method.

Now what I really want to have is to be able to compose scala object with traits. I have tried the same way:

object RealRunner extends LoggableRunner{
  def run = println("running...")
}

But I get: method run needs override modifier

So I tried:

 object RealRunner extends LoggableRunner{
      override def run = println("running...")
    }

But I get: method run needs abstract override modifiers. So I tried again with adding abstract and I got: abstract override modifier only allowed for members of traits.

Is mixing traits into objects even possible?

1
Hmmm, I don't know why it does that, but you can do what you want in two steps: first define a class class RealRunner extends Runner { def print = {...} }, and then: object RealRunner extends RealRunner with LoggableRunner. - Dima
Such a crazy use-case :) - Nikita
@Dima this approach seems to work but has one drawback - since the print method is in class and not in the object, but the LoggableRunner trait is extending the object, I cannot use anything that LoggableRunner could provide me in my print method - imagine e.g. defining val logLevel = "ERR" in LoggableRunner - how could I access it in my print method? - NNamed
See also this answer: stackoverflow.com/a/7499763/74631. - devkat

1 Answers

1
votes

I am not sure why it behaves this way (does indeed seem weird and confusing, hopefully, someone with more clue would chip in, and shed some light of reason on this), but here is how you can do what you want:

trait Runner {
  def run = () // making it non-abstract, makes things a lot easier!
}

trait LoggableRunner extends Runner {
  override def run = { 
      println("start")
      super.run
      println("stop")
  }
  def foo = "foo"
}

trait RealRunner extends Runner { self: LoggableRunner => 
   override def run = println(foo) // uses things from LoggableRunner
}

object RealRunner extends RealRunner with LoggableRunner 

scala> RealRunner.run
start
foo
stop

Woo-hoo!