Why `*const T` and not `*T`?

While normally I also am in favor of consistency, personally I think the Rust developers made the right tradeoff ('cause that’s what it is):

  • While the current choice is not all that consistent with the rest of the language on the surface, it can easily be argued that any unsafe code is not like the rest of Rust in that the semantics differs significantly between raw pointers on the one hand and borrows and ownership on the other.
  • When doing C FFI, the const acts as an extra “watch out here!” by explicitly marking non-writable raw pointers as such. This is useful, especially since C errs to the side of mutability.
  • The real goal of consistency is to make similar-but-different features easier to use, by leveraging what a programmer already knows. But as I stated above, the semantics between the raw ptr camp vs borrows/ownership seem to differ as least as much as they are related, and the differences are tiny but impactful.

None of this can make the argument that having the const is better than omitting it. But there’s one factor that is: it is already in play, and people are already using it. Quite often during language discussions it appears to me as if the cost of changing what people know is essentially “low enough to be worth it”. But I see 2 issues with that:

  1. There will be relearning fatigue among Rustaceans at some point, and the current discourse in the various threads this forum does not seem (to me at least) very cognizant of the budget-like nature of this aspect of humanity. Therefore I think there should be a relatively strong bias against changing things that already work in Rust today, in favor of extending them to do new things.
  2. If the way to do something is changed, this actively hampers learnability: a new Rustacean would have to wonder which to use: *T or *const T, and the only things that would enlighten them are either some (possibly outdated) post on StackOverflow or reading the discussions and/or the RFC. This is ultimately somewhat workable but wastes prodigious amounts of new Rustaceans’ time. Incidentally, this is another thing that Rust feature proposals could (should?) be more cognizant about.
  3. If changes like these are implemented, suddenly we have a more complex language to deal with: some projects will use *T, others *const T, and Rust programmers will be required to know both forms and deal with each. Worse yet, the rust compiler won’t ever be able to live down this complexity as neither regular releases nor Epochs (or whatever they’re called nowadays) allow for breaking changes e.g. removal of deprecated APIs.
    This is a simple example, but each time new syntax is suggested for things that are already possible this point will be a constant. And worse, the effects of such implemented proposals accumulate and grow exponentially.
4 Likes