I think Zig's biggest advantage is that it's just C without the warts, or footguns as is said in the Zig world. The comptime feature is probably the most exciting thing I've seen in a while. I've looked at Rust and feel it's more of a competitor to C++, Java and C#. Whereas Zig is C done right.
"Rust is a competitor to C++, not C" is a meme, and there's some truth there, but I don't think it's all that accurate. I know lots of folks who prefer C to C++, but still like Rust.
I do think that these sorts of language comparisons are useful, but they don't always generalize. Partially this is because what a language means to each person can vary. As long as they're understood in a very coarse grained way, I think they can still make sense, but it's tricky!
> I know lots of folks who prefer C to C++, but still like Rust.
I'm one of those people, and, while I have yet to use Rust or Zig for any real work, at least so far I also see Rust as being more directly a competitor to C++, and Zig as the more direct competitor to C.
Or perhaps I should say analogue. Because, it's true, I might choose Rust over C. I'm even tentatively planning to, for one project that's still in the idea phase, and that I would normally have wanted to do in C. Though that's not really because I see Rust as being more C-like. It's more that I see choosing Rust as being perhaps more likely to be worth the extra effort than I've found to be the case for C++.
Yes, it also can matter what you even mean by "competitor." Some people take it to mean "similarity in language features." Others can take it to mean "would I choose it as a substitute." Some take it to mean "would I choose it as a substitute for this specific domain or project."
I've seen this play out a number of times. "Rust cannot compete with C, because C is too entrenched in embedded." "I do embedded development in Rust, so it can." "Well, I work with these chips that Rust can't target yet, so it can't, for me." None of these statements are incorrect, but they can lead to huge back-and-forths.
I'm one of those, but, any way, Rust is mainly competitor for C++, while no-std Rust (or Core Rust) is direct competitor for C.
I did fairly large and complex program in Rust for bicycle computer, and, while I like developer ergonomic, speed, and memory usage, I'm disappointed by the total size of the binary, number of dependencies used, and compilation time.
Have you researched this space already[1]? By default Rust doesn't optimize for the resulting binary size, but there are lots of things that can be done to bring size down where you'd expect.
> number of dependencies used
When this comes up it becomes as much a technical discussion as a philosophical one :)
> and compilation time.
No arguments there. There are some things that can be done in your project to avoid spending too much time (simplify bounds to minimize recalculation in the type system, avoid proc macros, leverage cfg conditional compilation), but they are work arounds.
Yes. I think Zig is a safer C, while Rust is a safer C++. C programmers will be more excited by Zig than by rust, and the opposite is true for C++ afficionados.
Those are nice taglines, but while Rust is a safer C++ in the sense that it is a language that espouses C++'s design philosophy and has a similar feel to it, Zig is something new altogether. The only thing that makes it more similar to C than to C++ is that C is an extremely simple language, as is Zig, while C++ is an extremely complex language. But other than that, Zig is a low-level language that is its own family, and with a design that is radically different from either C or C++; it's hard to compare it to anything, really. Zig goes well beyond C in its power of abstraction to match C++/Rust, but it does so in a very different way than C++/Rust.
They're low-level languages -- with all the attention to low-level detail all low-level languages require -- that aim to appear like high-level code on the page. All the same details are still there, and you must confront them when changing the code, but they don't appear as text when you look at the code.
The safety guarantees of Rust are much stronger than Zig's. For example Rust statically prevents use-after-free and data races, and Zig doesn't (and I don't think anyone expects it ever to). To me this matters more than which one is more like C or C++ (partly because I don't think Rust is very much like either).
It's interesting people keep saying this. I see Rust as being much closer to C than it is to C++. Rust is safer C with the bare minimum of added advanced features.
Although Rust syntax might feel familiar with other languages the point of comparison shouldn't end there. The Rust language community is big and growing (including the number of Crates) and the mindset behind writing safe code is actually what got me interested in the first place. I’m glad that other languages are inspired by that and are able to provide some of those features on their specific niches (like in the case of Zim is simplicity)
D is much more "C++ done right" (and then some). C and Zig are very barebones, close-to-the-metal language. D has garbage collection, classes, templates, exceptions, built-in dynamic arrays and hash tables, and on and on and on. The "Features Overview" page makes me go cross-eyed [1].
Yes, you can turn many of these things off or ignore them and just use D as a better C, but the same could be said of C++ (for some definition of "better"). Or most languages, really, if you squint enough.
Yes, and people do use C++ as a better C to get OO and a stronger type system, at the cost of compilation times (and the usual C++ pitfalls).
I use D as better C. I use it as better C++ at times. Once ownership/borrowing [1] is stable, I'll use it as a better Rust too.
For close-to-the-metal code, I use D's inline assembler [2]. "To go any lower level than that, you'd need a miniature soldering iron and a very, very steady hand." (Andrei Alexandrescu)
A common misconception, probably because the majority of D users are C++ veterans. But D was never designed as a successor to C++.
"One of the earliest design decisions that Walter made about D was that it would be easy to use
with software written in C. Many widely-used libraries are implemented in C or have a C interface.
He wanted to provide an easy path for established software companies to adopt the D language. A
straightforward approach was to guarantee that users of D could immediately take advantage of
any C library their project required without the need to reimplement it in D." from "Origins of the D programming language" by W.Bright, A.Alexandrescu, M.Parker.
D has an optional conservative mark-sweep Boehm GC which only gets triggered when you attempt to allocate something on the heap. If you don't do that, it won't bother you. Finally, you can explicitly disable it.
People generally ignore or miss the fact that D really shines when it comes CTFE, reflection and metaprogramming.
But native code is native code, there isn't a magical layer underneath that would make Zig closer to the metal than D, unless perhaps the voluntary Undefined Behaviour zig is willing to take such as those for loops.
This is the first time I see such a comparison :) D is a systems programming language with an optional GC and in the league with C/C++/Rust. I would add Nim and Zig here as well.
Nim is in the GC category (and its documentation says you should use a refcounting GC rather than turning it off). Zig does not use GC.
Memory management is one of the more important aspects of systems programming so it is useful to be clear about what is the main strategy used by each language.
You can use packages that have been converted to not use the GC and all of the libraries you would be using in C or C++.
You still get the following language features, which is more than what C, C++ or Rust have to offer (though Rust is hot on D's trail).
Unrestricted use of compile-time features
Full metaprogramming facilities
Nested functions, nested structs, delegates and lambdas
Member functions, constructors, destructors, operating overloading, etc.
The full module system
Array slicing, and array bounds checking
RAII (yes, it can work without exceptions)
scope(exit)
Memory safety protections
Interfacing with C++
COM classes and C++ classes
assert failures are directed to the C runtime library
switch with strings
final switch
unittest
printf format validation
> The comptime feature is probably the most exciting thing I've seen in a while
Just please do not make the mistake of believing that it is unique to Zig. Factor brings the best of Forth and Lisp together, so meta-programming or extending the language is possible quite easily, for example. You could extend the syntax or add constructs pretty easily, and so forth. Anyways, an example can be found here: https://rosettacode.org/wiki/Compile-time_calculation#Factor but this barely scratches the surface. It does not mention `<< ... >>` which evaluates some code at parse time. You can execute code before the words in a source file are compiled.
Those are just some examples, but it is pretty powerful. It supports (and encourages) interactive development. Profiling and debugging is a breeze and highly detailed and useful, you can easily disassemble words (functions), you can get a list of how many times malloc has been called in some circumstances, there is runtime code reloading (a vocabulary that implements automatic reloading of changed source files[1]), and so on. And on top of all this, you can compile your stuff to an executable that is less than 4 MB!
And of course you do not have to do stack shuffling at all, you can easily use locals which is useful for math equations and whatnot. Plus did you know that the Factor compiler supports advanced compiler optimizations that take advantage of the type information it can glean from source code? The typed vocabulary (yes, it is not part of the language, but implemented as a vocab) provides syntax that allows words to provide checked type information about their inputs and outputs and improve the performance of compiled code.
I would like to repeat because if this was not the case, I would have never bothered with it: you can create a single executable file that is less than 4 MB of size if you wish so! Of course it encourages interactive development, but still, it is great to have an optimizing compiler that can do all this easily. And mind you, this part is also written in Factor itself and is available as a vocabulary (vocab).
So all in all, I think Factor is great. I was shocked at how modern (and how many) libraries it has, especially considering only a handful of people have been working on it. Slava Pestov created the language, and some people joined him later on. If you want to learn more about it, start here: https://concatenative.org/wiki/view/Factor. There are videos, there are papers, there are lots of resources to get started. :) The language misses a couple of things, but it is being worked on.
> Just please do not make the mistake of believing that it is unique to Zig. Factor brings the best of Forth and Lisp together...
What is unique to Zig is that it has these features without bringing together "the best of Forth and Lisp". Sometimes, just being pedestrian is a virtue.
But comptime is kind of LISP's unique feature, it's just called macros.
EDIT: In fairness, Zig's presentation is pretty likeable. You can do a comptime expression pretty trivially in LISP, a comptime parameter or block would require actual effort.
No. There is a real difference between staged computation of the type that zig has and macros in common lisp, scheme/rust have (so much for lisp's uniqueness BTW). In common lisp you can do completely arbitrary computation at compile- (or read-)time in zig you cannot and crucially you are also not responsible for manually ordering the "stages". E.g. in common lisp you have use eval-when to make sure that stuff is available at the right phase, whereas zig works out the dependency for you.
In common-lisp you could do something equivalent, but you'd have to wrap the definitions you want to be able at both compile and and run time in eval-when.
It's almost just C without the warts; I wish someone would make a language that was both as good as Zig or Rust, and could be compiled to C code. The dependency on LLVM rules out a lot of embedded use cases, because some chipsets require forks of LLVM, or worse, proprietary C compilers or forks of GCC or something else, to run. Would be nice to have a language that just works everywhere.
I feel like the onus should be on chip makers to write LLVM backends because proprietary C compilers and GCC forks almost universally suck. I understand why they don't, but it's just disappointing on both ends of the pipeline. That said, ARM is great, and you can target most ARM chips with LLVM.
There's also the downside that transpiling to C locks you into an ABI, which limits what compiler developers can do towards the end of the compilation passes.
But a strict improvement on the preprocessor madness that you have to get into with C. Having `static if`-like behavior is much preferable to `#ifdef` and the like and other things falling out of that system is just a bonus.
It's tempting to view `comptime` as additional complexity, but the truth is that it replaces a much more complicated and hard-to-work-with system. That one is just one that people have gotten used to over decades.