Here's a mind dump:
> Zig manages to provide many of the same features with a single mechanism - compile-time execution of regular zig code. This comes will all kinds of pros and cons, but one large and important pro is that I already know how to write regular code so it's easy for me to just write down the thing that I want to happen.
This is a huge one for me, and I really don't understand why Rust didn't jump on this earlier. Using the programming language for configs, generics, macros, and anything else that you'd want at compile time just seems like such a huge win, instead of having weird preprocessors-like systems, some config file format with arbitrary limitations, and weird marcro-like systems that either have crazy syntax (like `macro_rules!` in Rust), or that are way too limiting (like `const` functions in Rust).
Jon Blows language seem to take a similar stance as Zig; let's see if it ever hits public beta.
> On the other hand, we can't type-check zig libraries which contain generics. We can only type-check specific uses of those libraries.
This is definitely a concern I have about this "C++-like generics". My experience with C++ suggests that this is bad, but on the other hand, improving even just error messages would be such a day-night improvement, that I don't really trust my judgement on this one.
> Both languages will insert implicit casts between primitive types whenever it is safe to do so, and require explicit casts otherwise.
Is this really true? I seem to recall having to have plenty of `as usize` in my code when using smaller integer types for indices, but maybe this has changed (or maybe I'm misreading what's being said here).
> In rust the Send/Sync traits flag types which are safe to move/share across threads. In the absence of unsafe code it should be impossible to cause data races.
This is probably Rust's main selling point, because as far as I can tell, no other mainstream language comes even close to getting static thread safe guarantees (up to your definition of mainstream). As time goes on, however, I'm getting less and less excited about this, because most of my programs are not multithreaded, and the very few times that I need multiple threads, there is often very obvious and small boundaries in between the threads. It's just not very interesting to me that I _could_ be writing programs with thousands of threads all jumping around without having to worry about data races, because I don't really worry about it in the first place. But still, I as a Rust programmer, have to pay the price for this option being available.
> Undefined behavior in rust is defined here. It's worth noting that breaking the aliasing rules in unsafe rust can cause undefined behavior but these rules are not yet well-defined.
I'm not sure what to say about this, except that it's surprising that there seem to be a lack of voices about this in the Rust community. How can anyone comfortably write `unsafe` code without knowing what the rules are? Especially when the compiler is so "good" at depending on the "rules"? I don't understand. I have pretty limited experience with unsafe, but I have written some, and was often confused about which bugs were my logic bugs and which were the compiler assuming I didn't break some rule I didn't know about. Combine this with a poor debugging story overall, and you have a pretty miserable experience programming.
Maybe this isn't a problem in practice, or maybe all people succesfully writing `unsafe` code for libraries are also `rustc` veterans?
> @import takes a path to a file and turns the whole file into a struct. So modules are just structs.
This is a very nice approach! I remember from earlier Rust that the module system was a real pain point for beginners, and can also remember really struggeling with it. Curiously though, I also remember looking back, not understanding why anything was confusing about it. This was also redone(?) at some point, and I think it's nicer now.
> In rust my code is littered with use Expr::* and I'm careful to avoid name collisions between different enums that I might want to import in the same functions. In zig I just use anonymous literals everywhere and don't worry about it.
I've always been bothered by Rust's inability to infer the `enum` type in a `match`; in other places Rust has no problems being automagick, and this is really very annoying to go around, either with `use Foo::*` before each match, or having it in file scope and hope for no collisions. Zig seems to take exactly the approach I'd go for.
> Re allocators
I think Zig's stand on explicit allocators is very good; I've seen enough bad code in other languages that allocates here and there for things that, very clearly, doesn't need to be there. Having the language be explicit about allocations makes it easier to stop and say "hey wait a minute, is this realy the way I'm supposed to do it?", but without having to jump through hoops if you _just_ want to allocate something somewhere (define a global allocator yourself). And, as a bonus, it's easier to handle the allocations of other peoples code.
> Zig has no syntax for closures.
I definitely need to write more Zig to find out whether this is a problem or not. I've written a lot of C++ lately, and while there _are_ closures available, I think I've only used them once. Maybe the reason for my comparatively heavy closure usage in Rust was that so many methods in the standard libray took closures that you're shephearded into making similar methods for your own types.
> Zig's error handling model is similar to rust's, but it's errors are an open union type rather than a regular union type like rust's.
I really think the error story is why I prefer Zig to Rust now. The giant error `enum` in Rust is definitely what I'd go with because it's simply not feasible to manually track which functions return what errors and making individual enums yourself, even though this is super easy for the compiler to do, like Zig shows.
Not to pick on anyone in particular, but sometimes it feels like many programmers think that a program only consist of the happy path and that errors are somehow rare and not worth dealing with properly. Both Rust and Zig are huge helps to combat this mindset, but I do think that Zig comes out ahead, simply by being less annoying to work with. Also, while some people might say that `Result` just being a part of `core` and not a magic special language thing is cool, I do appreciate Zig's usage of `?` since it's way less typing for something that happens _all_ the time.
> Zig's compilation is lazy. Only code which is actually reachable needs to typecheck. So if you run zig test --test-filter the_one_test_i_care_about_right_now then only the code used for that test needs to typecheck.
I didn't know this, but this is awesome!
> Zig has absurdly good support for cross-compiling.
I've never understood why cross-compiling isn't an out-of-the-box feature in all languages. Don't you basically just have to target a different instruction set? Well, and a different executable format. But still, compared to all of the other crazy things compilers are doing, this seems very straight forward in comparison.
> Zig has an experimental build system where the build graph is assembled by zig code.
See above. I really really really don't understand why all languages doesn't do this already.
> In rust, blocks are expressions.
This is something I really like about Rust and a pattern I've used a lot, where I'd say
let some_thing = {
let foo = ...
let bar = foo.baz() + quiz();
...
foo
};
to avoid accidently using `bar` somewhere else. Granted, since Rust allows shadowing this isn't really
a problem most of the time, but it's definitely something I miss when writing C++.
Zigs version is somewhat verbose, but I'll manage.> There is an in-progress incremental debug compiler for zig that aims for sub-second compile times for large projects. Based on progress so far, this is a plausible goal.
Andrew's work on binary patching executables is really cool. I hope we'll get to compile times this low, even for moderately sized projects.
> real 23m27.475s
This is just sad. Despite all the work the contributors to `rustc` are doing, it just seems that they are in a completely different league with respect to compile times than what I'd like. I hope the steady progess they're making will either make some jumps, or continue for a while :)
> Main points so far:
This is a great summary, and I think people reading it (or the whole post) will have a pretty good idea of where they stand re. the two languages.