[HN Gopher] Looking at Zig Programming Language ___________________________________________________________________ Looking at Zig Programming Language Author : ksec Score : 122 points Date : 2022-04-05 14:19 UTC (8 hours ago) (HTM) web link (codecs.multimedia.cx) (TXT) w3m dump (codecs.multimedia.cx) | mc4ndr3 wrote: | Zig's ticketing moderation staff are humorless, gatekeeping | stiffs. No thanks. | xtian wrote: | Sorry- what?? Is the implication that you made a joke issue and | are upset about how it was handled? | Shadonototra wrote: | You should take a look at D, if all you want is C/C++ like code, | then you can focus on -betterC and use the libc or your own | batteries (like i do) | | It is the perfect language, don't sleep on it! | throw_m239339 wrote: | D had its chance. It made the mistake of trying to be a paid | language (like Rebol) and failed at it, because clearly unless | you're target a niche but lucrative industry, languages with a | paid compiler are mostly a failure in the era of GCC and co. | It's too late to develop a significant community around D. Rust | clearly got the community aspect right. | Shadonototra wrote: | Rust is a failure because it takes an eternity to build | projects, and is now infected by NPM-hell dependency | management | | Imagine you have to wait for hours for your tests to compile | and then to run, and then your micro services to compile to | deploy a security update for a major CVS | | Rust is poorly designed with poor syntax with a poor | foundation that can't scale in today day and age | the__alchemist wrote: | I've been doing a lot of translating C to Rust lately, and | the Rust variants are much cleaner and more explicit. | Especially regarding namespaces (ie no need to | name_space_name_every_data_structure), explicitly declaring | array types and references of instead of using pointers, | and state management. | Shadonototra wrote: | Everything 'RE'written in X, Y or Z will look better | because the problem was already solved, you only have to | rewrite the text | tialaramex wrote: | There's perhaps some tiny kernel of truth in this, but as | a generalisation it's obviously horribly wrong. | | Imagine trying to rewrite GCC in Bourne shell, or trying | to rewrite the Linux kernel as Java. The results are not | going to "look better" they're going to be awful, these | languages are a terrible fit for the problem. | | What people keep finding with Rust is that it's a really | _nice_ language to write software you might otherwise | write in C or C++. The defaults are correct, the tooling | is great, the errors are superb, it 's just a very nice | experience. | audunw wrote: | Zig and D comes at it from different ends. With D, it feels | like the C replacement aspect of it is an afterthought, an add- | on (I don't remember it being a big focus at all when I used | it). | | Zig aims to be a C replacement from the start, including being | a much better toolchain for cross-compiling C code than any | other C compiler. | | For embedded development, which is what is relevant to me, I | never found D a good option. If that has changed they need to | work on the marketing. | | As an object-oriented garbage collected language with various | nice features, I don't see what sets it significantly apart | from C# anymore. Well, you can compile proper binaries. But | dotnet core interpreters seems to be spreading on our Linux | boxes, so then being able to run the same .exe in Linux and | Windows is actually a nice thing. Then again I'm not in the | market for such a language, so I probably shouldn't comment. | Shadonototra wrote: | Zig aims to be a total C replacement | | D is a natural evolution of C, fixes its issues (bounds | checking and use after free for example), and adds some | niceties that makes it pragmatic and polyvalent on top of a | solid alternative to MACROs and metaprogramming capabilities | | You can do native system development, embedded development, | high-level tasks thanks to the optional GC and it can also | becomes a scripting language | | Something you can't have with Zig, but that's not its goal | anyways | | Also D is one of the rare languages that maintains its own | backend, its own compiler (with optimizations available!) and | a community that grows organically without needing major | corporations support, it is a true labor of love, and it | still gets new features today (ImportC) | | Why i stick with D? because of all of the above! it's an | unmatched language, that compiles code SUPER FAST! | | .. and the syntax remains similar to C/C++; no need to learn | new syntax gymnastic | jmull wrote: | Eh, this is an entirely superficial take. (Pattern match: not | just like the things I currently already know.) | | I don't think this has any value. | | (Not that there might not be valid criticisms of zig or insights | into its value... But this article doesn't contain them.) | ajkjk wrote: | It all seemed like valid criticism to me. It wasn't at all | pattern-matching to things they know, it was evaluating and | critiquing in each in term, and preferring one or the other for | various reasons. | GeorgeTirebiter wrote: | "No idea though where pointer dereferencing as foo.* = 42" I have | no idea either, but it does remind me of BLISS; I remember there | being BLISS-10 (for pdp-10) and BLISS-11 (for pdp-11), came out | of CMU. (Apparently there were even more versions | https://en.wikipedia.org/wiki/BLISS ) | | All variables were pointers; and so a common BLISS statement | would be: | | .Z = .X + .Y which in 'C' would of course be z = x + y | gsliepen wrote: | Interestingly, you can do foo.operator*() in C++: | https://godbolt.org/z/f5Geqcvdj | [deleted] | nemo1618 wrote: | I actually love the foo.* syntax. Think about it like this: if | foo were a struct, then foo.x would give you the x field. But | what if you want _all_ the fields? Then you 'd write foo.* -- a | Unix glob! | skywal_l wrote: | TLDR: The author discuss its subjectivity towards the language. | In short, they're not a fan of how zig handles errors, some loop | constructs and the language design regarding keywords and built- | in functions. They will not use the language even though it comes | with interesting innovations. | | On the first two points, it's disappointing not to see a | discussion on the goals of zig and why these choices were made | [0]. Like any trade-off, there is a reason behind it. | | The third point, which occupies the biggest paragraph, is | somewhat irrelevant to me. | | An interesting take but which remains at the surface. Might not | be worth the 5 minutes it takes to read it. | | [0] https://ziglang.org/learn/overview/ | synergy20 wrote: | why is this downvoted? I like the short description. I spent a | few hours two weeks ago to walk through ziglang's tutorial(to | see how fit it is to replace c/c++ for system programming), my | summary so far is: interesting stuff, but not good enough for | me to switch yet. Will be on my watch list for next few years. | | Did similar thing with rust(ziglang to c vs rust to c++), | decided to stay with modern c++ but will keep an eye on rust as | well. | karmakaze wrote: | This was my first assessment for my own use as well. Seems | very much a 'kitchen sink' language that has everything, but | nothing in particular that draws me to it. If I had pick out | one differentiator it would be that the weird case/camel- | insensitivity makes integrating convenient. | aserafini wrote: | What case/camel-insensitivity are you referring to? | nrclark wrote: | Are you possibly thinking of Nim instead of Zig here? | AnIdiotOnTheNet wrote: | As mentioned in a reply to your other post, Zig has no such | feature except within number literals. `12345E04` is | equivalent to `12_345e04`, but `identifierName` is wholly | separate from `identifier_name`. | verdagon wrote: | I made a tiny roguelike game in Zig a few months back and was | really impressed. | | One thing I really appreciate about the language is the emphasis | on keeping things simple. I heard someone put it really well | yesterday: when you're programming in Zig, you spend your time | tackling the original problem, not tackling the language. | | Also, the article's complaints may be valid, but most of them are | very superficial, which speaks to good language design, in my | opinion. | anoncow419 wrote: | Do you have a public repository for said game you published? | sk1pper wrote: | Hmm, I didn't find that quite to be the case. I wrote a toy | GPU-accelerated (using OpenGL via C) terminal emulator in Zig. | My take is that I'll probably wait for at least a 1.0 before I | start hacking my side projects in it again. | | My main issue was around finding good documentation and (not- | outdated) examples, which I guess just comes with using a | bleeding-edge language. The biggest thing I find lacking is a | "Learn Zig" book that takes you through the whole language. | Sure, https://ziglearn.org/ exists, but it needs about 10 more | chapters. Zig types can get somewhat complex, especially when | interfacing with C, for example - I remember some difficulty | deciphering those. For many things I ended up just reading | Zig's source code itself, especially when looking up standard | library stuff. | | I mean I get it, who wants to write a book for a language whose | features are unstable? | | On the plus side, I agree that I fought Zig a _lot_ less than | when I first started learning Rust. And I still fight Rust if | anything involving generics and/or nontrivial annotations is | involved. | loeg wrote: | Seems to be getting hugged to death. | https://web.archive.org/web/20220405142923/https://codecs.mu... | roblabla wrote: | Tiniest of nits to pick but: | | > and I wish rustc would have a stand-alone assembly files | support | | Rustc now supports inline assembly and global assembly in Rust | 1.59 (the very latest release). So this is now possible: | /// Lib.rs file global_asm!(include_str!("asmfile.s"), | options(raw)); | | Which will cause asmfile.s to be assembled and included in the | rust library. | JoshTriplett wrote: | Absolutely, and any time you can use the built-in asm support, | I'd recommend using it. | | But also, I'd _love_ to see support for C and assembly files in | rustc. | wyldfire wrote: | Note that a really common use case for assembly files (.S | files) is to expect that the file be transformed with the C | preprocessor. | | It would be interesting to imagine a replacement with a rust | equivalent but I can't help thinking that it's difficult or | impossible to come up with an architecture / exec format | independent replacement. gas and cc1as support .macro | directives - maybe that would suffice? But compatibility with | existing assembly source files would suffer. | Dork1234 wrote: | Given the current political landscape Zig really needs to change | there logo. | speed_spread wrote: | Nyet, other guys change logo. Zig not yielding. Zig strong. | | If start moving over anytime some fucker claims ownership of | some symbol, you're gonna have a bad time. Much easier in the | long term to stick to your guns (eh) and make it clear that you | 1 - were there first and 2 - have nothing to do with those | little suka | anonymoushn wrote: | Regarding error handling verbosity, you don't actually have to | write _ = file.write(data) catch |err| { | silence_err_somehow(err); ... }. | | You can just write _ = file.write(data) catch { | ... }. | | And the first example of using `catch` in the docs[0] does this. | It may be useful to also use the non-error return value of | `write` though, because partial writes will return an amount of | written bytes less than the amount you asked to write. You need | `writeAll` if you want to ignore this concern, and then you don't | have to write `_ = ` because the non-error part of the error | union is void (so you don't have to use it). Then you get | file.writeAll(data) catch { ... } | | [0]: https://ziglang.org/documentation/master/#catch | nonsequitur wrote: | Hint: It's `catch {}` instead of `catch { ... }`. | anonymoushn wrote: | That's right if you want to do nothing on error. I think TFA | uses `...` to represent the code they would actually want to | run if an error happened. | wyldfire wrote: | That makes sense. But it's easy to confuse a prose ellipsis | with the C++ notation for indicating the wildcard exception | acceptance pattern. | kjs3 wrote: | Zig is not C++. | hibbelig wrote: | May no programming language ever introduce "foo" or "bar" | keywords, lest mayhem be upon us. | wyldfire wrote: | Sorry, I suppose you could infer that but it was not my | intent. It was merely my suggestion that someone's new | exposure to Zig might be 'tainted' by previous exposure | to C++ syntax. | karmakaze wrote: | One 'catch' that makes me uncomfortable with Zig is the | camel/underscore-insensitivity. How do you find all references | of a method? Does your editor/IDE know how to find writeAll | when I search for references of write_all? Do you have lint | rules that are enforced for a project's source? | AnIdiotOnTheNet wrote: | Unless something has drastically changed since I last used | Zig, it doesn't have the feature you're talking about except | in the case of number literals. `write_all` is a completely | different identifier from `writeAll`. | lhorie wrote: | That's nim[0], not zig | | [0] https://nim-lang.org/docs/manual.html#lexical-analysis- | ident... | nrclark wrote: | Is is possible you're mixing up Zig and Nim? | kristoff_it wrote: | Well, if those are the biggest problems the author has with Zig, | then we're doing a fine job :^) | | WRT having error unions just be a userland tagged union type, | here's a reason why we don't do that: | https://ziglang.org/documentation/master/#Error-Return-Trace... | lhorie wrote: | The error thing to me hints more at how people use errors in | the wild than anything specifically about Zig per se. The | example that comes to mind is propagating parsing errors from a | recursive descent parser. Typically one just wants to unwind | the stack with some user friendly string error message | indicating what exactly went wrong, but philosophically | speaking, a parse error isn't really exceptional, it's an | expected code path for invalid input. | | The way zig seems to think about errors is that early returns | via `try` shouldn't be leveraged as a control flow mechanism to | bail and bubble up values across the call stack. I think rather | than saying why the error handling is done the way it is, it'd | be more valuable if there were documentation on how one is | supposed to go about coding to be able to use this bail-to- | bubble-up-values pattern. Currently, the workaround is indeed | somewhat verbose as it requires mimicking the `try` mechanism | (and/or using some sort of global error store or whatever). | throwawayzig wrote: | I think more importantly, the error return mechanism in zig | creates a trace, and for parser early returns you don't want | a trace, so a 'richer' struct union mechanism makes sense. | anonymoushn wrote: | I didn't really understand. What is the problem and what is | the workaround? Can you give an example? | defen wrote: | The problem (which is a deliberate design decision) is that | Zig's error unions, which have special built-in support at | the syntax level, are just tagged unions with an integer | payload. In other words, when you return an error (either | implicitly via `try` or directly with `return | error.MyError`), that error payload is just an integer | indicating which error was returned. So to use OP's parser | example, there's not a built-in way to attach some sort of | diagnostic info to the error itself, the way you would | with, for example, python exceptions. Using the built-in | syntax, you can't do the equivalent of `raise | ParserException(token, line_number)` and then unpack that | error later in your code to display a nice error message. | | The workaround would be to store that info in some sort of | global struct (which has all the usual drawbacks of global | variables); add a context/diagnostics parameter to your | function, or manually manage your own error union in | userspace, which means you lose the nice `try` syntax. | lhorie wrote: | The problem is that in other languages, it's common to do | this sort of idiom throw new | Error("Expected foo, found bar at line " + line) | // ...then elsewhere catch (e) { log("In | file " + file + ":\n" + e.message); } | | In zig, you can't attach arbitrary strings to errors | because errors are effectively enums (in the sense of that | constant names map exclusively to ints). You can only do | this `try callMe() catch return error.Something` (The | `return error.Something` part is zig's "equivalent" to | `throw error`, but notice how I can't tack on the error | message string to the error) | | `try` only shortcircuits into the `catch return` expression | for errors, but for cases like parsers you want to | shortcircuit _and_ bubble up error messages simultaneously. | You can kinda do weird workarounds by having a pointer to | an error field in your input struct and mutating that prior | to returning an error value, and /or doing weird nullable- | to-sentinel-value-promotion shenanigans with idioms like | `callMeMaybe() orelse return someSentinel("Expected foo")` | to simulate the early-return-from-expression semantics from | `try callMe() catch return error.Something`. | Hoppetosse wrote: | If you want to handle the error and also bubble it up, | maybe even changing the what error bubbles up, you can | just return an error from within the catch block after | doing whatever handling you want. Either the captured | error or something else. | | Specifically for recursive descent parsers, I pass around | a reference to an regular struct that acts as an | ErrorInfo object, and use that to pass diagnostic | information up the stack. Control flow is still managed | by the error returns, any additional info goes in the | parameter. | | There is (was?) a proposal to add that capability to the | language but Im not sure it had much traction. | lhorie wrote: | Yeah I think a lot of people have been settling for that | pattern, but it's admittedly not ideal, in the same way | that it's generally preferable to work with discrete | values in a functional/pure fashion than shuffling values | in and out of an out param list everywhere. | samatman wrote: | > _a parse error isn 't really exceptional_ | | And a parse error should (I will argue) not be what Zig | thinks of as an error. | | There are languages where try/catch became in effect the poor | man's coroutine, and it's doubly confusing with parser | "errors" because this is not something we need to handle as | equivalent to an actual error in our program. A parser error | is normal control flow. | | I would suggest that in Zig one might use suspend/resume to | pass a parser error to something which prints an error, | possibly returning with a 'fix' which lets parsing continue | and maybe find more errors. https://ziglearn.org/chapter-5/ | zozbot234 wrote: | Rust implements this at the library level via common crates | like 'anyhow' and 'thiserror', on top of a tagged type and a | standard "Error" trait. The latter was recently extended to | allow for implementation of these features. ___________________________________________________________________ (page generated 2022-04-05 23:00 UTC)