What are type projections in Scala useful for? Why does Scala's type system support both type projections and path dependent types? What was the rationale behind this design decision?