Understanding the Aux pattern in Scala Type System

scala, shapeless

Solution

Imagine a typeclass for getting the last element of any tuple.

trait Last[A] {
  type B
  def last(a: A): B
}

object Last {
  type Aux[A,B0] = Last[A] { type B = B0 }

  implicit def tuple1Last[A]: Aux[Tuple1[A],A] = new Last[Tuple1[A]] {
    type B = A
    def last(a: Tuple1[A]) = a._1
  }

  implicit def tuple2Last[A,C]: Aux[(A,C),C] = new Last[(A,C)] {
    type B = C
    def last(a: (A,C)) = a._2
  }

  ...
}

The type `B` always depends on the type `A`, that's why `A` is an input type of the typeclass and `B` is an output type.

Now if you want a function that can sort any list of tuples based on the last element you need access to the `B` type in the same argument list. That's the main reason, in the current state of Scala, why you need the `Aux` pattern: currently it's not possible to refer to the `last.B` type in the same parameter list as where `last` is defined, nor is it possible to have multiple implicit parameter lists.

def sort[A,B](as: List[A])(implicit last: Last.Aux[A,B], ord: Ordering[B]) = as.sortBy(last.last)

Of course you can always write `Last[A] { type B = B0 }` out in full, but obviously that becomes very impractical very quickly (imagine adding a couple more implicit parameters with dependent types, something that's very common with Shapeless); that's where the `Aux` type alias comes in.

Problem

This question may be asked and answered before, but I would like to understand this with an example and I could not reason out where the Aux pattern might be helpful! So here is the trait: ``` trait Foo[A] { type B def value: B } ``` Why do I have a type that is kind of bound to the return type of the value function? What do I achieve doing this? In particular, where would I use such patterns?

Original source