Herança e reutilização de código em traços empilháveis

Neste experimento simplificado, eu quero ser capaz de construir rapidamente uma classe com traços empilháveis ​​que possam relatar quais traços foram usados ​​para construí-la. Isso me lembra muito o padrão decorador, mas eu prefiro que isso seja implementado em tempo de compilação, e não em tempo de execução.

Exemplo de trabalho com código redundante

class TraitTest {
  def report(d: Int) : Unit = {
    println(s"At depth $d, we've reached the end of our recursion")
  }
}

trait Moo  extends TraitTest {
  private def sound = "Moo"
  override def report(d: Int) : Unit = {
    println(s"At depth $d, I make the sound '$sound'")
    super.report(d+1)
  }
}
trait Quack extends TraitTest {
  private def sound = "Quack"
  override def report(d: Int) : Unit = {
    println(s"At depth $d, I make the sound '$sound'")
    super.report(d+1)
  }
}

Executando(new TraitTest with Moo with Quack).report(0) então relataria:

> At depth 0, I make the sound 'Quack'
  At depth 1, I make the sound 'Moo'
  At depth 2, we've reached the end of our recursion 

Infelizmente, há um monte de código redundante lá que faz meu olho se contorcer. Minha tentativa de limpeza me leva a:

Exemplo não funcional sem código redundante

class TraitTest {
  def report(d: Int) : Unit = {
    println(s"At depth $d, we've reached the end of our recursion")
  }
}

abstract trait Reporter extends TraitTest {
  def sound : String
  override def report(d: Int) : Unit = {
    println(s"At depth $d, I make the sound '${sound}'")
    super.report(d+1)
  }
}

trait Moo extends Reporter {
  override def sound = "Moo"
}
trait Quack extends Reporter{
  override def sound = "Quack"
}

Quando mais uma vez executamos(new TraitTest with Moo with Quack).report(0), agora vemos:

> At depth 0, I make the sound 'Quack'
  At depth 1, we've reached the end of our recursion

Questão 1: Para onde foi a linha de 'Moo'?

Eu estou supondo que Scala só vêoverride def report(d: Int) a um tempo e, portanto, só o coloca na cadeia de herança uma vez. Estou me agarrando a palhas, mas se for esse o caso, como posso trabalhar com isso?

Questão 2: Como cada característica concreta pode fornecer umasound?

Depois de resolver a primeira pergunta, presumo que os resultados da execução(new TraitTest with Moo with Quack).report(0) seria algo parecido com o seguinte, devido a como a herança desound trabalharia.

> At depth 0, I make the sound 'Quack'
  At depth 1, I make the sound 'Quack'
  At depth 2, we've reached the end of our recursion  

Como podemos fazer com que cada traço use osound especificado em sua implementação?

questionAnswers(3)

yourAnswerToTheQuestion