4 ms·
> I think unless you have some precise needs about memory allocation, and want to control exactly where when and how memory is allocated, it is hard to argue in
by MrBuddyCasino 4y ago
> I think unless you have some precise needs about memory allocation, and want to control exactly where when and how memory is allocated, it is hard to argue in favour of Zig.
I do have a hard time to think of use cases other than embedded microcontroller work where that matters nowadays. That said, I suspect that while they could have written TigerBeetle in Rust (no_std does not assume the existence of an allocator), it would have been more difficult.
- AnIdiotOnTheNet 4y ago> I do have a hard time to think of use cases other than embedded microcontroller work where that matters nowadays. People keep saying things like this and software keeps getting more bloated and shittier. It is difficult to believe there isn't a correlation.
- mr_00ff00 4y agoI might be misreading this comment, but the answer to bloated software is not writing all of it in rust/C++/zig. The reasons for bloat is not garage collection.
- AnIdiotOnTheNet 4y agoIt is not about the minutiae of language choices no, it's about a pervasive programmer mindset of not wanting to think about resources like memory of clock cycles or bandwidth as things that actually matter.
- titzer 4y agoA lot of it is that APIs, particularly for GC'd languages, often require lots of intermediate garbage and defensive copies. It wasn't until Java 17 that there was a standard way of parsing integers that didn't allocate. I blame libraries more than languages, TBH.
- kaba0 4y agoSure, I am just confirming that mindset, but can you really reason about the performance impact of that allocation? Even if it does end up allocating due to escape analysis not being sufficient, it will do a thread local pointer bump allocation on a hot, in-cache arena basically, and will just be zero-cost cleared once the still achievable objects are moved. My point is, knowing when to think/not think about allocating and its relevant costs is the proper way to program in a high level language. Only care about it when you are at a part that runs in a hot loop or very often, etc. Pretty much as per the second part of the often partially quoted “premature optimization…”.
- wyldfire 4y agoI think as hardware and software have matured, more and more people have access to develop software. They get correct results without having to dictate every little item. I think it's great, personally. I don't know if it's necessarily "bloat" because it's probably a net win that we wouldn't get some of this software otherwise. The really awesome news is that for those of us who still develop software whose requirements mandate this kind of control - better tools like Zig (and Rust) are making things easier but without requiring things like a GC.
- cmrdporcupine 4y agoThe issue is not always garbage collection. The issue is, as others have pointed out, not having to think about it (memory & cycles.) But this also ties very much into another thing about many modern applications: excessive reliance on third-party packages, many of which are written with (or without) constraints and features that aren't always a match for the core application. It's very easy to blow out your memory use and runtime costs this way. And in this respect Rust could be vulnerable, because Cargo.toml makes it way-easy to pull in a huge tree of transitive third party dependencies without even thinking about it.
- spacechild1 4y ago> I do have a hard time to think of use cases other than embedded microcontroller work where that matters nowadays. Another example: realtime audio applications. There are rather strict rules about what you can and cannot do in the audio callback. In particular, you must not use the system memory allocator (because it may block). Instead you have to pre-allocate memory or use real-time safe memory pools. For this reason, the vast majority of (realtime) audio code is still written in C and C++.
- snek_case 4y agoJIT compilers, games, database server. Anything where you need high performance and do a lot of allocations.
- kaba0 4y agoJIT compilers don’t actually need that low-level programming, and compilers in general use memory in a very haphazard way so they are likely better off with a GC. In fact, you probably loose way more by not being able to write as many/great optimizations in a low-level language than what you lose on a slight overhead — e.g. Java’s Graal JIT compiler is nowadays performing better (written in Java itself) than the “original” C2 compiler which is written in C++. But this is mostly a maintainability question.
- titzer 4y agoI second that; there is nothing inherent about a JIT that requires low-level memory tricks, except that last step of making the machine code executable and callable. I'm not sure that Rust is a good fit for optimizing compilers, either. E.g. most compiler IRs are fundamentally graph-based and use unrestricted cycles. TurboFan in V8 uses arena-style allocation, as do most of the JITs in other JSVMs, mostly because managing every single node is overkill. A GC with a big enough young gen will do well for the kinds of allocation patterns of a JIT.
- snek_case 4y agoFirstly, an arena-based allocator is a custom allocator, which is something most programmers never need to touch and probably don't know even know about. It is a "low-level memory trick". Secondly, we were talking about how Zig makes allocation first-class. This is a prime use case: specifying your own custom arena-based allocator.
- cmrdporcupine 4y agoIndeed, having played with doing compiler / parser / transformation type work (for relational query transformation, etc) in Rust, and got stuck in a maze of borrow-checker disasters around the tree of references... what I'd say is: this kind of thing is actually better done in a higher level statically typed garbage collected language. For myself, I'd use a mature functional something like OCaml/StandardML or a Lisp or similar. It's just easier to not have to worry about borrow checking references and allocation issues when writing stuff like that. The case against garbage collection is where latency is key. P95, P99 latency always suffers under any kind of garbage collector, no matter how advanced. You can minimize pauses, you can move them around, you can play with different collector aspects, but in the end... compare to explicit allocation/destruction/lifetime mgmt, it's going to suffer. I don't think compilers generally have these latency concerns. Throughput matters, but not the odd unpredictable pause. There's only so many application domains where that is super important: Certain kinds of high traffic servers, database engines [not so much query parsing & planning, but execution, data structures, buffer mgmt, networking], operating systems, and games. Also embedded systems where a tight memory profile is important. I like Rust (and Zig) but sometimes when people have a good hammer, they go looking for nails where there aren't any... (All that said, I feel like some tree/DAG-heavy problems in garbage collected languages could benefit from static (and runtime) reference analysis tools that look a lot like Rust's borrow checker, purely for code sanitation/tracing. Also, GC tracing and some of the programming patterns GC encourages can cause havoc on L1 caches reducing throughput as well as a side-effect, so there's that)
- cmrdporcupine 4y agoRe: TigerBeetle... caveat with I haven't looked at the TigerBeetle internals&source code, but. Some thoughts... The kind of page buffer allocation done inside databases is kind of a different nature than the kind where you, e.g. override the default allocator in STL collections, or pass a different allocator into your standard collections library in Zig. It's generally such that only specific data structures -- usually BTrees or HashTables meant to store relations/tables/indexes -- are managed this way. And so they're usually built from scratch around an explicit specific page buffer mgmt system. In some systems (like Umbra or LeanStore) this might be somewhat murkier in that it might use pointer swizzling etc behind the scenes, but it's still usually the case that the data structures used for relation storage are tied directly to the DB's own page buffer implementation anyways. Now, other parts of the application stack may benefit from having a custom allocator in the same way as any performance critical system might, but that's of a different nature. (That said, Rust is also not easily suited to the kind of "pointer-swizzling" behind the scenes bait-and-switch with memory that e.g. LeanStore does with C++. I've tried, and, while it's possible, the language in general gets in the way and you're `unsafe` all over the place anyways.) Anyways, all this to say, TLDR given that all serious databases do explicit memory / buffer pool mgmt ... and build data structures specific to them, I don't see any intrinsic advantage to Zig for this purpose really? Other than it's a decently modern systems programming language that mostly stays out of your way. But... I can see major advantages to using Rust: more developers, bigger community, larger ecosystem, safer for memory mgmt elsewhere in the stack, safer for concurrency, etc.