Live data from Hacker News

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

forrestthewoods.com

51–60 of 115 posts

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

#51
post #45

> 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.)

This has irked me as well. Is there an acceptable way to make this less verbose? A crate with a derive macro for example?

There is, https://lib.rs/derive_more

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

#52

This reminds me of the years I wasted writing C++, always looking for the idiomatic approach, rather than learning about security, networking, architecture and so on. In exactly the same way, Rust is just too complicated.

This article demonstrates that it is overthinking the issue — both approaches are correct and about as fast. For non-copyable structs move vs borrow are semantically different, so the choice is even clearer.

With built-in style lints and Clippy, Rust is doing quite well in keeping codebases simple and idiomatic.

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

#54
I don't really understand the complaints in the 'ergonomics' section, this code won't even compile:

  fn dot_product(a: &Vector3, b: &Vector3) -> float {
      a.x*b.x + a.y*b.y + a.z*b.z
  }

  fn do_math(p1: &Vector3, p2: &Vector3, d1: &Vector3, d2: &Vector3, s: f32, t: f32) -> f32 {
      let a = p1 + &(&d1*s);
      let b = p2 + &(&d2*t);
      let result = dot_product(&(&b - &a), &(&b - &a));
  }

Namely, how are you going to multiply a struct like d1 by an f32? Rust has deref coercions also, so there's plenty of times you don't even need to put a &.

Also, I think the idiomatic thing to do would be to implement 'Add' for Vector3.

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

#55

The Cpp Core Guidelines suggest that the cutoff between copy and const reference should be "up to two or three words" (item F.16). Following this advice, the f32 vector would be passed by value, and the f64 vector would end up in the grey zone. https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC...

That's what the Nim compiler does.

Bigger than 3 words, pass-by-ref, otherwise pass-by-value.

So the only important modifier is whether the parameter is mutable or not. Obviously if mutable it's always passed-by-reference.

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

#56

This reminds me of the years I wasted writing C++, always looking for the idiomatic approach, rather than learning about security, networking, architecture and so on. In exactly the same way, Rust is just too complicated.

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

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

#57
I've had a smaller but similar dive recently while working on embedded machine (32 bit) with Rust. Clippy was pushing me to use move/copy instead of reference for passing a [u8; 8].

I thought this strange on a 32bit machine so I dived in and it turned out the "rule" is supposed to be "up to 2 register sized" variables are supposed to be copied, anything bigger is supposed to be referenced.

The trick here is that due to compatibility and no knowlege of target platform and setup clippy assumes 32bit register size. So on 64 bit platforms you'll only get this warning up to 8 bytes as well for example.

I never went in to actually see if it makes any sense on that particular 32bit platform, so good to see someone taking a dive on the actual compiled code side.

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

#58
post #29

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…

> so the compiler can do a lot of pointer and inlining magic that C and other languages can't. Isn't this a negative for Rust for when you actually do care about such micro-optimizations? It feels as if you not only need to know the language itself but also how the particular version of the compiler you are using has decided to interpret the language and apply optimizations - essentially having to know how the magic…

[deleted]

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

#59
post #54

I don't really understand the complaints in the 'ergonomics' section, this code won't even compile: fn dot_product(a: &Vector3, b: &Vector3) -> float { a.x*b.x + a.y*b.y + a.z*b.z } fn do_math(p1: &Vector3, p2: &Vector3, d1: &Vector3, d2: &Vector3, s: f32, t: f32) -> f32 { let a = p1 + &(&d1*s); let b = p2 + &(&d2*t); let result = dot_product(&(&b - &a), &(&b - &a)); } Namely, how are you going to multiply a struct l…

> Namely, how are you going to multiply a struct like d1 by an f32?

https://en.wikipedia.org/wiki/Scalar_multiplication

Here's a Rust Playground with the vector math impls he's probably assuming (dummied): https://play.rust-lang.org/?version=stable&mode=debug&editio...

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

#60
post #45

> 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.)

This has irked me as well. Is there an acceptable way to make this less verbose? A crate with a derive macro for example?

As danieldk mentioned elsewhere, you could get partway there with std::borrow::Borrow

    impl Add for &Vector3 where T: Borrow
Post reply on HN