Skip to content

Commit a559ca6

Browse files
authored
Update proposal
* fix typos * more explanation
1 parent a3aa732 commit a559ca6

File tree

1 file changed

+47
-28
lines changed

1 file changed

+47
-28
lines changed

text/0001-int.md

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ ReScript Issue: (leave this empty)
77

88
## Summary
99

10-
Semantics deifinition of the ReScript's `int` type and integer primitives.
10+
Semantics definition of the ReScript's `int` type and integer primitives.
1111

1212
## Motivation
1313

14-
ReScript has three numeric primitive types, `int`, `float` and `bigint`.
14+
ReScript has three numeric primitive types, `int`, `float`, and `bigint`.
1515

1616
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.
1717

@@ -21,49 +21,59 @@ This RFC describes its semantics and chosen trade-offs as precisely as possible.
2121

2222
## Definition
2323

24-
TBD
24+
`int` is a built-in type.
2525

2626
```res
2727
type int
28+
```
29+
30+
A numeric literal with only an integer part has type `int`.
2831

32+
```res
2933
let n = 100
3034
```
3135

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."`
3339

3440
## Primitives
3541

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$
3743

38-
### `fromNumber(x: number)`
44+
### `fromNumber: (x: number) => int`
3945

4046
1. If `x` is JavaScript's `Infinity`, return `max_value`.
4147
2. If `x` is JavaScript's `-Infinity`, return `min_value`.
4248
3. Let `int32` be [`ToInt32`]`(x)`, return `int32`.
4349

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.
4553

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:
4755

56+
- `-0`
4857
- `NaN`
4958
- `Infinity` and `-Infinity`
50-
- `-0`
59+
- $x < $`min_value`
60+
- $x > $`max_value`
5161

5262
`fromNumber(x)` must be idempotent.
5363

54-
### `add(x: int, y: int)`
64+
### `add: (x: int, y: int) => int`
5565

56-
1. Let `number` be mathmatically $x + y$.
66+
1. Let `number` be mathematically $x + y$.
5767
2. Let `int32` be `fromNumber(number)`, return `int32`.
5868

59-
### `subtract(x, y)`
69+
### `subtract: (x: int, y: int) => int`
6070

61-
1. Let `number` be mathmatically $x - y$.
71+
1. Let `number` be mathematically $x - y$.
6272
2. Let `int32` be `fromNumber(number)`, return `int32`.
6373

64-
### `multiply(x, y)`
74+
### `multiply: (x: int, y: int) => int`
6575

66-
1. Let `number` be mathmatically $x * y$.
76+
1. Let `number` be mathematically $x * y$.
6777
2. Let `int32` be `fromNumber(number)`, return `int32`.
6878

6979
The `multiply(x, y)` must produce the same result as `add(x)` accumulated `y` times.
@@ -81,9 +91,9 @@ let multiply = (x, y) => {
8191
}
8292
```
8393

84-
### `exponentiate(x, y)`
94+
### `exponentiate: (x: int, y: int) => int`
8595

86-
1. Let `number` be mathmatically $x ^ y$.
96+
1. Let `number` be mathematically $x ^ y$.
8797
2. Let `int32` be `fromNumber(number)`, return `int32`.
8898

8999
The `exponentiate(x, y)` must produce the same result as `multiply(x)` accumulated `y` times.
@@ -101,45 +111,54 @@ let exponentiate = (x, y) => {
101111
}
102112
```
103113

104-
### `divide(x, y)`
114+
### `divide: (x: int, y: int) => int`
105115

106116
1. If `y` equals `0`, raise `Divide_by_zero`.
107-
2. Let `number` be mathmatically $x / y$.
117+
2. Let `number` be mathematically $x / y$.
108118
3. Let `int32` be `fromNumber(number)`, return `int32`.
109119

110-
### `remainder(x, y)`
120+
### `remainder: (x: int, y: int) => int`
111121

112122
1. If `y` equals `0`, raise `Divide_by_zero`.
123+
2. Let `number` be mathematically $x / y$.
113124

114-
### `abs(x)`
125+
### `abs: (x: int) => int`
115126

116127
1. If `x` is `min_value`, raise `Overflow_value`.
117128

118129
## API consideration
119130

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+
120137
TBD
121138

122139
## Questions
123140

124141
### Why do we even use `int`?
125142

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.
127144

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.
129146

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.
131148

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 element kind 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.
133150

134151
### Why do we truncate values instead of bounds-checking?
135152

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.
137156

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.
139158

140159
### Can we somehow make it match JavaScript's `number`?
141160

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.
143162

144163
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.
145164

0 commit comments

Comments
 (0)