Live data from Hacker News

Should small Rust structs be passed by-copy or by-borrow?

forrestthewoods.com

91–100 of 115 posts

Re: Should small Rust structs be passed by-copy or by-borrow?

#91
That's the compiler's decision. Whether to pass something as a reference or as a copy is up to the compiler, provided that it can tell if this affects program semantics. If a argument is not modified (or cannot be), and lifetime analysis can exclude aliasing and concurrency conflicts, then it doesn't need to be copied. It can be if it's tiny; that's the compiler's call.

That feature was in an early Modula compiler.

Re: Should small Rust structs be passed by-copy or by-borrow?

#92

You should be careful trying to apply these micro benchmarks to modern optimising compiles, behaviour may be different depending on the exact code being compiled. Rust especially has immutability and known types in generics at compile time, so the compiler can do a lot of pointer and inlining magic that C and other languages can't. In the below example Rust switches to using a pointer when you might think it's doing…

0. Generously use black_box 1. a large sample size 2. a single thread 3. high-precision monotonic timestamps on an unloaded system 4. mean/std dev from more than several runs

5. run them long enough to stabilize thermally so you don't have bursts of performance (potentially minutes), and/or use something like perflock to lock down your cpu speed: https://github.com/aclements/perflock (general tactic, this is just the last tool I heard of)

6. for similar reasons, run them in a random order each time

Re: Should small Rust structs be passed by-copy or by-borrow?

#93
post #85

Earlier quoted context omitted.

Rust is too complicated because you can choose to take parameters by-value or by-reference?

It's because: a) the language designers decided to cram several paradigms into it, including a heavier than usual dose of functional. b) most people don't want to get pedantic about resource management c) the syntax is weird for people coming from the C language family

> a) the language designers decided to cram several paradigms into it, including a heavier than usual dose of functional.

Rust is actually really close to JavaScript in that regard, with its mix of OOP-without-inheritance and the whole collection of functional method on Arrays and iterators (map, reduce, etc.). And while People have a ton of complain about JavaScript, none of them is «the JavaScript language is too complex».

> b) most people don't want to get pedantic about resource management

But Rust is explicitly aimed at people who do! You can't use Python or JavaScript to write a web browser, a kernel or anything where performance is paramount.

> c) the syntax is weird for people coming from the C language family

What ? Do you mean “ not coming from the C language family”? Because its syntax is clearly in the C-family (semicolon, braces).

Re: Should small Rust structs be passed by-copy or by-borrow?

#94
post #84
post #62

Earlier quoted context omitted.

Rust is less complicated than C++, but it is more complicated than Go. However I’m a big proponent of minimizing complexity wherever possible - language overhead should not become an obstacle to programmer time. The nice thing about Rust is that it allows you to compartmentalize complexity very nicely by creating rules the compiler will enforce, whereas with C++ the programmer is also burdened with knowing them. I’m…

I recently realized that trying to order C++ and Rust precisely on a complexity scale is rather pointless and misleading, since it's obvious that they are in the same class of trickiness, but for different reasons. If a significant number of the developers that come into contact with a language think it's hard, then... it's very likely hard.

Rust is harder than many languages, but just because something is hard doesn't mean that it's complicated. I find that the strictness of the compiler ends up all-but-forcing code to end up rather simple.

Re: Should small Rust structs be passed by-copy or by-borrow?

#95
post #7
post #3

Thanks for sharing. As a Rust learner, I still don't know how to place the cursor between performance with borrowing and ergonomic with copying. Most of the time, I just copy/clone and I tell myself that the performance does not matter that much because it will be fast enough for my purpose anyway.

> it will be fast enough for my purpose anyway It probably will be. I've been using Rust in production for a while now, and our bottlenecks are never Rust's performance. Something else is the bottleneck way before we approach anything close to Rust's peak throughput. This is especially true if you're doing anything that touches networking or interacts with other services.

We've used this to our advantage when performance testing things on the JVM. We might not write the final solution in Rust, but we'll use it to figure out a theoretical upper limit with various things like Kafka and misc. databases.

Re: Should small Rust structs be passed by-copy or by-borrow?

#96
post #41

Earlier quoted context omitted.

That's interesting, and a bit surprising. I know Ada does this, but it's explicit about only specifying semantics ("in, "out" or "in out") and letting the compiler decide. Surely C or C++ optimizers won't do this?

> Surely C or C++ optimizers won't do this? When they can prove it doesn't change the semantics on ways that violate the standard I think you will find that they do. Rust doesn't really have it's own optimizer after all, just a repurposed C/C++ one.

For objects with trivial constructors and destructors, that's certainly a possibility. But anything with non-trivial move constructor or destructor, e.g. anything that allocates memory, is going to be much harder to optimise in C++.

The problem is, "moving" a C++ object means executing an arbitrary function, which at the very least needs to put the object to a "do nothing on destruction" state. The moved-from object still exists and has to have its destructor run (which is also an arbitrary function). In Rust, even an unoptimised move is just a bitwise copy, and the moved-from object doesn't need a destructor run because its lifetime ends completely when it is moved from.

Re: Should small Rust structs be passed by-copy or by-borrow?

#97
post #8

This purports to discuss pass-by-copy or reference but ends up not discussing that particular issue at all since every single compiler naturally inlined and vectorized his trivial micro-benchmark. If you were to discuss the headline issue, I guess you could delve deep into calling conventions, register pressure, various instruction set extensions that compilers can abuse to carry the data.. or you take the compiler o…

> or you take the compiler optimizations as a hint that concerning yourself with this is mostly pointless, as long as you don't start passing huge structures by-copy.

That's exactly what the author did.

Re: Should small Rust structs be passed by-copy or by-borrow?

#98
post #34

Earlier quoted context omitted.

In Rust (end even C++ afaik) it usually makes more sense to let the callee decide. Does it need to own the value? -> Call by value. Does it only need to inspect or (visibly) mutate the value during the function call? -> Call by reference (modulo optimization concerns).

Functions can also be generic over references vs. move/copy semantics, e.g.: fn foo (frob: T) where T: Borrow { // Do something with frob.borrow() } Due to monomorpization, foo is specialized for moves/clones when called as foo(frob) where frob is a value type or for borrows when called as foo(&frob) . Similarly, you can use Clone , ToOwned or even Into for going in the opposite direction. Whether such functions are…

You want AsRef, not Borrow, unless you need the additional guarantees that Borrow provides (identical comparisons and hashing).

Re: Should small Rust structs be passed by-copy or by-borrow?

#99
post #75

Earlier quoted context omitted.

I've mostly only dabbled in Rust, but I recall it being really difficult to pass data by copy in Rust. It seemed to want you to pass things by reference, especially if your type is meant to implement any prominent trait. It didn't matter if my type was an int, Rust seemed to want me to pass it by reference.

Do you have an example? Copying is only hard to the extent that you need to #[derive(Copy)] for your type, and ints are already Copy. I also don't see how other traits factor here.

It's been a while, but I tried implementing a trait that took `&self` with several different types. One such type was an integer type, so I had to pass by reference. It's probably not a big deal, but there are many things like this that seem to prefer you move or reference rather than copy.

I think it would be better for all traits to implement their methods on `self` and then the caller can choose whether the type that implements the trait is `i64` or `&i64` (instead of the trait being prescriptive about the type, which largely defeats the purpose of traits to begin with).

That said, I'm not very experienced in Rust, so I expect someone can correct me about why this is a Very Bad Idea.

Re: Should small Rust structs be passed by-copy or by-borrow?

#100
post #89

> Blech! Having to explicitly borrow temporary values is super gross. You can cut down on a lot of that by implementing basic operations (Add, Mul, etc.) for both value and reference types. impl Add for Vector3 { … } impl Add for Vector3 { … } impl Add for &Vector3 { … } impl Add for &Vector3 { … } (The first three can delegate to the last one, unless there are value-specific optimizations you want to apply.)

Does that essentially overload + for it?

Yes; Rust uses traits to implement behavior for operators on custom types (see the full list here: https://doc.rust-lang.org/std/ops/#traits)
Post reply on HN