I'm trying to understand singleton types in shapeless and faced misunderstanding about singleton types compile-time type. Here is an example:
val x: Witness.`120`.T = 120.narrow
It works fine, but this constructions looks very unusual. What is Witness.120? In IDE it points to some macro function selectDynamic:
def selectDynamic(tpeSelector: String): Any = macro SingletonTypeMacros.witnessTypeImpl
which has compile-time type Any and judging by the construction Witness.120.T a type member T. This looks like magic... Can anyone give some explanation on what actually is going on when one writes something like:
val x: Witness.`120`.T = //...
Witness creates a so-called literal-based singleton type. Literal type means it's a type that can only accept one value.
So if you create a function like this:
def f(x: Witness.`120`.T) = x
it would accept only integer 120, but not 121.
Since Scala 2.13 literal types are integrated into the language, so you can write it simply as:
def f(x: 120) = x
Function narrow narrows type of value 120 from general Int to literal 120.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With