thread 16198 panic: integer overflow
Unwind error at address `./development:0x2dc2f6` (unwind info unavailable), remaining frames may be incorrect
???:?:?: 0x3e12ff in multi_array_list.MultiArrayList(array_hash_map.Custom([ ]const u8,[ ]const u8,process.Environ.Map.EnvNameHashContext,false).Data).slice (./development)
???:?:?: 0x3e1ff0 in multi_array_list.MultiArrayList(array_hash_map.Custom([ ]const u8,[ ]const u8,process.Environ.Map.EnvNameHashContext,false).Data).items__anon_24407 (./development)
???:?:?: 0x3e1f28 in array_hash_map.Custom([ ]const u8,[ ]const u8,process.Environ.Map.EnvNameHashContext,false).keys (./development)
???:?:?: 0x3e1df6 in process.Environ.Map.keys (./development)
???:?:?: 0x44761e in process.Environ.Map.deinit (./development)
???:?:?: 0x442e83 in start.posixCallMainAndExit (./development)
???:?:?: 0x441bf1 in start.\_start (./development)
zsh: abort ./development
I removed the deinit part and it was fine(I also tried making environ_map mutable).
Another thing that added to the confusion is …
const environ = init.minimal.environ;
var environ_map = environ.createMap(gpa);
defer environ_map.deinit();
So, does it allocate?
If so, then how come that it didn’t accept an allocator parameter?
If not, then what is the significance of the part of the doc comment that says “initialized with gpa”?
A general rule of thumb is if you didn’t ever pass an allocator, then you don’t have to call deinit.
This is a special case of that rule. Juicy main did the allocation, so you don’t have to.
The special case is that since juicy main does the deallocation, you don’t have to worry about it, even if you call one of the apis and pass in an allocator.
True. I was talking more about allocation specifically. It’s good to call this out. Generally if you create the resource, you are incharge of calling deinit
Then it will also be true for any programming language if your read the source code and documentation.
At this point hidden flow is not but an illusion
I mean… no. Memory allocation is not control flow. Also, this is exactly the same as any other case where someone hands you some memory that you didn’t allocate— if you didn’t allocate it then you shouldn’t be responsible for freeing it.
At best this is a hidden dynamic allocation, since you have to know about the different process initialization options to control it, but in no way is this control flow.
OP’s initial code and argument (passing a gpa to the map) seemed very reasonable to me. The reason why it failed was hidden in non-trivial code which was nowhere in his source code or dependencies. That’s hidden control flow, or hidden code, whatever you want to call it.
I forgot to check start.zig source code thank you for posting that.
But still one does not pass an allocator parameter to allocate that memory, but sense it happens in callMain() I think it’s less bad because what! you want to pass an allocator the main function!
Then, why even include it to begin with? what big problem does this exception to “In Zig if an API allocates memory then it must take an allocator” solve?
I personally will not use init.environ_map I think the following is just fine …
var environ_map = init.minimal.environ.createMap(gpa);
defer environ_map.deinit();
that is literally what init.environ_map is, not only that, but your snippet is still using the full std.process.Init so init.environ_map still exists meaning your allocation is unecessary.
If you were to use std.process.Init.Minimal as the parameter it would be fine, but to ask for the full thing, then duplicate what it does with no changes is just un optimal.
Juicy Main is great to get things quickly, especially allocator and io. It’s a nice way to lower the barrier for newcomers to the language, as Hello World might have been frightening at first sight.
I never saw Juicy Main as something else than pure convenience to start with. But at some point in a project, I assume it has to be removed, at least to choose from Threaded/Evented io.
Thank you for reminding me.
I actually thought about using Init.Minimal but I got lazy replacing init.io and init.gpa (which picks an appropriate allocator not just debug_allocator).
I don’t know if it’s just familiarity, but my knee-jerk reaction was, “why would you deinit() when you weren’t responsible for init()?” And I don’t even use juicy-main, and know very little about it! I think that what makes this “not hidden magic” is that symmetry.
What would be “wrong”, for sure, is if I called foo.init(gpa) (or create() or whatever) and was informed, in a back alley, that I should NOT call defer foo.deinit(), or otherwise consider my responsibility for the resource that required an allocator to create/init. That would be “bad magic” (which some might wrongly think “a nice convenience”, in the vein of GC). But juicy-main does feel like it’s supposed to be a batteries-included power-tool, so I’d enter into its use expecting it to do allocations, initializations, setups as well as the symmetric deallocations, deinitializations, and teardowns for me. I’d expect this with environ_map, io, and the whole kitten kaboodle (unless std.process.Init.Minimal was used instead of the full .Init, apparently, as @vulpesx pointed out, and about which I knew nothing about before).
in my question as I was telling my thought process, I was telling the whole story that led to my confusion.
I don’t mean that should be the way.
What I do think should be the way is …