Skip to content

Commit da7d52e

Browse files
committed
Merge pull request rust-lang#452 from tbu-/pr_inti32
Change RFC rust-lang#212 (integer fallback) to use `i32` instead of `int` as the fallback
2 parents c8feb4a + e66e34e commit da7d52e

File tree

1 file changed

+70
-31
lines changed

1 file changed

+70
-31
lines changed

text/0212-restore-int-fallback.md

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
# Summary
66

77
Restore the integer inference fallback that was removed. Integer
8-
literals whose type is unconstrained will default to `int`, as before.
8+
literals whose type is unconstrained will default to `i32`, unlike the
9+
previous fallback to `int`.
910
Floating point literals will default to `f64`.
1011

1112
# Motivation
@@ -102,7 +103,7 @@ To our knowledge, there has not been a single bug exposed by removing
102103
the fallback to the `int` type. Moreover, such bugs seem to be
103104
extremely unlikely.
104105

105-
The primary reason for this is that, in production code, the `int`
106+
The primary reason for this is that, in production code, the `i32`
106107
fallback is very rarely used. In a sense, the same [measurements][m]
107108
that were used to justify removing the `int` fallback also justify
108109
keeping it. As the measurements showed, the vast, vast majority of
@@ -111,25 +112,56 @@ used to print out and do assertions with. Specifically, any integer
111112
that is passed as a parameter, returned from a function, or stored in
112113
a struct or array, must wind up with a specific type.
113114

114-
Another secondary reason is that the lint which checks that literals
115-
are suitable for their assigned type will catch cases where very large
116-
literals were used that overflow the `int` type (for example,
117-
`INT_MAX`+1). (Note that the overflow lint constraints `int` literals
118-
to 32 bits for better portability.)
119-
120-
In almost all of common cases we described above, there exists *some*
121-
large constant representing a bound. If this constant exceeds the
122-
range of the chosen fallback type, then a `type_overflow` lint warning
123-
would be triggered. For example, in the accumulator, if the
124-
accumulated result `i` is compared using a call like `assert_eq(i,
125-
22)`, then the constant `22` will be linted. Similarly, when invoking
126-
range with unconstrained arguments, the arguments to range are linted.
127-
And so on.
128-
129-
The only common case where the lint does not apply is when an
130-
accumulator result is only being printed to the screen or otherwise
131-
consumed by some generic function which never stores it to memory.
132-
This is a very narrow case.
115+
## Rationale for the choice of defaulting to `i32`
116+
117+
In contrast to the first revision of the RFC, the fallback type
118+
suggested is `i32`. This is justified by a case analysis which showed
119+
that there does not exist a compelling reason for having a signed
120+
pointer-sized integer type as the default.
121+
122+
There are reasons *for* using `i32` instead: It's familiar to programmers
123+
from the C programming language (where the default int type is 32-bit in
124+
the major calling conventions), it's faster than 64-bit integers in
125+
arithmetic today, and is superior in memory usage while still providing
126+
a reasonable range of possible values.
127+
128+
To expand on the perfomance argument: `i32` obviously uses half of the
129+
memory of `i64` meaning half the memory bandwidth used, half as much
130+
cache consumption and twice as much vectorization – additionally
131+
arithmetic (like multiplication and division) is faster on some of the
132+
modern CPUs.
133+
134+
## Case analysis
135+
136+
This is an analysis of cases where `int` inference might be thought of
137+
as useful:
138+
139+
**Indexing into an array with unconstrained integer literal:**
140+
141+
```
142+
let array = [0u8, 1, 2, 3];
143+
let index = 3;
144+
array[index]
145+
```
146+
147+
In this case, `index` is already automatically inferred to be a `uint`.
148+
149+
**Using a default integer for tests, tutorials, etc.:** Examples of this
150+
include "The Guide", the Rust API docs and the Rust standard library
151+
unit tests. This is better served by a smaller, faster and platform
152+
independent type as default.
153+
154+
**Using an integer for an upper bound or for simply printing it:** This
155+
is also served very well by `i32`.
156+
157+
**Counting of loop iterations:** This is a part where `int` is as badly
158+
suited as `i32`, so at least the move to `i32` doesn't create new
159+
hazards (note that the number of elements of a vector might not
160+
necessarily fit into an `int`).
161+
162+
In addition to all the points above, having a platform-independent type
163+
obviously results in less differences between the platforms in which the
164+
programmer "doesn't care" about the integer type they are using.
133165

134166
## Future-proofing for overloaded literals
135167

@@ -141,12 +173,12 @@ be necessary for those literals to have some sort of fallback type.
141173

142174
# Detailed design
143175

144-
Integeral literals are currently type-checked by creating a special
176+
Integral literals are currently type-checked by creating a special
145177
class of type variable. These variables are subject to unification as
146178
normal, but can only unify with integral types. This RFC proposes
147179
that, at the end of type inference, when all constraints are known, we
148180
will identify all integral type variables that have not yet been bound
149-
to anything and bind them to `int`. Similarly, floating point literals
181+
to anything and bind them to `i32`. Similarly, floating point literals
150182
will fallback to `f64`.
151183

152184
For those who wish to be very careful about which integral types they
@@ -156,21 +188,23 @@ integer or floating point literal is unconstrained.
156188

157189
# Downsides
158190

159-
Although we give a detailed argument for why bugs are unlikely, it is
160-
nonetheless possible that this choice will lead to bugs in some code,
161-
since another choice (most likely `uint`) may have been more suitable.
191+
Although there seems to be little motivation for `int` to be the
192+
default, there might be use cases where `int` is a more correct fallback
193+
than `i32`.
194+
195+
Additionally, it might seem weird to some that `i32` is a default, when
196+
`int` looks like the default from other languages. The name of `int`
197+
however is not in the scope of this RFC.
162198

163-
Given that the size of `int` is platform dependent, it is possible
164-
that a porting hazard is created. This is mitigated by the fact that
165-
the `type_overflow` lint constraints `int` literals to 32 bits.
166199

167200
# Alternatives
168201

169202
- **No fallback.** Status quo.
170203

171204
- **Fallback to something else.** We could potentially fallback to
172-
`i32` or some other integral type rather than `int`.
173-
205+
`int` like the original RFC suggested or some other integral type
206+
rather than `i32`.
207+
174208
- **Fallback in a more narrow range of cases.** We could attempt to
175209
identify integers that are "only printed" or "only compared". There
176210
is no concrete proposal in this direction and it seems to lead to an
@@ -182,5 +216,10 @@ the `type_overflow` lint constraints `int` literals to 32 bits.
182216
like `range(0, 10)` to work even without integral fallback, because
183217
the `range` function itself could specify a fallback type. However,
184218
this does not help with many other examples.
219+
220+
# History
221+
222+
2014-11-07: Changed the suggested fallback from `int` to `i32`, add
223+
rationale.
185224

186225
[m]: https://gist.github.com/nikomatsakis/11179747

0 commit comments

Comments
 (0)