Things Zig comptime won't do

(matklad.github.io)

142 points | by JadedBlueEyes 3 hours ago

12 comments

  • pron 1 hour ago
    Yes!

    To me, the uniqueness of Zig's comptime is a combination of two things:

    1. comtpime replaces many other features that would be specialised in other languages with or without rich compile-time (or runtime) metaprogramming, and

    2. comptime is referentially transparent [1], that makes it strictly "weaker" than AST macros, but simpler to understand; what's surprising is just how capable you can be with a comptime mechanism with access to introspection yet without the referentially opaque power of macros.

    These two give Zig a unique combination of simplicity and power. We're used to seeing things like that in Scheme and other Lisps, but the approach in Zig is very different. The outcome isn't as general as in Lisp, but it's powerful enough while keeping code easier to understand.

    You can like it or not, but it is very interesting and very novel (the novelty isn't in the feature itself, but in the place it has in the language). Languages with a novel design and approach that you can learn in a couple of days are quite rare.

    [1]: In short, this means that you get no access to names or expressions, only the values they yield.

    • User23 26 minutes ago
      Has anyone grafted Zig style macros into Common Lisp?
      • Zambyte 3 minutes ago
        There isn't really as clear of a distinction between "runtime" and "compile time" in Lisp. The comptime keyword is essentially just the opposite of quote in Lisp. Instead of using comptime to say what should be evaluated early, you use quote to say what should be evaluated later. Adding comptime to Lisp would be weird (though obviously not impossible, because it's Lisp), because that is essentially the default for expressions.
      • toxik 8 minutes ago
        Isn’t this kind of thing sort of the default thing in Lisp? Code is data so you can transform it.
  • ephaeton 32 minutes ago
    zig's comptime has some (objectively: debatable? subjectively: definite) shortcomings that the zig community then overcomes with zig build to generate code-as-strings to be lateron @imported and compiled.

    Practically, "zig build"-time-eval. As such there's another 'comptime' stage with more freedom, unlimited run-time (no @setEvalBranchQuota), can do IO (DB schema, network lookups, etc.) but you lose the freedom to generate zig types as values in the current compilation; instead of that you of course have the freedom to reduce->project from target compiled semantic back to input syntax down to string to enter your future compilation context again.

    Back in the day, where I had to glue perl and tcl via C at one point in time, passing strings for perl generated through tcl is what this whole thing reminds me of. Sure it works. I'm not happy about it. There's _another_ "macro" stage that you can't even see in your code (it's just @import).

    The zig community bewilders me at times with their love for lashing themselves. The sort of discussions which new sort of self-harm they'd love to enforce on everybody is borderline disturbing.

    • User23 25 minutes ago
      Learning XS (maybe with Swig?) was a great way to actually understand Perl.
  • hiccuphippo 1 hour ago
    The quote in Spanish about a Norse god is from a story by Jorge Luis Borges, here's an English translation: https://biblioklept.org/2019/04/02/the-disk-a-very-short-sto...
    • _emacsomancer_ 31 minutes ago
      And in Spanish here: https://www.poeticous.com/borges/el-disco?locale=es

      (Not having much Spanish, I at first thought "Odin's disco(teque)" and then "no, that doesn't make sense about sides", but then, surely primed by English "disco", thought "it must mean Odin's record/lp/album".)

      • wiml 17 minutes ago
        Odin's records have no B-sides, because everything Odin writes is fire!
  • pyrolistical 2 hours ago
    What makes comptime really interesting is how fluid it is as you work.

    At some point you realize you need type information, so you just add it to your func params.

    That bubbles all the way up and you are done. Or you realize in certain situation it is not possible to provide the type and you need to solve a arch/design issue.

    • Zambyte 41 minutes ago
      If the type that you're passing as an argument is the type of another argument, you can keep the API simpler by just using @TypeOf(arg) internally in the function instead.
  • paldepind2 16 minutes ago
    This is honestly really cool! I've heard praises about Zig's comptime without really understanding what makes it tick. It initially sounds like Rust's constant evaluation which is not particularly capable. The ability to have types represented as values at compilation time, and _only_ at compile time, is clearly very powerful. It approximates dynamic languages or run-time reflection without any of the run-time overhead and without opening the Pandora's box that is full blown macros as in Lisp or Rust's procedural macros.
  • ashvardanian 2 hours ago
  • karmakaze 2 hours ago
    > Zig’s comptime feature is most famous for what it can do: generics!, conditional compilation!, subtyping!, serialization!, ORM! That’s fascinating, but, to be fair, there’s a bunch of languages with quite powerful compile time evaluation capabilities that can do equivalent things.

    I'm curious what are these other languages that can do these things? I read HN regularly but don't recall them. Or maybe that's including things like Java's annotation processing which is so clunky that I wouldn't classify them to be equivalent.

    • foobazgt 54 minutes ago
      Yeah, I'm not a big fan of annotation processing either. It's simultaneously heavyweight and unwieldy, and yet doesn't do enough. You get all the annoyance of working with a full-blown AST, and none of the power that comes with being able to manipulate an AST.

      Annotations themselves are pretty great, and AFAIK, they are most widely used with reflection or bytecode rewriting instead. I get that the maintainers dislike macro-like capabilities, but the reality is that many of the nice libraries/facilities Java has (e.g. transparent spans), just aren't possible without AST-like modifications. So, the maintainers don't provide 1st class support for rewriting, and they hold their noses as popular libraries do it.

      Closely related, I'm pretty excited to muck with the new class file API that just went GA in 24 (https://openjdk.org/jeps/484). I don't have experience with it yet, but I have high hopes.

    • awestroke 2 hours ago
      Rust, D, Nim, Crystal, Julia
      • elcritch 36 minutes ago
        Definitely, you can do most of those things in Nim without macros using templates and compile time stuff. It’s preferable to macros when possible. Julia has fantastic compile time abilities as well.

        It’s beautiful to implement an incredibly fast serde in like 10 lines without requiring other devs to annotate their packages.

        I wouldn’t include Rust on that list if we’re speaking of compile time and compile time type abilities.

        Last time I tried it Rust’s const expression system is pretty limited. Rust’s macro system likewise is also very weak.

        Primarily you can only get type info by directly passing the type definition to a macro, which is how derive and all work.

    • ephaeton 29 minutes ago
      well, the lisp family of languages surely can do all of that, and more. Check out, for example, clojure's version of zig's dropped 'async'. It's a macro.
  • ww520 1 hour ago
    This is a very educational blog post. I knew ‘comptime for’ and ‘inline for’ were comptime related, but didn’t know the difference. The post explains the inline version only knows the length at comptime. I guess it’s for loop unrolling.
  • no_wizard 2 hours ago
    I like the Zig language and tooling. I do wish there was a safety mode that give the same guarantees as Rust, but it’s a huge step above C/C++. I am also extremely impressed with the Zig compiler.

    Perhaps the safety is the tradeoff with the comparative ease of using the language compared to Rust, but I’d love the best of both worlds if it were possible

    • ksec 1 hour ago
      >but I’d love the best of both worlds if it were possible

      I am just going to quote what pcwalton said the other day that perhaps answer your question.

      >> I’d be much more excited about that promise [memory safety in Rust] if the compiler provided that safety, rather than asking the programmer to do an extraordinary amount of extra work to conform to syntactically enforced safety rules. Put the complexity in the compiler, dudes.

      > That exists; it's called garbage collection.

      >If you don't want the performance characteristics of garbage collection, something has to give. Either you sacrifice memory safety or you accept a more restrictive paradigm than GC'd languages give you. For some reason, programming language enthusiasts think that if you think really hard, every issue has some solution out there without any drawbacks at all just waiting to be found. But in fact, creating a system that has zero runtime overhead and unlimited aliasing with a mutable heap is as impossible as finding two even numbers whose sum is odd.

      [1] https://news.ycombinator.com/item?id=43726315

      • the__alchemist 19 minutes ago
        Maybe this is a bad place to ask, but: Those experienced in manual-memory langs: What in particular do you find cumbersome about the borrow system? I've hit some annoyances like when splitting up struct fields into params where more than one is mutable, but that's the only friction point that comes to mind.

        I ask because I am obvious blind to other cases - that's what I'm curious about! I generally find the &s to be a net help even without mem safety ... They make it easier to reason about structure, and when things mutate.

      • skybrian 1 hour ago
        Yes, but I’m not hoping for that. I’m hoping for something like a scripting language with simpler lifetime annotations. Is Rust going to be the last popular language to be invented that explores that space? I hope not.
        • Philpax 4 minutes ago
          You may be interested in https://dada-lang.org/, which is not ready for public consumption, but is a language by one of Rust's designers that aims to be higher-level while still keeping much of the goodness from Rust.
        • hyperbrainer 33 minutes ago
          I was quite impressed with Austral[0], which used Linear Types and avoids the whole Rust-like implementation in favour of a more easily understandable system, albeit slightly more verbose.

          [0]https://borretti.me/article/introducing-austral

      • spullara 14 minutes ago
        With Java ZGC the performance aspect has been fixed (<1ms pause times and real world throughput improvement). Memory usage though will always be strictly worse with no obvious way to improve it without sacrificing the performance gained.
    • xedrac 1 hour ago
      I like Zig as a replacement for C, but not C++ due to its lack of RAII. Rust on the other hand is a great replacement for C++. I see Zig as filling a small niche where allocation failures are paramount - very constrained embedded devices, etc... Otherwise, I think you just get a lot more with Rust.
      • rastignack 54 minutes ago
        Compile times and painful to refactor codebase are rust’s main drawbacks for me though.

        It’s totally subjective but I find the language boring to use. For side projects I like having fun thus I picked zig.

        To each his own of course.

      • xmorse 1 hour ago
        Even better than RAII would be linear types, but it would require a borrow checker to track the lifetimes of objects. Then you would get a compiler error if you forget to call a .destroy() method
    • throwawaymaths 45 minutes ago
      in principle it should be doable, possibly not in the language/compiler itself, there was this POC a few months ago:

      https://github.com/ityonemo/clr

    • hermanradtke 2 hours ago
      I wish for “strict” mode as well. My current thinking:

      TypeScript is to JavaScript

      as

      Zig is to C

      I am a huge TS fan.

      • rc00 1 hour ago
        Is Zig aiming to extend C or extinguish it? The embrace story is well-established at this point but the remainder is often unclear in the messaging from the community.
        • PaulRobinson 12 minutes ago
          It's improved C.

          C interop is very important, and very valuable. However, by removing undefined behaviours, replacing macros that do weird things with well thought-through comptime, and making sure that the zig compiler is also a c compiler, you get a nice balance across lots of factors.

          It's a great language, I encourage people to dig into it.

        • dooglius 1 hour ago
          Zig is open source, so the analogy to Microsoft's EEE [0] seems misplaced.

          [0] https://en.m.wikipedia.org/wiki/Embrace,_extend,_and_extingu...

          • rc00 54 minutes ago
            Open source or not isn't the point. The point is the mission and the ecosystem. Some of the Zig proponents laud the C compatibility. Others are seeking out the "pure Zig" ecosystem. Curious onlookers want to know if the Zig ecosystem and community will be as hostile to the decades of C libraries as the Rust zealots have been.

            To be fair, I don't believe there is a centralized and stated mission with Zig but it does feel like the story has moved beyond the "Incrementally improve your C/C++/Zig codebase" moniker.

            • ephaeton 21 minutes ago
              zig's C compat is being lowered from 'comptime' equivalent status to 'zig build'-time equivalent status. When you'll need to put 'extern "C"' annotations on any import/export to C, it'll have gone full-circle to C++ C compat, and thus be none the wiser.

              andrewrk's wording towards C and its main ecosystem (POSIX) is very hostile, if that is something you'd like to go by.

            • Zambyte 36 minutes ago
              > Curious onlookers want to know if the Zig ecosystem and community will be as hostile to the decades of C libraries as the Rust zealots have been.

              Definitely not the case in Zig. From my experience, the relationship with C libraries amounts to "if it works, use it".

              • rc00 10 minutes ago
                Are you referring to static linking? Dynamic linking? Importing/inclusion? How does this translate (no pun intended) when the LLVM backend work is completed? Does this extend to reproducible builds? Hermetic builds?

                And the relationship with C libraries certainly feels like a placeholder, akin to before the compiler was self-hosted. While I have seen some novel projects in Zig, there are certainly more than a few "pure Zig" rewrites of C libraries. Ultimately, this is free will. I just wonder if the Zig community is teeing up for a repeat of Rust's actix-web drama but rather than being because of the use of unsafe, it would be due to the use of C libraries instead of the all-Zig counterparts (assuming some level of maturity here). While Zig's community appears healthier and more pragmatic, hype and ego have a way of ruining everything.

  • curtisszmania 2 hours ago
    [dead]
  • gitroom 2 hours ago
    Cool!