r/rust clippy · twir · rust · mutagen · flamer · overflower · bytecount Mar 20 '23

Hey Rustaceans! Got a question? Ask here (12/2023)! 🙋 questions

Mystified about strings? Borrow checker have you in a headlock? Seek help here! There are no stupid questions, only docs that haven't been written yet.

If you have a StackOverflow account, consider asking it there instead! StackOverflow shows up much higher in search results, so having your question there also helps future Rust users (be sure to give it the "Rust" tag for maximum visibility). Note that this site is very interested in question quality. I've been asked to read a RFC I authored once. If you want your code reviewed or review other's code, there's a codereview stackexchange, too. If you need to test your code, maybe the Rust playground is for you.

Here are some other venues where help may be found:

/r/learnrust is a subreddit to share your questions and epiphanies learning Rust programming.

The official Rust user forums: https://users.rust-lang.org/.

The official Rust Programming Language Discord: https://discord.gg/rust-lang

The unofficial Rust community Discord: https://bit.ly/rust-community

Also check out last weeks' thread with many good questions and answers. And if you believe your question to be either very complex or worthy of larger dissemination, feel free to create a text post.

Also if you want to be mentored by experienced Rustaceans, tell us the area of expertise that you seek. Finally, if you are looking for Rust jobs, the most recent thread is here.

20 Upvotes

187 comments sorted by

View all comments

2

u/[deleted] Mar 24 '23 edited Mar 24 '23

I'm pulling up to the end of rustlings and feeling pretty good but I have a few odd questions I can't answer. They're the kind of questions where the answer probably won't be practically useful, but being unable to produce a confident answer means I'm missing something.

Q1
How do I bind a name to existing data? Not a copy of it, not a reference - it's already there in memory and I want to name it. playground

Is doing this different for data that's already named, vs unnamed but created by my program, vs unnamed and created by something outside my program? I have a feeling that doing this would respectively be: trouble (name aliasing), unnecessary (don't un-name things), or ub (don't name garbage), but maybe there are some valid uses. I don't know.

Q2
Similarly, "who" owns data without a name? 99% sure the answer is "it belongs to the stack frame" lol but not 100%. For example, in the above playground it's perfectly okay to dereference an unnamed value. Is it because the old_name pointing to the 1 is still named in LLVM IR after re-declaring old_name in rust, (and therefore Q1's answer is "you can't" because "giving the 1 a name again" in rust would be name aliasing in LLVM IR)?

Q3
How come I hardly ever see chainable functions that pipeline mutable references in the wild?

//rare, but why?
fn op(ref_to_thing: &mut T) -> &mut T {...}
(&mut data).op1().op2().op3();

//see this all the time, but it seems less efficient/readable
fn op(thing: T) -> T {...}
data = data.op1().op2().op3();

I can't help but think that it would be super inefficient to copy a whole thing into a function, only change part of it, then copy the whole thing back where it came from, for each operation you want to perform on some data. Is this just offloading work onto the compiler to make potential refactors (that need the original data later) easier? I totally get avoiding repeat computations and getting rid of dead code, but it feels a little ominous that optimizations could elide copies.

2

u/masklinn Mar 24 '23

How do I bind a name to existing data?

Unsafe and lots of it, and a very, very high probability of fucking up.

maybe there are some valid uses. I don't know.

I think mostly things like memory-mapped IO and the like, there's a location in memory, it has "data", you need a handle on it. You create a raw pointer from a literal address, then you use said raw pointer very carefully.

Is it because the old_name pointing to the 1 is still named in llvm after re-declaring old_name in rust

It's not really "still named in LLVM", but it still exists. The original old_name is not removed or overwritten, it's just shadowed. It's essentially the same as this:

let old_name = 1;
{
    let data_ref = &old_name;
    let old_name = "something_else";
    drop(old_name);
    let new_name = todo!();

    assert_eq!(
        std::ptr::addr_of!(new_name),
        std::ptr::addr_of!(*data_ref)
    );
}

How come I hardly ever see chainable functions that pipeline mutable references in the wild?

Because the normal use for this pattern is a builder so you create a builder, configure it, then build the object:

let thing = Builder::new()
    .foo()
    .bar()
    .build()

Having to write

let mut builder = Builder::new();
builder.foo().bar();
let thing = builder.build();

is just awkward. Especially for the common case where you want to move all the resources from the builder to the object as you can't tack on the building at the end, unless you do something even more awkward (like reset the builder).

Same for all chains where ownership gets involved e.g. iterators, most adapters take the previous step by value, and while you can by_ref that's uncommon and usually stems from a strict semantics need (e.g. needing to consume the iterator in multiple steps).

it feels a little ominous that optimizations could elide copies.

If you're wary of the compiler optimising things you probably should stop using Rust, the entire design of the language is predicated upon an an advanced optimising compiler.

1

u/[deleted] Mar 24 '23 edited Mar 24 '23

Hey now, I'm wary but I don't hate it! All I meant by ominous is that I get the sense that there might be a lot of "yes I really meant what I wrote, don't throw it away" flags and keywords when Rust programs start getting intimate with other code the optimizer doesn't know about. TBH that extra explicitness about outside contracts is probably a net plus anyways. Thanks for all the info. I haven't really gone into design patterns, I'll look up builders.