|
| 1 | +# Implicit By-Name Parameters |
| 2 | + |
| 3 | +Call-by-name implicit parameters can be used to avoid a divergent implicit expansion. |
| 4 | + |
| 5 | +```scala |
| 6 | +implicit def serializeOption[T](implicit ev: => Serializable[T]): Serializable[Option[T]] = |
| 7 | + new Serializable[Option[T]] { |
| 8 | + def write(x: Option[T], out: DataOutputStream) = t match { |
| 9 | + case Some(x) => ev.write(x) |
| 10 | + case None => |
| 11 | + } |
| 12 | + } |
| 13 | + |
| 14 | + val s = serializeOption[Option[Int]] |
| 15 | + s.write(Some(33)) |
| 16 | + s.write(None) |
| 17 | +``` |
| 18 | +As is the case for a normal by-name parameter, the argument for the implicit parameter `ev` |
| 19 | +is evaluated on demand. In the example above, if the option value `x` is `None`, it is |
| 20 | +not evaluated at all. |
| 21 | + |
| 22 | +The synthesized argument for an implicit parameter is backed by a lazy |
| 23 | +val, which means that the parameter is evaluated at most once. The |
| 24 | +lazy val is also available as a value for implicit search, which can |
| 25 | +be useful to avoid an otherwise diverging expansion. |
| 26 | + |
| 27 | +The precise steps for constructing an implicit argument for a by-name parameter of type `=> T` are: |
| 28 | + |
| 29 | + 1. Create a new implicit value with a fresh name _lv_, which has the signature of the following definition: |
| 30 | + |
| 31 | + implicit lazy val lv: T |
| 32 | + |
| 33 | + The current implementation uses the prefix `$lazy_implicit$` followed by a unique integer for _lv_. |
| 34 | + |
| 35 | + 1. 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. |
| 36 | + |
| 37 | + 1. If this implicit search succeeds with expression `E`, and `E` contains references to the lazy implicit value _lv_, replace `E` by |
| 38 | + |
| 39 | + { implicit lazy val lv: T = E; lv } |
| 40 | + |
| 41 | + Otherwise, return `E` unchanged. |
| 42 | + |
0 commit comments