4 ms·
I'm no expert on either languages, but I tried Zig for the first time properly the other day. I really liked it up until I hit hashmaps. One thing that I think
by bodge5000 3y ago
I'm no expert on either languages, but I tried Zig for the first time properly the other day. I really liked it up until I hit hashmaps. One thing that I think goes under-appreciated about C (and other languages with a similar paradigm) is thats its pretty upfront and clear about what it can and can't do out of the box. If you want hashmaps in C, you need to create your own implementation, otherwise think of a way round them. In Zig meanwhile, they exist in the standard library, but at least for me, were more work than they were worth to work with. The result was the same, when making my test project in both C and Zig I ended up not using hashmaps, the difference is that in C I came to this decision in 2 minutes rather than 2 hours.
I imagine if I had more experience in Zig, none of that would be a problem, and its not aiming to be a beginner-friendly language anyway, but that was just my experience of it so far
- hazebooth 3y agoWould you mind elaborating on the complications you ran into? I ask because I think you used std.HashMap instead of std.AutoHashMap, the latter of which automatically chooses a hash function based on the types provided.
- bodge5000 3y agoIt was a little over a week ago now so my memory is a bit hazy, but I'll try to the best of my knowledge. Without getting into the weeds of why (happy to do so, just want to keep this readable), basically I needed to define and populate a hashmap in a new script and then import it into my main script, which to my mind left me with two options: * Define and initialise it at the same time (my preferred method) as a constant. I don't have much to say on this as iirc, I had no luck with it at all, never even got close. * Define it in a (public) function, add each field in with "put" and then return the hashmap. I tried with std.AutoHashMap and various other things, but to what I could work out there was no type of hashmap, so it wouldn't accept my return type.
- ForkMeOnTinder 3y agoHere's how you return a hashmap from a function: fn buildMap(allocator: std.mem.Allocator) !std.AutoHashMap(u64, u64) { var result = std.AutoHashMap(u64, u64).init(allocator); errdefer result.deinit(); try result.put(10, 100); try result.put(20, 200); return result; } Your #1 option should be possible once Zig has comptime allocators -- it's on the roadmap, but not possible yet iirc.
- bodge5000 3y agoIf I remember correctly I tried almost exactly that, I think it was just the bang operator I missed out (obviously essential in this case). Cheers for letting me know though!
- hazebooth 3y agoI think for the first point you wanted a block that evaluated to the map, unsure if that’s what you wanted though
- bodge5000 3y agoI think so, if I write it out in pseudo code it might make more sense. What I was trying to do was pretty much: const mymap = {1: "hello", 2: "world"}; But the only thing I could find any answers for was something more like: const mymap; mymap.put(1, "hello"); mymap.put(2, "world");
- jeltz 3y agoI can't remember having any issues with using hash maps in Zig when I tried it out during Advent of Code. They were almost as easy to use in Zig as in Rust. Only extra complication was returning error on failed allocation rather than panicking.
- matklad 3y agoAs counter point, the way that Zig implements hash maps is absolutely instrumental for TigerBeetle. Zig hashmaps _are_ quite a bit more cumbersome than, eg, in Rust --- you need to decided whether you want the allocator to be bundled with the hasmap, and its also up to the user of the hash map to provide equality and hash code (and, of course, there's manual defer instead of RAII). However, this flexibility and verbosity comes with a super-power --- you can pass an allocator to a hash map at creation time, and then _not_ pass an allocator when you actually use the hash map. This is huge. This means that we get compile-time guarantee that we follow rule 3 of NASA's 10 rules 3. Do not use dynamic memory allocation after initialization. And we _still_ can enjoy using a hashmap from the standard library! No other language I know has an equivalent tool.
- the__alchemist 3y agoNot quite std, but Rust's heapless lib let's you use a statically-allocated Hashmap. The distinction is its max size is declared on construction.
- matklad 3y agoThat's not quite it: with heapless, memory is fully static, the size of hash map is a compile-time parameter, which is a part of HashMap's type. In Zig, the map could be initialized and sized at runtime, but you still can enforce, statically, that it doesn't do any allocations after that. In both nightly Rust and Zig, heapless version can be expressed by passing a fixed-buffer-backed allocator to the standard hash map.
- menaerus 3y agoI don't quite understand how do you change the size of a zig hashmap in runtime by, for example, inserting 1M items at some point but at the same time being able to enforce in compile-time that such operation will not result with dynamic allocation?
- 8n4vidtmkvmk 3y ago