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
Copy file name to clipboardExpand all lines: docs/docs/reference/changed-features/numeric-literals.md
+29-27Lines changed: 29 additions & 27 deletions
Original file line number
Diff line number
Diff line change
@@ -70,7 +70,7 @@ the string is passed to `fromDigits`.
70
70
71
71
The companion object `FromDigits` also defines subclasses of `FromDigits` for
72
72
whole numbers with a given radix, for numbers with a decimal point, and for
73
-
numbers that can have both a decimal point and an exponent:
73
+
numbers that can have both a decimal point and an exponent, along with methods to summon a given instance of each subclass:
74
74
```scala
75
75
objectFromDigits {
76
76
@@ -92,12 +92,32 @@ object FromDigits {
92
92
* exponent `('e' | 'E')['+' | '-']digit digit*`.
93
93
*/
94
94
traitFloating[T] extendsDecimal[T]
95
+
96
+
/** Does `T` have a given `FromDigits[T]` instance?
97
+
*/
98
+
inlinedeffromDigits[T](givenx:FromDigits[T]): x.type= x
99
+
100
+
/** Does `T` have a given `FromDigits.WithRadix[T]` instance?
101
+
*/
102
+
inlinedeffromRadixDigits[T](givenx:FromDigits.WithRadix[T]): x.type= x
103
+
104
+
/** Does `T` have a given `FromDigits.Decimal[T]` instance?
105
+
*/
106
+
inlinedeffromDecimalDigits[T](givenx:FromDigits.Decimal[T]): x.type= x
107
+
108
+
/** Does `T` have a given `FromDigits.Floating[T]` instance?
109
+
*/
110
+
inlinedeffromFloatingDigits[T](givenx:FromDigits.Floating[T]): x.type= x
95
111
...
96
112
}
97
113
```
98
-
A user-defined number type can implement one of those, which signals to the compiler
99
-
that hexadecimal numbers, decimal points, or exponents are also accepted in literals
100
-
for this type.
114
+
A user-defined number type, that provides a given instance of one of the above subclasses, signals to the compiler
115
+
that hexadecimal numbers, decimal points, or exponents are also accepted in literals for that type. A numeric literal with a concrete type `T` and digits `digits` is replaced as follows, when a given instance for `FromDigits[T]` is available:
116
+
117
+
-`fromDigits[T].fromDigits(digits)` if the digits form a decimal whole number.
118
+
-`fromRadixDigits[T].fromDigits(digits, 16)` if the digits form a hexadecimal whole number.
119
+
-`fromDecimalDigits[T].fromDigits(digits)` if the digits are decimal with a single decimal point `"."`.
120
+
-`fromFloatingDigits[T].fromDigits(digits)` if the digits are decimal with an exponent and optionally a single decimal point `"."`.
101
121
102
122
### Error Handling
103
123
@@ -112,37 +132,19 @@ class NumberTooSmall (msg: String = "number too small") extends FromDigi
112
132
classMalformedNumber(msg: String="malformed number literal") extendsFromDigitsException(msg)
113
133
```
114
134
115
-
### Compiler Expansion
116
-
117
-
The companion object `FromDigits` also defines four methods that may be used to provide a given instance of one of the subclasses of `FromDigits`:
118
-
```scala
119
-
inlinedeffromDigits[T](givenx:FromDigits[T]): x.type= x
120
-
121
-
inlinedeffromRadixDigits[T](givenx:FromDigits.WithRadix[T]): x.type= x
122
-
123
-
inlinedeffromDecimalDigits[T](givenx:FromDigits.Decimal[T]): x.type= x
124
-
125
-
inlinedeffromFloatingDigits[T](givenx:FromDigits.Floating[T]): x.type= x
126
-
```
127
-
128
-
If a numeric literal has a concrete expected type `T` that is not one of the primitive numeric types, the compiler will search for a given instance of `FromDigits[T]`. If one exists, then the compiler will replace the numeric literal with an application of its digits to the `fromDigits` method on the result of the application of `T` to one of the above four methods, resulting in the following:
129
-
130
-
-`fromDigits[T].fromDigits(digits)` if the literal forms a whole number with base-10.
131
-
-`fromRadixDigits[T].fromDigits(digits, 16)` if the literal forms a whole number with base-16.
132
-
-`fromDecimalDigits[T].fromDigits(digits)` if the literal is base-10 with a single decimal point.
133
-
-`fromFloatingDigits[T].fromDigits(digits)` if the literal is base-10 with an exponent and optionally a single decimal point.
135
+
### Number Format Safety
134
136
135
-
<!-- on the `fromDigits` method on the result obtained from calling one of the -->
137
+
A benefit of implementing one of the specialised subclasses of `FromDigits` is that the compiler preserves invariants about the format of digits passed to the `fromDigits` method.
136
138
137
-
As an example, the literal below has a nonsensical expected type `BigDecimal`, which can not be constructed with hex digits:
139
+
As an example, the constructor for `BigDecimal` can not accept digits in hexadecimal format, so it does not make sense to allow hexadecimal number literals with expected type `BigDecimal`. Below is such an expression:
138
140
```scala
139
141
0xABC_123:BigDecimal
140
142
```
141
-
Upon the compiler finding a given instance for `FromDigits[BigDecimal]`, the hex literal above expands to the following, after removing numeric separators:
143
+
We can protect against this poorly formed expression by restricting the domain of acceptable number literals. The `FromDigits` companion object provides a given instance of `FromDigits.Floating[BigDecimal]`, which does not accept non-decimal literals. As described above, because the compiler can see a given instance for `FromDigits[BigDecimal]`, the hex literal is replaced with the following, after removing numeric separators:
The given clause of `fromRadixDigits` asserts that the prior found `FromDigits`instance is a subtype of `FromDigits.WithRadix[BigDecimal]`, or else following error is issued:
147
+
Because the given instance for `FromDigits[BigDecimal]` in the `FromDigits`companion object is not a subtype of `FromDigits.WithRadix[BigDecimal]`, as expected by the given clause of `fromRadixDigits`, the following error is issued:
0 commit comments