On the Zig vs. Rust debate, people like to focus on memory safety, but Rust's RAII is just as important to writing clean, maintainable code.

There is something truly magical about seeing my GPU driver cleaning up dozens of nested GPU and host objects when the GPU job completes. Always exactly then, never too early, never too late, never leaking anything. That's all thanks to RAII and automatic Drop calls.

defer foo.deinit() really doesn't cut it. You have to explicitly write it, and it only works if all code paths free the object at the end. errdefer is just a special case, and then the only way to know if you forgot it is by testing with a leak checker. And then the deinit function has to manually deinit all child objects.

All this stuff is just done automatically in Rust. Most of my types don't even implement Drop, or only do something trivial there, because the compiler recursively dropping objects is 99% of the work.

It's knowing the compiler is on your side and taking care of all this that makes it magical. If you have to write out the code by yourself, that's more work, and a huge chance for bugs. The compiler is doing some very complex tracking to figure out what to drop when and where. You'd have to do that all in your head correctly without its help.

I see some of the pro-Zig folks arguing that "I don't want the compiler doing magic behind my back".

The compiler is there to help you. That's its job! Once you learn to trust the compiler, then you don't have to worry about getting cleanup code right ever again.

Is the compiler magically invoking drop() sometimes a problem? Yes, but that's the minority of cases, and there are solutions to that. I even worked on some of them (Arc::drop() integration with kernel lockdep to catch potential locking issues with refcounted objects across all invoked drop sites, not just those that actually drop the ref count to zero). The point is that it makes a lot more sense to work on solving these corner cases, than to just throw away the entire mechanism and have fallible humans in charge of writing more complex code as a result.

Trust the compiler, and when it does the wrong thing, find a good, general solution so it doesn't any more. Rust is actively working on solving some of these issues upstream too, and I find that a lot more positive than just saying "we won't even try, just write cleanup code manually".

@lina if you're putting all your trust in the compiler to keep you safe, wouldn't that lead to being taken down the path of bad habits? Surely it's better to learn how to keep your own code safe and not depend all your trust into a compiler?

The take away, for me, is this; if you can't write clean code and need something else to do it for you, learn. Learning makes you better, and being better makes you want to learn more.

@meatlotion @lina This is an insane statement. I have fixed multiple people's code, from extremely smart and competent people, by enabling GCC/Clang compiler warnings to catch *very* easy mistakes (i.e. `if (x > 15 && x < 0) {}`).

The point of a compiler, and abstractions in general, is to allow you to work on a higher semantic level *without* needing to care about the inner workings of it 99% of the time, which allows you to focus on the things that matter.

@meatlotion @lina Because if the focus is on writing "clean code" and need something else to do it for you, then even writing C or Zig is too high of an abstraction layer, and you should be writing assembly directly.

@Girgias @lina you can write clean code in BASIC, and you can write lazy code in BASIC.

Lazy code and clean code is a choice.

@meatlotion @Girgias You can write correct code in C and Zig and Rust, it just happens to be easier to do it and do it correctly in Rust.

Conversely, correct code is *less* clean in C than in Rust, because the language requires you to micro-manage resources. There is simply *no* way to write correct C code that is as clean as correct Rust code.