Basically, for larger arrays, it uses ~ 1.5 x the requested capacity. So, when you request space for 2000 items, it reserves space for 3000, so the next 1000 append calls do not need to allocate/resize.
Could you link to the code, because following the chain in the stdlib that i linked i did not see any size dependend reallocate.
Sorry, Iâm on the phone. Look at growCapacity.
No worries. You can look it up when you are back at a proper computer. I also just left and have only my phone with me.
I canât find the reference, but I think there was a development plan to output code more aggressively in the face of compilation error. At the time, I tought of it as transforming many errors into warnings, and even skipping function with compilation error (e.g. replace it with a panic). I didnât pay too much attention at the time as it was not in the next release, but I thought of it as an acknowledgment that stopping at the first compilation error was not the best.
I wouldnât call that something to remove, itâs more a feature request for non-fatal error, with a touch of more resilient parser that would be better at skipping broken functions/types.
The chain is append â addOne â ensureTotalCapacity â growCapacity. The definition of growCapacity is:
pub fn growCapacity(minimum: usize) usize {
if (@sizeOf(T) == 0) return math.maxInt(usize);
const init_capacity: comptime_int = @max(1, std.atomic.cache_line / @sizeOf(T));
return minimum +| (minimum / 2 + init_capacity);
}
So basically minimum + minimum / 2 + cache_line = minimum * 1.5 + cache_line
While the reserver first concept is something to be preferred, itâs not necessarily something you can always properly do.
I at least donât want to constantly write when the final element number is unknown to me beforehand:
try list.ensureUnusedCapacity(1);
list.appendAssumeCapacity(e);
I think it would be nice to remove the error for âuselessly discardingâ a value:
Hereâs a slightly contrived example that Iâve modified from Zig Comptime ORM
pub fn update(bundle: *Bundle, value_new: Value) void {
const id = value_new.id;
assert(@intFromEnum(id) != 0);
const value_old = bundle.get(value_new.id).?;
assert(value_old.id == id);
bundle.objects.remove(value_old);
_ = value_old; // Don't mix up with value_new
bundle.objects.insert(value_new);
}
This could also be useful for things like conversions:
const count = 10;
const size = count*@sizeOf(T);
_ = count; // Everything is now in bytes
Iâve had nasty bugs due to mixups like this pop up a couple of times (especially programming in C++ where editor tooling is really bad). Less when initially writing something, more when editing existing code, where itâs easier to miss small changes to the names of variables.
Explicitly discarding a value expresses my intent to never use it again, and if I change that decision later or accidentally mix things up, Iâd have some friction that helps me think it through.
Hmm, hard to say, actually.
But probably inferred error sets on pub functions.
I think it creates sloppy interfaces for 3rd parties.
_ = doesnât really âdiscardâ stuff its more like touching it for lack of better words. I am wrong. (I donât think I am wrong.) I would write your examples like:
pub fn update(bundle: *Bundle, value_new: Value) void {
const id = value_new.id;
assert(@intFromEnum(id) != 0);
{
const value_old = bundle.get(value_new.id).?;
assert(value_old.id == id);
bundle.objects.remove(value_old);
}
bundle.objects.insert(value_new);
}
const size = b: {
const count = 10;
break :b count * @sizeOf(T);
};
The problem with the current approach is that during the WIP stage, we use _ = unused to temporarily suppress unused var error.
But this silencer is risky, if it was forget to be removed, unused variables will never trigger warnings in the final stage of development.
On the other hand, compiler warnings are always noticeable, so developers can tolerate them in the WIP stage, but not at all in the finished product stage.
That doesnât work with function parameters
True. You have defeated me in the marketplace of ideas
Did some digging, the current behavior is the result of this proposal
Sorry i take everything back. I have missread that definition. That makes append much better than i expected. Thank you for pointing it out
One of the (many) problems with compiler warnings is that they donât interact well with incremental compilation, which zig is trying to use to its fullest.
At least with _ = unused you can just grep your codebase for it, or you can add automated checks to CI/CD pipelines or pre-commit hooks. Since itâs just syntax, the automated checks donât even need a working compiler!
Inferred error sets were a breath of fresh air when I first tried Zig, having just come from an awful experience trying to learn Rust where the error handling broke me long before the borrow checker could have. (This was several years ago, maybe itâs gotten better since then). I know thereâs monsters here that I havenât fully dealt with yet (and Iâm still quietly holding out hope for error payloads one day), but I think it would be very sad if they were taken out.
I do have an issue with try though, and thatâs that itâs a prefix operator, where all the other âunexpected valueâ operators are postfix. It leads to some weird cases of having to add parentheses simply because I want to try part of the expression. Iâd much prefer a .!.
One somewhat surprising fact is that explicit discards in the final code are very likely harmless; their presence doesnât necessarily indicate a code smell. In certain implementations of interfaces, parameters that the interface requires but arenât actually used are a benign case of explicit discards.
A tiny number of bad discard cases used to suppress errors during the WIP phase because of no warning mechanism can get mixed in with a large number of benign cases, making them hard to analyze.
Isnât it kinda strange to have _ = unused but you can have dead functions all over . I know the compiler just omitted them . But in the spirit of clean as you go wouldnât it make since to do the same with functions like fn blah() _ {}
It sort of would, I guess, but if the compiler subjected all declarations to semantic analysis, Zigâs ability to do conditional compilation would be significantly hampered. Particularly, requiring this error would be fairly problematic, since some functions are reached or not based on comptime data (like the target, or the optimization mode)