You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In Scala 2, numeric literals were confined to the primitive numeric types `Int`, `Long`, `Float`, and `Double`. Scala 3 allows to write numeric literals also for user-defined types. Example:
14
-
15
-
```scala
16
-
valx:Long=-10_000_000_000
17
-
valy:BigInt=0x123_abc_789_def_345_678_901
18
-
valz:BigDecimal=110_222_799_799.99
19
-
20
-
(y: BigInt) match
21
-
case123_456_789_012_345_678_901=>
22
-
```
23
-
24
-
The syntax of numeric literals is the same as before, except there are no pre-set limits
25
-
how large they can be.
26
-
27
-
### Meaning of Numeric Literals
28
-
29
-
The meaning of a numeric literal is determined as follows:
30
-
31
-
- If the literal ends with `l` or `L`, it is a `Long` integer (and must fit in its legal range).
32
-
- If the literal ends with `f` or `F`, it is a single precision floating point number of type `Float`.
33
-
- If the literal ends with `d` or `D`, it is a double precision floating point number of type `Double`.
34
-
35
-
In each of these cases the conversion to a number is exactly as in Scala 2 or in Java. If a numeric literal does _not_ end in one of these suffixes, its meaning is determined by the expected type:
36
-
37
-
1. If the expected type is `Int`, `Long`, `Float`, or `Double`, the literal is
38
-
treated as a standard literal of that type.
39
-
2. If the expected type is a fully defined type `T` that has a given instance of type
40
-
`scala.util.FromDigits[T]`, the literal is converted to a value of type `T` by passing it as an argument to
41
-
the `fromDigits` method of that instance (more details below).
42
-
3. Otherwise, the literal is treated as a `Double` literal (if it has a decimal point or an
43
-
exponent), or as an `Int` literal (if not). (This last possibility is again as in Scala 2 or Java.)
44
-
45
-
With these rules, the definition
46
-
47
-
```scala
48
-
valx:Long=-10_000_000_000
49
-
```
50
-
51
-
is legal by rule (1), since the expected type is `Long`. The definitions
52
-
53
-
```scala
54
-
valy:BigInt=0x123_abc_789_def_345_678_901
55
-
valz:BigDecimal=111222333444.55
56
-
```
57
-
58
-
are legal by rule (2), since both `BigInt` and `BigDecimal` have `FromDigits` instances
59
-
(which implement the `FromDigits` subclasses `FromDigits.WithRadix` and `FromDigits.Decimal`, respectively).
60
-
On the other hand,
61
-
62
-
```scala
63
-
valx=-10_000_000_000
64
-
```
65
-
66
-
gives a type error, since without an expected type `-10_000_000_000` is treated by rule (3) as an `Int` literal, but it is too large for that type.
67
-
68
-
### The FromDigits Trait
69
-
70
-
To allow numeric literals, a type simply has to define a `given` instance of the
71
-
`scala.util.FromDigits` type class, or one of its subclasses. `FromDigits` is defined
72
-
as follows:
73
-
74
-
```scala
75
-
traitFromDigits[T]:
76
-
deffromDigits(digits: String):T
77
-
```
78
-
79
-
Implementations of the `fromDigits` convert strings of digits to the values of the
80
-
implementation type `T`.
81
-
The `digits` string consists of digits between `0` and `9`, possibly preceded by a
82
-
sign ("+" or "-"). Number separator characters `_` are filtered out before
83
-
the string is passed to `fromDigits`.
84
-
85
-
The companion object `FromDigits` also defines subclasses of `FromDigits` for
86
-
whole numbers with a given radix, for numbers with a decimal point, and for
87
-
numbers that can have both a decimal point and an exponent:
88
-
89
-
```scala
90
-
objectFromDigits:
91
-
92
-
/** A subclass of `FromDigits` that also allows to convert whole
classNumberTooLarge (msg: String="number too large") extendsFromDigitsException(msg)
125
-
classNumberTooSmall (msg: String="number too small") extendsFromDigitsException(msg)
126
-
classMalformedNumber(msg: String="malformed number literal") extendsFromDigitsException(msg)
127
-
```
128
-
129
-
### Example
130
-
131
-
As a fully worked out example, here is an implementation of a new numeric class, `BigFloat`, that accepts numeric literals. `BigFloat` is defined in terms of a `BigInt` mantissa and an `Int` exponent:
The macro implementation takes an argument of type `Expr[String]` and yields
241
-
a result of type `Expr[BigFloat]`. It tests whether its argument is a constant
242
-
string. If that is the case, it converts the string using the `apply` method
243
-
and lifts the resulting `BigFloat` back to `Expr` level. For non-constant
244
-
strings `fromDigitsImpl(digits)` is simply `apply(digits)`, i.e. everything is
245
-
evaluated at runtime in this case.
246
-
247
-
The interesting part is the `catch` part of the case where `digits` is constant.
248
-
If the `apply` method throws a `FromDigitsException`, the exception's message is issued as a compile time error in the `ctx.error(ex.getMessage)` call.
249
-
250
-
With this new implementation, a definition like
251
-
252
-
```scala
253
-
valx:BigFloat=1234.45e3333333333
254
-
```
255
-
256
-
would give a compile time error message:
257
-
258
-
```scala
259
-
3|valx:BigFloat=1234.45e3333333333
260
-
|^^^^^^^^^^^^^^^^^^
261
-
| exponent too large: 3333333333
262
-
```
7
+
[Document was moved](../experimental/numeric-literals.md)
0 commit comments