Description
Compiler version
All 3.x versions
Minimized example
Here's some code that illustrates a problem found in Lichess:
class Item(x: String)
inline given Conversion[String, Item] = Item(_)
inline given Conversion[String, Int] with
def apply(x: String) = Item(x)
Output
Here's the code generated for the first version:
final inline given def given_Conversion_String_Item:
Conversion[String, Item] =
{
def $anonfun(_$1: String): Item = new Item(_$1)
closure($anonfun:Conversion[String, Item])
}:Conversion[String, Item]
And here's the code generated for the 2nd version:
given class given_Conversion_String_Int() extends Conversion[String, Int]()
{
def apply(x: String): Int = new Item(x)
}
final inline given def given_Conversion_String_Int:
given_Conversion_String_Int =
new given_Conversion_String_Int():given_Conversion_String_Int
The first version generates an anonymous function for the SAM-type Conversion, which will be expanded to an anonymous class later. Since the conversion is inline
, this means that every one of its invocations will generate an anonymous class. This can lead to increased code pressure without the user noticing the problem, since all invocations are implicit. It's probably this what caused the increased code size in the Lichess port to Scala 3.
The second version does not have this problem. There's a single class generated and every inline conversion just creates a new object instance.
Question
Should we prevent the first version or at least warn about it? I see the following possibilities:
- Don't allow inline givens with a SAM closure as the right hand side. Suggest the rewriting to explicit
apply
. - Warn about inline givens with a SAM closure as the right hand side, with the same suggestion.
- Silently rewrite the first version to the second.
What do people think? Which of these should be preferred?