I love this discussion, because it illustrates so well what I love about Zig.
While learning Zig, I kept missing language features I am used to from other environments.
The more I worked in Zig, the less I missed these features. But that’s not because the features are bad or Zig has better concepts, it’s simply because my mind set adapted to the scope in which Zig operates. For example, Zig’s scope does not cover dynamic dispatch, so you don’t have interfaces. So you only use dynamic dispatch when you really needed or in other words when it’s a user or system requirement (one example would be a plugin interface).
Some things I tried with Zig were awkward. I concluded that these are things I would do in other languages, because they also don’t really benefit much from Zigs advantage, or Zig’s ecosystem (available Zig libraries) don’t support such a use case well.
I would love to completely switch to Zig, mostly because of personal preferences. But for some tasks it’s just not practically feasible for me.
Code generation is no longer fashionable. For me however it looks really attractive. I see Zig as an ideal target language for code generation, because it is so readable and offers so much control while at the same time it has this awesome cross compiling functionality. Last not least, this approach benefits a lot from compile time functionality, because the results can be highly optimized allowing a front-end language to create zero cost abstractions rather easily.
During my learning phase, I caught myself trying to come up with ways to make Zig more higher level. But the only thing I got out of this was higher complexity.
There seems to be a real benefit from Zig being a low level language refusing to add sugar. What I miss is not a more comfortable or feature rich Zig language, I would like the languages providing higher level abstractions to have more of the benefits of Zig. To me it looks like you can’t have both in one language.
Bun is an interesting project. It got a lot of attention, though in recent times I didn’t hear much about it. I think Bun could be much more interesting if instead of implementing a runtime for a language in Zig for performance sake, it would transpile code into Zig. JS is not my favorite higher language, but it has most of the features often requested for Zig. If you can implement JS using a runtime, you can trivially transpile it (with a modest quality). Once that works, the transpilation can gradually be improved. So this is at least possible. If it’s good depends.
I was disappointed by the removal of async at first. Now I wonder if that is really bad at all. There are so many ways to implement asynchronicity with hugely different characteristics, that it would be incredible if Zig managed to find “the best” solution. Implementing it on the application level is no good, because it’s too complex to easily get right. Implementing it on the library level is difficult, because libraries tempted to implement it are likely to have a broader scope (f.e. associating asynchronicity with HTTP or slightly more general with networking).
Finding a good solution for this is hard. If you have a layer between the Zig level and a higher level language used for application development, you can isolate this problem, offer several different implementations for different use cases and ideally replace one solution transparently with another.
When my task is to satisfy user requirements and I’m payed by the hour, I don’t want to be bothered by constraints imposed by Zig purism. When my task is to develop high quality system components, I don’t need high level language constructs, I might even not want them.