Hacker News new | ask | show | jobs
by tialaramex 20 days ago
(Sigh)

Fine. If we put a growable array type inside Goose the backing store for such a type would [if needed] live on the heap, unfortunately in Java we're not allowed to use a primitive type like the signed integer here, so lets put a growable array of Doodads where each Doodad is 64 bits.

So now each Java Goose has an ArrayList<Doodad> and yup, each Doodad goes on the heap, and then the ArrayList's backing store goes on the heap with pointers to the Doodads, and then the rest of the Goose goes on the heap too.

In Rust we skip most of those steps for Vec<Doodad> but if there's at least one Doodad we do need to actually have the backing store, the Doodads live directly in that backing store.

Of course if there aren't any Doodads, Java still pays to make the backing store anyway, that's just how Java works again. Rust doesn't do that, an empty Vec<Doodad> is just a dangling pointer, zero capacity, zero length. Since the length and capacity are zero we'll never dereference the pointer.

The story doesn't get better for Java if you make it more convoluted, that's not how any of this works.

1 comments

To be clear I am not picking nits, nor am I trying to prove that 'language X' is better than Rust - but if you want to mention stack allocation as an advantage, then it has to be general enough to work all the time - in my sibling comment I mentioned arenas, which fix this issue. If you malloc in a function-local arena, both the Goose and the Vec inside it end up in there, and will be automatically freed on return.