7 ms·
Zig is a very low level language. I think the fancy type system can trip up people into thinking they are working with a high-level language. Zig is basically
by socialdemocrat 5y ago
Zig is a very low level language. I think the fancy type system can trip up people into thinking they are working with a high-level language.
Zig is basically C with a fancy type system, so you should not expect things like special String types, overloading of index based access etc.
I think the author was thinking that Zig was very close to Rust or C++, when in reality it is much closer to C. I had to keep reminding myself of that many times as I was learning Zig.
I had my own struggled with Zig, but not quite as much as the author. I think will probably have a much better experience if you don't try to jump and code right away but read some articles or listen to some videos to get a sense of the overall philosophy of Zig.
I am normally against having to look at source code, but with Zig that is kind of needed but also not quite as bad as it sounds. Zig code base is not that large and it is relatively easy to search. You can lookup a Zig function signature very easily. You need to do this if you are going to use any of the standard library apart from the most basic stuff.
- k__ 5y agoInteresting. I had the impression Zig proponents were praising it because it wasn't as low-level as Rust.
- klyrs 5y agoQuite the opposite. The very broad-brush overview is that zig aims to replace C and rust aims to replace C++... but among other issues with that analogy, that can't happen unless zig and rust have a dead-simple integration story.
- dagmx 5y agoI've only ever really seen it in Zig communities that Rust is closer to C++ In Rust communities, it's often pitched as alternates to both, but closer to C. I suppose it's all relative, but the comparison of rust to c++ seems external
- k__ 5y agoYes, I also had the impression Rust is a C replacement.
- mst 5y agoI sort of look at it as aiming at the spot where you could write the code in C with a sprinkle of C++ features and whether to add that sprinkle or do things like hand-rolling a vtable system where you need one is a decision that will vary depending on circumstances. Though I believe the mozilla code it's replaced was all -very- C++.
- eximius 5y agoFrom a programming language design space, it's much more like C++. However it can occupy some niches that C can but C++ does poorly because of zero cost abstractions, I think. (Very handwavy)
- ncmncm 5y agoThere are no niches where Rust can do better than C++. In many places Rust can, uniquely, match C++.
- nix23 5y ago>>Feature Highlights Small, simple language >>There is no hidden control flow, no hidden memory allocations, no preprocessor, and no macros. https://ziglang.org/learn/overview/ https://ziglang.org/learn/overview/ It try's (achieves?) to be a C without the flaws and historic ballast.
- jibalt 5y agoWhere did you get that impression? No one has ever done that.
- k__ 5y agoHere at HN. I never read anything about Zig outside of HN. What I remember was mostly that Zig should be easier to use than Rust, because Zig doesn't have lifetimes.
- jibalt 5y agoThat doesn't make Zig higher level than Rust. It doesn't have lifetimes because it's low level, on a par with C ... all memory management is manual and you can abuse pointers to your heart's content.
- deleted 5y ago[deleted]
- yjftsjthsd-h 5y ago> Zig is basically C with a fancy type system, so you should not expect things like special String types, If I can't have nice strings, what should I be expecting from a fancy type system?
- deleted 5y ago[deleted]
- dundarious 5y agoZig's "fancy" (I don't think they're that fancy) type features that IMO make it a great C alternative are: - non-null pointers, and distinct types for single-item pointers and multi-item pointers (multi-item pointers are rarely used except indirectly via slices, so unchecked pointer arithmetic errors are largely banished) - builtin tagged unions (AKA algebraic data types) with very pleasant to use switch logic -- it can't be overstated how nice the "handle all the cases" logic is in Zig in general (catch, orelse, if-else/switch expressions) - a decent proposition for errors (the error union, and try keyword), but I haven't decided if I really like it yet There's lots of non-type stuff there too. I was writing personal projects in C without libc, but found there to be a lot of annoying work involved -- happy to do it, but it's not earned/fruitful annoyance, more like a long list of incidental historical annoyances. Zig seems to cater to the same level of the stack, but with all that boring stuff taken care of.
- spc476 5y agoSo it sounds like Zig makes a distinction between pointers and arrays. Am I reading that right?
- dundarious 5y agoYes, arrays are another distinction: - an array [3]u8 - a single item non-nullable pointer *u8 - a single item nullable pointer ?*u8 - a multi-item non-nullable pointer [*]u8 - a multi-item nullable pointer ?[*]u8 - a slice []u8 Typically your API is just made up of slices and non-nullable single item pointers. Arrays are just the typical backing store for a slice, that you might define in main or for small scratch buffers. Here's a typical example of an OS read (where the fd has been set to non-blocking already): fn readUpTo32Bytes(fd: std.os.fd_t) ![]u8 { var array: [32]u8 = undefined; var data = array[0..]; // slice of entire array data.len = std.os.read(fd, data) catch |err| switch (err) { error.WouldBlock => 0, else => return err, }; handle(data); } fn handle(data: []const u8) void { ... } If you don't need to handle EAGAIN/error.WouldBlock, then just do `data.len = try std.os.read(fd, data);` I didn't explain the `!` in the `![]u8` return type, but it's basically saying "an error or a []u8", where it's compile time known what the full set of errors is (in this case every error std.os.read can return, minus WouldBlock).
- octoberfranklin 5y agoI still can't figure out how Zig proposes to prevent undefined behavior without a borrow checker (aka MLKit regions) or GC. AFAICT the answer is "inject as many runtime checks as needed" although the docs seem to go way out of their way to avoid making this explicit.... or deal with the fact that these checks are now runtime failures rather than compile-time failures, and therefore need code to handle them. It seems like it would be the same as writing Rust code using std::cell instead of references, except that Rust would force you to insert handlers for all the new failure modes this would create (of course you could just panic!(), but at least the compiler would force you to insert those panics...).
- _vvhw 5y agoYou're conflating undefined behavior with spatial/temporal memory safety, the latter of which is what is 100% prevented by Rust's borrow checker, provided you're not interfacing with hardware, in which case I believe that things change more in binary fashion. However, Zig treats memory safety not as an extreme-at-all-costs but as a spectrum (there are reasons for wanting to think like this, at least when writing low-level code if you want to make more use of the hardware), getting 100% on the spatial memory safety front and reaching to 50-75% on the temporal memory safety front through the GPA. That's already an order of magnitude more safety than C, at which point memory exploits have dropped in ranking, and you should be more concerned about things like explicit control flow, error handling and checked arithmetic, not to mention the orthogonality of the language. Furthermore, in the systems world, there are many safety critical systems where dynamic allocation and multi-threaded control planes are simply off the table to begin with because they're dangerous in some domains and not as safe as static allocation and single-threaded control planes, which are less dimensional and easier to reason about. And in those cases, UAFs and multi-threaded races are less of a concern (still a concern, but less). Also, Rust won't protect you from all undefined behavior, and Zig often helps more than you think. For example, you might be surprised to hear that Rust has checked arithmetic off by default in safe builds, whereas Zig has this enabled. I've done a little security work on some large systems and the decision to disable checked arithmetic always blows my mind. Integer overflow and underflow are right up there as threat vectors when writing anything that's touching hostile data. I'm waiting for the day when Rust changes direction on this, and I think there's a chance this will happen because the alternative status quo of not checking arithmetic (at all) is just not tenable, at least not if we care about safety and security holistically, and not only memory safety.