5 ms·
Even more unfriendly-yet-typical line is where you create an allocator, and few lines further you run allocator() method on it, to get ...an allocator (but you
by kunley 2y ago
Even more unfriendly-yet-typical line is where you create an allocator, and few lines further you run allocator() method on it, to get ...an allocator (but you had it already! Or maybe you didn't ?) Same: you create Writer, but then you run a writer() method on it.
Here is the code to illustrate:
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var visited = std.BufSet.init(arena.allocator());
var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
const stdout = bw.writer();
So.. what are the entities we use, conceptually? "allocatorButNotReally" and "thisTimeReallyAnAllocatorIPromise"? Same for the writer?
Plus, the documentation isn't much explaining wtf is this and why.
The answer is probably buried somewhere in forums history, blogs and IRC logs, because there must have been consensus established why is it ok to write code like that. But, the lack of clear explanation is not helping with casual contact with the language. It's rather all-or-nothing - either you spend a lot of time daily in tracking all the media about the ecosystem, or you just don't get the basics. Not good IMO. (and yes I like a lot about the language).
- kristoff_it 2y agostd.mem.Allocator is the allocator interface. For that struct to be considered an interface, it must not contain directly any specific concrete implementation as it needs to be "bound" to different implementations (GenealPurposeAllocator, ArenaAllocator, ...), which is done via pointers. An allocator implementation holds state and implements alloc, free and resize for its specific internal mechanisms, and then pointers to all these things are set into an instance of std.mem.Allocator when you call the `.allocator()` function on an instance of an allocator. https://ziglang.org/documentation/master/std/#std.mem.Allocator https://ziglang.org/documentation/master/std/#std.mem.Alloca... File and Socket both offer a `.writer()` function to create a writer interface bound to a specific concrete "writeable stream". BufferedWriter has both extra state (the buffer) and extra functions (flush) that must be part of a concrete implementation separate from the writer interface. > The answer is probably buried somewhere in forums history That's just how computers work, languages that don't expose these details do the same exact thing, they just hide it from you.
- Aeolun 2y agoI think most languages hide this by default because 99% of people don’t have to deal with it.
- metaltyphoon 2y agoYep. For some reason they want to make it boilerplate to write interfaces. Its so pointless
- kristoff_it 2y agoThere are a few different ways of implementing interfaces, each with different tradeoffs, so it's not boilerplate :^)
- 0x696C6961 2y agoI'm only familiar with the vtable approach, what other ways are there?
- throwawaymaths 2y agofieldparentptr. The zig allocators used to use this because it enabled allocator interfaces without type erasure, but it was found to have a minor but real performance penalty as it is impossible for any compiler to optimize for this in scenarios that are useful for allocators. Other interfaces might actually have the opposite performance preference
- cgh 2y agoIf you control every implementation (ie you aren’t writing a library where others will implement your interfaces), then tagged unions are a simple way to accomplish this. See the bottom of this page: https://www.openmymind.net/Zig-Interfaces/ https://www.openmymind.net/Zig-Interfaces/
- kcbanner 2y agoIt's not pointless, because you get to select exactly the design pattern that is best for the situation. Other languages may decide this for you.
- flohofwoe 2y agoIMHO the Zig stdlib (including the build system) by far isn't as elegantly designed as the language. There's more trial-and-error and adhoc-solutions going on in the stdlib and there are also obvious gaps and inconsistencies where the stdlib still tries to find its "style". I think that can be expected of a pre-1.0 language ecosystem though. Currently it's more important to get the language right first and then worry about cleaning up the stdlib APIs.
- klabb3 2y agoAll languages have these problems. Even Go with famously excellent std has many rough spots that either were not available (such as context) or was just a bit poorly designed. The most important job of std is not (contrary to popular belief) to provide a “bag of useful high quality things” but rather providing interfaces and types that 3p packages can use without coordinating with each other. I’d argue that http.Handler, io.Reader/Writer/Closer are providing the most value and they are just single method signatures. When there’s universal agreement of what shape different common “things” have, it unlocks interop which just turbo charges the whole ecosystem. Some of those are language, but a lot more is std and that’s why I always rant about people over focusing on languages.
- flohofwoe 2y agoAlso tbf, even in its current state the Zig stdlib is already infinitely more useful than the C stdlib and even the C++ stdlib.
- flykespice 2y agoAnd will they ever do a revamp on the stdlib API or will stick with it because of backward compatibility concerns just like C/C++ does?
- throwawaymaths 2y agoThey already have had several cleanup-quakes in the stdlib.
- 2y ago
- 0x696C6961 2y agoThis is a good explanation https://www.openmymind.net/Zig-Interfaces/ https://www.openmymind.net/Zig-Interfaces/
- throwawaymaths 2y agoThis is a naming convention problem. In a certain other language that zig is trying hard to not become one of those things would be called an AllocatorFactory.