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