Live data from Hacker News

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

forrestthewoods.com

201–210 of 238 posts

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

#201
post #195

Earlier quoted context omitted.

A Rust program can trivially return a tuple of values, so it doesn't need out params.

Out params are needed to ensure zero-copy in-place initialization of large objects, i.e. what C++ does with placement new. You can sort of fake it with MaybeUninit https://doc.rust-lang.org/std/mem/union.MaybeUninit.html but it's quite fiddly, requires unsafe code, and has undesirable effects on the layout of containing objects.

In–place initialization is nice to have, but not strictly required.

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

#202

Earlier quoted context omitted.

I would still consider myself a go novice, but I have been burned a number of times passing simple objects by reference and then that object gets mutated causing subtle bugs. Also, go is happy to blow your foot off if you take the reference of a loop variable. Although, there is a proposal to fix that. Generally I find that less bugs get introduced when using copy instead of pass by reference, but I’m sure others hav…

This is about rust though and thats not really possible there (at least to my knowledge). You should get a compiler error if you attempt this. I got very little experience in rust though, so there might be a way (I'm just not aware of) to circumvent this check

Indeed, you can use interior mutability to accomplish this:

https://doc.rust-lang.org/reference/interior-mutability.html

Usually (read: near universally) something that provides interior mutability will implement a runtime check to protect you (eg, a lock), but you could make a footgun if you were cavalier about it. And recent I misused a framework (I kept a value returned by the framework around that should've been dropped) without realizing it was holding locks internal to the framework, and ended up with a tricky to diagnose deadlock (though only tricky before I hadn't read the documentation as closely as I should've).

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

#203

Earlier quoted context omitted.

Yeah inline is an absolute classic for this. The number of uncommented __attribute__((always_inline))s I see in C code drives me crazy. There are absolutely legitimate reasons to use that attribute but there should ALWAYS be a comment about why, so that later readers know in what conditions they can safely remove it.

In the old days I saw C code with massive overuse of the "register" keyword. Meaning this variable should be kept in a register. Someone had ove 12 of these in one function back when that was waaaay more variables then processors had registers. Good thing modern register allocation by compilers makes this irrelevant.

As I recall, "register" was already a no-op in C compilers by the 90s or so (maybe except for embedded? I just don't know enough about that).

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

#204
post #115

Earlier quoted context omitted.

Ugh, you are right but then someone comes and uses this to rationalize not including things like map, filter and reduce in a language because they are supposedly too complicated and you can just do it with a for loop

I work in a Rust codebase that uses a lot of functional functions, and I’ll say this: on average the imperative style takes less lines of code and less indentation. I also find it more readable personally, and idiomatic.

I suspect this has more to do with the lack of first-class sequence comprehensions in the syntax. If you had to write imperative style, but all loops were HOFs, it would hardly be ergonomic, either. OTOH a good query language is much more readable.

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

#205

I don’t feel like this gave a satisfactory answer the question. Since everything was inlined, the argument passing convention made no difference in the micro benchmarks. But what happens when it does not inline? Then you would actually be testing by-borrow be by-copy instead of how good rust is at optimizing.

In Rust it's considered idiomatic to pass things by-value whenever you can. Usually this is also the most performant option, since it avoids dereferencing in the callee. Of course, if your struct is truly enormous, you may want to break this rule to avoid large copies. But in that case you probably want to Box the struct anyway. Of course, if your struct contains something that can't be copied--like a Vec --you'll ha…

When the compiler can see both the callee and the caller (the most common case), why should it even matter? If you pass by value, but don't actually do anything that mutates the copy, and there are no aliasing concerns, surely the compiler can make it by-ref under the hood?

(The other direction is trickier, since by-ref implies the desire to observe aliasing, even though that's usually not expected in practice - but the compiler cannot tell.)

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

#207
post #14

Earlier quoted context omitted.

> This is one advantage of Ada, where parameters are abstractly declared as "in" or "in out" or "out". Also Fortran has "in", "inout" and "out".

C++23 is not too late to the party https://en.cppreference.com/w/cpp/memory/out_ptr_t/out_ptr

So far as I can tell, it's not quite the same thing since these still have pointer semantics (and thus have to deal with aliasing etc). The in/out approach is more generic, since "in" can map to a pointer where it makes sense, and to a copy where it does not.

Better yet when you prohibit such arguments from aliasing (or at least make no-alias the default) - now the compiler can also implement "in out" by copying the value back and forth, if it's faster than indirection.

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

#208
post #56

Earlier quoted context omitted.

As long as the calling convention is deterministic from the declaration of the function it should be fine right?

If it's deterministic, the compiler cannot actually choose the best way to optimise it.

At the minimum, the compiler can look at the size of the type to decide whether copying or indirection makes more sense. The size is stable for a given parameter signature and architecture, so the ABI is stable.

But also, the ABI only matters between two pieces that are separately compiled. A static binary optimized at link-time doesn't have to care.

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

#209

Earlier quoted context omitted.

Agreed - and this applies in nearly every language: start simple, trust your compiler, and optimize only when performance becomes untenable.

This advice hinges hugely on what "start simple" really means. There's a ton of counter-examples here where that just isn't true at all depending on what you're calling "simple". In particular JIT'd languages can be especially problematic here. An example would be using Java's Streams interfaces to do something that could be done without much difficulty with a regular boring ol' for loop. At the end of the day you're…

> you're hoping the JIT will eventually convert the streams version into the same bytecode

Not really. I'm just hoping that it will be "fast enough", which in the vast majority of cases it is.

Post reply on HN