Description
Motivation
Generic programming often exhibits scenarios where an implicit expansion would diverge, were it not for a lazy implicit value that "ties the knot". Current Shapeless has the Lazy
pseudo-type to handle this using some tricky macro machinery. Following an idea of @milessabin it seems cleaner to put this in the language and tie it to by-name implicit parameters.
Status Quo
By-name implicit parameters are disallowed in Scala-2. They have been introduced recently in dotty, but without attaching special meaning to them.
Proposal
Modify implicit search as follows:
When searching for an implicit value of type T
to provide an argument for a by-name parameter of type => T
:
-
Create a new implicit value with a fresh name lv, which has the signature of the following definition:
implicit lazy val lv: T
The current implementation uses the prefix
$lazy_implicit$
followed by a unique integer for lv. -
This lazy val is not immediately available as candidate for implicit search (making it immediately available would result in a looping implicit computation). But it becomes available in all nested contexts that look again for an implicit argument to a by-name parameter.
-
If this implicit search succeeds with expression
E
, andE
contains references to the lazy implicit value lv, replaceE
by{ implicit lazy val lv: T = E; lv }
Otherwise, return
E
unchanged.
Implementation Status
This proposal has been implemented in #1993. The test cases in that PR starting with
lazy-implicits-... . scala
show where the feature is useful. All these test cases would have given a diverging implicit expansion before the change.