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: text/0001-int.md
+47-28Lines changed: 47 additions & 28 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,11 +7,11 @@ ReScript Issue: (leave this empty)
7
7
8
8
## Summary
9
9
10
-
Semantics deifinition of the ReScript's `int` type and integer primitives.
10
+
Semantics definition of the ReScript's `int` type and integer primitives.
11
11
12
12
## Motivation
13
13
14
-
ReScript has three numeric primitive types, `int`, `float` and `bigint`.
14
+
ReScript has three numeric primitive types, `int`, `float`, and `bigint`.
15
15
16
16
The semantics of `float` and `bigint` completely match JavaScript's ones, but `int` is unique to ReScript and originally came from OCaml's `int` type.
17
17
@@ -21,49 +21,59 @@ This RFC describes its semantics and chosen trade-offs as precisely as possible.
21
21
22
22
## Definition
23
23
24
-
TBD
24
+
`int` is a built-in type.
25
25
26
26
```res
27
27
type int
28
+
```
29
+
30
+
A numeric literal with only an integer part has type `int`.
28
31
32
+
```res
29
33
let n = 100
30
34
```
31
35
32
-
Using unbounded integer literals may result in compile-time errors with messages such as `"Integer literal exceeds the range of representable integers of type int."`
36
+
The valid range of an integer literal is limited to the range of signed 32-bit integers $[-2^{31} .. 2^{31}-1]$.
37
+
38
+
Using unbounded numbers in literals may result in compile-time errors with messages such as `"Integer literal exceeds the range of representable integers of type int."`
33
39
34
40
## Primitives
35
41
36
-
Let `max_value` be $2^{31}-1$ and `min_value` be $-2^{31}$.
42
+
Let `min_value` be $-2^{31}$ and `max_value` be $2^{31}-1$
37
43
38
-
### `fromNumber(x: number)`
44
+
### `fromNumber: (x: number) => int`
39
45
40
46
1. If `x` is JavaScript's `Infinity`, return `max_value`.
41
47
2. If `x` is JavaScript's `-Infinity`, return `min_value`.
42
48
3. Let `int32` be [`ToInt32`]`(x)`, return `int32`.
43
49
44
-
The actions 1 and 2 are intended to reduce confusion when converting from an infinate value. (e.g. https://github.com/rescript-lang/rescript/issues/6737) However, it can be omitted if it is obvious that the `x` is not `Infinity` or `-Infinity`.
50
+
Actions 1 and 2 are intended to relax confusion when converting from infinite value directly. (e.g. https://github.com/rescript-lang/rescript/issues/6737) However, it can be omitted if the input is obviously not `Infinity` or `-Infinity`.
51
+
52
+
The [`ToInt32`] behavior follows the definition in ECMA-262 as is. ReScript compiler uses `bitwiseOR(number, 0)` in action. This is what appears in the output as `number | 0`, which truncates all special numbers defined in IEEE-754.
45
53
46
-
The [`ToInt32`] behavior follows the definition in ECMA-262 as is. In action, the ReScript compiler uses `bitwiseOR(number, 0)`. This is what appears in the output as `number | 0`. And this removes all special numbers defined in IEEE-754. `int` never contain the following values:
54
+
`int` never contains the following values:
47
55
56
+
-`-0`
48
57
-`NaN`
49
58
-`Infinity` and `-Infinity`
50
-
-`-0`
59
+
- $x < $`min_value`
60
+
- $x > $`max_value`
51
61
52
62
`fromNumber(x)` must be idempotent.
53
63
54
-
### `add(x: int, y: int)`
64
+
### `add: (x: int, y: int) => int`
55
65
56
-
1. Let `number` be mathmatically $x + y$.
66
+
1. Let `number` be mathematically $x + y$.
57
67
2. Let `int32` be `fromNumber(number)`, return `int32`.
58
68
59
-
### `subtract(x, y)`
69
+
### `subtract: (x: int, y: int) => int`
60
70
61
-
1. Let `number` be mathmatically $x - y$.
71
+
1. Let `number` be mathematically $x - y$.
62
72
2. Let `int32` be `fromNumber(number)`, return `int32`.
63
73
64
-
### `multiply(x, y)`
74
+
### `multiply: (x: int, y: int) => int`
65
75
66
-
1. Let `number` be mathmatically $x * y$.
76
+
1. Let `number` be mathematically $x * y$.
67
77
2. Let `int32` be `fromNumber(number)`, return `int32`.
68
78
69
79
The `multiply(x, y)` must produce the same result as `add(x)` accumulated `y` times.
@@ -81,9 +91,9 @@ let multiply = (x, y) => {
81
91
}
82
92
```
83
93
84
-
### `exponentiate(x, y)`
94
+
### `exponentiate: (x: int, y: int) => int`
85
95
86
-
1. Let `number` be mathmatically $x ^ y$.
96
+
1. Let `number` be mathematically $x ^ y$.
87
97
2. Let `int32` be `fromNumber(number)`, return `int32`.
88
98
89
99
The `exponentiate(x, y)` must produce the same result as `multiply(x)` accumulated `y` times.
3. Let `int32` be `fromNumber(number)`, return `int32`.
109
119
110
-
### `remainder(x, y)`
120
+
### `remainder: (x: int, y: int) => int`
111
121
112
122
1. If `y` equals `0`, raise `Divide_by_zero`.
123
+
2. Let `number` be mathematically $x / y$.
113
124
114
-
### `abs(x)`
125
+
### `abs: (x: int) => int`
115
126
116
127
1. If `x` is `min_value`, raise `Overflow_value`.
117
128
118
129
## API consideration
119
130
131
+
These primitive operations for `int` often don't work as intended by the user due to the `fromNumber` truncation.
132
+
133
+
APIs that use this should make it safer by providing appropriate errors with standard types.
134
+
135
+
### Standard error types
136
+
120
137
TBD
121
138
122
139
## Questions
123
140
124
141
### Why do we even use `int`?
125
142
126
-
The use of`int` is primarily for backward compatibility — not with OCaml, but with all existing ReScript codebases.
143
+
Using`int` is primarily for backward compatibility — not with OCaml, but with all existing ReScript codebases.
127
144
128
-
Additionally, using `int`is beneficial for JavaScript programs since major JavaScript engines treat integers differently.
145
+
Additionally, using `int`benefits JavaScript programs since major JavaScript engines treat integers differently.
129
146
130
-
Depending on the implementation, integer values (especially 32-bit integers) may have a distinct memory representation compared to floating-point numbers. For example, V8 (the JavaScript engine in Chromium) employs an internal element kind called "SMI" (Small integers). This provides an efficient memory representation for signed 32-bit integers and enhances runtime performance by avoiding heap allocation.
147
+
Depending on the implementation, integer values (especially 32-bit integers) may have a distinct memory representation compared to floating-point numbers. For example, V8 (the JavaScript engine for Chromium and Node.js) employs an internal element kind called "SMI" (Small integers). This provides an efficient memory representation for signed 32-bit integers and enhances runtime performance by avoiding heap allocation.
131
148
132
-
At compile time, the compiler ensures that certain operations are restricted to using only `int` types. This increases the likelihood of utilizing the optimized execution paths for SMIs and reduces the potential for runtime de-optimization caused by elementkind transitions.
149
+
At compile time, the compiler ensures that certain operations are restricted to using only `int` types. This increases the likelihood of utilizing the optimized execution paths for SMIs and reduces the potential for runtime de-optimization caused by element-kind transitions.
133
150
134
151
### Why do we truncate values instead of bounds-checking?
135
152
136
-
It is also for backward compatibility. Bounds-checking and failure early may be more useful for fast feedback loop, but we don't want to break any programs that (accidentally) worked before.
153
+
It is also for backward compatibility.
154
+
155
+
Bounds-checking and failure early may be more useful for a fast feedback loop, but we don't want to break any programs that (accidentally) worked before.
137
156
138
-
The `number | 0` is actually the most concise output form we can consistently use. Introducing any other runtime codes universally would lead to significant code bloat in the output.
157
+
The `number | 0` is the most concise output form we can consistently use. Introducing any other runtime codes universally would lead to significant code bloat in the output.
139
158
140
159
### Can we somehow make it match JavaScript's `number`?
141
160
142
-
Perhaps in the future, we can make our number literals actually match JavaScript's number semantics. We could also rename `int` to `int32` and assign another literal like `0l`, as it was in OCaml syntax.
161
+
Perhaps, we can make our number literals match JavaScript's number semantics. We could also rename `int` to `int32` and assign another literal like `0l`, as it was in OCaml syntax.
143
162
144
163
However, this is not something that will happen in the near future. It won't occur until we are confident in our migration strategy to avoid breaking existing codebases. If done incorrectly, it could completely break compatibility with existing code.
0 commit comments