Hacker News new | ask | show | jobs
by est31 2128 days ago
The most exciting component of this release is the const fn improvements. With loops and if available, you can now do non-trivial computation in const fn for the first time. It reduces the gap between Rust's const fn and C++'s constexpr to a large degree. Ultimately, the miri execution engine that this feature builds upon, supports a much larger set of features that even constexpr supports. It's been a project spanning years to get it merged into the compiler, used for const fn evaluation, and stabilize it's features (this part is far from over).

In addition to the linked examples, I have some code of my own which is made simpler due to this feature: https://github.com/RustAudio/ogg/commit/b79d65dced32342a5f93...

Previously, the table was present as an array literal in C-style, now I can remove it once I decide for the library to require the 1.46 compiler or later versions.

Link to the old/current generation code: https://github.com/RustAudio/ogg/blob/master/examples/crc32-...

3 comments

Dlang has had CTFE for a long time. The engine just needs to be rewritten to reduce memory usage. https://tour.dlang.org/tour/en/gems/compile-time-function-ev...
> supports a much larger set of features that even constexpr supports

This sounds promising. Can you give examples? I don't know Rust at all, and the reason I like C++ is its metaprogrammability.

Basically, the interpreter interpret's rustc's internal IR, so it can theoretically support the entire language. That's not a good idea for various reasons, though, so its capabilities are effectively on an allowlist, that we expand over time as we're sure we want to enable a given feature.
That seems like a really good design, as opposed to having an AST interpreter like I might do otherwise. But would this indeed support a "much larger set of features" than constexpr as was claimed?
I think that the earlier const evaluator was an AST interpreter? It's been a long time and I don't work on this code, so I'm not 100% sure.

I don't know constexpr well enough to comment on that claim.

It has been a while, and I’m remembering from a discussion of new features in C++20, but I recall that constexpr isn’t capable of fully supporting memory allocations made during evaluation, while Rust’s const fn will eventually be able to.
I think some clarification is warranted here, because Miri is intended to be used for more than just constant evaluation. In particular, Miri wants to be able to dynamically verify `unsafe` code in order to detect undefined behavior, which means that it will eventually want to support the entire Rust language. However, just because Miri supports any given Rust feature does not necessarily mean that that feature will be made available for constant evaluation; consider features that are non-deterministic (like RNG) or architecture-dependent/nonportable (like floating-point operations), and how const-evaluating such things could potentially cause memory-unsafety to occur when runtime output and const output differ.
I believe in a talk[1] it was mentioned that Rust's const eval will support heap-allocated values (accessed as references). A quick search suggests that C++20 will also support this, although it may be safer in Rust as it can give a stronger guarantee that the static memory won't be written to.

[1]https://youtu.be/wkXNm_qo8aY?t=888

I wonder why && and || are not allowed in const functions?

> All boolean operators except for && and || which are banned since they are short-circuiting.

I guess I'm missing something obvious but why does the short circuiting break const-ness?

That was a restriction from before 1.46 stabilized control flow in const functions. Now that we have worked out the details around `if`, we can also stabilize `&&` and `||`.

(I'm a little surprised they weren't stabilized at the same time! Edit: they were! I just didn't look closely enough.)

> (I'm a little surprised they weren't stabilized at the same time!)

They were stabilized at the same time, see the release announcement.

https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html

Short circuiting introduces conditional branching. If you call a function on the right hand side of a || or && it might or might not be executed depending on the value of the left hand side.

Until this version of rust, all conditional branches were banned from const functions.

I guess to keep things simple they just banned any feature that might cause branching.

Why is branching a problem? Since `if` is now enabled in a const fn, it's trivial to rewrite && with & and if.
`if` wasn't enabled before, so `&&` wasn't enabled. Now that `if` is enabled, `&&` now works too.
Ahh that makes a lot of sense, if you're going to have a compiler insert the result of a function having conditional branching seems a bit gnarly I guess?
For the history of this feature request, see https://github.com/rust-lang/rust/issues/29608 as a starting point.
It's conditional based on what's ultimately constant data, so you end up with predictable output regardless.
That's a weird restriction on not allowing logical operators. AFAIK C++ allows this for constexpr functions - as long as it can be evaluated at compile time.