Most of the time, the Scala compiler is able to infer the generic type of some object or function for you. However, when it is unable to do so, it requires you to specify all of the generic arguments (since it will resolve the unknown generics to Nothing
, which I think is still fine).
The problem is when you want to avoid writing out possibly long types, for instance suppose we have the following and a function.
class ParsecE[S <: Stream[_, _], U, E, +A](/*args*/)
def pure[S <: Stream[_, _], U, E, A](a: =>A): ParsecE[S, U, E, A]
Now suppose we’ve got this function call somewhere pure[S, U, E, ParsecE[S, U, E, A]](atom)
. This is a bit long for my liking… for pure(atom)
the compile infers ParsecE[Nothing, Nothing, Nothing, ParsecE[S, U, E, A]]
so we are forced to add those generics. But the compiler got the last parameter correct! What would be nice is if we could write something like this instead; pure[S=S, U=U, E=E](atom)
.
An additional way this problem could be solved is by implicit generics; This requires a bit more work to implement however. Let’s redefine ParsecE
and pure
like so
class ParsecE[+A][implicit S <: Stream[_, _], U, E](/*args*/)
def pure[A][implicit S <: Stream[_, _], U, E](a: =>A): ParsecE[A] //S, U, E is implicit for ParsecE
Then, if we have the implicit types of S, U, E
defined somewhere, then the compiler can substitute them in, allowing us to write pure(atom)
or pure[ParsecE[A]](atom)
.
So where would the compiler look for these implicit generics? Well the first option would be if the enclosing class or method had generics of the same name defined and they were implicit (you can see this in the new definition of pure
in the return value). For example, the pure(atom)
call is within a method of the class ExpressionParser[S <: Stream[_, _], U, E, A]
. If this were defined as ExpressionParser[A][implicit S <: Stream[_, _], U, E]
then that provides all three types and they fit the constraints.
Alternatively we could declare implicit types in the same scope as the pure(atom)
call, like so;
implicit type S = Stream[String, Char]
implicit type U = Unit
implicit type E = Default
pure(atom) // A is inferable, that's no problem, then there is an implicit S, U, E in scope!
pure[ParsecE[A]](atom) // also valid, the S, U, E are implicitly available for both types!
Thoughts?