Search code examples
scalashapeless

Combine instances of 2 traits to form instance of third trait


Similar to Using shapeless scala to merge the fields of two different case classes Given the following traits

trait A {
  val a: String
}
trait B {
  val b: String
}

trait AB extends A with B

Is it possible to do something like this ?

val q = new A { val a = "a" }
val w = new B { val b = "b" } 
val e = combine(A, B) // Returns type AB

It seems like if it were all case classes then I could do it with shapeless Generic


Solution

  • This cannot be done by a normal function. With case classes, you know that you are merely storing values and that these values are already computed, they are not something like lazy val or def which can fail if you run them, and shapeless can build on top of this assumption to safely repack these values into some other structures, that are easy to combine.

    If you want to do the same with traits, and return some A with B you would have to basically build a macro that takes A instance, B instance, and combines them - which would have a lot of corner cases (like, what if both traits have the same methods/values names but of different result types? Or what if both have the same value with the same name - which should be used?).

    Unfortunately, I cannot find such macro anywhere, so it would have to be written. Most people would just merge these traits manually like this:

    val ab: A with B = new (A with B) {
      override val a: String = a.a
      override val b: String = b.b
    }