[HN Gopher] Why is Zig so cool?
       ___________________________________________________________________
        
       Why is Zig so cool?
        
       Author : vitalnodo
       Score  : 473 points
       Date   : 2025-11-07 23:04 UTC (23 hours ago)
        
 (HTM) web link (nilostolte.github.io)
 (TXT) w3m dump (nilostolte.github.io)
        
       | ForHackernews wrote:
       | > I can't think of any other language in my 45 years long career
       | that surprised more than Zig. I can easily say that Zig is not
       | only a new programming language, but it's a totally new way to
       | write programs, in my opinion. To say it's merely a language to
       | replace C or C++, it's a huge understatement.
       | 
       | I don't understand how the things presented in this article are
       | surprising. Zig has several nice features shared by many modern
       | programming languages?
        
         | raincole wrote:
         | > One may wonder how the compiler discovers the variable type.
         | The type in this case is *inferred* by the initialization.
         | 
         | That the author feels the need to emphasize this means either
         | that they haven't paid attention to modern languages for a very
         | long time, or this article is for people who haven't paid
         | attention to modern languages for a very long time.
         | 
         | Type inference has left academy and proliferated into
         | mainstream languages for so many years that I almost forgot
         | that it's a worth mentioning feature.
         | 
         | > One is Zig's robustness. In the case of the shift operation
         | no wrong behavior is allowed and the situation is caught at
         | execution time, as has been shown.
         | 
         | Panicking at runtime is better than just silently overflowing,
         | but I don't know if it's the best example to show the
         | 'robustness' of a language...
        
           | creata wrote:
           | > Type inference has left academy and proliferated into
           | mainstream languages for so many years that I almost forgot
           | that it's a worth mentioning feature.
           | 
           | I'm not even sure I'd call this type inference (other people
           | definitely do call it type inference) given that it's only
           | working in one direction. Even Java (var) and C23 (auto), the
           | two languages the author calls out, have that. It's much less
           | convenient than something like Hindley-Milner.
        
           | sarchertech wrote:
           | > Type inference has left academy and proliferated into
           | mainstream languages for so many years that I almost forgot
           | that it's a worth mentioning feature.
           | 
           | It's not common in lower level languages without garbage
           | collectors or languages focused on compilation speed.
        
             | foobar1726 wrote:
             | C++ added auto 14 years ago. Swift had it since day 1 back
             | in 2014 if I remember right. What else is there?
        
               | sarchertech wrote:
               | C, Ada, Fortran, Pascal.
        
             | jolux wrote:
             | Compilation speed -- OCaml, Go, D, C#, Java
             | 
             | "Low-level" languages -- Rust, C++, D
        
               | sarchertech wrote:
               | I meant for focused on compilation speed to apply only to
               | lower level languages. And when I say lower level I don't
               | really include D because it has a garbage collector (I
               | know it's optional but much of the standard library uses
               | it I believe).
        
               | jibal wrote:
               | That a language has a garbage collector is completely
               | orthogonal to whether it has type inference ... what the
               | heck does it matter what "much of the standard library
               | uses" to this issue? It's pure sophism. Even C now has
               | type inference. The plain fact is that the claim is
               | wrong.
        
               | sarchertech wrote:
               | The x axis is orthogonal to the y axis, so I can't be
               | interested in the area where x < 1 and y = 5?
               | 
               | > what the heck does it matter what "much of the standard
               | library uses" to this issue?
               | 
               | It matters in that most people looking for a low level
               | manually memory managed language won't likely choose D,
               | so for the purposes of "is this relatively novel among
               | lower level, memory managed languages" D doesn't fit my
               | criteria.
               | 
               | > Even C now has type inference. The plain fact is that
               | the claim is wrong.
               | 
               | Almost no one is using C23 yet.
        
             | spacechild1 wrote:
             | The only popular language I can think of is C (prior to
             | C23). If you want to include Fortran and Ada, that would be
             | three, but these are all very old languages. All modern
             | system languages have type deduction for variable
             | declarations.
        
             | jibal wrote:
             | That's true if the only lower level languages one considers
             | are C and assembler. Virtually every other language has
             | moved way beyond that.
        
           | jibal wrote:
           | And it's not caught in ReleaseFast builds ... which is not at
           | all unique to Zig (although Zig does do many innovative
           | things to catch errors in debug builds).
        
         | fuzzy_biscuit wrote:
         | Of which, perhaps, the author isn't aware? Perhaps the author
         | has very narrow experience in programming languages.
         | 
         | Or it's hyperbolic.
        
           | moralestapia wrote:
           | >Perhaps the author has very narrow experience in programming
           | languages.
           | 
           | I got that impression as well.
           | 
           | Xi's impressed about types being optional because they can be
           | inferred.
           | 
           | That's ... hardly a novelty ...
        
             | forgotpwd16 wrote:
             | >Only the first and third part are compulsory in Zig, which
             | is kind of puzzling, coming from Java or C.
             | 
             | Funny they mention Java that has got type inference few
             | years now. Even C got a weaker version of C++'s auto in
             | C23.
        
               | tialaramex wrote:
               | One of the many things I don't like about C++ is that
               | auto isn't type inference but instead C++ has type
               | "deduction" which is a little different, in some cases a
               | type will be "deduced" even though what you wrote was
               | ambiguous and you may have wanted a different type.
        
         | blahgeek wrote:
         | This. Is Zig an interesting language? Yes sure. But "a totally
         | new way to write programs"? No, I don't see a single feature
         | that is not found in any other programming languages.
        
         | chrisco255 wrote:
         | I feel like the article didn't really hit on the big ones:
         | comptime functions, no hidden control flow, elegant defaults,
         | safe buffers, etc.
         | 
         | What Zig really does is make systems programming more
         | accessible. Rust is great, but its guarantees of memory safety
         | come with a learning curve that demands mastering lifetimes and
         | generics and macros and a complex trait system. Zig is in that
         | class of programming languages like C, C++, and Rust, and
         | unlike Golang, C#, Java, Python, JS, etc that have built-in
         | garbage collection.
         | 
         | The explicit control flow allows you as a developer to avoid
         | some optimizations done in Rust (or common in 3rd party
         | libraries) that can bloat binary sizes. This means there's no
         | target too small for the language, including embedded systems.
         | It also means it's a good choice if you want to create a system
         | that maximizes performance by, for example, preventing heap
         | allocations altogether.
         | 
         | The built-in C/C++ compiler and language features for
         | interacting with C code easily also ensures that devs have
         | access to a mature ecosystem despite the language being young.
         | 
         | My experience with Zig so far has been pleasurable. The main
         | downside to the language has been the churn between minor
         | versions (language is still pre-1.0 so makes perfect sense, but
         | still). That being said, I like Zig's new approach to explicit
         | async I/O that parallels how the language treats Allocators. It
         | feels like the correct way to do it and allows developers again
         | the flexibility to control how async and concurrency is handled
         | (can choose single-threaded event loop or multi-threaded pool
         | quite easily).
        
           | fleventynine wrote:
           | > This means there's no target too small for the language,
           | including embedded systems. It also means it's a good choice
           | if you want to create a system that maximizes performance by,
           | for example, preventing heap allocations altogether.
           | 
           | I don't think there's is any significant different here
           | between zig, C and Rust for bare-metal code size. I can get
           | the compiler to generate the same tiny machine code in any of
           | these languages.
        
             | chrisco255 wrote:
             | That's not been my experience with Rust. On average
             | produces binaries at least 4x bigger than the Zig I've
             | compiled (and yes, I've set all the build optimization
             | flags for binary size). I know it's probably theoretically
             | possible to achieve similar results with Rust, it's just
             | you have to be much more careful about things like
             | monomorphization of generics, inlining, macro expansion,
             | implicit memory allocation, etc that happen under the hood.
             | Even Rust's standard library is quite hefty.
             | 
             | C, yes, you can compile C quite small very easily. Zig is
             | like a simpler C, in my mind.
        
               | fleventynine wrote:
               | The Rust standard library in its default config should
               | not be used if you care about code size (std is compiled
               | with panic/fmt and backtrace machinery on by default).
               | no_std has no visible deps besides memcpy/memset, and is
               | comparable to bare metal C.
        
               | chrisco255 wrote:
               | I understand this, but that is a pain that you don't get
               | with Zig. The no_std constraint is painful to deal with
               | as a dev even with no dependencies and also means that if
               | you're working on a target that needs small binaries,
               | that the crates.io ecosystem is largely unavailable to
               | you (necessitating filtering by
               | https://crates.io/categories/no-std and typically further
               | testing for compilation size beyond that).
               | 
               | Zig on the other hand does lazy evaluation and tree
               | shaking so you can include a few features of the std
               | library without a big concern.
        
               | fleventynine wrote:
               | Rustc does a good job of removing unused code, especially
               | with LTO. The trick is to make sure the std library
               | main/panic/backtrace logic doesn't call code you don't
               | want to pay for.
               | 
               | IIRC there's also a mutex somewhere in there used to
               | workaround some threading issues in libc, which brings in
               | a bespoke mutex implementation; I can't remember whether
               | that mutex can be easily disabled, but I think there's a
               | way to use the slower libc mutex implementation instead.
               | 
               | Also, std::fmt is notoriously bad for code size, due to
               | all the dyn vtable shenanigans it does. Avoid using it if
               | you can.
               | 
               | Regardless, the only way to fix many of the problems with
               | std is rebuilding it with the annoying features compiled
               | out. Cargo's build-std feature should make this easy to
               | do in stable Rust soon (and it's available in nightly
               | today).
        
           | jibal wrote:
           | Zig's generics cause bloat just like any other language with
           | generics--explicit flow control has nothing to do with it.
           | 
           | Zig is a good language. So are Rust, D, Nim, and a bunch of
           | others. People tend to think that the ones they know about
           | are better than all the rest because they don't know about
           | the rest and are implicitly or explicitly comparing their
           | language to C.
        
             | chrisco255 wrote:
             | Zig's generics can potentially, but not necessarily,
             | because Zig's generics are explicitly controlled through
             | comptime functions, which give the developer a ton of
             | control of how the generic code is unrolled. They're also
             | frequently less used in general than Rust generics.
             | 
             | Of course both Zig and Rust are good languages. But my
             | experience, and I believe your experience will be too if
             | you try to compile programs of similar complexity using
             | standard practices of each language, is that Zig compiles
             | much more compactly in .ReleaseSmall mode than Rust does
             | even with optimization flags, which makes it more ideal for
             | embedded systems, in my opinion. I learned this on my own
             | by implementing the same library in both languages using
             | standard default practices of each.
             | 
             | Of course, at the desktop runtime level, binary size is
             | frequently irrelevant as a concern. I just feel that since
             | Zig makes writing "magic" code more difficult while Rust
             | encourages things like macros, it is much easier to be
             | mindful of things that do impact binary size (and perhaps
             | performance).
        
               | zozbot234 wrote:
               | Rust has macros that allow for arbitrary compile-time
               | generated code, just like Zig. Most Rust-compiled
               | programs are a bit bloated because libstd is statically
               | linked and not rebuilt from scratch with a project-
               | specific trimmed feature set, which leads to potentially
               | unwanted code being included for e.g. recoverable panics,
               | backtraces, UTF-8 string handling etc. A set of new RFC's
               | is being worked on that may at some point allow libstd to
               | be rebuilt from scratch within Stable Rust projects, with
               | well-defined, stable, subsetted features.
        
               | jibal wrote:
               | > Rust has macros that allow for arbitrary compile-time
               | generated code, just like Zig.
               | 
               | This is not true. Zig, D, and Nim all have full-language
               | interpreters built into the compiler; Rust does not. Its
               | macros (like macros generally) manipulate source tokens,
               | they don't do arbitrary compile-time calculations (they
               | live in separate crates that are compiled and then run on
               | source code, which is very different from Zig/D/Nim
               | comptime which is intermixed with the source code and is
               | interpreted). Zig has no macros (Andrew hates them)--you
               | cannot "generate code" in Zig (you can in D and Nim);
               | that's not what comptime does. Zig's comptime allows
               | functions written in Zig to execute _at compile time_
               | (the same functions can also be used to run at execution
               | time if they only use execution-time types). The Zig
               | trick is that comptime code can not only operate on
               | normal data like ints and structs, but also _types_ ,
               | which are first class comptime objects. Comptime code has
               | access to the TypeInfo of types, both to read the
               | attributes of types and to create types with specified
               | attributes, which is how Zig implements generics.
        
         | bsder wrote:
         | Winning at chess is more "avoid gigantic blunders" than "make
         | brilliant moves".
         | 
         | Zig feels like one of the few programming languages that mostly
         | just avoids gigantic blunders.
         | 
         | I have some beefs with some decisions, but none of them that
         | are an immutable failure mode that couldn't be fixed in a
         | straightforward manner.
        
       | hamandcheese wrote:
       | Zig being able to (cross)compile C and C++ feels very similar to
       | how UV functions as a drop in replacement for pip/pip-tools.
       | Seems like a fantastic way to gain traction in already
       | established projects.
        
         | fastball wrote:
         | Strangler fig
        
           | FragenAntworten wrote:
           | This is referring to the Strangler Fig design pattern, which
           | is relevant: https://learn.microsoft.com/en-
           | us/azure/architecture/pattern...
        
         | archargelod wrote:
         | I love Zig. Never tried to write it though =).
         | 
         | I just use a it as cross-compiler for my Nim[0] programs.
         | 
         | [0] - https://nim-lang.org
        
       | pphysch wrote:
       | That inline test syntax is pretty cool; where does it come from?
        
       | ufko_org wrote:
       | I would like to see the output of the:                   ldd
       | your-zig-executable :)
        
         | alexrp wrote:
         | Zig defaults to statically linking musl when targeting Linux,
         | so the output will not be very interesting unless you target
         | dynamic musl, or glibc, or FreeBSD/NetBSD.
        
       | pron wrote:
       | > I can't think of any other language in my 45 years long career
       | that surprised more than Zig.
       | 
       | I can say the same (although my career spans only 30 years), or,
       | more accurately, that it's one of the few languages that
       | surprised me most.
       | 
       | Coming to it from a language design perspective, what surprised
       | me is just how far partial evaluation can be taken. While
       | strictly weaker than AST macros in expressive power (macros are
       | "referentially opaque" and therefore more powerful than a
       | referentially transparent partial evaluation - e.g. partial
       | evaluation has no access to an argument's name), it turns out
       | that it's powerful enough to replace not only most "reasonable"
       | uses of macros, but also generics and interfaces. What gives
       | Zig's partial evaluation (comptime) this power is its access to
       | reflection.
       | 
       | Even when combined with reflection, partial evaluation is more
       | pleasurable to work with than macros. In fact, to understand the
       | program's semantics, partial evaluation can be ignored altogether
       | (as it doesn't affect the meaning of computations). I.e. the
       | semantics of a Zig program are the same as if it were interpreted
       | by some language Zig' that is able to run all of Zig's partial-
       | evaluation code (comptime) at runtime rather than at compile
       | time.
       | 
       | Since it also removes the need for other specialised features
       | (generics, interfaces) - even at the cost of an aesthetic that
       | may not appeal to fans of those specialised features - it ends up
       | creating a very expressive, yet surprisingly simple and easy-to-
       | understand language (Lisps are also simple and expressive, but
       | the use of macros makes understanding a Lisp program less easy).
       | 
       | Being simple and easy to understand makes code reviews easier,
       | which may have a positive impact on correctness. The simplicity
       | can also reduce compilation time, which may also have a positive
       | impact on correctness.
       | 
       | Zig's insistence on explicitness - no overloading, no hidden
       | control flow - which also assists reviews, may not be appropriate
       | for a high-level language, but it's a great fit for an
       | unabashedly low-level language, where being able to see every
       | operation as explicit code "on the page" is important. While its
       | designer may or may not admit this, I think Zig abandons C++'s
       | belief that programs of all sizes and kinds will be written in
       | the same language (hence its "zero-cost abstractions", made to
       | give the illusion of a high-level language without its actual
       | high-level abstraction). Developers writing low-level code lose
       | the explicitness they need for review, while those writing high-
       | level programs don't actually gain the level of abstraction
       | required for a smooth program evolution that they need. That
       | belief may have been reasonable in the eighties, but I think it
       | has since been convincingly disproved.
       | 
       | Some Zig decisions surprised me in a way that made me go more
       | "huh" than "wow", such as it having little encapsulation to speak
       | of. In a high-level language I wouldn't have that (after years of
       | experience with Java's wide ecosystem of libraries, we learned
       | that we need even _more_ and stronger encapsulation than we
       | originally had to keep compatibility while evolving code). But
       | perhaps this is the right choice for a low-level language where
       | programs are expected to be smaller and with fewer dependencies
       | (certainly shallower dependency graphs). I 'm curious to see how
       | this pans out.
       | 
       | Zig's terrific support for arenas also makes one of the most
       | powerful low-level memory management techniques (that, like a
       | tracing garbage collector, gives the developer a knob to trade
       | off RAM usage for CPU) very accessible.
       | 
       | I have no idea or prediction on whether Zig will become popular,
       | but it's certainly fascinating. And, being so remarkably easy to
       | learn (especially if you're familiar with low-level programming),
       | it costs little effort to give it a try.
        
         | sreekotay wrote:
         | This is the real answer (amongst other goodness) - this one is
         | well executed and differentiated
         | 
         | Every language at scale needs a preprocessor (look at the "use
         | server" and "use gpu" silliness happening in TS) - why is it
         | not the the same as the language you use?
        
           | jibal wrote:
           | Languages such as D and Nim (both greatly underappreciated)
           | offer full-language compile-time interpretation.
        
         | andyferris wrote:
         | I agree.
         | 
         | I look forward to a future high-level language that uses
         | something like comptime for metaprogramming/interfaces/etc, is
         | strongly typed, but lets you write scripts as easily as python
         | or javascript.
        
           | pron wrote:
           | Thing is, having a good JIT gives you the performance of
           | partial evaluation pretty much automatically (at the cost of
           | less predictability), as compilation occurs at runtime, so
           | the distinction between compile-time and runtime largely
           | disappears. E.g., in Java, a reflective call will eventually
           | be compiled by the JIT into a direct call; virtual dispatch
           | will also be compiled into direct dispatch or even inlined
           | (when appropriate) etc..
        
           | elcritch wrote:
           | Tryout Nim, it has powerful comptime/metaprogramming,
           | statically typed, automatic memory management and is as easy
           | to program as python or javascript while still allowing low
           | level stuff.
           | 
           | For me it'd be hard to go back to languages that don't have
           | all that. Only swift comes close.
        
             | jibal wrote:
             | D comes close ... it too has a full-language comptime
             | interpreter and other metaprgramming features (though not
             | as rich as Nim's), statically typed, optional garbage
             | collection, and you can write
             | 
             | #!/usr/bin/env rdmd
             | 
             | [D code]
             | 
             | and run it as if it were an executable. (The compilation is
             | cached so it runs just as fast on subsequent runs.)
        
           | signa11 wrote:
           | perhaps mojo might be your cup of tea ?
        
           | jibal wrote:
           | D and Nim both offer that. D has a tool, rdmd, that compiles
           | (with caching) and runs a script written in D, so you write
           | 
           | #!/usr/bin/env rdmd D code ...
           | 
           | and run it as if it were an executable.
        
             | tmtvl wrote:
             | If you want to write a code example on HN you can just
             | indent it by 2 spaces and it'll work like you'd expect. For
             | example:                 #!/usr/bin/env rdmd       D
             | code...
        
               | jibal wrote:
               | Thanks. I didn't catch that it didn't display correctly
               | until it was too late to edit it.
        
         | newpavlov wrote:
         | Great comment! I agree about comptime, as a Rust programmer I
         | consider it one of the areas where Zig is clearly better than
         | Rust with its two macro systems and the declarative generics
         | language. It's probably the biggest "killer feature" of the
         | language.
        
           | aw1621107 wrote:
           | > as a Rust programmer I consider it one of the areas where
           | Zig is clearly better than Rust with its two macro systems
           | and the declarative generics language
           | 
           | IMHO "clearly better" might be a matter of perspective; my
           | impression is that this is one of those things where the
           | different approaches buy you different tradeoffs. For
           | example, by my understanding Rust's generics allows generic
           | functions to be completely typechecked in isolation at the
           | definition site, whereas Zig's comptime is more like C++
           | templates in that type checking can only be completed upon
           | instantiation. I believe the capabilities of Rust's macros
           | aren't quite the same as those for Zig's comptime - Rust's
           | macros operate on syntax, so they can pull off
           | transformations (e.g., #[derive], completely different
           | syntax, etc.) that Zig's comptime can't (though that's not to
           | say that Zig doesn't have its own solutions).
           | 
           | Of course, different people can and will disagree on which
           | tradeoff is more worth it. There's certainly appeal on both
           | sides here.
        
         | travisgriggs wrote:
         | Well put. The majority of language development for the last 20
         | years has proceeded by _adding_ more features into languages,
         | as they all borrow keywords and execution semantics from each
         | other. It 's like a neighborhood version of corporate
         | bureaucracies, where each looks across the street, and decides
         | "they've got a department we don't have, we better add one of
         | those".
         | 
         | I like languages that dare to try to do more with less. Zig's
         | comptime, especially the way it supplants generics, is pretty
         | darn awesome.
         | 
         | I was having a similar feeling with Elixir the other day, when
         | I realized that I could built every single standard IPC
         | mechanism that you might find in something like
         | python.threading (Queue, Mutex, RecursionLock, Condition,
         | Barrier, etc) with the Erlang/Beam/Process mailbox.
        
         | mi_lk wrote:
         | This review should be much higher as TFA provides little
         | substance
        
       | simonw wrote:
       | A neat little thing I like about Zig is one of the options for
       | installing it is via PyPI like this:
       | https://pypi.org/project/ziglang/                 pip install
       | ziglang
       | 
       | Which means you don't even have to install it separately to try
       | it out via uvx. If you have uv installed already try this:
       | cd /tmp       echo '#include <stdio.h>
       | int main() {           printf("Hello, World!");           return
       | 0;       }' > hello.c            uvx --from ziglang python-zig cc
       | /tmp/hello.c       ./a.out
        
         | giancarlostoro wrote:
         | That's really cool actually. Now that AI is a little more
         | commonly available for developer tooling I feel like its easier
         | than ever to learn any programming language since you can
         | braindrain the model.
        
           | yoyohello13 wrote:
           | The standard models are pretty bad a zig right now since the
           | language is so new and changes so fast. The entire language
           | spec is available in one html file though so you can have a
           | little better success feeding that for context.
        
             | hdjrudni wrote:
             | > The entire language spec is available in one html file
             | though so you can have a little better success feeding that
             | for context.
             | 
             | This is what I've started doing for every library I use. I
             | go to their Github, download their docs, and drop the whole
             | thing into my project. Then whenever the AI gets confused,
             | I say "consult docs/somelib/"
        
               | RamtinJ95 wrote:
               | Just use gh_grep mcp and the model will fetch what it
               | needs if you tell it to, no need to download from GitHub
               | manually like this
        
           | pjmlp wrote:
           | I on the other hand see most languages become superfluous, as
           | coding agents keep improving.
           | 
           | During the last year I have been observing how MCP, tools and
           | agents, have reduced the amount of language specific code we
           | used to write.
        
         | the__alchemist wrote:
         | For anyone not familiar: You can bundle arbitrary software as
         | Python wheels. Can be convenient in cases like this!
        
           | johnisgood wrote:
           | What "cases" are those? Tell me one useful and neat case. Why
           | is it useful and neat, you think?
        
             | IshKebab wrote:
             | It's useful as a distro-agnostic distribution method. CMake
             | is also installable like this despite having nothing to do
             | with Python.
             | 
             | Or I should say it _was_ useful as a distribution method,
             | because most people had Python already available. Since
             | most distros now don 't allow you to install stuff outside
             | a venv you need uv to install things (via `uv tool
             | install`) and we're not yet at the point where most people
             | already have uv installed.
        
             | the__alchemist wrote:
             | For one example, a number of years back, I built a python
             | package, env, and version manager. It was built entirely
             | Rust and distributed as a binary. Since I know users would
             | likely have pip installed, it provided an easy way for them
             | to install, regardless of OS.
             | 
             | You could go further like in this case, and use wheels +
             | PyPi for something unrelated to Python.
        
             | gordonhart wrote:
             | Bundling a browser frontend together with your Python
             | application.
        
         | elSidCampeador wrote:
         | For this sort of stuff I find micromamba / pixi a better way of
         | managing packages, as oppposed to the pip / uv family of tools
        
           | mikepurvis wrote:
           | Pixi, Conan, or Nix-- all better choices than abusing the
           | Python ecosystem to ship arbitrary executables.
        
             | wavemode wrote:
             | It could easily be the case that the zig compiler is useful
             | in some mixed-language project and this is not actually
             | "abuse".
        
               | mikepurvis wrote:
               | Regular Python bindings / c extensions don't depend on a
               | pypi-packaged instance of gcc or llvm though. It's
               | understood that these things are provided externally from
               | the "system" environment.
               | 
               | I know some of it has already happened with rust, but
               | perhaps there's a broader reckoning that needs to occur
               | here wrt standards around how language specific build and
               | packaging systems handle cross language projects... which
               | could well point to phasing those in favour of nix or
               | pixi, which are designed from the getgo to support this
               | use case.
        
         | skavi wrote:
         | reinventing nix but worse.
        
           | shim__ wrote:
           | Not even close, that's still imperative package management
        
         | pietroppeter wrote:
         | I wish we had that for Nim too!
        
           | elSidCampeador wrote:
           | try pixi!
        
         | postepowanieadm wrote:
         | That's a nice trick!
        
       | pyrolistical wrote:
       | I totally vibe with the intro but then the rest of the article
       | goes on to be a showcase bits of zig.
       | 
       | I feel what is missing is how each feature is so cool compared to
       | other languages.
       | 
       | As a language nerd zig syntax is just so cool. It doesn't feel
       | the need to adhere to any conventions and seems to solve the
       | problems in the most direct and simple way.
       | 
       | An example of this declaring a label and referring to a label. By
       | moving the colon to either end it makes labels instantly
       | understood which form it is.
       | 
       | And then there is the runtime promises such as no hidden control
       | flow. There are no magical @decorators or destructors. Instead we
       | have explicit control flow like defer.
       | 
       | Finally there is comptime. No need to learn another macro syntax.
       | It's just more zig during compilation
        
         | rvrb wrote:
         | matklad did it justice in his post here, in my opinion
         | 
         | https://matklad.github.io/2025/08/09/zigs-lovely-syntax.html
        
           | srcreigh wrote:
           | Thread: https://news.ycombinator.com/item?id=44855881
        
         | badtuple wrote:
         | I was also curious what direction the article was going to
         | take. The showcase is cool, and the features you mentioned are
         | cool. But for me, Zig is cool is because all the pieces simply
         | fit together with essentially no redundancy or overloading. You
         | learn the constructs and they just compose as you expect.
         | There's one feature I'd personally like added, but there's
         | nothing actually _missing_. Coding in it quickly felt like
         | using a tool I'd used for years, and that's special.
         | 
         | Zig's big feature imo is just the relative absence of warts in
         | the core language. I really don't know how to communicate that
         | in an article. You kind of just have to build something in it.
        
           | rvrb wrote:
           | out of curiosity, what feature do you want?
        
             | brucehoult wrote:
             | The feature _I_ want is multimethods -- function
             | overloading based on the runtime (not compile time) type of
             | all the arguments.
             | 
             | Programming with it is magical, and its a huge drag to go
             | back to languages without it. Just so much better than
             | common OOP that depends only on the type of one special
             | argument (self, this etc).
             | 
             | Common Lisp has had it forever, and Dylan transferred that
             | to a language with more conventional syntax -- but is very
             | near to dead now, certainly hasn't snowballed.
             | 
             | On the other hand Julia does it very well and seems to be
             | gaining a lot of traction as a very high performance but
             | very expressive and safe language.
        
               | zevets wrote:
               | I think this is a major mistake for Zig's target adoption
               | market - low level programmers trying to use a better C.
               | 
               | Julia is phenomenally great for solo/small projects, but
               | as soon as you have complex dependencies that _you_ can't
               | update - all the overloading makes it an absolute
               | nightmare to debug.
        
               | pjmlp wrote:
               | Ada has them, and I guess we all agree on its systems
               | programming nature.
        
               | brucehoult wrote:
               | NOOOO!
               | 
               | What Ada (and Rust) calls generics is very different --
               | it is like template functions in C++.
               | 
               | In those languages the version of the function that is
               | selected is based on the declared type of the arguments.
               | 
               | In CLOS, Dylan, Julia the version of the function that is
               | selected is based on the runtime type of the actual
               | arguments.
        
               | SatvikBeri wrote:
               | For what it's worth, that hasn't been my experience with
               | Julia - I've found it easier to debug than Python, Scala,
               | or Clojure (other languages I've used at jobs.)
               | 
               | The tooling makes it easy to tell which version of a
               | method you're using, though that's rarely an issue in
               | practice. And the fact that methods are open to extension
               | makes it really easy to fix occasional upstream bugs
               | where the equivalent has to wait for a library maintainer
               | in Python.
               | 
               | 500kloc Julia over 4 years, so not a huge codebase, but
               | not trivial either.
        
               | fuzztester wrote:
               | >The feature I want is multimethods -- function
               | overloading based on the runtime (not compile time) type
               | of all the arguments.
               | 
               | >Programming with it is magical, and its a huge drag to
               | go back to languages without it. Just so much better than
               | common OOP that depends only on the type of one special
               | argument (self, this etc).
               | 
               | Can you give one or two examples? And why is programming
               | with it magical?
        
               | brucehoult wrote:
               | For a start it means you can much more naturally define
               | arithmetic operators for a variety of built in and user-
               | defined types, and this can all be done with libraries
               | not the core language.
               | 
               | Because methods aren't "inside" objects, but just look
               | like functions taking (references to) structs, you can
               | add your own methods to someone else's types.
               | 
               | It's really hard to give a concise example that doesn't
               | look artificial, because it's really a feature for large
               | code bases.
               | 
               | Here's a tutorial example for Julia
               | 
               | https://scientificcoder.com/the-art-of-multiple-dispatch
        
               | fuzztester wrote:
               | Thanks.
        
               | nomdep wrote:
               | Erlang/Elixir also has that
        
           | andai wrote:
           | Yeah, the real strength of Zig isn't what's there, but what
           | _isn 't._
        
           | smj-edison wrote:
           | > Coding in it quickly felt like using a tool I'd used for
           | years, and that's special.
           | 
           | That's been my exact experience too. I was surprised how fast
           | I felt confident in writing zig code. I only started using it
           | a month ago, and already I've made it to 5000 lines in a
           | custom tcl interpreter. It just gets out of the way of me
           | expressing the code I want to write, which is an incredible
           | feeling. Want to focus on fitting data structures on L1
           | cache? Go ahead. Want to automatically generate lookup tables
           | from an enum? 20 lines of understandable comptime. Want to
           | use tagged pointers? Using "align(128)" ensures your pointers
           | are aligned so you can pack enough bits in.
        
           | dragonelite wrote:
           | Having spend a year tinkering in zig and it's absence of
           | features has made me want to drop c#/java professionally and
           | pick up Golang. Its quiet annoying when you see a codebases
           | written in C#/java and you can tell in which year/era it was
           | written because of the language features. The way of writing
           | things in C# changes like every 4 years or so.
           | 
           | There's a certain beauty in only having to know 1~2
           | loops/iteration concepts compared to 4~5 in modern multi
           | paradigm languages(various forms of loops, multiple shapes of
           | LINQ, the functional stuff etc).
        
             | pjmlp wrote:
             | You already have have Go, before and after modules, before
             | and after generics, before and after ranges over function
             | types.
             | 
             | Skipping other minor changes.
             | 
             | However I do agree C# is adding too much stuff, the team
             | seems trying to justify their existence.
        
       | rvrb wrote:
       | I've tried writing a similar post, but I think it's a bit
       | difficult to sound convincing when talking about why Zig is so
       | pleasant. it's really not any one thing. it's a culmination of a
       | lot of well made, pragmatic decisions that don't sound
       | significant on their own. they just culminate in a development
       | experience that feels pleasantly unique.
       | 
       | a few of those decisions seem radical, and I often disagreed with
       | them.. but quite reliably, as I learned more about the decision
       | making, and got deeper into the language, I found myself agreeing
       | with them afterall. I had many moments of enlightenment as I dug
       | deeper.
       | 
       | so anyways, if you're curious, give it an honest chance. I think
       | it's a language and community that rewards curiosity. if you find
       | it fits for you, awesome! luckily, if it doesn't, there's plenty
       | of options these days (I still would like to spend some quality
       | time with Odin)
        
         | andai wrote:
         | +1 for Odin. I wrote a little game in it last year and found it
         | delightful.
        
           | brabel wrote:
           | I prefer Odin to Zig after trying both... but it seems Odin's
           | performance is a bit lower than Zig, C and Rust?! Have you
           | noticed any performance issues or it's not something to worry
           | about?
        
             | 59nadir wrote:
             | No, I write Odin for production and there is no performance
             | difference to speak of coming from the way the compiler or
             | language works. If you have one it's likely because of an
             | older/different LLVM version being used, but AFAIK Odin
             | stays as up-to-date as you can without tearing your hair
             | out (and that's good because GingerBill has none of that to
             | spare).
             | 
             | There might be a few pathological code paths in the core
             | libraries or whatever for certain things that aren't what
             | they should be, but in terms of the raw language you're in
             | the land of C as much as with any of these languages; Odin
             | really doesn't do much on top of C, and what it's doing is
             | identifiable and can be opted out of; if you find that a
             | function in a hot loop is marginally slower than it ought
             | to be, you can make it contextless, for example, and see
             | whether that makes a difference.
             | 
             | We haven't found (in a product where performance is
             | explicitly a feature, also containing a custom 3D engine on
             | top of that) that the context being passed automatically in
             | Odin is of much concern performance-wise.
             | 
             | Out of the languages mentioned Rust is the one I've seen in
             | benchmarks be routinely marginally slower, but it's not by
             | a meaningful amount.
        
       | didip wrote:
       | Is it cool? It seems to be in nether land between Rust and Go.
       | Not sure what is the unique use case for Zig.
        
         | jorangreef wrote:
         | We could not have written TigerBeetle, at least not the way it
         | is, without Zig:
         | 
         | https://tigerbeetle.com/blog/2025-10-25-synadia-and-tigerbee...
        
           | sgt wrote:
           | TigerBeetle has a clear purpose and needed those brilliant
           | optimizations. Do you think Zig is suitable as, say, a Go
           | replacement for prod network services and such?
           | 
           | Aside from the fact that Zig is still a bit immature in its
           | std library and ecosystem, I mean. Is it a suitable systems
           | language going forward?
        
             | jorangreef wrote:
             | Thanks!
             | 
             | Zig is actually perfect for production network services
             | (that's all TB is essentially, or how I see it, and what I
             | was looking for in Zig--how to create something with
             | explicit limits that can handle overload--it's hard to
             | build anything production-grade if it's not doing NASA's
             | Power of Ten and getting allocation right--GC is not a good
             | idea for a network service).
             | 
             | I wouldn't say Zig's std lib is immature. Or if anything,
             | it has higher quality than most std libs. For example, the
             | unmanaged hashmap interface is :chefskiss. In comparison,
             | many std libs are yet to get non-global allocators or
             | static allocation or I/O right.
        
           | metaltyphoon wrote:
           | Read that and what part of that can't be done in Rust in
           | 2025?
        
             | jorangreef wrote:
             | "done" or "done as well"?
        
         | rvrb wrote:
         | not being a direct competitor to either of these already
         | existing languages is exactly why it is interesting!
        
         | crabmusket wrote:
         | As far as I can tell from my outsider perspective, Rust might
         | be used instead of C++, Zig instead of C, and Go instead of
         | Java.
        
         | mlavergn wrote:
         | Well, it's insanely simple, insanely fast, often more
         | performant than Rust with lower resource usage, with first
         | class C-interop and cross-compiling out of the box. It's easily
         | my favorite language now, with Go being a close second. Both
         | are opinionated and have a standard formatter that makes Zig
         | code instantly readable when you see it, similar to Go. Rust
         | was once interesting, but it's firmly in macro hell territory
         | now, just like Swift, with concealed execution paths aplenty
         | and neither cross-compiling out of the box.
        
           | newpavlov wrote:
           | >often more performant than Rust with lower resource usage
           | 
           | [citation needed]
           | 
           | If we are to trust this page [0] Rust beats Zig on most
           | benchmarks. In the Techempower benchmarks [1] Rust
           | submissions dominate the TOP, while Zig is... quite far.
           | 
           | Several posts which I've seen in the past about Zig beating
           | Rust by 3x or such all turned to be based on low quality Rust
           | code with some performance pitfalls like measuring
           | performance of writing into stdout (which Rust locks by
           | default and Zig does not) or iterating over ..= ranges which
           | are known to be problematic from the performance perspective.
           | 
           | [0]: https://programming-language-benchmarks.vercel.app/rust-
           | vs-z...
           | 
           | [1]: https://www.techempower.com/benchmarks/
        
             | uecker wrote:
             | I would say in most submission-based benchmarks among
             | languages that should perform similar, this mostly reflects
             | the size and enthusiasm of the community.
        
         | chrisco255 wrote:
         | It's more of an in-between C and Rust than Go as it is a
         | systems language with no built-in garbage collector for memory
         | management. It has a lot of memory safety features, but it's
         | not as memory safe as Rust. However, it avoids a lot of the
         | complexity of Rust like implicit macro expansion, managing
         | lifetimes, generics and complex trait system, etc. It also
         | compiles much more compactly than Rust, in my experience.
         | 
         | In my mind, it's an accessible systems language. Very readable.
         | Minimal footprint.
        
           | metaltyphoon wrote:
           | > managing lifetimes
           | 
           | If you are not using a GC language, you WILL be managing
           | lifetimes. Rust just makes it explicit, when the compiler
           | can't prove it's safe, which Zig, C don't really care.
        
             | chrisco255 wrote:
             | A better way of saying it is that Rust makes lifetimes
             | implicit (by default), but in some cases it is necessary to
             | manually manage lifetimes in Rust, when there's ambiguity
             | the compiler can't resolve on its own.
             | 
             | In Zig and C, it's always expected that you will explicitly
             | manage your lifetimes. Zig uses the allocator interface to
             | explicitly allocate new buffer or heap values and its
             | keyword 'defer' to clean up allocated variables after the
             | scope exits so that allocations and frees generally live
             | next to each other.
             | 
             | C on the other hand, is relatively unopinionated about how
             | lifetimes are managed. The defer keyword honestly takes
             | most of the pain of managing lifetimes away.
        
       | meisel wrote:
       | For a language that's so low level and performance focused, I'm
       | surprised that it has those extra io and allocator arguments to
       | functions. Isn't that creating code bloat and runtime overhead?
        
         | rvrb wrote:
         | the answer I've seen when it has been brought up before is that
         | (for allocators) there is not a practical impact on performance
         | -- allocating takes way more time than the virtual dispatch
         | does, so it ends up being negligible. for code bloat, I'm not
         | sure what you mean exactly; the allocator interface is
         | implemented via a VTable, and the impact on binary size is
         | pretty minimal. you're also not really creating more than a
         | couple of allocators in an application (typically a general
         | purpose allocator, and maybe an arena allocator that wraps it
         | in specific scenarios).
         | 
         | for IO, which is new and I have not actually used yet, here are
         | some relevant paragraphs:                 The new Io interface
         | is non-generic and uses a vtable for dispatching function calls
         | to a concrete implementation. This has the upside of reducing
         | code bloat, but virtual calls do have a performance penalty at
         | runtime. In release builds the optimizer can de-virtualize
         | function calls but it's not guaranteed.              ...
         | A side effect of proposal #23367, which is needed for
         | determining upper bound stack size, is guaranteed de-
         | virtualization when there is only one Io implementation being
         | used (also in debug builds!).
         | 
         | https://kristoff.it/blog/zig-new-async-io/
         | 
         | https://github.com/ziglang/zig/issues/23367
        
           | jibal wrote:
           | He's talking about passing the pointers to the allocators and
           | Io objects as parameters throughout the program, not how
           | allocator vtables for calling the allocator's virtual
           | functions are implemented. But context pointers are a
           | requirement in any program. Consider that a context pointer
           | (`this`) is passed to every single method call ... it's no
           | more "code bloat" than having to save and restore registers
           | on every call.
        
         | garbagepatch wrote:
         | Regarding runtime overhead, I'd assume you would still need an
         | io implementation, it is just showing it to you explicitly
         | instead of it being hidden behind the std lib.
         | 
         | For simple projects where you don't want to pass it around in
         | function parameters, you can create a global object with one
         | implementation and use it from everywhere.
        
           | chrisco255 wrote:
           | Yeah thing is it's usually better to have allocator in
           | particular defined as a parameter so that you can use the
           | testing allocator in your tests to detect memory leaks,
           | double frees, etc. And then you use more optimal allocators
           | for release mode.
        
           | jibal wrote:
           | You still have to pass arguments to library functions that
           | need to allocate or do I/O ... but the alternative is worse.
           | This is really a bogus issue ... no one is crying over having
           | to pass a `this` pointer to every single call of a method in
           | other languages. Context pointers are a requirement in any
           | sizeable or multi-threaded program, and Zig gives the user
           | full control over what the context object looks like.
        
         | chrisco255 wrote:
         | io and allocator objects each only contain 4 pointers or so.
         | They are very fast to wire up and don't create much overhead at
         | all.
        
         | wmedrano wrote:
         | I haven't looked to deeply, but I haven't noticed any
         | performance impact. Inlining probably helps too.
        
         | jibal wrote:
         | Every class method in other languages receives a hidden
         | argument. Odin passes a hidden context argument that contains
         | the allocator. The alternative is global variables--which you
         | can also use in Zig if you're so inclined. The extra arguments
         | aren't something the Zig language imposes, it's a convention.
        
         | vjerancrnjak wrote:
         | Given that Zig has functions which can return functions, maybe
         | you could capture the top level io and allocator and return a
         | struct with a bunch of functions that now have the top scope io
         | and allocator visible.
         | 
         | Don't know. That's how people usually get rid of repeat
         | arguments (or OOP constructor).
        
       | KerrAvon wrote:
       | Nothing against (or for) Zig, but the article author seems
       | unfamiliar with other modern languages in common use... imagine
       | if they saw Swift or Rust. Their mind would be utterly, utterly
       | blown.
        
       | robotresearcher wrote:
       | > Probably the most incredible virtue of Zig compiler is its
       | ability to compile C code. This associated with the ability to
       | cross-compile code to be run in another architecture, different
       | than the machine where it is was originally compiled, is already
       | something quite different and unique.
       | 
       | Isn't cross compilation very, very ordinary? Inline C is cool,
       | like C has inline ASM (for the target arch). But cross-compiling?
       | If you built a phone app on your computer you did that as a
       | matter of course, and there are many other common use cases.
        
         | crest wrote:
         | > Isn't cross compilation very, very ordinary?
         | 
         | Working cross compilation out of the box any-to-any still
         | isn't.
        
           | BoorishBears wrote:
           | Yes, very rare and there is a strong cartel of companies
           | ensuring it doesn't happen in more mainstream langs through
           | multiple avenues to protect their interests!
           | 
           | From helicoptering folks onto steering committee and
           | indoctrination of young CS majors.
        
             | rmunn wrote:
             | If I had the ability to downvote a comment yet, I'd
             | downvote you. If you're going to spout conspiracy-theory-
             | sounding stuff, at least provide _some_ evidence for your
             | claims!
        
               | BoorishBears wrote:
               | It doesn't sound like a conspiracy theory, you just have
               | an _incredibly_ poorly calibrated sense of judgement as
               | to the tone of a statment.
               | 
               | Not uncommon in this space though, especially as you get
               | closer to the metal (close as cross-compilation is
               | relative to something like React frontends, at least)
        
             | TylerE wrote:
             | This comment deserves a [citation needed] visible from
             | geosynchronous orbit.
        
           | robotresearcher wrote:
           | Any-to-any? Do you mean host-to-any (or host-to-many)? I'd be
           | surprised if there's a single build that runs on any host
           | arch.
           | 
           | I guess it's convenient to have support for many target
           | architectures built in by default. I wonder how big that
           | package is.
        
         | jibal wrote:
         | If you install Zig, you can now generate executables for
         | virtually any target with just a CLI argument specifying the
         | target, regardless of what machine you installed it on. Nothing
         | else does that--cross compilation generally requires compiling
         | the compiler to target a different architecture.
        
       | leshokunin wrote:
       | Move Zig. For great justice!
        
       | dxxvi wrote:
       | There's at least 1 thing that Zig is better than Rust is that Zig
       | compiler for Windows can be downloaded, unzipped then used
       | without admin right. Rust needs msvc, which cannot be installed
       | without admin right. It is said that Rust on Windows can use
       | cygwin but I cannot make it work even with AI help.
        
         | tremololo wrote:
         | You should check out cargo-zigbuild which makes use of zig for
         | cross compiling rust projects. https://github.com/rust-
         | cross/cargo-zigbuild
        
         | newpavlov wrote:
         | Have you tried the GNU toolchain? IIRC rustup provides the
         | option to use it instead of the MSVC toolchain during the
         | initial installation.
        
         | dgrunwald wrote:
         | cygwin is a POSIX-emulating library intended for porting POSIX-
         | only programs to Windows. That is: when compiling for cygwin,
         | you'd use the cygwin POSIX APIs _instead of_ the Windows APIs.
         | So anything compiled with cygwin won 't be a normal Windows
         | program.
         | 
         | There's no reason to use cygwin with Rust, since Rust has
         | native Windows support. The only reason to use x86_64-pc-cygwin
         | is if you would need your program to use a C library that is
         | not available for Windows, but is available for cygwin.
         | 
         | If you don't want to/can't use the MSVC linker, the usual
         | alternative is Rust's `x86_64-pc-windows-gnu` toolchain.
        
       | evgpbfhnr wrote:
       | To author -- code sample as images is great for syntax highlight
       | but I wanted to play with the examples and.. got stuck trying to
       | copy the content.
       | 
       | (also expected tesseract to do a bit better than this:
       | $ wl-paste -t image/png | tesseract -l eng - -       Estimating
       | resolution as 199       const std = @import("std");       const
       | expect = std.testing.expect;              const Point = struct
       | {x: i32, y: i32};              test "anonymous struct literal" {
       | const pt: Point = .{       x = 13,       -y = 67,       33
       | try expect (pt.x       try expect(pt.y              13);
       | 67);          )
        
         | porridgeraisin wrote:
         | tesseract does well for me...                   const std =
         | @import("std");         const expect = std.testing.expect;
         | const Point = struct {x: i32, y: i32};              test
         | "anonymous struct literal" {              const pt: Point = .{
         | .x = 13,         .y = 67,         };         try expect(pt.x ==
         | 13);         try expect(pt.y == 67);
         | 
         | The trick is to preprocess the image a little bit like so:
         | ocr ()          {              magick - -monochrome -negate - |
         | tesseract stdin stdout 2> /dev/null         }
        
           | evgpbfhnr wrote:
           | Thank you!
           | 
           | Unfortunately I get the same kind of garbage around closing
           | curly braces / closing parenthesis / dots with this magick
           | filter... It seems to do slightly better with an extra
           | `-resize 400%`, but still very far from as good as what
           | you're getting (to be fair the monochrome filter is not
           | pretty (bleeding) when inspecting the result).
           | 
           | I wonder what's different? (
           | ImageMagick-7.1.1.47-1.fc42.x86_64 and
           | tesseract-5.5.0-5.fc42.x86_64 here, no config, langpack(s)
           | also from the distro)
        
         | NewsaHackO wrote:
         | Yeah, he definitely should have used a code block for the
         | examples. To the author, if you are trying to preserve code
         | formatting and syntax highlighting, there are JS packages that
         | will take care of all of that and produce clean, copyable,
         | well-rendered, accessible code formatting for you.
        
       | haiji1992 wrote:
       | What is Zig?
        
         | signa11 wrote:
         | what comes before Zag ?
        
       | d3Xt3r wrote:
       | Is there a decent native GUI library for Zig yet? I don't want to
       | use bloated toolkits like GTK and Qt.
       | 
       | I like the simplicity and speed of Rust's eGUI. Something similar
       | for Zig would be amazing.
        
         | NoteyComplexity wrote:
         | Is dvui something you want to see? Although the use of backends
         | are still c based, the core part of the gui seems written fully
         | in zig rather than a binding from a c library.
         | 
         | https://github.com/david-vanderson/dvui
        
         | hommelix wrote:
         | There is capy https://capy-ui.org/
        
           | d3Xt3r wrote:
           | Unfortunately capy uses Gtk+ on Linux, so it's a no-go for
           | me. :(
        
       | qouteall wrote:
       | In my opinion the biggest issue of Zig is that it doesn't allow
       | attaching data to error. The error can only be passed via side
       | channel, which is inconvenient and ENOURAGES TOOL DEVELOPERS TO
       | NOT PASS ERROR DATA, which greatly increase debugging difficulty.
       | 
       | Somethings there are 100 things that possibly go wrong. With
       | error data you can easily know which exact thing is wrong. But
       | with error code you just know "something is wrong, don't know
       | which exactly".
       | 
       | See:
       | https://github.com/ziglang/zig/issues/2647#issuecomment-1444...
       | 
       | > I just spent way longer than I should have to debugging an
       | issue of my project's build not working on Windows given that all
       | I had to work with from the zig compiler was an error:
       | AccessDenied and the build command that failed. When I finally
       | gave up and switched to rewriting and then debugging things
       | through Node the error that it returned was EBUSY and the
       | specific path in question that Windows considered to be busy,
       | which made the problem actually tractable ... I think the fact
       | that even the compiler can't consistently implement this pattern
       | points to it perhaps being too
       | manual/tedious/unergonomic/difficult to expect the Zig ecosystem
       | at large to do the same
        
         | qouteall wrote:
         | I know that Zig doesn't allow attaching data to error for valid
         | reasons. If error data contains interior pointer then it can
         | easily cause memory safety problem. Zig doesn't have a borrow
         | cheker or ownership system to prevent that.
         | 
         | https://github.com/ziglang/zig/issues/2647#issuecomment-2670...
        
           | metaltyphoon wrote:
           | > I know that Zig doesn't allow attaching data to error for
           | good reasons. If error data contains interior pointer then it
           | causes memory safety problem
           | 
           | IMO this is not a good reason at all.
        
             | qouteall wrote:
             | Changed to "valid reasons"
        
               | jibal wrote:
               | The problem of dangling pointers is not unique to error
               | data.
        
           | 59nadir wrote:
           | If you wanted to have a parameter that gets filled in when
           | there is an error, this exact issue will remain, it's
           | completely unrelated to which language construct you use to
           | capture errors and has more to do with having a good idea of
           | how your errors are allocated, if they require allocation. I
           | don't think the commenter in the GitHub issue thought this
           | through at all, and probably didn't expect to have it be held
           | up as some example of why you can't return tagged unions
           | (because it's not an example of that, not even remotely).
        
         | jandrewrogers wrote:
         | The "correct" way is highly context dependent with the added
         | proviso that Zig assumes a low-level systems context.
         | 
         | In this context, adding data to an error may be expedient but
         | 1) it has a non-trivial overhead on average and 2) may be
         | inadvisable in some circumstances due to system state. I
         | haven't written any systems in Zig yet but in low-level high-
         | performance C++20 code bases we basically do the same thing
         | when it comes to error handling. The conditional late binding
         | of error context lets you choose when and where to do it when
         | it makes sense and is likely to be safe.
         | 
         | A fundamental caveat of systems languages is that expediency
         | takes a back seat to precision, performance, and determinism.
         | That's the nature of the thing.
        
           | qouteall wrote:
           | If the error rarely happens then passing error data shouldn't
           | affect performance in visible way. If the error occurs in
           | common path then it's designed wrongly.
           | 
           | I agree that in special states like OOM passing error data
           | with allocation is not ok.
        
             | 59nadir wrote:
             | Error data being returned instead of just error codes
             | doesn't require allocation at all, and never would, unless
             | the specific unions that you're returning require as much.
             | Zig already has tagged unions with a tag field and
             | associated payload, that is exactly what you would return.
             | The overhead isn't remarkably worse than the cost of
             | modifying the value someone passed in to "Fill this in in
             | case of errors" (which is what you have to do now in Zig).
        
           | librasteve wrote:
           | For quite a long time, I have been wondering why I like to
           | code in Raku so much ... in a round about way you set me
           | thinking. Perhaps it's because, in Raku, precision,
           | performance and determinism take a back seat to expediency.
           | (Sorry for the tangent).
        
             | jamiejquinn wrote:
             | Wow, Raku looks like a really interesting language, I'd
             | never heard of it before!
             | 
             | Have you used it in any large projects?
        
               | throwaway2037 wrote:
               | Had you heard of Perl 6?
        
               | jamiejquinn wrote:
               | Perl I used in 2008 or so but not since. Haven't come
               | across Perl 6.
        
               | johnisgood wrote:
               | Perl 6 = Raku.
        
               | lizmat wrote:
               | Please, stop deadnaming the Raku Programming Language :-)
        
               | librasteve wrote:
               | =b
        
               | johnisgood wrote:
               | I thought it was useful information for people who did
               | not know this. Of course Wikipedia would have sufficed,
               | too: "Raku, formerly known as Perl 6 [...]".
        
               | librasteve wrote:
               | I love it. My largest project is about 20k lines ... so
               | nothing too big. But if you need to be expedient (just
               | quickly make a data extract/load/transform or a command
               | line thingy) it is great fun. The LLMs seem to be pretty
               | good too, just the usual hallucination here and there.
        
             | rixed wrote:
             | Went to have a look to the (beautiful and informative)
             | website for the raku language to refresh my memory, and
             | looking at the examples I though "Oh god, those sigills,
             | those criptic short keywords... it looks like a modern
             | perl, I doubt we would be happy together", then I went to
             | wikipedia to check and yes indeed, that's perl 6! I'll
             | pass. :)
        
               | librasteve wrote:
               | Thanks for the feedback on the raku.org site. We like
               | sigils $ for one thing (scalar), @ for many things
               | (array) and % for dictionaries (hash). The linguistic
               | idea is that such words stand out as "nouns" in contrast
               | to all the routine names which are "verbs". In practice,
               | after you get familiar, it really helps code to be
               | written in an expressive way to better convey the intent.
               | Sure, if sigils makes you glaze over then maybe it's not
               | for you.
        
         | ajross wrote:
         | This seems kinda contrived. In practice that "ERROR DATA" tends
         | not to exist. Unexpected errors almost never originate within
         | the code in question. In basically all cases that "ERROR DATA"
         | is just recapitulating the result of a system call, and the OS
         | doesn't have any data to pass.
         | 
         | And even if it did, interpreting the error generally doesn't
         | every work with a microscope over attached data. You got an
         | error from a write. What does the data contain? The file
         | descriptor? Not great, since you really want to know the path
         | to the file. But even then, it turns out it doesn't really
         | matter because what really happened was the storage filled up
         | due to a misbehaving process somewhere else.
         | 
         | "Error data" is one of those conceits that sounds like a good
         | idea but in practice is mostly just busy work. Architect your
         | systems to fail gracefully, don't fool yourself into pretending
         | you can "handle" errors in clever ways.
        
           | TylerE wrote:
           | Seralizing error data to text and then dumping that in a log
           | can be _pretty_ useful.
        
           | skybrian wrote:
           | I think you've skipped over all the cases where knowing the
           | filename is actually helpful? It's true that sometimes it
           | isn't.
           | 
           | Also, a line number is often helpful, which is why compilers
           | include it. Some JSON parsers omit that, which is annoying.
        
             | ajross wrote:
             | > Also, a line number is often helpful
             | 
             | That's not error data, that's (one level of) a stack trace.
             | And you can do that in zig, but not by putting call stack
             | data into error return codes.
             | 
             | The conflation between exception handling and error
             | flagging (something that C++ did largely as a mistake, and
             | that has been embraced by managed runtimes like Python or
             | Java) is actually _precisely_ what this feature is designed
             | to untangle. Exception support actually turns out to have
             | very non-trivial impact on the generated code, and there 's
             | a reason why languages like Rust and Zig don't include
             | them.
        
               | dns_snek wrote:
               | > That's not error data, that's (one level of) a stack
               | trace.
               | 
               | They're not talking about the stack trace, but about the
               | common case where the error is not helpful without
               | additional information, for example a JSON parsing
               | library that wants to report the position (line number)
               | in the string where the error appears.
               | 
               | There's no way of doing that in Zig, the best you can do
               | is return a "ParseError" and build you own, non-standard
               | diagnostic facilities to report detailed information
               | though output arguments.
        
               | kps wrote:
               | Another way to look at this example is that, for the
               | parser, this is not an error. The parser is doing its job
               | correctly, providing an accurate interpretation of its
               | input, and for the parser, this is qualitatively
               | different from something that prevents it doing its job
               | (say, running out of memory).
        
               | skybrian wrote:
               | At the next level up, though, there might be code that
               | expects to be able to read a JSON config file at a
               | certain location, and if it fails, it's reasonable to
               | report which file it tried to read, the line number, and
               | what the error was.
        
               | kps wrote:
               | Sure, but that's a different level with different
               | considerations. The JSON parser shouldn't care about
               | things like 'files' with 'locations'; maybe it's running
               | on some little esp8266 device that doesn't have such
               | things.
        
           | LoganDark wrote:
           | Error data should specify where the error occurred and what
           | failed. So you'll know which file had a problem, and that the
           | problem in question was a failure to write. From that you can
           | make the inference that maybe the disk is full, etc.
        
         | b33j0r wrote:
         | This is annoying. It's because errors were designed to be a
         | bitset and not have pointers. I would also prefer that they
         | were a `union(enum)`.
         | 
         | We are free to do that as a return type like `Result(T)` and
         | just forgo using `try`, but yeah, I wish this was in there.
        
         | cornstalks wrote:
         | People are working on this. std.zon is generally considered to
         | be a good example of how to handle errors and diagnostics,
         | though it's an area of active exploration. The plan is to
         | eventually collect all the good patterns people have come up
         | with and (1) publish them in a collection, and (2) update std
         | to actually use them.
        
           | throwaway2037 wrote:
           | > how to handle errors and diagnostics, though it's an area
           | of active exploration
           | 
           | I am flabbergasted and exasperated by this sentiment. Zig is
           | over 9 years old at this point. This feels this same kind of
           | circular arguments from Golang "defenders" about generics and
           | error handling.
        
             | dlisboa wrote:
             | Go gets a lot of flack for getting some things wrong but it
             | was a stable and productive language within a couple of
             | years.
             | 
             | If you look at the current Zig website the hello world
             | example doesn't compile because they changed the IO
             | interface. Something as simple as writing to the console.
             | 
             | It's easier to get things right if you have no issues
             | breaking backward compatibility for a decade. It feels
             | it'll be well over 10 years before Zig is "1.0".
        
               | sneakinsnake wrote:
               | +1
        
             | sgt wrote:
             | When will we see Zig 1.0?
        
         | MrJohz wrote:
         | Interestingly, I just read an article from matklad (who works a
         | lot with Zig) talking about the benefits of splitting up error
         | codes and error diagnostics, and the pattern of using a
         | diagnostic sync to provide human-readable diagnostic
         | information:
         | 
         | https://matklad.github.io/2025/11/06/error-codes-for-control...
         | 
         | Honestly I was quite convinced by that, because it kind of
         | matches my own experiences that, even when using complex
         | `Error` objects in languages with exceptions, it's still often
         | useful to create a separate diagnostics channel to feed
         | information back to the user. Even for application errors for
         | servers and things, that diagnostics channel is often just
         | logging information out when it happens, then returning an
         | error.
        
           | qouteall wrote:
           | I agree that building a special diagnostic system is better
           | than just using language's builtin error system. However that
           | takes efforts.
           | 
           | Library developers tend to choose the path of least
           | resistance, which is to not pass diagnostic information.
           | 
           | The most convenient diagonistic system is the good old
           | logging. Logging is easy.
           | 
           | Maybe logging will be the de facto solution of passing error
           | data in Zig ecosystem, due to psychological reasons.
        
             | Xss3 wrote:
             | I tend to follow the rest of the ecosystem when developing
             | libraries. If i wanted to make a zig lib id look at what
             | other major libs are doing (or not doing) and copy that.
             | 
             | If i found no consistency id be making a post like OP but
             | from a different perspective.
        
           | bragr wrote:
           | Your and GP's two statements are not mutually exclusive. This
           | paradigm can have significant benefits, and at the same time
           | be too cumbersome for people to want to use consistently.
        
           | lenkite wrote:
           | The separation of error codes and diagnostics is fine, but
           | the language needs a standard mechanism to optionally pass
           | this error diagnostic information. Otherwise, everyone will
           | develop their own different way with ZERO consistency and
           | many will simply not pass error diagnostics at all.
        
           | recursivetree wrote:
           | Having metadata with the error doesn't exclude having a
           | separate diagnostics system. You don't have to use errors
           | with metadata.
        
           | scuff3d wrote:
           | If they want to keep to the error/diagnostic pattern I think
           | they're gonna have to adopt some kind of standard context
           | object that gets passed around. Passing an allocator, an IO
           | implementation, and a diagnostic object all over your code
           | base is going to get really fucking old.
        
         | pyrolistical wrote:
         | I can see pros and cons. Preventing data being attached to an
         | error forces more clear and precise errors.
         | 
         | Whereas lazy devs could just attach all possible data in a
         | giant generic error if they don't want to think about it.
        
           | dns_snek wrote:
           | I don't follow, because there's a possibility that someone
           | somewhere might create a bad overly-generic error set if they
           | were allowed to stuff details in the payload when those
           | should be reflected in the error "type", it's a good idea to
           | make the vast majority of error reporting bad and overly-
           | generic by eliminating error payloads entirely?
        
           | Galanwe wrote:
           | > Preventing data being attached to an error forces more
           | clear and precise errors.
           | 
           | Okay maybe theorically, but in the real world I would like to
           | have the filename on a "file not found", an address on a
           | "connection timeout", a retry count on a "too many failures",
           | etc.
        
             | audunw wrote:
             | But also in the real world I may not be interested in any
             | error information for the library I'm using. I'd like to be
             | able to pass a null for the error information structure and
             | have the compile optimize away everything related to
             | tracking and storing error information.
             | 
             | I'd like my parser library to be able to give me the exact
             | file, line and column number an error occurred. But I'd
             | also like to use the library in a "just give me an error if
             | something failed, I don't really care why" mode.
        
           | Xss3 wrote:
           | Id rather have data in a generic error type than no data in a
           | specific error type.
           | 
           | How useful is a file not found error type without data (the
           | filename) when the program is looking for 50 files? Not very.
           | 
           | How useful is a generic error type with '{filename} not
           | found' as generic string data packed in? Quite.
        
         | fpoling wrote:
         | There are plans in Zig to allow to include custom information
         | into error stack trace
         | https://github.com/ziglang/zig/issues/14446.
         | 
         | But that is not implemented.
         | 
         | In any case, when debugging annotating error with extra context
         | often is not enough. One often needs a detailed trace of what
         | happens before.
         | 
         | So what I would like to see in any programming language is
         | ability to do a structured logging with extra context from the
         | call stack (including asynchronous support in languages that
         | have that) that has almost zero overhead when the log is not
         | printed.
         | 
         | Various languages and runtimes have some libraries that try to
         | do that, but the usage is awkward and the performance overhead
         | is not trivial.
        
           | ulbu wrote:
           | closed as not planned :)
        
           | ayende wrote:
           | Not this is explicitly marked as Not Planned
        
           | jandrewrogers wrote:
           | I made a go of this using the stacktrace functionality built
           | into C++23. The overhead and complexity it introduced made it
           | not worth it, unfortunately. There may be a way to do this
           | but it seems non-trivial in implementation.
        
         | otabdeveloper4 wrote:
         | Yeah, every single newbie programming language designer starts
         | with a maximalist position of "exceptions are hard, just return
         | an error code", and then end up inventing their own shitty, ad-
         | hoc and malfeatured exception handling system.
         | 
         | I want off this ride.
        
         | dns_snek wrote:
         | Agreed, this is probably my biggest ongoing issue with Zig. I
         | really enjoy it overall but this is a really big sticking
         | point.
         | 
         | I find it really amusing that we have a language that has built
         | its brand around "only one obvious way to do things", "reducing
         | the amount one must remember", and passing allocators around so
         | that callers can control the most suitable memory allocation
         | strategy.
         | 
         | And yet in this language we supposedly can't have error
         | payloads because not every error reporting strategy is suitable
         | for every environment due to memory constraints, so we must
         | rely on every library implementing its own, yet slightly unique
         | version of the diagnostic pattern that should really be
         | codified as some sort of a language construct where the caller
         | decides which allocator to use for error payloads (if any).
         | 
         | Instead we must hope that library authors are experienced and
         | curious enough to have gone out of their way to learn this
         | pattern because it isn't mentioned in any official
         | documentation and doesn't have any supporting language
         | constructs and isn't standardized in any way.
         | 
         | There must be an argument against this (rather obvious)
         | observation but I'm not aware of it?
        
           | smj-edison wrote:
           | Genuine question, how would error set unioning work with
           | payloads? error.WriterFailed (might be getting the exact name
           | wrong) is returned from many different writers, whether
           | writing to a statically allocated array, writing to a socket,
           | or writing to a file. Each error would have a very different
           | payload, so how would you disambiguate between the different
           | payloads with a global error type? The way I see it is either
           | you have error sets, or payloads, but not both.
        
             | weebull wrote:
             | I'm also wondering what payload people want. There's
             | already an error handling trace (similar but different to a
             | normal stack trace) that captures the how the error
             | propagates up to the point it's being handled so shows you
             | exactly where the initial point was.
        
         | tialaramex wrote:
         | I agree, I like e.g. https://doc.rust-
         | lang.org/std/string/struct.FromUtf8Error.ht...
         | 
         | See, we were trying to make this data we had into a string,
         | Rust says all strings are UTF-8 encoded - but, turns out the
         | data wasn't UTF-8 after all, here's an error _with the data
         | inside it_.
         | 
         | Or a really delicate piece of design, (nightly for now)
         | Vec::push_within_capacity. We're hoping the growable array
         | (Vec<T>) has enough space for this T, thus getting rid of it,
         | but if not we don't want to _grow_ the array, maybe we 're bare
         | metal software and can't afford to allocate on this hot path,
         | so we get back an error with the T we were trying to push onto
         | the array inside it, so we can do something else with that T
         | but _only_ when the problem happened, otherwise it 's gone.
        
       | jayd16 wrote:
       | Is the inline testing good in practice? I do like the clear
       | proximity and scope of the code being tested but I can also
       | imagine trying to cram in all the unit tests and mocking and
       | logging and such.
       | 
       | Does the feature end up feeling unused, dominating app code with
       | test code, or do people end up finding a happy medium?
        
       | RexFactorem wrote:
       | I like D better. And had some of the "cool" features of Zig from
       | quite some time, such as scope(exit) which is clearer.
       | 
       | I don't find Zig nearly as readable as my D code, but alas, I
       | don't do systems programming.
        
       | RagnarD wrote:
       | "This associated with the ability to cross-compile code to be run
       | in another architecture, different than the machine where it is
       | was originally compiled, is already something quite different and
       | unique."
       | 
       | Perhaps I'm missing something but this is utterly routine. It
       | even has the name used here: Cross-compiling.
        
         | jibal wrote:
         | If you install Zig, you can now generate executables for
         | virtually any target with just a CLI argument specifying the
         | target, regardless of what machine you installed it on. Nothing
         | else does that--cross compilation generally requires compiling
         | the compiler to target a different architecture.
        
           | mrgaro wrote:
           | Doesn't Golang support this as well, out of the box?
        
             | jibal wrote:
             | Apparently; I wasn't aware. But unlike Zig this doesn't
             | work with FFI ... everything has to be Go code ... cross
             | compilation works by compiling the library code for the
             | target and caching it ... but if you need anything outside
             | of that you're out of luck ... or maybe not ... I ran
             | across this tidbit:
             | 
             | "When a Go project utilizes CGo to interact with C code,
             | standard Go cross-compilation might require additional
             | steps. This is because Go can cross-compile Go code but not
             | C code directly, necessitating the availability of target
             | system libraries on the development machine. Tools like Zig
             | can be used as a C compiler (zcc) to facilitate cross-
             | compilation for CGo-dependent projects by providing the
             | necessary cross-compilation capabilities for the C code."
        
         | andsoitis wrote:
         | > this is utterly routine. It even has the name used here:
         | Cross-compiling.
         | 
         | Zig makes cross-compilation trivial and part of the language
         | philosophy.
         | 
         | Other languages either rely on external toolchains (C/C++, Rust
         | with C deps) or are limited in target flexibility (Go).
         | 
         | For projects targeting multiple OS/architectures, Zig is
         | currently the most straightforward option.
        
       | mobeigi wrote:
       | I've heard good things about Zig. I want to pick it up and
       | experiment with it but at ~2% market share I find it hard to
       | justify spending the time to learn and master it right now. It's
       | usually much easier to find the time to learn a new language if
       | there is a project (work or open source) that is also using it.
       | 
       | https://survey.stackoverflow.co/2025/technology
        
         | dtj1123 wrote:
         | Check out Ghostty. It's a relatively new and ambitious open
         | source project but is rapidly gaining popularity.
        
         | 59nadir wrote:
         | It can be useful sometimes to learn things irrespective of what
         | the rest of the world thinks of them.
         | 
         | My personal experience was (back in 2019) that Zig was
         | basically a language you could learn in a weekend and end up
         | being reasonably productive after a week. With that in mind,
         | you might find that you can try it out and either find
         | something that you really like in it and continue, or simply
         | drop it (I ended up picking Odin over Zig, for example, and
         | have found it delightful even 1+ years into production).
         | 
         | The truth is that if you only ever learn what is already
         | popular you'll end up being the professional equivalent of a
         | gray mass with zero definition and unique value proposition.
        
       | krosaen wrote:
       | I like the idea of the `defer `keyword - you can have automatic
       | cleanup at the end of the scope but you have to make it obvious
       | you are doing so, no hidden execution of anything (unlike c++
       | destructors).
        
         | jibal wrote:
         | Adopted from go, first appeared in D, invented by one of its
         | major developers, Andrei Alexandrescu.
        
           | jibal wrote:
           | P.S. In D it's `scope(exit)` = defer, `scope(failure)` =
           | Zig's errdefer, and `scope(success)` -- which no one else has
           | and which I have made good use of. e.g., I have a mixin that
           | traces entry and exit from a function, the latter with
           | scope(success). If I use scope(exit) instead then when an
           | exception is thrown all the leave messages are printed and
           | _then_ the stack trace, rather than seeing the stack trace at
           | the point of failure (this baffled me when it first
           | happened).
        
           | fuzztester wrote:
           | I vaguely remember reading somewhere recently that Andrei
           | left the D community / foundation. Do you know if that is
           | true?
        
             | jibal wrote:
             | He's moved on: https://research.nvidia.com/person/andrei-
             | alexandrescu
        
         | tcfhgj wrote:
         | But you can forget it, unlike C++ destructors
        
         | lenkite wrote:
         | I would like a language to support _both_ defer and C++ style
         | destructors  / Rust Drop. There are good use-cases for having
         | both. For things like a mutex or straight-forward resource
         | cleanup - having a bunch of brain-dead defer statements adds
         | little value and only bloats unnecessary line count. Let the
         | resource type handle its own release/cleanup at scope close.
         | Code is made sweet, succinct and safe.
        
           | rustacean wrote:
           | In Rust, there's a drop guard pattern to do this, which
           | leverages the lazy execution of closure, checkout the
           | scopeguard crate. C++ should be easy to do that too I think
        
           | 1718627440 wrote:
           | GNU C++?
        
         | 1718627440 wrote:
         | The GNU C and C++ dialect also has attribute cleanup.
         | https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attribute...
        
         | coolThingsFirst wrote:
         | C++ doesn't have hidden execution, you just don't know the
         | language. Once you exit scope destructor is invoked.
        
       | unscaled wrote:
       | I'm afraid this article kinda fails at at its job. It starts out
       | with a very bold claim ("Zig is not only a new programming
       | language, but it's a totally new way to write programs"), but
       | ends up listing a bunch of features that are not unique to Zig or
       | even introduced by Zig: type inference (Invented in the late 60s,
       | first practically implemented in the 80s), anonymous structs (C#,
       | Go, Typescript, many ML-style languages), labeled breaks,
       | functions that are not globally public by default...
       | 
       | It seems like this is written from the perspective of C/C++ and
       | Java and perhaps a couple of traditional (dynamically typed)
       | languages.
       | 
       | On the other hand, the concept that makes Zig really unique
       | (comptime) is not touched upon at all. I would argue compile-time
       | evaluation is not entirely new (you can look at Lisp macros back
       | in the 60s), but the way Zig implements this feature and how it
       | is used instead of generics is interesting enough to make Zig
       | unique. I still feel like the claim is a bit hyperbolic, but
       | there is a story that you can sell about Zig being unique. I
       | wanted to read this story, but I feel like this is not it.
        
         | tourist2d wrote:
         | As a c++ developer who's heard of Zig but never dived into it,
         | I was reading this article scratching my head wondering what is
         | it actually so unique about it.
         | 
         | Why the blog has a section on how it install it on the path is
         | also very puzzling.
        
         | phplovesong wrote:
         | Agreed.
         | 
         | But i would not put comptime as some sort of magical invention.
         | Its still just a newish take on meta programming. We had that
         | since forever. From my minimal time with Zig i kind of think
         | comptime as a better version of c++ templates.
         | 
         | That said Zig is possibly a better alternative to c++, but not
         | that exiting for me. I kind of dont get why so many think its
         | the holy grail, first it was rust, and now zig.
        
           | johnisgood wrote:
           | As much as I dislike Rust, I gotta give it credit where it's
           | due. It has something unique: a borrow checker. What is so
           | unique in Zig?
        
             | flohofwoe wrote:
             | > It has something unique: a borrow checker.
             | 
             | Rust's borrow checker isn't unique either but was inspired
             | by Cylone: https://en.wikipedia.org/wiki/Cyclone_(programmi
             | ng_language)
             | 
             | IMHO a programming language doesn't need a single USP, it
             | just needs to include good existing ideas and (more
             | importantly) exclude bad existing ideas (of course what's
             | actually a good and bad idea is highly subjective, that's
             | why we need many programming languages, not few).
        
               | simonask wrote:
               | Rust's borrow checker is unique in the sense that it is
               | production-ready. Cyclone is indeed prior art, but it's
               | not as if it ever got beyond the research project stage.
        
               | johnisgood wrote:
               | I don't necessarily disagree, of course. That is why I
               | like Odin the most so far, and perhaps C3.
        
         | Shorel wrote:
         | Compile time seems to be a standard feature in D-lang as well.
         | 
         | Powerful macros that generate code that then gets compiled =)
        
         | nwhnwh wrote:
         | "this article kinda fails at at its job"
         | 
         | Definitely.
        
         | WalterBright wrote:
         | D has had compile time function execution since 2007 or so.
         | 
         | https://dlang.org/spec/function.html#interpretation
         | 
         | It doesn't need a keyword to trigger it. Any expression that is
         | a const-expression in the grammar triggers it.
        
           | jhgb wrote:
           | But Zig doesn't need a keyword to trigger it either? If it's
           | possible at all, it will be done. The keyword should just
           | _prevent_ run-time evaluation. (Unless I grossly
           | misunderstood something.)
        
             | WalterBright wrote:
             | I'm no expert on Zig, but "comptime" is the keyword to
             | trigger it.
        
           | rurban wrote:
           | Perl5 had it before. Either by constant-folding, or by BEGIN
           | blocks.
           | 
           | Constant-folding just got watered down by the many dynamic
           | evangelists in the decades after, that even C or C++ didn't
           | enforce it properly. In perl5 is was watered down on add (+)
           | by some hilariously wrong argumentation then. So you could
           | precompute mult const expressions, but not add.
        
             | zbentley wrote:
             | How are perl5's BEGIN blocks equivalent to comptime? It's
             | been awhile, but I recall BEGIN blocks executing at
             | _require_ time--which, in complicated pre-forking setups
             | that had to be careful about only requiring certain modules
             | later during program execution because they did dumb things
             | like opening connections when loaded, meant that reasoning
             | about BEGIN blocks required a lot more careful thought than
             | reasoning about comptime.
             | 
             | The same is true for templates, or macros--all of which are
             | distinguished by being computed in a _single_ pass (you
             | don't have to think about them later, or worry about their
             | execution being interleaved with the rest of the program),
             | _before_ runtime start (meaning that certain language
             | capabilities like IO aren't available, simplifying
             | reasoning). Those two properties are key to comptime's
             | value and are not provided by perl5's BEGIN blocks--or
             | probably even possible at all in the language, given that
             | it has eval and runtime require.
        
               | rurban wrote:
               | BEGIN blocks execute at compile-time. require is just a
               | wrapper to load a module at compile-time.
               | 
               | When you want to use state, like openening a file for
               | run-time, use INIT blocks instead. These are executed
               | first before runtime, after compile-time.
               | 
               | My perl compiler dumps the state of the program after
               | compile-time. So everything executed in BEGIN blocks is
               | already evaluated. Opening a file in BEGIN would not open
               | it later when required at run-time, and compile-time from
               | run-time is seperated. All BGEIN state is constant-
               | folded.
        
               | zbentley wrote:
               | I think we're using different definitions of "compile
               | time".
               | 
               | I know who you are, and am sure everything you say about
               | the mechanisms of BEGIN is correct, but when I refer to
               | "compile time", I'm referring to something that happens
               | _before my program runs_. Perl5's compilation happens the
               | first time a module is required, which may happen at
               | runtime.
               | 
               | Perhaps there's a different word for what we're
               | discussing here: one of the primary benefits of comptime
               | and similar tools is that they are completed before the
               | program starts. Scripting languages like perl5 "compile"
               | (really: load code into in-memory intermediate data
               | structures to be interpreted) at arbitrary points during
               | runtime (require/use, eval, do-on-code).
               | 
               | On the other hand, while code in C/Zig/etc. is sometimes
               | _loaded_ at runtime (e.g. via dlopen(3)), it's compile-
               | time evaluation is always done _before_ program start.
               | 
               | That "it completed before my code runs _at all_ "
               | property is really important for locality of
               | behavior/reasoning. If the comptime/evaluation step is
               | included in the runtime-code-load step, then your
               | comptime code needs to be vastly more concerned with its
               | environment, and code loading your modules has to be
               | vastly more concerned with the side effects of the import
               | system.
               | 
               | (I guess that doesn't hold if you're shelling out to
               | compile code generated dynamically from runtime inputs
               | and then dlopen-ing that, but that's objectively insane
               | and hopefully incredibly rare.)
        
           | brabel wrote:
           | Yes and D's comptime is much more fun, IMHO than Zig's! Yet
           | everyone talks about Zig's comptime as if it were unique or
           | new.
        
           | tialaramex wrote:
           | Maybe I don't understand, in D, how do I write a function
           | which makes a new type?
           | 
           | For example Zig has a function ArrayHashMapWithAllocator
           | which returns well, a hash table type in a fairly modern
           | style, no separate chaining and so on
           | 
           | Not an _instance_ of that type, it returns the type itself,
           | the type didn 't exist, we called the function, now it does
           | exist, at compile time (because clearly we can't go around
           | making new types at runtime in this sort of language)
        
             | pjmlp wrote:
             | You use templates and string mixins alongside each other.
             | 
             | The issue with mixins is that using string concatenation to
             | build types on the fly isn't the greatest debugging
             | experience, as there is only printf debugging available for
             | them.
        
             | WalterBright wrote:
             | See my other post.
        
           | ScottRedig wrote:
           | Hello Mr. Bright. I've seen similar comments from you in
           | response to Zig before. Specifically, in the comments on blog
           | post I made about Zig's comptime. I took some time reading
           | D's documentation to try to understand your point (I didn't
           | want to miss some prior art, after all). By the time I felt
           | like I could give a reply, the thread was days old, so I
           | didn't bother.
           | 
           | The parent comment acknowledges that compile time execution
           | is not new. There is little in Zig that is, broad strokes,
           | entirely new. It is in the specifics of the design that I
           | find Zig's ergonomics to be differentiated. It is my
           | understanding that D's compile time function execution is
           | significantly different from Zig's comptime.
           | 
           | Mostly, this is in what Zig doesn't have as a specific
           | feature, but uses comptime for. For generics, D has
           | templates, Zig has functions which take types and return
           | types. D has conditional compilation (version keyword), while
           | Zig just has if statements. D has template mixins, Zig trusts
           | comptime to have 90% of the power for 10% of the headache.
           | The power of comptime is commonly demonstrated, but I find
           | the limitations to be just as important.
           | 
           | A difference I am uncertain about is if there's any D
           | equivalent for Zig having types being expressions. You can,
           | for example, calculate what the return type should be given a
           | type of an argument.
           | 
           | Is this a fair assessment?
        
             | WalterBright wrote:
             | > A difference I am uncertain about is if there's any D
             | equivalent for Zig having types being expressions. You can,
             | for example, calculate what the return type should be given
             | a type of an argument.
             | 
             | This is done in D using templates. For example, to turn a
             | type T into a type T star:                   template
             | toPtr(T) { alias toPtr = T*; } // define template
             | toPtr!int p; // instantiate template
             | pragma(msg, "the type of p is: ", typeof(p));
             | 
             | The compiler will deduce the correct return type for a
             | function by specifying _auto* as the return type:
             | auto toPtr(int i) { return cast(float)i; } // returns float
             | 
             | For conditional compilation at compile time, D has _ static
             | if _:                   enum x = square(3);  // evaluated
             | at compile time         static if (x == 4)             int
             | j;         else             double j;         auto k = k;
             | 
             | Note that the _ static if* does not introduce a new scope,
             | so conditional declarations will work.
             | 
             | The _version_ is similar, but is intended for module-wide
             | versions, such as:                   version (OSX)
             | { stuff for OSX }         else version (Win64)         {
             | stuff for Windows 64 }         else             static
             | assert(0, "unsupported OS");
             | 
             | Compile time execution is triggered wherever a const-
             | expression is required. A keyword would be redundant.
             | 
             | D's mixins are for generating code, which is D's answer to
             | general purpose text macros. Running code at compile time
             | enables those strings to be generated. The mixins and
             | compile time execution are not the same feature. For a
             | trivial example:                   string cat(string x,
             | string y) { return x ~ "," ~ y; }         string s =
             | mixin(cat("hello", "betty")); // runs cat at compile time
             | writeln(s); // prints: hello,betty
             | 
             | I'll be happy to answer any further questions
        
           | jadbox wrote:
           | Hi Walter! Big fan. What do you think of Zig? How would you
           | like to see it evolve? Are there any things from Zig that
           | inspire you to work in D?
        
             | WalterBright wrote:
             | I have never written a Zig program, I've just browsed the
             | specification. I do admire the energy and enthusiasm of its
             | creators. The fast compiles of it are well done.
             | 
             | Mostly what I think is the syntax is more complex with less
             | utility than the equivalent D syntax. For example, the use
             | of the 'comptime' keyword is not necessary. For another,
             | the import declaration is overly complex.
             | 
             | I don't know enough about Zig to make informed suggestions
             | on evolving it. D has borrowed stuff from many languages,
             | but I don't recall suggestions in the D forums of a Zig
             | feature that should be added to D, though I might have
             | missed it.
        
           | pron wrote:
           | Partial evaluation has been quite well known at least since
           | 1943 and Kleene's Smn proof. It has since been put to use, in
           | various forms, by quite a few languages (including C++ in
           | 1990, and even C in the early seventies). But the extent and
           | the way in which Zig specifically puts it to use -- which
           | includes, but is not limited to, how it is used to _replace_
           | other features that can then be avoided (and all _without_
           | macros) -- is unprecedented.
           | 
           | Pointing out that other languages have used partial
           | evaluation, sometimes even in ways that somewhat overlap with
           | Zig's use, completely misses the point. It's at least as
           | misplaced as saying that there was nothing new or special
           | about iPhone's no-buttons design because touch screens had
           | existed since the sixties.
           | 
           | If you think Zig's comptime is just about running some
           | computations at compile time, you should take a closer look.
        
             | WalterBright wrote:
             | I'd like to see an example! as I cannot think of one.
        
               | pron wrote:
               | An example of what?
        
               | WalterBright wrote:
               | An unprecedented use.
        
               | pron wrote:
               | Ok, so a primary goal of comptime in Zig is to avoid
               | needing certain specialised features while still enjoying
               | their functionality, in particular, generics, interfaces,
               | and macros. I'm not aware of any language that has been
               | able to eliminate all of these features and replace them
               | with a simple, unified partial evaluation mechanism.
               | 
               | In addition, there's the classic example of implementing
               | a parameterised print (think printf) in Zig. This is a
               | very basic use of comptime, and it isn't used here in
               | lieu of generics or of interfaces, but while there may be
               | some language that can do that without _any_ kind of
               | explicit code generation (e.g. macros), there certainly
               | aren 't many such examples:
               | https://ziglang.org/documentation/0.15.2/#Case-Study-
               | print-i...
               | 
               | But the main point is that the unprecedented use of
               | partial evaluation is in having a single unified
               | mechanism that replaces generics, interfaces, and macros.
               | If a language has any one of them as a distinct feature,
               | then it is not using partial evaluation as Zig does. To
               | continue my analogy to the novel use of a touchscreen in
               | the iPhone, the simplest test was: if your phone had a
               | physical keypad or keyboard, then it did not use a
               | touchscreen the way the iPhone did.
        
               | WalterBright wrote:
               | D's `write` function is generic:
               | write(1,2,"abc",4.0,'c');
               | 
               | write is declared as:                   void
               | write(S...)(S args) { ... }
               | 
               | where `S...` means an arbitrary sequence of types
               | represented by `S`. The implementation loops over the
               | sequence, handling each type in its own individual
               | fashion. User defined types work as well.
        
               | pron wrote:
               | If D has a separate feature for one of: generic types,
               | interfaces and macros, then obviously it doesn't use
               | partial evaluation similarly to how Zig does. It seems to
               | me that it has all three: templates, interfaces, and
               | string mixins. So if I say that Zig uses its unified
               | partial evaluation feature to eliminate these three
               | separate features, why bring up D, which clearly does
               | _not_ eliminate any one of them?
               | 
               | It's like you keep saying the the iPhone design wasn't
               | novel except for the fact that prior art all had a
               | keypad. But the design was novel in that it was intended
               | to _eliminate_ the keypad. Zig 's comptime feature is
               | novel in that it exists to _eliminate_ interfaces,
               | generics, and macros, and you 're bringing up a language
               | that eliminates none of them.
               | 
               | So D clearly isn't an example, but perhaps there's some
               | other language I haven't heard of. Just out of curiosity,
               | can a printf in D not only check types at compile time
               | but also generate formatting code while still allowing
               | for runtime variables and _without_ (!!!) the use of
               | string mixins? Like I said, it 's possible there's
               | precedent for that (even though it isn't the
               | distinguishing feature), and I wonder if D is that. I'm
               | asking because examples I've seen in D either do use
               | string mixins or do not actually do what the Zig
               | implementation does.
        
               | eden-u4 wrote:
               | Not OP, but I guess based on your comment:
               | 
               | > But the extent and the way in which Zig specifically
               | puts it to use -- which includes, but is not limited to,
               | how it is used to replace other features that can then be
               | avoided (and all without macros) -- is unprecedented.
               | 
               | That MrWhite wanted to knkw an example of Zig's comptime
               | that is not merely a "macro", rather the usage as a
               | replacement of other features (I guess more complex..)
               | 
               | PS just interested in zig, I'd like some pointer to these
               | cool feature :)
        
         | brabel wrote:
         | The code samples are so weird... Some are images, others are
         | not, and there's like 10 different color schemes (even among
         | the textual ones, it's not consistent). That actually takes
         | some kind of effort to achieve :D.
        
           | bdangubic wrote:
           | gives you a preview of the experience of using it :)
        
         | pmkary wrote:
         | When I read "I can easily say that Zig is not only a new
         | programming language, but it's a totally new way to write
         | programs" I expected to see something as shocking as
         | LISP/Smalltalk/Realtalk/EVE/FORTH/Prolog... A whole new
         | paradigm, a whole new way to program. Or at least a new concept
         | like the pure functionalism of Haskell, or Prototyping like in
         | Lua/JS/Io. And I was so damn shocked how I must have missed
         | something so huge, having read the entirety of Zig's
         | documentation and not have noticed anything? As you mentioned,
         | turned out nothing, and I was shocked then why is it in the top
         | of HN? Also turned out for no reason based on the comments.
        
           | skotobaza wrote:
           | The idea of modern society is "get hyped for the new thing".
           | Tech crowd did not escape that unfortunately, and keeps
           | rediscovering techniques that were already possible more that
           | 50 years ago. Because they don't want to learn the history of
           | the technology they are using.
        
             | pjmlp wrote:
             | "Computing is a fashion show"
             | 
             | -- Alan Kay
        
           | wolvesechoes wrote:
           | Dev celebs makes blogposts and videos on how Zig is awesome
           | and unique, so the herd repeats.
        
         | otabdeveloper4 wrote:
         | > C/C++
         | 
         | No such thing. Also C++ has most of those features too.
        
         | jb1991 wrote:
         | > C/C++
         | 
         | It has been several decades since putting a slash between these
         | two made sense, lumping them together like this. It would be
         | similar to saying something like Java/Scala or
         | ObjectiveC/Swift. These are completely different languages.
        
           | pjmlp wrote:
           | Nope, that is a English grammar construct that is a shortcut
           | for "and" and "or", as any good English grammar book will
           | explain.
           | 
           | Indeed you see those for Java/Scala and Objective-C/Swift in
           | technical books and job adverts.
           | 
           | Any search on the careers sites, or documentation, on
           | companies that have seats at ISO, sell/develop C and C++
           | compilers, have such C/C++ references in a couple of places.
           | 
           | Do you need any example?
        
             | 1718627440 wrote:
             | In the general case yes, but "C/C++" became an idiom for
             | the stance, that C and C++ are essentially the same, that
             | C++ is a superset of C or that C++ is just the replacing
             | successor of C and it should be treated as superseded. This
             | is quite wrong and thus there is a lot of rightful
             | intervention to that term. Personally I use "C, C++" when I
             | want to talk about both without claiming, that they are the
             | same language.
        
               | pjmlp wrote:
               | Nah, that is what pedantic folks without English grammar
               | knowledge keep complaining about, instead of actually
               | discussing better security practices in _both_ languages.
               | 
               | It is a bikeshedding discussion that doesn't help in
               | anything, regarding lack of security in C, or the legions
               | of folks that keep using C data types in C++, including
               | bare bones null terminated strings and plain arrays
               | instead of collection types with bounds checking enabled.
        
               | 1718627440 wrote:
               | In my opinion, this is an important issue and not
               | "bikeshedding", but it can be discussed whether the term
               | "C/C++" is always an example of that idea or not. I think
               | it is not, but it is connected enough, that I won't use
               | it to side step the issues.
        
               | pjmlp wrote:
               | So there will be zero C language constructs, and C
               | standard library functions being called, on your C++
               | source code?
        
               | 1718627440 wrote:
               | I mostly write C, but yes even a simple call to e.g.
               | malloc has different semantics in C++ (you need to cast).
        
               | pjmlp wrote:
               | Proper C++ should use _new_ , _delete_ , custom
               | allocators, and standard collection types.
               | 
               | Even better, all heap allocations should be done via
               | ownership types.
               | 
               | Calling into _malloc ()_ is writing C in C++, and should
               | only be used for backwards compatibility with existing C
               | code.
               | 
               | Additionally there is no requirement on the C++ standard
               | that _new_ and _delete_ call into _malloc()_ / _free()_ ,
               | that is usually done as a matter of convenience, as all
               | C++ compilers are also C compilers.
        
               | 1718627440 wrote:
               | > Calling into malloc () is writing C in C++, and should
               | only be used for backwards compatibility
               | 
               | And this is exactly the stance I am arguing against. C++
               | is not the newer version of C. It forked of at some point
               | and is a quite different language now.
               | 
               | One of the reasons I do use malloc for, is for
               | compatibility with C. It is not for backward
               | compatibility, because the C code is newer. In fact I
               | actively change the code, when it needs a rewrite anyway,
               | from C++ to C.
               | 
               | The other reason for using it even when writing C++ is,
               | that new alone doesn't allow to allocate without also
               | calling the constructor. For that I call malloc first and
               | then invoke the constructor with placement new. For
               | deallocating I call the destructor and then free. This
               | also has the additional benefit, that your constructor
               | and deconstructor implementation can fail and you can
               | roll it back.
        
               | pjmlp wrote:
               | So it would fail to compile when configuring static
               | analysis to build on error when using C with C++
               | compiler.
               | 
               | Finally, people like to argue between C and C++ when it
               | convenient to do so, yet the compiler language switches
               | to use C extensions in C++ mode keep being used across
               | many projects.
        
               | jb1991 wrote:
               | This has nothing to do with bikeshedding, it is a genuine
               | misunderstanding of these two languages that is
               | propagated in this way. This is not about grammar.
        
               | pjmlp wrote:
               | Yet those complaining usually make use of plenty C
               | constructs, data types and standard library on their C++
               | projects, instead of modern C++ practices.
        
             | jb1991 wrote:
             | Not in this context, that's incorrect.
        
               | pjmlp wrote:
               | What context?
               | 
               | The pedantic folks that jump of their chair when seeing
               | something all companies that pay WG21 salaries use on
               | their docs?
               | 
               | If only they would advocate for writing safer code with
               | the same energy, instead of discussing nonsense.
               | 
               | That is why C and C++ communities are looked down by
               | security folks, and governments.
        
           | tmtvl wrote:
           | The problem is that it's a bit tricky to type the
           | intersection symbol ([?]), because C [?] C++ makes more
           | sense.
        
         | wseqyrku wrote:
         | > Zig is not only a new programming language, but it's a
         | totally new way to write programs
         | 
         | I'd say the same thing about Rust. I find it the best way to
         | express when what code should run at any given point in the
         | program and the design is freakin interstellar: It is basically
         | a "query engine" where you write a query of some code against
         | the entire available "code space" including root crate and its
         | dependencies. Once you understand that programming becomes
         | naming bits and then queries for the ones you wish to execute.
        
           | JoeyJoJoJr wrote:
           | As someone not really familiar with Rust, this sounds
           | intriguing, but I don't full understand. Do you have any
           | links that can or examples that could clarify this for
           | someone who is just starting out with Rust?
        
             | vacuity wrote:
             | Not GP, but I genuinely don't understand what GP is talking
             | about.
        
         | pjmlp wrote:
         | Yeah, as I keep repeating, it is a Modula-2 in C clothes, minus
         | comptime, which as others have mentioned D has had for quite
         | some time.
        
         | 1718627440 wrote:
         | Anonymous structs and type interference are things even C has,
         | although support for the later one is quite recent and limited.
        
         | HarHarVeryFunny wrote:
         | > I'm afraid this article kinda fails at at its job
         | 
         | Yeah, I know nothing about Zig, and was excited by the author's
         | opening statement that Zig is the most surprising language he
         | has encountered in a 45 yr software career...
         | 
         | But this is then immediately followed by saying that ability to
         | compile C code, and to cross-compile, are the most incredible
         | parts of it, which is when I immediately lost interest. Having
         | a built-in C compiler is certainly novel, and perhaps
         | convenient for inter-op, but if the value goes significantly
         | beyond that then the author is failing to communicate that.
        
       | hardwaresofton wrote:
       | It's incredibly silly but I dislike zigs identifier policy.
       | Mixing snake case and camel case for functions is cursed.
       | 
       | That said, amazing effort, progress and results from the
       | ecosystem.
       | 
       | Bursting on the scene with amazing compilation dx, good allocator
       | (and now io) hygiene/explicitness, and a great build system
       | (though somewhat difficult to ramp on). I'm pretty committed to
       | Rust but I am basically permanently zig curious at this point.
       | 
       | [EDIT] "hate" > "dislike". Hate is a strong word and surely I
       | just need to spend some time writing zig and I'd get used to it.
        
         | ivanjermakov wrote:
         | Me too, so I don't follow a convention for private functions.
         | Good thing is you barely interact with ones defined in
         | dependencies.
         | 
         | Prefix anf different naming conventions of C-imported libraries
         | is not less annoying.
        
       | eviks wrote:
       | The article doesn't answer the question, it's all just about "the
       | basics of zig" (there is nothing cool manually editing
       | environment variables on Windows with 8 labeled steps (and 5
       | preliminary steps missing))
       | 
       | and the actual cool stuff is missing:
       | 
       | > with its concept of compile time execution, unfortunately not
       | stressed enough in this article.
       | 
       | indeed
        
       | jandrewrogers wrote:
       | One of the things I like about Zig is that it pretty explicitly
       | recognizes all the weird edge cases that exist in low-level
       | systems code. A rather large cross-section of languages kind of
       | pretend these cases don't exist because addressing it would
       | violate the aesthetic they are trying to achieve with the
       | language. Nonetheless, these are real cases because low-level
       | hardware and system behavior doesn't care about aesthetics as
       | might be expressed in a programming language.
       | 
       | Even C++ didn't fully repent from this sin until around C++17. I
       | appreciate the non-begrudging acceptance of this reality in Zig.
        
         | sho_hn wrote:
         | Interesting, but really in need of some examples.
        
           | jandrewrogers wrote:
           | I would highlight `std::launder` as an example. It was added
           | in C++17. Famously, most people have no idea what it is used
           | for or why it exists. For low-level systems it was a godsend
           | because there wasn't an official way to express the intent,
           | though compilers left backdoors open because some things
           | require it.
           | 
           | It generates no code, it is a compiler barrier related to
           | constant folding and lifetime analysis that is particularly
           | useful when operating on objects in DMA memory. As far as a
           | compiler is concerned DMA doesn't exist, it is a Deus Ex
           | Machina. This is an annotation to the compiler that
           | everything it thinks it understands about the contents and
           | lifetime of a bit of memory is now voided and it has to start
           | over. This case is endemic in high-end database engines.
           | 
           | It should be noted that `std::launder` only works for
           | different instances of the same type. If you want to
           | dynamically re-type memory there is a different set of APIs
           | for informing the compiler that DMA dropped a completely
           | different type in the same memory address.
           | 
           | All of this is compiled down to nothing. It annotates for the
           | compiler things it can't understand just by inspecting the
           | code.
        
             | sho_hn wrote:
             | This is a good example because I'm familiar with it (I'm a
             | C++ programmer; I haven't had occasion to use `launder`,
             | but I read about it back then).
             | 
             | But what's the Zig equivalent?
        
               | smj-edison wrote:
               | One thing that I've found really useful is being able to
               | annotate o pointer's alignment. I'm working on an
               | interpreter, and I'm using tagged pointers (6 bits), so
               | the data structure needs to have 128 byte alignment. I
               | can define a function like `fn toInt(ptr: *align(128)
               | LongString) u56` and the compiler will track and enforce
               | the alignment.
               | 
               | You might also find some of the builtin functions
               | interesting as well[1], they have a lot of really useful
               | functions that in other languages are only accessible via
               | the blessed stdlib, such as @addrSpaceCast, @atomicLoad,
               | @branchHint, @fieldParentPtr, @frameAddress, @prefetch,
               | @returnAddress(), and more.
               | 
               | [1] https://ziglang.org/documentation/master/#Builtin-
               | Functions
        
             | comex wrote:
             | I don't think that's quite right. For DMA you would
             | normally use an empty asm block, which is what's typically
             | referred to as a "compiler barrier" and does tell the
             | compiler to discard everything it knows about the contents
             | of a some memory. But std::launder doesn't have the same
             | effect. It only affects type-based optimizations, mainly
             | aliasing, plus the assumption that an object's const fields
             | and vtable can't change.
             | 
             | For example, in this test case:
             | 
             | https://gcc.godbolt.org/z/j3Ko7rf7z
             | 
             | GCC generates a store followed by a load from the same
             | location, because of the asm block (compiler barrier) in
             | between. But if you change `if (1)` to `if (0)`, making it
             | use `std::launder` instead of an asm block, GCC doesn't
             | generate a load. GCC still assumes that the value read back
             | from the pointer must be 42, despite the use of
             | `std::launder`.
        
               | jandrewrogers wrote:
               | This doesn't seem quite right. The asm block case is
               | equivalent to adding a volatile qualifier to the pointer.
               | If you add this qualifier then `std::launder` produces
               | the same codegen.
               | 
               | I think the subtle semantic distinction is that
               | `volatile` is a current property of the type whereas
               | `std::launder` only indicates that it was a former
               | property not visible in the current scope. Within the
               | scope of that trivial function in which the pointer is
               | not volatile, the behavior of `std::launder` is what I'd
               | expect. The practical effect is to limit value
               | propagation of types marked `const` in that memory. Or at
               | least this is my understanding.
               | 
               | DMA memory (and a type residing therein) is often only
               | operationally volatile within narrow, controlled windows
               | of time. The rest of the time you really don't want that
               | volatile qualifier to follow those types around the code.
        
         | wmedrano wrote:
         | Zig makes the standard library accessible. Just by clicking "go
         | to definition", you run into all the weird cases.
         | 
         | For example, apparently the plan9 OS gets special
         | page_allocator handling:
         | https://ziglang.org/documentation/master/std/#std.heap.page_...
        
       | jibal wrote:
       | I don't think Zig--which certainly is innovative in a number of
       | ways--benefits from this sort of thing. Up front is a claim that
       | it's "totally new way to write programs", but zero support is
       | offered, and almost nothing else "meta" said about the language,
       | other than a couple of sentences in the conclusion that are
       | likewise inaccurate hype. I've programmed in many languages
       | including Zig and it definitely is _not_ a new way of
       | programming. It imposes disciplines that are different from those
       | of other languages, but the same is true of other languages.
       | 
       | The final paragraph says "This is all quite surprising" -- why
       | so? "and let one think that many advantages previously found only
       | in interpreted languages are gradually migrating to compiled
       | languages in order to offer more performance" -- sure, but Zig is
       | hardly the first ... D and Nim both have interpreters built into
       | the compiler that allow extensive comptime computation--both of
       | those languages have far more metalanguage facilities than Zig,
       | in addition to many other language features that Zig lacks--which
       | is not necessarily a fault, as it aims for a certain kind of
       | simplicity and close-to-the-metal performance ... although both D
       | and Nim are highly performant (both have _optional_ garbage
       | collection, though Nim is more advanced in making GC-free
       | programming approachable). One thing you can say about Zig though
       | --it compiles like a bat out of hell.
       | 
       | P.S. Another thing about Zig worth mentioning that came up in
       | some comments is cross compilation. I don't think people
       | understand how Zig is different and what an engineering feat it
       | is (Andrew has a writeup somewhere of how it's done--it's
       | shocking):
       | 
       | If you install Zig, you can now generate executables for
       | virtually any target with just a command line argument specifying
       | the target, regardless of what machine you installed it on.
       | Nothing else does that--cross compilation generally requires
       | recompiling the compiler and library to target a different
       | architecture. Zig comes with precompiled libraries for a huge
       | number of targets.
       | 
       | I noticed a comment where someone said they love Zig but they've
       | never programmed in it--they use it to cross-compile their Nim
       | programs. (The Nim compiler has a C code backend, and Zig has a C
       | compiler built in, so Nim inherits instant arbitrary cross-
       | compilation to any target via Zig).
        
       | Panzerschrek wrote:
       | Zig is not cool. It's a mediocre new language, missing key
       | features needed for industrial development, like destructors or
       | overall memory safety. But for some reason it's overhyped.
        
         | otabdeveloper4 wrote:
         | It's ""simple"", so low-information, high-blogspam software
         | developers have something to talk about instead of programming.
        
         | 59nadir wrote:
         | If you think destructors/`Drop` traits or the like are good
         | then Zig was never for you. It has nothing to do with
         | "industrial development", neither does memory safety. The irony
         | is that memory safety as a concept definitely _is_ overhyped.
        
           | Panzerschrek wrote:
           | Destructors aren't just good. They are one of the most
           | important innovations in programming, since they reduce
           | boilerplate and prevent many bugs. Developing a language
           | without them means introducing more bugs which could be
           | avoided.
        
             | pyrolistical wrote:
             | It violates one of zigs principle of no hidden control flow
        
       | nikitalita wrote:
       | This article made me want to beat up Zig.
        
       | mk89 wrote:
       | Some days ago I decided to look at Zig a bit more in detail. So I
       | skipped the usual marketing and I checked why it could be an
       | alternative to C or Rust. Could it be?
       | 
       | It seems that (debug) allocators are a nice idea, however, it
       | seems that they exist "somehow" already for C, so I wonder: why
       | would you pick this language for your next low level program?
       | They provide runtime checks, so you need thorough testing before
       | you can spot use-after-free or so. It's very similar to the
       | existing situation with c/c++ and the sanitizers, although they
       | work a bit differently.
       | 
       | So the question I have for hardcore low level programmers: why
       | don't they invest more on the memory allocators like
       | hardened_malloc[0] instead of starting a new programming
       | language? It would probably be less expensive in terms of time
       | and would help fix _existing_ software.
       | 
       | [0]: https://github.com/GrapheneOS/hardened_malloc
        
         | astrobe_ wrote:
         | > So the question I have for hardcore low level programmers:
         | why don't they invest more on the memory allocators
         | 
         | A partial answer is that part of low-level programmers avoid
         | memory allocation and threads like plague. In some cases they
         | are not even an option (small embedded programming, it's nearly
         | as low-level as you can get before going hardcore for real with
         | assembly programming), but when they can the keywords are
         | efficiency, reliability, predictability, and simplicity :
         | statically allocating in advance is a thing you can do because
         | the product is typically with max specs written on the box
         | (e.g. max number of entries in a phone book, to take a generic
         | dumb example), and you have to meet these requirements even if
         | the customer uses all of the capabilities to the max; no memory
         | overbooking allowed, which is basically what dynamic allocation
         | is, in a sense.
         | 
         | > instead of starting a new programming language
         | 
         | If I were to start a new low-low level programming language, I
         | would basically just fix C's weak typing problem, fix the UB
         | problems that only come from issues with long-gone processors
         | (like C++11 finally did with sign encoding), "backport" some
         | C++ features (templates? constexpr?), add a pinch of syntactic
         | sugar and fix union types to have proper sum types. But
         | probably I've just described D and apparently a significant
         | chunk of C23.
        
           | uecker wrote:
           | Indeed, and if someone wants to help work on C, this is very
           | much possible both on the compiler side or on the standards
           | side.
        
         | bvrmn wrote:
         | Slices and UB-explicitness are quite nice comparing to C. Makes
         | head free to think about really important things.
        
         | brabel wrote:
         | People are also doing that, see FillC. It's just different
         | people doing different things because, well, they have freedom
         | to do what they want.
        
       | cat-whisperer wrote:
       | I just discovered that you can add build-time arguments that get
       | baked in. It's soo awesome!
        
       | oezi wrote:
       | Unfortunately the article glosses too quickly over aspects which
       | seem unique. For instance, I don't get what labeled breaks have
       | to do with comp-time or why a labeled break was used in this
       | situation over a normal function call:
       | 
       | >>>
       | 
       | Labeled breaks
       | 
       | Zig can do many things in compilation time. Let's initialize an
       | array, for example. Here, a labelled break is used. The block is
       | labelled with an : after its name init and then a value is
       | returned from the block with break.
       | 
       | >>>
       | 
       | The article hasn't even talked about how the language decides
       | what an open curly brace is causing.
        
       | hamasho wrote:
       | > Zig  for ( 0..9 ) |i| { }       > C    for (i = 0; i < 9; i++)
       | { }
       | 
       | I know an open interval [0..9) makes sense in many cases, but
       | it's counterintuitive and I often forget whether it includes the
       | last value or not. It's the same for python's range(0, 9).
        
         | jamiejquinn wrote:
         | I completely agree. One of Zig's big competitors, Odin, has a
         | more explicit syntax for this where `0..<5` is an open interval
         | and `0...5` is closed.
        
           | brabel wrote:
           | I think that comes from Ruby, right? I know Groovy is
           | inspired by Ruby and has exactly the same syntax.
           | 
           | EDIT: oh just noticed it's 3 dots in the close case... in
           | Groovy it's just 2.
        
           | psnehanshu wrote:
           | I even forget which word means what, "open", "close"
        
         | reorder9695 wrote:
         | Rust's solution to this is quite good, that's 0..9 and if you
         | want to include 9 it's 0..=9, it looks a bit funny but knowing
         | one with an = sign in it exists removes any doubt
        
           | mirsadm wrote:
           | Adding additional syntax to a language for this case seems
           | bonkers to me. People can just write 0..10.
        
             | dgrunwald wrote:
             | If you need `0..=n`, you can't write `0..(n+1)` because
             | that addition might overflow.
        
               | hgomersall wrote:
               | I'm actually curious now how this is stored on `Range` in
               | rust. I've certainly used ..= for exactly the reason you
               | say, but as far as I'm aware `.end` on the range is the
               | exclusive upper bound in all cases. What happens to
               | `.end` in the overflowing case?
               | 
               | Edit: it doesn't use Range for ..=, but rather
               | RangeInclusive, which works fine.
        
             | zygentoma wrote:
             | It's more meant for usage with variables:
             | for i in 0..length {         ...       }            for i
             | in 0..=maxindex {         ...       }
        
         | adrian_b wrote:
         | The better solution to forgetting whether an interval is closed
         | or half-open is to always use only half-open intervals, without
         | any exceptions.
         | 
         | In most cases half-open intervals result in the simplest
         | program, so I agree with the choice of Zig, which is inherited
         | from other languages well-designed from this point of view,
         | e.g. Icon.
         | 
         | I find half-open intervals more intuitive than either closed
         | intervals or open intervals, and much less prone to errors, for
         | various reasons, e.g. the size of a half-open interval is equal
         | to the difference between its limits, unlike for closed
         | intervals or open intervals. Also when accessing the points in
         | the interval backwards or circularly, there are simplifications
         | in comparison with closed intervals.
        
           | Milpotel wrote:
           | > always use only half-open intervals
           | 
           | That means you have to waste bytes for the index when you
           | need to include ..._MAX.
        
             | adrian_b wrote:
             | By "..._MAX" I assume that you mean the maximum value of a
             | given integer type.
             | 
             | In a language where half-open intervals are supported
             | consistently in all the places, this would be solved
             | trivially, e.g. for a signed byte the _MIN and the _MAX
             | values would be defined as -128 and +128, more intuitively
             | than when using closed intervals, where you must remember
             | to subtract 1 from the negated minimum value.
             | 
             | Even the C language has some support for half-open
             | intervals, because the index pointing after the last
             | element of an array is a valid index value, not an out-of-
             | range value (though obviously, attempting to access the
             | array through that index value would be trapped as an out-
             | of-range access, if that is enabled).
             | 
             | Applied consistently, the same method would ensure that the
             | value immediately above the last representable value of an
             | integer type is valid in ranges of that type, even if it
             | would be invalid in an expression as an operand of that
             | type.
        
         | 1718627440 wrote:
         | > an open interval [0..9)
         | 
         | See Dijkstra for why this is the right way to represent ranges:
         | https://www.cs.utexas.edu/~EWD/transcriptions/EWD08xx/EWD831...
        
       | jamiejquinn wrote:
       | The article's claim of Zig being a "totally new way to write
       | programs" is quite mad but I'd like to make a different claim:
       | Zig's own development is a totally new way of writing programming
       | languages (or is at least very rare).
       | 
       | While I don't wholly agree with all choices made by Andrew and
       | the Zig team, I greatly appreciate the care with which they
       | develop features. The slow pace of deliberating over features,
       | refining them, and removing unnecessary ones seems in sharp
       | contrast to the development of any other langauge I'm aware of.
       | I'm no language historian though, happy to be challenged.
        
         | brabel wrote:
         | It seems pretty common to me?! Java is developed that way. So
         | is Rust. And many others. What exactly do you see as different
         | in Zig?
        
           | koeng wrote:
           | I don't think Java and Rust were so ok with completely
           | removing features. For example, in Zig 0.15 they completely
           | overhauled the io, meaning all libraries now have to rewrite
           | up usage. Just to make sure they did it right
        
             | otabdeveloper4 wrote:
             | > Just to make sure they did it right
             | 
             | Let me guess: they didn't, and now there is a third-party
             | "right" way to do it.
             | 
             | (We've been here before, many times.)
        
             | reichstein wrote:
             | Semantic major/minor version 0.15 means it's still in
             | development. It's not supposed to be stable. Going from
             | 0.14 to 0.15 allows breaking changes.
             | 
             | Try making a similar change between version 5.0 and 6.0,
             | with hundreds of thousands of existing users, programs,
             | packages and frameworks that all have to be updated. (Yes,
             | also the users who have to learn the new thing.)
        
             | kibwen wrote:
             | _> I don't think Java and Rust were so ok with completely
             | removing features._
             | 
             | This just shows that you weren't around for pre-1.0 Rust.
             | Back then Rust was infamous for the language making
             | breaking changes every _week_. Check out this issue from
             | 2013 tracking support for features which were deprecated
             | but had yet to be removed from the compiler:
             | https://github.com/rust-lang/rust/issues/4707 , and that's
             | just a single snapshot from one moment in Rust's
             | prehistory.
        
           | murkt wrote:
           | Java and Rust have surpassed 1.0 version a long time ago, so
           | they don't remove features left and right on each feature
           | release.
           | 
           | Not that it's a bad thing. Python removes stuff, and it takes
           | time to upgrade to new versions.
        
             | Milpotel wrote:
             | And Zig has surpassed 1.0 or where is the argument?
        
               | murkt wrote:
               | Zig has not surpassed 1.0 and explicitly strives to
               | remove features, which Java and Rust don't do anymore.
               | That's why it feels different.
        
         | SleepyMyroslav wrote:
         | I am not sure if a slow pace is as beneficial as you say. I
         | scrolled through the error handling issue brought up in this
         | comment section (
         | https://github.com/ziglang/zig/issues/2647#issuecomment-2670...
         | ) and its clear that only thing that happened there was
         | communication on the issue was hindered. I come from C++ side
         | and our "ISO C++ committee" language development process leaves
         | a lot to be desired. Now look at error handling that they did
         | passed in C++23 ( std::expected ). It raises some questions on
         | how slow you can be while still appearing to be moving forward.
         | 
         | Disclaimer: I would like to see Zig and other new languages to
         | become a viable alternatives to C++ in Gamedev. But I
         | understand that it might happen way after me retiring =)
        
         | sesm wrote:
         | In terms of programming language development, take a look at
         | Clojure. The clarity of reasoning behind every decision is
         | unmatched.
        
       | DeathArrow wrote:
       | >totally new way to write programs
       | 
       | To me it seems like a better C but not at all unique since most
       | concepts in Zig are already present in other languages.
       | 
       | Zig is cool but not unique. And that is cool, too. Originality
       | for the sake of originality doesn't add value in programming.
        
       | cyber1 wrote:
       | The biggest advantages of Zig for me are that everything is
       | explicit (no hidden features like overloads or implicit
       | conversions) and that its metaprogramming is powerful, easy to
       | use, and easy to understand.
        
       | bjourne wrote:
       | Do you _need_ pointer arithmetic? I think that 's the one feature
       | a modern C replacement should do away with. The other being
       | support for arithmetic with unsigned types.
        
       | m00dy wrote:
       | Why would I write in Zig instead of Rust ? Only meaningful
       | comments here
        
       | pjmlp wrote:
       | Author is apparently unaware of alternatives like Ada, Object
       | Pascal and Modula-2, where most of those "innovations" were
       | already available.
       | 
       | It is kind of interesting that packaging the same ideas with a C
       | like syntax suddenly makes them "cool", 40 years later.
        
         | materielle wrote:
         | I'm actually not a huge Zig person.
         | 
         | But yes, avoiding arcaneness for the sake of arcaneness will
         | earn you more users.
         | 
         | A big success of Rust has nothing to do with systems
         | programming or the borrow checker.
         | 
         | But just that it brings ML ideas to the masses without having
         | to learn a completely new syntax and fight with idiosyncratic
         | toolchains and design decisions.
        
       | arbitrandomuser wrote:
       | Zig structs are "modules" in themselves, apart from c like struct
       | fields , they can have local variables, structs and functions
       | declared and used inside of them .
       | 
       | in fact files in zig are just structs !
        
       | Raphael_Amiard wrote:
       | I love systems programming language and have worked on the Ada
       | language for a long time. I find Zig to be incredibly
       | underwhelming. Absolutely nothing about it is new or novel, the
       | closest being comptime which is not actually new.
       | 
       | Also highly subjective but the syntax hurts my eyes.
       | 
       | So I'm kind of interested by an answer to the question this
       | articles fails to answer. Why do you guys find Zig so cool ?
        
         | uecker wrote:
         | As someone who still thinks one should write C (so as a
         | completely uncool person), what I like about Zig is that it is
         | no-nonsense language that just makes everything work as it is
         | supposed to be without unnecessary complications, D is similar,
         | except that it fell into the trap of adding to many features.
         | 
         | So, no, I do not really see anything fundamentally new either.
         | But to me this is the appealing part. Syntax is ok (at least
         | compared to Rust or C++).
         | 
         | Having said this, I am still skeptical about comptime for
         | various reasons.
        
         | pjmlp wrote:
         | It gets hyped by a few SV influencers.
        
         | audunw wrote:
         | It's hard to do something that is truly novel these days.
         | Though I'd argue that Zigs upcoming approach to Async IO is
         | indeed novel on its own. I haven't seen anything like it in an
         | imperative language.
         | 
         | What's important is the integration of various ideas, and the
         | nuances of their implementation. Walter Bright brings up D
         | comptime in every Zig post. I've used D. Yet I find Zigs
         | comptime to be more useful and innovative in its implementation
         | details. It's conceptually simpler yet - to me - better.
         | 
         | You mention Ada. I've only dabbled with it, so correct me if
         | I'm wrong, but it doesn't have anything as powerful as Zigs
         | comptime? I think people get excited about not just the ideas
         | themselves, but the combination and integration of the ideas.
         | 
         | In the end I think it's also subjective. A lot of people like
         | the syntax and combination of features that Zig provides. I
         | can't point to one singular thing that makes me excited about
         | Zig
        
         | vendiddy wrote:
         | We've recently adopted Zig at a few systems at our company but
         | I think maybe "cool" or "new" is the wrong metric?
         | 
         | I view Zig as a better C, though that might be subjective.
        
       | gethly wrote:
       | Why are people so obsessed with Zig when Odin has been stable,
       | though not yet with official spec, for such a long time and used
       | in real production for years? Is it just syntax preference or
       | does Zig provide something amazing that I am missing? Not that I
       | use any of them, I am not interested in manual memory management
       | and i stick to Go. But I'm curious.
        
         | 59nadir wrote:
         | Zig has a lot of manpower behind it in comparison to Odin and
         | this is one of the most important things for people, they see a
         | proverbial crowd and that builds a lot more interest.
         | 
         | With that said, here are a couple of things you have in Zig
         | that you don't get in Odin:
         | 
         | - Cross-compilation & cross-linking (more or less works): Odin
         | doesn't do cross-linking.
         | 
         | - Comptime; you can actually use it to effectively get Functors
         | from ML, which means passing in interfaces to modules and
         | getting compile-time generated modules back (structs in this
         | case)
         | 
         | - Error set inference; Zig can figure out the complete set of
         | errors a code path can return and make sure you handle them, or
         | bubble that exact set (plus your own errors) up. This comes
         | with the caveat that Zig has no capability to attach actual
         | data to the errors, so you have to side-channel that info if
         | you have it. Odin doesn't do error inference apart from the
         | type checking side of it, but does allow using tagged unions as
         | errors, which is great. They still interact exactly as they
         | ought to with the zero-value-as-no-error machinery.
         | 
         | I didn't use comptime much when I used Zig, and I like tagged
         | unions as errors much more than I value being able to cross-
         | link, so I decided that Odin was better for me. Defaulting to
         | zero-values and the zero-value being blessed in terms of
         | language features didn't feel right to me before I started
         | using it but now I can't really imagine going back to _not_
         | assuming the zero-value being there.
        
           | gethly wrote:
           | Thanks for the info. I'm curious to see what people will do
           | when Jai will finally be released next year. So far, Rust has
           | been gaining a lot of traction, although wit ha lot of
           | controversies attached to it. Zig seems to be doing well but
           | the lack of progress towards v1.0 after all those years is
           | quite concerning, making it looks more and more like a toy
           | project rather than something serious. Odin seems to be
           | flying under the radar of most people a bit too much. Jai
           | will have John's name behind it and I am hearing a lot of
           | praise from insiders(people in the beta program). As I said,
           | I have no use for such languages but if i'll do in the
           | future, I'd like to have a clear choice rather than myriad of
           | languages in various stages of development, all trying to do
           | the same thing.
        
             | 59nadir wrote:
             | If Jai is ever actually released to a meaningful amount of
             | people I think we'll see just how little Blow's name means
             | to people in practice. There is an artificial mystery
             | around Jai right now and when the lid comes off the pot I
             | think a lot of that is going to dissipate very fast.
             | 
             | With that said, I'll try it out. I'm not really impressed
             | by what I've seen so far, though, it's very middle-of-the-
             | pack with some really nonsense ideas. The possibility of
             | easily creating your own checks with the compile-time
             | machinery is potentially interesting but would probably
             | turn into a nothingburger for us.
             | 
             | I think that's where most of this is at: After so many
             | years of "waiting" (I think most people stopped actually
             | waiting after a few years of mostly talking and very little
             | actual productive doing) we'll end up with a very meh
             | language that was touted as super special... And a
             | painfully simple sokoban game that people are going to
             | pretend is somehow super complex and hard to make.
        
         | audunw wrote:
         | Are you implying that Zig hasn't been used in production? What
         | about Tigerbeetle, Bun and Ghostty? I'm using Ghostty as my
         | terminal right now.
         | 
         | I feel like Zig is aiming a lot higher. So that's why it's
         | taking longer and also why people are more obsessed with it.
         | The work on doing their own backend and incremental linker is
         | impressive and interesting. So is their attempt at getting IO
         | and async right.
        
       | swiftcoder wrote:
       | Man who has only ever written C++ discovers other programming
       | languages exist, news at 11
        
       | BiteCode_dev wrote:
       | Top comment: this article sucks.
       | 
       | Then HN proceed to keep the article at the head of the front page
       | for the day.
        
       | kopollo wrote:
       | Why a new lang every day?
        
         | gabrielgio wrote:
         | Because people like to have fun.
        
       | nyfresh wrote:
       | I am surprised Native SIMD support is not mentioned in an article
       | with this title. Not sure if it could be applied to the sudoku
       | example he used.
        
       | beginnings wrote:
       | zig is not cool at all, its ugly as sin, and has zero use case
       | other than mingling with legacy c code, and who in their right
       | mind wants to be doing that
       | 
       | its a hipster language, absolute insanity to use it when rust
       | exists unless you have that very specific c related slave work to
       | do
        
         | estebank wrote:
         | > its ugly as sin
         | 
         | Uncalled for and subjective. Certainly plenty of people call
         | Rust's syntax ugly. Discussing syntax and not semantics is a
         | waste of time.
         | 
         | > has zero use case other than mingling with legacy c code
         | 
         | So it has a use case?
         | 
         | > who in their right mind wants to be doing that
         | 
         | Some people have to.
         | 
         | > absolute insanity to use it when rust exists unless you have
         | that very specific c related slave work to do
         | 
         | Some people do.
         | 
         | What's the need for such emotionally charged language in your
         | comment?
         | 
         | I have my own reasons not to use Zig at this moment. I want
         | enforced memory safety and am waiting on 1.0 to see what the
         | language finally looks like. Until stabilization I certainly
         | won't be using it in production. But that doesn't mean the
         | project is meritless, that experimenting with language features
         | before then is wrong, that making a language suitable for
         | specific niches is a bad idea.
         | 
         | I don't see Zig as a replacement for tools that would have been
         | written in Go, Java or C#, and I would rather we had less
         | memory unsafe software out there, but it is a clear step
         | function ahead of C.
         | 
         | Just like I and many others spend a lot of time trying to make
         | Rust the best it can be, their team is doing the same.
        
       | jsiepkes wrote:
       | While some of the features the author references are really
       | interesting, personally I don't see how any of that would justify
       | creating a new memory unsafe language in 2016. I thought it was
       | pretty obvious by now [1][2][3] memory safety is best left to
       | tooling / compilers and not to programmers.
       | 
       | [1] https://research.google/pubs/secure-by-design-googles-
       | perspe...
       | 
       | [2] https://www.microsoft.com/en-us/msrc/blog/2019/07/we-
       | need-a-...
       | 
       | [3] https://www.cisa.gov/case-memory-safe-roadmaps
        
         | 1718627440 wrote:
         | This sound a bit like Tanenbaum's rejection of Torvals'
         | project, because monolithic kernels are obsolete.
        
           | xiffle wrote:
           | Tanenbaum was right, the future of the Linux kernel is dire,
           | and it's been a huge setback to operating systems research in
           | practical terms.
           | 
           | Fortunately, vendors are gradually moving away from Linux,
           | having been hamstrung by its failures. Google is planning to
           | move to a capability-based microkernel in the coming years
           | for Android and ChromeOS, and Huawei has already done so with
           | HarmonyOS.
           | 
           | In a hundred years, Linux will be a footnote in computing
           | history.
        
             | 1718627440 wrote:
             | Irregardless of whether this is true, it has not prevented
             | adoption of Linux.
        
           | pjmlp wrote:
           | Most OSes use either hybrid kernels, or type 1 hypervisors,
           | which are microkernels by another name.
        
         | vkazanov wrote:
         | Unlike C/C++, Zig is not inherently memory-unsafe.
         | 
         | Where Rust insists on having either partial safety through the
         | checker or lack of control in unsafe code, Zig provides a
         | toolkit for contructing safe frameworks. Zig also doesn't have
         | main sources of unsafety coming from certain C design mistakes.
         | 
         | Besides, if you are after true memory safety then garbage
         | collection is the way to go.
        
         | wffurr wrote:
         | I think even in the year of our lord 2016 there's room for a
         | language with safe defaults but seamless interoperability with
         | existing unsafe code. It's certainly an improvement on the
         | status quo and provides an alternative to rewriting the world
         | in Rust or a GC language.
        
           | pjmlp wrote:
           | Except Zig defaults could be found on the year of our Lord in
           | 1976, 1978, 1983 and 1986.
           | 
           | Exercise from other posts of mine which languages those might
           | be.
        
             | wffurr wrote:
             | Sure, but Zig is bringing those to users and making
             | headlines on HN. I think that's generally a good thing.
             | Bringing the best of prior languages together in a new
             | package
        
               | pjmlp wrote:
               | Except in 2025 we know better regarding safer systems
               | programming languages, use after free is no longer
               | something that we should tolerate.
        
             | smj-edison wrote:
             | I've been programming in rust for three years, until I
             | picked up zig recently. I was also worried about memory
             | safety when I started using it, but I've been pleasantly
             | surprised how many safety features it has (it's certainly
             | been easier to debug than the C code I've had to work
             | with). Slices are often mentioned for safety, which they
             | are great, but even better has been all of the casting
             | functions. In Debug and ReleaseSafe mode, @intCast will
             | panic if you try to narrow on integer that's too big.
             | @alignCast checks that the alignment is correct. @bitCast
             | ensures that both types have the same bit width. Non-packed
             | unions will panic if you access the wrong field. Integer
             | under and overflow has revealed some of my bad code like
             | four times now. defer/errdefer is much easier to reason
             | about that "goto cleanup" (it also lets me write custom
             | cleanup code, instead of being beholden to the author's
             | drop implementation).
             | 
             | So no, it's not as safe as rust in terms of memory, but
             | it's quite close, and in the process lets you do some
             | really cool stuff.
        
       | awesan wrote:
       | A lot of comments here kind of miss the point, but that's to be
       | expected because you can only really get it when you have the
       | experience. Like hearing a description of a painting will not
       | give you the same emotion as looking at it yourself.
       | 
       | Zig has completely changed the way I program (even outside of
       | it). A lot of the goals and heuristics I used to have while
       | writing code have completely changed. It's like seeing
       | programming itself in a new way.
        
         | fuzztester wrote:
         | Examples?
        
       | portly wrote:
       | A super cool feature are labeled switches:
       | https://codeberg.org/ziglings/exercises/src/branch/main/exer...
       | 
       | They allow for super ergonomical coding of state machines, which
       | is a lot of fun.
        
       | coolThingsFirst wrote:
       | How on earth is it unique to compile code for different
       | architectures? This is a solved problem since the 80s.
       | 
       | It basically looks like C with different syntax, im also not
       | convinced the 0...9 implicit range is better for iteration - i
       | prefer it explicitly for lower level languages.
        
       | SonnyTark wrote:
       | This is a very confusing blog post. I found myself looking for
       | ChatGPT markers because it doesn't make sense to say: omg zig is
       | so much cooler than C here's why, then start listing the absolute
       | basics of the language that are identical in most modern
       | languages without any actual reflection why writing the same
       | thing in a different syntax somehow makes zig superior?
        
         | aib wrote:
         | You're absolutely correct! </s>
         | 
         | The "how to modify an environment variable" bit and the bin-
         | dec-hex table made me feel the same way. Then I saw the part
         | explaining how to check for duplicates in a row... I'm
         | struggling to understand the point of the article. Testing a
         | text generator?
        
           | joaogui1 wrote:
           | Also bizarre that it got to the front page of HN while being
           | so low quality :/
        
             | dustymcp wrote:
             | Well i think that is why it got there people really love
             | hating :)
        
         | raldu wrote:
         | Titles get the headlines.
        
           | antegamisou wrote:
           | Honestly this (the fact it is being massively upvoted) looks
           | a lot more like paid promotion. Not the first time and not
           | the only example of submission btw.
        
           | muragekibicho wrote:
           | I've learnt this the hard way. The most important thing is to
           | get you to click. Sometimes I'll first iterate over the title
           | before even writing on substack.
        
             | tamnd wrote:
             | I have learned that too. If you write about C, almost no
             | one clicks. It is not new, it is not flashy, and it does
             | not promise easy results. Yet almost everything still runs
             | on it. The quiet parts of computing rarely get attention,
             | even though they keep everything working.
             | 
             | I still write about C anyway. It may not trend, but it
             | lasts.
        
               | zamadatix wrote:
               | An alternative view of "not new and flashy" is "known and
               | expected", which not 100% of C conversations have to be.
               | Just look at the excitement around Fil-C lately!
        
               | tialaramex wrote:
               | I'm sure I'm not alone - after decades - already knowing
               | far too much about C, so that any article I'm likely to
               | read either I'm like "No, that's wrong and I even
               | understand why you thought that, but it's still wrong" or
               | I just nod along and sigh.
               | 
               | I spent a substantial fraction of my professional career
               | writing C, and I remain interested in WG14 (the language
               | committee) and in several projects written in C though I
               | avoid writing any more of it myself.
               | 
               | The reason it's so widespread is called "Worse is Better"
               | and I believe that has somewhat run its course. If you
               | weren't aware of "Worse is better" a quick Google should
               | find you the original essay on that topic years back.
               | 
               | In contrast when I read an article about say Zig, or
               | Swift, I am more likely to learn something new.
               | 
               | But I can certainly endorse your choice to write about
               | whatever you want - life is too short to try to get a
               | high score somehow.
        
               | tamnd wrote:
               | Thanks for sharing your thoughts. I have never deployed
               | any production C code and I would not choose C for
               | professional work either, but learning it, with all its
               | rough edges, has made me a better engineer. It helps me
               | understand how things really work under the hood. No
               | pain, no gain.
               | 
               | Maybe I am biased, but for professional work, I stay with
               | Go. I have built large distributed data systems that
               | handle hundreds of millions of business transactions
               | daily, and Go has been steady and reliable for that
               | scale. Its simplicity, strong concurrency model, and easy
               | deployment make it practical for production systems. I
               | still enjoy exploring Zig and Rust in my spare time, but
               | for shipping real systems, Go continues to get the job
               | done without getting in the way.
        
               | tamnd wrote:
               | > I'm sure I'm not alone - after decades - already
               | knowing far too much about C, so that any article I'm
               | likely to read either I'm like "No, that's wrong and I
               | even understand why you thought that, but it's still
               | wrong" or I just nod along and sigh.
               | 
               | If you have some spare time, I would really like to hear
               | more about your experiences. It sounds like you have
               | worked with C for a long time, and that kind of insight
               | is hard to find now.
               | 
               | Most people around me started with JavaScript or
               | TypeScript as their first language, and for many, that is
               | still all they know. I mean no disrespect, it is just how
               | things are today. It would be great to hear how your view
               | of programming has changed over the years and what
               | lessons from C still matter in your work today.
        
             | tamnd wrote:
             | Oh, and I just submitted a link to my article about C. I am
             | pretty sure no one will click it.
             | 
             | Articles about C never get much traffic, but that is fine.
             | I wrote it because I care about how things really work, not
             | because I expect it to trend. If even a few people read it
             | and see the beauty in the old language that still runs the
             | world, that is enough.
        
               | rand0m4r wrote:
               | I would like to find more articles on C so feel free to
               | share, thanks
        
               | tamnd wrote:
               | Here is the link for you: https://github.com/little-book-
               | of/c/blob/main/articles/zig-i...
               | 
               | I hope next month I will have more time to write deep
               | dives into the internals of SQLite, PostgreSQL, Redis and
               | maybe curl, all written in C.
        
               | zobzu wrote:
               | thanks, i enjoyed reading it (though a bit lengthy).
               | 
               | what gets me personally is what you describe at
               | https://github.com/little-book-
               | of/c/blob/main/articles/zig-i... - zig is made to feel
               | easy and modern for people who don't know any better, and
               | it does this well. But as soon as you actually need to do
               | complex stuff, it gets in the way moreso than C and it's
               | current environment/ecosystem will.
               | 
               | And to be fair, as much as I enjoyed writing in C in my
               | younger years - I only use C when I actually need C. And
               | asm when I actually need asm. Most of my code now uses
               | higher level languages - this puts zig into such a
               | niche.. it feels like golang to me: the cool language
               | that isn't really solving as much of a need as you'd
               | think.
        
               | tamnd wrote:
               | I mean, if you embed Zig in a larger C++, Rust, or Python
               | project, coordinating the build systems can be difficult.
               | Zig prefers to manage the entire pipeline itself, so
               | mixing it with other compilers and dependency managers
               | can require workarounds. In my opinion, the only
               | practical way to do this is by exposing C interfaces.
        
               | tamnd wrote:
               | And I want to clarify again, these are just personal
               | notes written with some help from LLMs. They may contain
               | mistakes, so please read them with curiosity, or feel
               | free to skip them altogether.
        
               | tamnd wrote:
               | and my favorites:                  -
               | https://daniel.haxx.se/blog/2025/04/07/writing-c-for-
               | curl/        - https://www.sqlite.org/whyc.html
        
               | rand0m4r wrote:
               | thanks again
        
         | scotty79 wrote:
         | What I got was:                 - pointers to bitfields       -
         | checked bitshifts       - small ints like u4       - imperative
         | array initialization blocks       - test code blocks       -
         | equivalent of debugger; keyword from js       - some vague
         | stuff about being able to do at compile time
         | 
         | The rest is pretty generic
        
           | beej71 wrote:
           | I had to dig farther on the compile time execution stuff.
           | It's actually pretty cool-looking. Recommend digging into it.
           | I don't know that it's a killer enough feature to draw me
           | away from Rust's guarantees, but it is interesting.
        
             | jandrewrogers wrote:
             | It is difficult to overstate how useful compile-time
             | execution is in practice. I can't imagine using a systems
             | language without it now. The term "modern C++" largely
             | denotes when compile-time execution was added to that
             | language.
             | 
             | I would love to see Rust get compile-time execution that is
             | as capable as Zig or C++20.
        
               | nicce wrote:
               | > I would love to see Rust get compile-time execution
               | that is as capable as Zig or C++20.
               | 
               | Can you give examples? Const functions are pretty capable
               | in Rust already.
        
       | tamnd wrote:
       | Zig is so cool, but C is cooler.
       | 
       | I like how Zig feels clear and simple to start with. I like that
       | it gives one toolchain and makes cross compilation easy. I like
       | that it helps people see how systems programming can feel
       | approachable again.
       | 
       | I also like that C has done these things for many years. I can
       | use different tools, link libraries, and trust that it will still
       | work. I can depend on standards that keep improving while staying
       | familiar.
       | 
       | I think Zig is exciting for what it adds today. I think C is
       | cooler because it has proved itself everywhere and still runs the
       | world.
        
         | grayhatter wrote:
         | I've used for well oven a year now, and I identify with this
         | comment... well no, but I used to. In between Zig, and another
         | language I enjoy was Python, and it was breath of fresh air to
         | come back to the C style that I know and love within Zig. I
         | would have said exactly this, when I first started writing Zig.
         | 
         | Today, Zig is so much better than C. I used to refer to Zig as
         | an improved version of C. But I don't anymore. C may have come
         | first, but chronological roles reversed. If Zig is a
         | programming language, than C is a toy trying to copy Zig's
         | functionality and usability.
         | 
         | Calling C easier to use in a cross platform context is
         | absolutely insane. If I was only concerned about $HOST I would
         | consider using C. Today, when I might want to copy a binary to
         | literally any other system, I wouldn't even consider C. Zig
         | wants code to work. C wants code to compile. There's a stark
         | and critically important difference between the two.
         | 
         | > I think Zig is exciting for what it adds today. I think C is
         | cooler because it has proved itself everywhere and still runs
         | the world.
         | 
         | I couldn't have put it better myself, the only thing C has over
         | Zig is inertia. But I wouldn't consider that a selling
         | point....
        
           | tamnd wrote:
           | Have you tried C23, especially its new Unicode support? It
           | really surprised me after returning to C more than ten years
           | later.
           | 
           | You can now write wide and UTF-8 string literals directly:
           | char8_t* s = u8"konnichiha";         char16_t* t = u"Privet";
           | char32_t* ustr = U"Ni Hao ";
           | 
           | It just works across compilers, no special libraries or hacks
           | needed.
           | 
           | C still feels like C, but cleaner, safer, and more
           | consistent.
        
             | grayhatter wrote:
             | I abandoned the goal of investing More time into C when
             | they couldn't get defer into their latest version.
             | 
             | 2 years later, already enjoying it in Zig `defer` is a lot
             | less important to me now. But I still view it as a symptom
             | of the death of the language. C isn't dead, by any stretch
             | of the imagination, but it's no longer learning from it's
             | mistakes, where as I still am.
        
               | tamnd wrote:
               | I started learning C again for one simple reason: to
               | understand the Linux kernel. You cannot do that without
               | knowing C, and soon you end up learning about GCC,
               | linkers, and how programs really run.
               | 
               | Once I spent time with it, I saw how many smart ideas
               | from the kernel could be used anywhere. the initcall
               | system that runs modules in order, the way structs with
               | function pointers create flexible drivers, the use of
               | macros to build type-safe lists and so on.
               | 
               | https://www.collabora.com/news-and-
               | blog/blog/2020/07/14/intr...
               | 
               | For real work, though, life is short. I use Go.
        
         | scuff3d wrote:
         | I want to love Zig. I like so many of the ideas on paper, but
         | fuck I found it so annoying to write. I ended up switching to
         | Odin and I'm enjoying that so much more.
        
       | api wrote:
       | Zig doesn't seem like a bad language, but I also don't see
       | anything to make it hands down better than Rust for systems
       | programming. So it kind of fails my "why yet another language?"
       | test. I don't think another language can be justified by marginal
       | improvements.
       | 
       | Rust passes that test because it's categorically better than C
       | and C++ in several ways: much better type system, safety, better
       | modules and code reuse, etc. It's complex, but as far as I can
       | tell most of its complexity is required to offer its level of
       | safety guarantees in a pure systems language without a garbage
       | collector or any kind of true dynamic typing. To make a safe
       | systems language you need to have a very rich type system that
       | can prove safety across a wide array of situations. Either that
       | or you'd have to go to the other far end of the simplicity-
       | complexity spectrum and have a language with virtually no
       | features, which would result in very verbose code and probably a
       | lot of boilerplate.
       | 
       | Zig's coolest feature to me seems like "comptime" and the lack of
       | a weird macro side-language, which is one of Rust's anti-features
       | that feels bolted on. Don't make me learn yet another language.
       | Of course sophisticated macros in Rust are usually instead
       | written in Rust itself via procedural macros, but that is more
       | unwieldy than "comptime."
       | 
       | Still not enough to justify a whole new language and ecosystem
       | though. Again: don't make me learn yet another language unless
       | there's a big payoff.
        
       | philippta wrote:
       | > The @breakpoint built-in
       | 
       | Inserting the literal one byte instruction (on x86) - INT 3 - is
       | the least a compiler should be able to do.
        
       | novabridge wrote:
       | Why is this article even on hacker news?
        
       | quincepie wrote:
       | I think what sets Zig apart from other low level languages is how
       | easy it is to navigate a Zig source code. I was discouraged at
       | the time (things probably changed now) when the best source for
       | documentation was "read the Zig's source code". But I was
       | impressed by how easy it was to find what I needed.
       | 
       | while this is due to Zig maintainers' code quality, I think a
       | large contributing factor is the choice of syntax. As an
       | exercise, try navigating a C, C++ and any other language source
       | code without an IDE or LSP. things like:
       | 
       | - "Where did that function come from?"
       | 
       | - "What and where is this type?"
       | 
       | what do you have to do to find that out? due to the flexible ways
       | you can declare things in C, it may take you a lot of steps to
       | find these information. even in search, a variable and a function
       | can share the same prefix due to the return type placement. hence
       | why some people prefer function return types in a separate line.
       | 
       | Even with languages like Rust for example, finding if a type in a
       | function parameters is an enum or struct and finding its
       | definition can require multiple steps like search "enum Foo" or
       | "struct Foo", in Zig i can search "const Foo" and i will
       | immediately know what it is.
       | 
       | while i do hope that C gets defer and constexpr functions in the
       | next standard or maybe better generics or enums, Zig syntax is
       | much better to work with in my opinion.
        
         | cyber1 wrote:
         | I also hope that WG14 eventually adopts successful features
         | from Zig, such as comptime, and reduces the use of ugly macros
         | and _Generic.
        
       | drnick1 wrote:
       | All these new languages like Zig, Rust, etc are ass with their
       | "fn" keywords and all that. Long live C!
        
       ___________________________________________________________________
       (page generated 2025-11-08 23:00 UTC)