3 ms·
Huh? What is it you think Rust copied here? I agree that the choice in C++ is essentially worthless, so that in practice you can write functions which are defin
by tialaramex 2y ago
Huh? What is it you think Rust copied here? I agree that the choice in C++ is essentially worthless, so that in practice you can write functions which are definitely never executed at compile time and aren't constant in any sense, label them constexpr and that compiles anyway. It just becomes yet more noise C++ programmers learn to type by reflex to get the correct behaviour from their compiler, joining explicit.
But in Rust that's not what you're getting. Rust's const fn is none of the options C++ decided it needed, Rust says if the parameters are themselves constants then we promise we can evaluate this at compile time and if appropriate we will -- this means we can use Rust's const fn where we'd use C++ consteval, but the function can also be called at runtime with variable parameters - and we can use Rust's const where we'd use C++ constinit, calling these const fn with constant parameters.
Because Rust is more explicit about safety of course, we can often get away with claiming some value is "constant" in C++ despite actually figuring out what it is at runtime, and Rust isn't OK with that, for example in my code
const OVERSIZE: u32 = SIG_BITS.next_power_of_two() << 1;
We can just calculate what power of two is bigger than SIG_BITS and shift it left at compile time. But...
pub(super) static SHORT_80: LazyLock<Rational> = LazyLock::new(|| Rational::fraction(1, 80).unwrap());
The Rational type is a big rational, it owns heap allocations so we'll just make one once, at runtime, and then re-use it whenever we need this particular fraction (it's for calculating natural logarithms of arbitrary computable real numbers).
- IshKebab 2y ago> Rust says if the parameters are themselves constants then we promise we can evaluate this at compile time and if appropriate we will Well exactly. "if appropriate". So like C++'s `constexpr`, Rust doesn't make any guarantees about compile-time evaluation. Zig's `comptime` must be evaluated at compile time.
- kibwen 2y ago> Zig's `comptime` must be evaluated at compile time. Yes, and the equivalent in Rust is any constant context, such as a const item, or a const block inside of a non-const function. Anything in a constant context is guaranteed to run at compile-time.
- tialaramex 2y agoIf we want a constant context, we can say so. Because Rust is expression oriented we can write for example a loop (though if you're unfamiliar with Rust it may not be clear why a for loop can't work yet, other loops are fine) and wrap the whole expression in a const block and that'll be evaluated at compile time. For example: let a = const { let mut x: u64 = 0; let mut k = 5; loop { if k == 0 { break x; } k -= 1; x += 2; x *= x; } };
- LegionMammal978 2y agoYeah, it's nice that const blocks are stable now. Before them, you had to use hacks like defining a trait impl with an associated const, which was verbose and messy. (If I recall correctly, one of the big questions was "Will const blocks unreachable at runtime still be evaluated at compile time?" It looks like the answer was to leave it unspecified.)