ZIO, fs2 and other libraries found out that a natural encoding in Scala relies on multiple type parameters with variance (I believe John called this effect rotation):
- ZIO[-R, +E, +A]
- fs2.Stream[F[_], +A]
- Optic[+E, -S, +T, +A, -B] or even more type parameters if include index optics
With this encoding, we can express the absence of error (E = Nothing), absence of effect (F = Nothing), absence of environment variables (R = Any) and all this with perfect type inference. So it is a big win on all fronts except for function signatures and error messages. As we can end-up with an Optic[Nothing, User, User, String, String] instead of Lens[User, String] or ZIO[Any, Nothing, Int] instead of UIO[A]. Type aliases help a little bit, but they often get lost.
Define a set of rules for the compiler to use the most "precise" type alias in type inference and error messages.
Proposed locations to look for type aliases:
- package object (Scala 3: package scope)
- companion object
How do we define the most "precise" type alias?
We can use the number of type parameters, e.g. Foo
is more precise than Bar[_]
which is more precise than Fizz[_, _]
.
It is not clear how variance should influence the ranking or how should we deal with tie, e.g.
is Foo[+_]
more precise than Bar[_]
or Fizz[-_]
?
Dotty but could be backported to Scala 2.