Remix.run Logo
zahlman 3 days ago

> Instead of macros it uses Zig itself to execute code at runtime (comptime).

Nice. FWIW, I have a vague PL design in my head that does this despite being a much higher-level language. (For that matter, I think of my idea much as "like a modern Python with lessons learned".) Point being I definitely think this is a good idea.

To my understanding, the things actually called "macros" in Lisp also do this.

> Custom allocators are the norm.

On the other hand, this doesn't sound to me like an upside. Of course it's fine and well if it's easy to do this. But hopefully you'd prefer not to have to... ?

> No hidden control flow, everything is very explicit and easy to follow.

What sort of hidden control flow do you see in C? (Are modern code bases using setjmp/longjmp in new code?) I would have thought that C++ is where that really started, via exceptions. But I also don't think most programmers see that as problematic for understanding the code.

> Single unit of compilation has some nice properties, allowing to support colorless async.

Would appreciate some explanation of the theory here. Though it does occur to me that the languages I can easily think of with "coloured" async also don't exactly statically link everything all the time.

Also, how does all of this compare to Rust, in your view?

ManBeardPc 3 days ago | parent | next [-]

Comptime is very nice but certainly more limited then Lisp. You can't generate arbitrary code with it. But good enough to implement something like JSON serialization or Struct-of-Arrays in normal code that is readable.

Custom allocators are very nice. We are very much in manual memory management + optimization territory here. Having things like arena allocators makes a lot of difference in specific use-cases when you want/need every bit of performance. Also nice being able to switch the allocator for tests that is able to report leaks for example.

Yes, hidden control flow I mean something like exceptions, RAII or Rust's Dispose. So more a comparison to other languages than C.

The explanation I would refer to the talks "Don't forget to flush" or "Zig Roadmap 2026" from Andrew Kelley. Also the blog post "Zig's New Async I/O". I think it has something to do with being able to infer the required size of the stack, but already forgot the details.

https://kristoff.it/blog/zig-new-async-io/ https://youtu.be/f30PceqQWko?si=g2nLTE4ubWD14Zvn https://youtu.be/x3hOiOcbgeA?si=SUntYOYNOaxCRagc&t=3653

As to compared to Rust. The fast compile times are nice. Having a small language that you actually can understand helps to be productive. Not being restricted by the borrow checker makes it easier to implement some low-level things. Just being able to import most C code without wrapper makes the smaller ecosystem a much smaller problem. Rust is nice and certainly a good pick for many cases, but personally I often feel overwhelmed by the complexity and tons of tons of types for everything.

taminka 2 days ago | parent | next [-]

> Yes, hidden control flow I mean something like exceptions, RAII or Rust's Dispose. So more a comparison to other languages than C.

C has macros, which is the ultimate form of hidden control flow, where a symbol can expand to any arbitrary code... also hidden allocations and functions that can error, which you could argue isn't traditionally understood as hidden control flow, but it's still nice to know when stuff is allocated and/or can create an error

rowanG077 3 days ago | parent | prev [-]

Rust dispose? I think you mean drop. But I don't see how that is hidden control flow. It's very clear when it drop is called.

pron 3 days ago | parent | next [-]

It's clear once you know that an object implements the Drop trait, but you can't see that at the use site, ergo it's hidden (same goes for C++ destructors). Zig wants every call to be visible.

The tradeoff is between making sure you don't forget to write the cleanup call (Rust, C++) and making sure you don't forget to read the cleanup call (Zig). For low-level code I personally prefer Zig's tradeoff; others prefer the C++/Rust tradeoff.

simonask 3 days ago | parent | next [-]

A funny thing I’ve noticed is that some Rust programmers will explicitly call `std::mem::drop(…)` in tricky situations where it really matters, like releasing a mutex with complex interactions - even at the end of scope. I kind of like it whenever a lock is held for more than a few lines.

I think it’s a good compromise, because the consequences of forgetting it are way harsher. Memory leaks, deadlocks…

pron 3 days ago | parent [-]

> I think it’s a good compromise, because the consequences of forgetting it are way harsher.

And easier to detect. Knowing that no operation is carried out unless you can see it is important to many who do low-level programming.

But there is no one right answer. Differences between programming languages, including those between Zig and Rust, are mostly about people's personal preferences because language designers rarely make choices that are universally inferior than others. When they differ, it's because both sides are reasonable and have their proponents.

rowanG077 3 days ago | parent | prev [-]

What do you mean if an object implements a drop? Whether an object implements a drop has no bearing on when it is called. I mean a developer can manually call it. But it is always clear when it is called.

ManBeardPc 2 days ago | parent [-]

The point is the code is on another type. Any variable could by of a type that implements some Drop logic. It is mostly called implicitly where it is used, wether you as a programmer are aware of it or not. You would need to check.

In Zig you need to call everything explicitly, meaning in the function you need to call what you want to be executed, no other code will run. The decision if you want some cleanup logic is made at the point of usage, not by the type itself.

That is the point of it, you look at a function and directly see what happens right there, not in other files/packages.

bnolsen a day ago | parent [-]

People seem to underestimate this. One of the first reasons I noticed about c++ was trying to figure out what functions were being called in an overly complex inheritance hierarchy. The next was from hidden behavior from seemingly benign looking sequence of statements. Both of these are a barrier of entry for bringing in new coders to a complex code base.

ManBeardPc 2 days ago | parent | prev [-]

Drop yes. Thanks for the correction.

It is clear when it is called, but you have to check in code you are not currently seeing as any type could implement it. May seem like a minor thing, but is not explicit at the point of usage. In Zig only code you call explicitly runs, meaning if there is no defer nothing happens at the end of the scope.

Cloudef 3 days ago | parent | prev [-]

> On the other hand, this doesn't sound to me like an upside. Of course it's fine and well if it's easy to do this. But hopefully you'd prefer not to have to... ?

Why wouldn't you? You can often make your code simpler and more performant by using certain allocation strategy rather than relying on global allocator. Malloc/Free style strategy is also very error prone with complex hierarchical data structures where for example arena allocation can tie the whole lifetime to a single deallocation.

> Would appreciate some explanation of the theory here. Though it does occur to me that the languages I can easily think of with "coloured" async also don't exactly statically link everything all the ti

Async is moot point, it does not exist in zig right now, it used to but it was removed. There are plans to reintroduce it back, but using async as any sort of benefit for zig is not being honest.

ManBeardPc 2 days ago | parent [-]

Regarding async I kind of agree with you right now, but the new design is there and currently getting implemented. If you don’t believe it will work out or need to use async right now sure, use something else. It is not a stable language yet and very much WIP. I don’t think it’s dishonest to write about something that has a design and is worked on right now with a realistic chance of working out.

Cloudef a day ago | parent [-]

Sure and I'm excited for it (especially stackless), but I'd be wary of marketing something that doesn't actually exist yet.