Pre-RFC: `usize` semantics

The difference in how you break things[1] as I see it is that usize being pointer sized is one of the most normatively specified things in Rust.[2] Not only is that a bigger deal than breaking an assumption which was never promised, it penalizes the people who went to the effort to figure out, to the extent possible, what Rust's guarantees are. We should support those people, not penalize them.

It's not "just" the official documentation, although that's very important. RFC 0544 is the one that defined usize. They are explicitly pointer-sized integers. Technically that was "just" a rename,[3] and you can see this was true before the rename (when they were int/uint) as well. They're also explicitly not ssize_t/size_t:

  • The names fail to indicate the precise semantics of the types - pointer-sized integers.

[ ...]

  • The names remind people of C's ssize_t/size_t, but isize/usize don't share the exact same semantics with the C types.

RFCs and discussions around that time (which was the leadup to 1.0) include...

And if you read through them, the constant is that the type is pointer sized, and pointer sized is always "good enough" for indexing even if a smaller size would be more efficient.

It's also true of any issue on the topic I've seen post-stabilization.

RFC 1861 also defines pointers to externs to be usize.


An undertone or presumption in the pre-1.0 discussion is that Rust should only have one signed/unsigned integer type where the width depends on the platform. In that world, the defining feature[7] has to be pointer width and not size_t, because it's "good enough" for the other uses, while the opposite is not true.

Part of this issue is basically "opting for only one platform integer[8] was wrong", which I can empathize with. The problem with the proposal here is that size_t is not the defining factor which has been promised, and people have -- reasonably and responsibly! -- relied on the definition.

I'm not convinced there isn't a way to change that definition in a way that blatantly breaks Rust's backwards compatibility promises, but anything I've thought of so far involves some sort of ecosystem split (like explicit opt-in, or crate-non-iteroperability across an edition).


  1. usize not pointer sized or usize not size_t ↩︎

  2. That's the definition any official place you look, should you choose to look. ↩︎

  3. there was a ton of pre-stable contention around integers ↩︎

  4. Excerpt:

    int and uint are always defined to have the same number of bits as a pointer on the target platform

    [...]

    it frequently happens that you have integers that are tied to the size of memory: for example, indices into an array or the size of an allocation. In these cases, uint and int are an excellent choice, though it may make sense to use smaller, fixed-size types if you know that the length of the array (or size of the allocation, etc) is limited.

    ↩︎
  5. Excerpt:

    it is certainly true that none of the listed proposals included variable-size integer types except for pointer-sized (and they all assume a flat address space as well). This is no accident.

    ↩︎
  6. Core team decision excerpt:

    On the other hand, seeing usize in the context of slice indexing or as the return of the len function is unlikely to lead to too much surprise for newcomers. A type like umem, on the other hand, is likely to raise eyebrows. Since "size" is general enough to refer to both the size of the address space and the size of a container and its indexes (which are, of course, closely related), and reasonably intuitive, we feel it is the best choice.

    ↩︎
  7. without committing to a stronger size_t == uintptr_t requirement ↩︎

  8. modulo signage ↩︎

5 Likes