0

I want to build a list from items provided by individual traits. I can do this using stackable traits for this purpose:

  trait StackableBuilder {
    def build: Seq[String] = Seq.empty
    def buildAll: Seq[String] = build
  }

  trait BuildA extends StackableBuilder {
    abstract override def build = super.build :+ "A"
  }

  trait BuildB extends StackableBuilder{
    abstract override def build = super.build :+ "B"
  }

  object AB extends StackableBuilder with BuildA with BuildB
  println(AB.buildAll)

Still, I would like to improve this a bit, so that each partial builder does not have to repeat the super.build call, something along the lines:

  trait StackableBuilder {
    def build: String

    def buildAll: Seq[String] = ???
  }

  trait BuildA extends StackableBuilder {
    def build = "A"
  }

  trait BuildB extends StackableBuilder {
    def build = "B"
  }

  object AB extends StackableBuilder with BuildA with BuildB
  println(AB.buildAll)

Now this does not compile, the error is "object AB inherits conflicting members", and even if it did, still the part ??? needs to be filled.

Is it possible somehow to define stackable traits so that the stacking using super calls does not have to be done by the individual traits, perhaps introducing some helper trait and method, perhaps a bit like How to call super method when overriding a method through a trait?

Suma
  • 33,181
  • 16
  • 123
  • 191
  • I don't have an answer to your question, but I have a strong feeling it's not possible, and I have a suggestion to not go down that road (even if you do manage to find a magical workaround to make the conflicting `build` members from A and B play along nicely). Stackable trait pattern is perfect for what you need, and its most important feature is using `abstract override` that calls super and decorates it. I'd stick with your initial version. – slouc Sep 20 '17 at 10:56

1 Answers1

0

One improvement is to separate the default functionality into another trait, which then reminds the user of the trait to call super by forcing him to use abstract override. Using plain override was possible without an error in the code in the question.

  trait StackableBuilder {
    def build: Seq[String]
  }

  trait StackableBuilderRoot extends StackableBuilder {
    override def build: Seq[String] = Seq.empty
    def buildAll: Seq[String] = build
  }

  trait BuildA extends StackableBuilder {
    abstract override def build = super.build :+ "A"
  }

  trait BuildB extends StackableBuilder{
    abstract override def build = super.build :+ "B"
  }

  object AB extends StackableBuilderRoot with BuildA with BuildB
  println(AB.buildAll)
Suma
  • 33,181
  • 16
  • 123
  • 191