←back to thread

451 points birdculture | 6 comments | | HN request time: 1.333s | source | bottom
Show context
ajross ◴[] No.43980170[source]
> Use String and clone() and unwrap generously; you can always refactor later

At that point you might as well be writing Java or Go or whatever though. GC runtimes tend actually to be significantly faster for this kind of code, since they can avoid all those copies by sharing the underlying resource. By the same logic, you can always refactor the performance-critical stuff via your FFI of choice.

replies(5): >>43980203 #>>43980432 #>>43980632 #>>43981812 #>>43981902 #
1. mikepurvis ◴[] No.43980632[source]
I went through this the first year that I did Advent of Code in rust, like okay I read in all the strings from the input file and now they're in a vector, so I'm going to iterate the vector and add references to those strings into this other structure, but of course they're still owned by the original vector, that's awkward. Oh wait I can iter_into and then I get owned objects and that ownership can be transferred to the other structure instead, but now I need them to also be keys in a map, do I use references for that too?

Cloning small objects is lightning fast, turns out in a lot of these cases it makes sense to just do the clone, especially when it's a first pass. The nice thing is that at least rust makes you explicitly clone() so you're aware when it's happening, vs other languages where it's easy to lose track of what is and isn't costing you memory. So you can see that it's happening, you can reason about it, and once the bones of the algorithm are in place, you can say "okay, yes, this is what should ultimately own this data, and here's the path it's going to take to get there, and these other usages will be references or clones.

replies(1): >>43980663 #
2. ajross ◴[] No.43980663[source]
> Cloning small objects is lightning fast

It's really not, it's the way python works. Heap allocations are "fast" on modern CPUs that are too fast to measure for most stuff, but they're much (much) slower than the function call and code you're going to use to operate on whatever the thing it was you cloned.

Code that needs memory safety and can handle performance requirements like this has many options for source language, almost none of which require blog posts to "flatten the learning curve".

(And to repeat: it's much slower than a GC which doesn't have to make the clone at all. Writing Rust that is "Slower Than Java" is IMHO completely missing the point. Java is boring as dirt, but super easy!)

replies(1): >>43982877 #
3. pkolaczk ◴[] No.43982877[source]
Cloning doesn’t imply heap allocation. Depends on the type.
replies(1): >>43985720 #
4. ajross ◴[] No.43985720{3}[source]
If the object had a stack-bounded lifetime, the borrow checker would have been able to prove the analysis though. The advice is to clone things it can't, which pretty much requires that it go into the general heap. I'm sure there are some interesting counterexamples, but the situation you're imagining seems kinda academic.
replies(1): >>44003024 #
5. pkolaczk ◴[] No.44003024{4}[source]
The fact something goes to heap doesn’t necessarily mean it needs more heap allocations. I’ve had it many times that I instantiated a new object on heap and had to pass cloned arguments to it (because it had to own them), yet they ended up as inline fields, so no additional allocations. Happens a lot with Rc / Arc.
replies(1): >>44005936 #
6. ajross ◴[] No.44005936{5}[source]
Once more: if the compiler can see to inline the object or put it on the stack or replace it with a by-value/in-register copy, then the borrow checker wouldn't have puked to begin with. The advice is very clearly to make heap allocations as a way to evade borrow analysis. I don't see why that's controversial.