[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)