Make trait methods callable in const contexts by oli-obk · Pull Request #3762 · rust-lang/rfcs (original) (raw)

@foonathan

https://www.foonathan.net/2020/10/constexpr-platform/

Good article, the idea is interesting and does deserves a mention in "Alternatives". But there may be cultural difference that Rust prefers doing precise constraint validation via type system instead of in human language (documentations) if possible. And I personally like the former because human language is imprecise, unverifiable, and far more complex than all RFC combined1.

You don't have a windows annotation on functions that can be executed on Windows, and executing a function that isn't marked windows on Windows is impossible, because what if a future version wants to use Linux specific APIs?

That's not exactly true in Rust. We do have cfg(windows) module which exposes Windows-only APIs. They are not callable on non-Windows platforms and are guaranteed (by semver) never call a Linux-only-API in the future. Generic APIs are exposed in generic modules with looser constraints: users can expected them to be callable, working and NOT instantly panic where they can call them (returning Err(_) is still a valid and working impl). In the consteval world, this "expectation" translates to "if there is a pub const fn with some constraints, you can expect calling it under specified constraints should always work".

Yes, someone can still violate this expectation by panic!() inside, but that serves an escape hatch for unwritable complex constraints, which we are constantly reducing. Otherwise, the library author is to blame, not the caller, similar to an non-unsafe fn causes UB when it's called weirdly in a safe context (is considered the library's fault).

@matklad

Indeed, though we can preserve some checking, and there's actually some flexibility in what we allow. I think the C++ semantics is this:

fn g() {}

constexpr fn f1() { g() } // declaration site error constexpr fn f2(b: bool) { if b { g() } // errors when f2(true) is called }

If we accept this and simply propagate (semantically, not type-wise) all implicit preconditions to the caller const fn instead of enforcing them, just after some layers of calls, preconditions grow unmanageable2: no one, including the author, knows or is able to describe what preconditions does the outermost const fn have. This is a nightmare for the caller3. Defining "calling me with inputs that makes me error is an error" is not helpful to anyone but a catchall disclaimer.
Yes it is possible today to do this via panic!, but again, I still want to blame library author, and don't want to be blamed for "calling it wrong by simply following its signature". 😢

  1. Because all RFCs are representable in human language.
  2. Finding a pre-image of a hash function is difficult if not impossible.
  3. Actually, post-monomorphization-error everywhere is one of the main reason why I left C++.