Inline const expressions have been stabilised (github.com)
from SorteKanin@feddit.dk to rust@programming.dev on 25 Apr 2024 12:45
https://feddit.dk/post/5223867

#rust

threaded - newest

kevincox@lemmy.ml on 25 Apr 2024 14:20 next collapse

This is a nice small feature. I’m curious about the commit description:


foo(const { 1 + 1 })

which is roughly desugared into

struct Foo;
impl Foo {
    const FOO: i32 = 1 + 1;
}
foo(Foo::FOO)

I would have expected it to desugar to something like:

foo({
  const TMP: i32 = 1 + 1;
  TMP
})

But I can’t seem an explanation why the struct with impl is used. I wonder if it has something to do with propagating generics.

0v0@sopuli.xyz on 25 Apr 2024 15:20 next collapse

It’s because it has to work in pattern contexts as well, which are not expressions.

SorteKanin@feddit.dk on 25 Apr 2024 16:04 collapse

Wait, in pattern context? How? Can you give an example?

0v0@sopuli.xyz on 25 Apr 2024 17:11 collapse

fn foo(x: i32) {
    match x {
        const { 3.pow(3) } => println!("three cubed"),
        _ => {}
    }
}

But it looks like inline_const_pat is still unstable, only inline_const in expression position is now stabilized.

Giooschi@lemmy.world on 25 Apr 2024 18:23 collapse

They tested the same strings on that implementation

The code they were looking at was used for writing the table, but they were testing the one that read it (which is instead correct).

though judging by the recent comments someone’s found something.

Yeah that’s me :)The translation using an associated const also works when the const block uses generic parameters. For example:

fn require_zst<T>() {
    const { assert!(std::mem::size_of::<T>() == 0) }
}

This can be written as:

fn require_zst<T>() {
    struct Foo<T>(PhantomData<T>);
    impl<T> Foo<T> {
        const FOO: () = assert!(std::mem::size_of::<T>() == 0);
    }
    Foo::<T>::FOO
}

However it cannot be written as:

fn require_zst<T>() {
    const FOO: () = assert!(std::mem::size_of::<T>() == 0);
    FOO
}

Because const FOO: () is an item, thus it is only lexically scoped (i.e. visible) inside require_zst, but does not inherit its generics (thus it cannot use T).

sugar_in_your_tea@sh.itjust.works on 25 Apr 2024 17:43 next collapse

Huh, this is awesome! From the link, this now works:

let v: Vec<i32> = const { Vec::new() };

I’m going to have to play with this to see how far it goes.

asdfasdfasdf@lemmy.world on 28 Apr 2024 10:46 next collapse

What I’m curious about - this function was already const, so for stuff like this, I’d think there’s basically a 100% chance the compiler would optimize this too, just implicitly.

AFAIK this new feature is just for times when it isn’t an optimization, but more your own domain invariants. E.g. assertions.

But I could be wrong. I wonder if this can be used for actual optimizations in some places that the compiler couldn’t figure out by itself.

jasory@programming.dev on 29 Apr 2024 23:12 collapse

Wouldn’t this just prevent you from allocating more memory (than zero)?

sugar_in_your_tea@sh.itjust.works on 30 Apr 2024 00:05 collapse

Ah, apparently for now you’re not allowed to allocate. But vec::new_in(allocator) looks interesting. This works in nightly today:

#![feature(allocator_api)]

use std::alloc::Global;

fn main() {
    const MY_VEC: Vec<i32> = const {
        Vec::new_in(Global)
    };
    println!("{:?}", MY_VEC);
}

Maybe at some point I can append to it at compile time too. I’d love to be able to put a const {} and have allocations that resolve down to a 'static, and this seems to be a step toward that.

I guess I’m just excited that Vec::new() is the example they picked, since the next obvious question is, “can I push?”

onlinepersona@programming.dev on 27 Apr 2024 12:27 collapse

I’m not getting it. What’s the point? It seems very much like a cpp-ism where you can put const in so many places.

const int n2 = 0;    // const object
int const n3 = 0;    // const object (same as n2)
// https://learn.microsoft.com/en-us/cpp/cpp/const-and-volatile-pointers?view=msvc-170
const char *cpch;  // const variable cannot point to another pointer
char * const pchc; // value of pointer is constant

int f() const; // members cannot be modified in this, only read
std::string const f(); // returns a constant

Then there are constant expressions.

Can anybody look at that and tell me it’s readable with a straight face? I hope they don’t start adding all this stuff to rust.

Anti Commercial-AI license

Miaou@jlai.lu on 27 Apr 2024 13:59 next collapse

It can be used for producing const values in arbitrary context. Can basically be swapped for c++'s constexpr.

C++'s const does not exist in rust (values are const by default).

fzz@programming.dev on 11 May 2024 11:07 collapse

Nope. This little neat feature mainly is just necessary part of bigger one - const-generics with const bounds.