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
}
}
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.