Search code examples
apiscalashapeless

Pattern behind shapeless Aux classes


While studying shapeless and spray libraries, i've seen many inner Aux types, traits, objects and classes. It's not hard to understand that it is used for augmenting existing internal API, it looks much like a "companion object pattern" for factories and helper method. Example from HList sources:

trait Length[-L <: HList] {
  type Out <: Nat
  def apply() : Out
}

trait LengthAux[-L <: HList, N <: Nat] {
  def apply() : N
}

object Length {
  implicit def length[L <: HList, N <: Nat](implicit length : LengthAux[L, N]) = new Length[L] {
    type Out = N
    def apply() = length()
  }
}

object LengthAux {
  import Nat._

  implicit def hnilLength = new LengthAux[HNil, _0] {
    def apply() = _0
  }

  implicit def hlistLength[H, T <: HList, N <: Nat](implicit lt : LengthAux[T, N], sn : Succ[N]) = new LengthAux[H :: T, Succ[N]] {
    def apply() = sn
  }
}

Solution

  • In the case of Length for instance, the Length trait is the shape we are hoping to end up with, because it conveniently has the length encoded as a member, but that isn't a convenient form doing an implicit search. So an "Aux" class is introduced which takes the result parameter, named Out in the Length trait, and adds it to the type parameters of the LengthAux as N, which is the length. Once this result parameter is encoded into the actual type of the trait, we can search for LengthAux traits in implicit scope, knowing that if we find any with the L we are searching for, that this type will have the correct length as the N parameter.