From 58c795ad959dfe4ec78ad93cd57f7f0d3e81b4f1 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 20 Jan 2022 13:56:17 -0800 Subject: [PATCH] Parameter untupling is not a conversion of functions --- .../parameter-untupling-spec.md | 9 +++--- .../other-new-features/parameter-untupling.md | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/docs/docs/reference/other-new-features/parameter-untupling-spec.md b/docs/docs/reference/other-new-features/parameter-untupling-spec.md index feedb77aa774..e01e91059a27 100644 --- a/docs/docs/reference/other-new-features/parameter-untupling-spec.md +++ b/docs/docs/reference/other-new-features/parameter-untupling-spec.md @@ -77,11 +77,12 @@ is feasible for parameter untupling with the expected type `TupleN[T1, ..., Tn] with the same expected type. ## Migration -Code like this could not be written before, hence the new notation would not be ambiguous after adoption. +Code like this could not be written before, hence the new notation is not ambiguous after adoption. -Though it is possible that someone has written an implicit conversion form `(T1, ..., Tn) => R` to `TupleN[T1, ..., Tn] => R` -for some `n`. This change could be detected and fixed by [`Scalafix`](https://scalacenter.github.io/scalafix/). Furthermore, such conversion would probably -be doing the same translation (semantically) but in a less efficient way. +It is possible that someone has written an implicit conversion from `(T1, ..., Tn) => R` to `TupleN[T1, ..., Tn] => R` for some `n`. +Such a conversion is now only useful for general conversions of function values, when parameter untupling is not applicable. +Some care is required to implement the conversion efficiently. +Obsolete conversions could be detected and fixed by [`Scalafix`](https://scalacenter.github.io/scalafix/). ## Reference diff --git a/docs/docs/reference/other-new-features/parameter-untupling.md b/docs/docs/reference/other-new-features/parameter-untupling.md index 1beed4968d4f..84bbe52bddc1 100644 --- a/docs/docs/reference/other-new-features/parameter-untupling.md +++ b/docs/docs/reference/other-new-features/parameter-untupling.md @@ -33,11 +33,42 @@ or, equivalently: ```scala xs.map(_ + _) ``` +and +```scala +def combine(i: Int, j: Int) = i + j +xs.map(combine) +``` Generally, a function value with `n > 1` parameters is converted to a pattern-matching closure using `case` if the expected type is a unary function type of the form `((T_1, ..., T_n)) => U`. +More specifically, the adaptation is applied to the mismatching formal +parameter list. In particular, the adaptation is not a conversion +between function types. That is why the following is not accepted: + +```scala +val combiner: (Int, Int) => Int = _ + _ +xs.map(combiner) // Type Mismatch +``` + +The function value must be explicitly tupled, rather than the parameters untupled: +```scala +xs.map(combiner.tupled) +``` + +A conversion may be provided in user code: + +```scala +import scala.language.implicitConversions +transparent inline implicit def `fallback untupling`(f: (Int, Int) => Int): ((Int, Int)) => Int = + p => f(p._1, p._2) // use specialized apply instead of unspecialized `tupled` +xs.map(combiner) +``` + +Parameter untupling is attempted before conversions are applied, so that a conversion in scope +cannot subvert untupling. + ## Reference For more information see: