← Back to context

Comment by tialaramex

2 days ago

Given you like pointers so much a dislike for Rust would make sense if Rust didn't have pointers, but it does and IMO as somebody who spent years getting paid to write in C, Rust's pointers are better.

I don't know if Zig has made any clear decisions about this (chime in any Zig experts) but in C [and C++] the pointers are crap because they're "zapped" when the thing pointed to is gone. Now of course in reality your compiler won't overwrite your pointer just because the standard says it could, but because the compiler knows it would be allowed to do that, it can optimise pointer tricks in surprising ways. To work around this, C and C++ provide pointer-sized integers and exhort you to do any tricks with those instead because there's no zap.

In Rust that's unnecessary, the pointers are just pointers, if the thing pointed at is invalidated, you mustn't dereference that pointer because it's not pointing at anything now, but you can still for example XOR it against another pointer. Clever pointer tricks are thus your responsibility as programmer, and you can just do them with pointers rather than needing this pointer-sized-integer workaround.

Not familiar with the idea of "zapped", and I thought that Rust had a similar provenance model?

Working with pointers in Zig is much nicer, since

1. They're not nullable. If you want a nullable pointer, you would use `?*Object` instead of `*Object`.

2. They distinguish between single item and multi-item pointers. `*u8` is a pointer to a single u8, so I couldn't add to it or index it. `[*]u8` is a multi-item u8, which you can index.

3. Pointers track their alignment. I could make a pointer with `*align(128) Object` if I wanted to tag the bottom bits for example. Zig will require casts when changing alignment, for example casting from `*Object`.

4. Everyone uses slices when possible, pretty much Rust's slices.

5. A smaller detail, but there are sentinel pointers/slices, where you guarantee that the last item is a certain things. For example, a C string would be `[*:0]u8`, because it ends with 0.

  • Today the C and C++ standards do not have a provenance model. The model Rust chose is certainly related to the PNVI-ae-udi model proposed for C, in particular "Provenance Not Via Integers" is a core choice in both schemes. Martin Uecker (who has commented elsewhere in this thread) would I think say they're more similar than I would and he is an expert in this area as he co-authored the C proposal.

    Zap isn't much related to provenance, it's more of a difference in philosophy about what pointers are for. With zap they're a very bare bones reference type, they always refer to things which exist and that's all, it's important that they never point anywhere without in fact referencing a thing. Without zap most of the behaviour you associate with hardware addresses works, you can do arithmetic on them, including atomic compare operations, you can use them as parameters to MMIO features and so on. Since C doesn't have any other reference types their role in C makes sense, in Rust and C++ of course actual reference types also exist.