Earlier quoted context omitted.
I disagree, Rust and C++ are very different languages with significant impedance mismatches once you go beyond the common C-like subset. Referencing C++ as a matter of course in docs and blog posts would just cause confusion. If you want a modern language that really is a lot closer to C++ you may want to check out Carbon.
Rust was created as a C++ replacement, borrows the 'zero cost abstractions' motto from C++, relies on RAII for resource management like C++ (not many languages do it), has the same approach to concurrency (in-place mutation guarded by locks), uses the codegen backend that was created for C++. It's mostly a C++ subset with more guardrails. Edit: RAII
Under the hood: Vec
91–100 of 142 posts
Re: Under the hood: Vec<T>
#92Earlier quoted context omitted.
From your description, I cannot determine the difference. Engineers like exact things, whats this fuzzy concept called “hint”?
The difference according to Rust doc itsef: reserve() > Reserves capacity for at least additional more elements to be inserted in the given Vec . The collection may reserve more space to speculatively avoid frequent reallocations. reserve_exact() > Reserves the minimum capacity for at least additional more elements to be inserted in the given Vec . Unlike reserve, this will not deliberately over-allocate to speculati…
Do reserve and reserve_exact increment the capacity, or ensure there’s still at least that much capacity remaining?
If the former, if I reserve(1) 10 times in a row, does that mean it could be rounding up to a thousand elements (say, because of the page table size) each time?
Re: Under the hood: Vec<T>
#93Because this is focused on how the data structure works it doesn't mention lots of nice API design choices in Rust. The one I particularly want to call out because it came up this morning is providing both Vec::reserve and Vec::reserve_exact Vec::reserve lets us hint about our upcoming capacity expectations without damaging the O(1) amortized growth which is the whole point of this collection type, but it can waste s…
From your description, I cannot determine the difference. Engineers like exact things, whats this fuzzy concept called “hint”?
reserve_exact() reallocates by exactly what you ask for.
If you reserve() space for 1 more element a 1000 times, you will get ~30 reallocations, not 1000.
This inexact nature is useful when the total size is unknown, but you append in batches. You could implement your own amortised growth strategy, but having one built-in makes it simple for different functions to cooperate.
Re: Under the hood: Vec<T>
#94Earlier quoted context omitted.
I’m getting old. I can understand the words, but not the content. At this point, show me dissassembly so that I can understand what actually happens on the fundamental byte/cpu instruction level, then I can figure out what you’re trying to explain.
Nothing really happens on the instruction level because this is all type system logic.
Re: Under the hood: Vec<T>
#95Earlier quoted context omitted.
In prehistoric Rust, variance used to be named more explicitly. However, the terminology of covariant and contravariant subtyping of lifetimes is a language theory jargon. This is the right perspective for language design, but programmers using the language don't necessarily use these terms. It's been replaced with a "by example" approach. It's much easier to teach it: just add a fake field that acts if you had this…
Years ago, I introduced Flow gradual typing (JS) to a team. It has explicit annotations for type variance which came up when building bindings to JS libraries, especially in the early days. I had a loose grasp on variance then, didn't teach it well, and the team didn't understand it either. Among other things, it made even very early and unsound TypeScript pretty attractive just because we didn't have to annotate typ…
Re: Under the hood: Vec<T>
#96Earlier quoted context omitted.
The difference according to Rust doc itsef: reserve() > Reserves capacity for at least additional more elements to be inserted in the given Vec . The collection may reserve more space to speculatively avoid frequent reallocations. reserve_exact() > Reserves the minimum capacity for at least additional more elements to be inserted in the given Vec . Unlike reserve, this will not deliberately over-allocate to speculati…
I could look this up, but I’m enjoying reading this conversation. Do reserve and reserve_exact increment the capacity, or ensure there’s still at least that much capacity remaining? If the former, if I reserve(1) 10 times in a row, does that mean it could be rounding up to a thousand elements (say, because of the page table size) each time?
So reserve(1) 10 times in a row will just repeatedly ensure there's enough space for at least 1 more item, which after the first time there certainly is†
There's an excellent chance the capacity check in particular got inlined, so the optimized machine code will not "actually" call a function ten times, it'll call it once and then maybe emit a single capacity check inline, the subsequent checks even a crap 1980s optimiser will go "We do not need to check that again" and skip it.
† If the Vec is full and can't grow, which really can happen for Zero Size Types in particular, then this panics, and what happens next is a compile time choice, in debug likely it just tells you what went wrong and suggests how to make a backtrace. In the ordinary case that we instead got to keep running then it succeeded.
Re: Under the hood: Vec<T>
#97Because this is focused on how the data structure works it doesn't mention lots of nice API design choices in Rust. The one I particularly want to call out because it came up this morning is providing both Vec::reserve and Vec::reserve_exact Vec::reserve lets us hint about our upcoming capacity expectations without damaging the O(1) amortized growth which is the whole point of this collection type, but it can waste s…
From your description, I cannot determine the difference. Engineers like exact things, whats this fuzzy concept called “hint”?
Re: Under the hood: Vec<T>
#98related: https://doc.rust-lang.org/nomicon/vec/vec.html
Oh, I never knew that Rust had variance. I always just assumed everything was invariant. Strange that they've got no way to write it down in the type system.
Separately, if everything were invariant, you wouldn't be able to use a `&'static T` where a `&'non_static T` was expected, which would be quite unpleasant!
Re: Under the hood: Vec<T>
#99Earlier quoted context omitted.
Suppose I think I may need 128 entries at some point, but the vector is allocated with room for 16 entries by default. I may not want to allocate and then immediately allocate again. But if I get to a 17th entry then I’m already causing allocation. So I might as well allocate 128 at that time so there are no more allocations at all.
All the functions mentioned above, even the cpp one, will reserve atleast the number of elements given to resize() or resize_exact(), but may reserve more than that. After some pondering, and reading the rust documentation, I came to the conclusion that te difference is this: reserve() will grow the underlaying memory area to the next increment, or more than one increment, while reserve_exact() will only grow the und…
By contrast reserve will allocate space for the extra elements following the growth strategy. If you reserve(100) on an empty Vec the allocation will be able to actually insert 128 (assuming the growth strategy is pow(n))
Re: Under the hood: Vec<T>
#100Earlier quoted context omitted.
All the functions mentioned above, even the cpp one, will reserve atleast the number of elements given to resize() or resize_exact(), but may reserve more than that. After some pondering, and reading the rust documentation, I came to the conclusion that te difference is this: reserve() will grow the underlaying memory area to the next increment, or more than one increment, while reserve_exact() will only grow the und…
> even the cpp one, will reserve atleast the number of elements given The C++ one, however, will not reserve more than you ask for (in the case that you reserve greater than the current capacity). It's an exact reservation in the rust sense. > reserve() will grow the underlaying memory area to the next increment, or more than one increment, while reserve_exact() will only grow the underlaying memory area to the next…
It would be nice if this were true but AFAIK the memory allocator interface is busted - Rust inherits the malloc-style from C/C++ which doesn’t permit the allocator to tell the application “you asked for 128 bytes but I gave you an allocation for 256”. The alloc method just returns a naked u8 pointer.