"I have to carefully make sure that each resource has been freed/closed (but not too soon!)"
You can use defer keyword to free right after allocating and it won't be called until the function/program completes. You can use debug or testing allocators to ensure no memory is left unfree'd or double free'd. The std lib has a large selection of custom allocators that you can use depending on your needs. One great one is an "Arena Allocator" which is just a linked-list of allocations that can be free'd at one time, versus tracking all these individual allocations. And if none of these allocators fit your needs, the interface to define one is pretty easy to implement.
https://ziglang.org/documentation/0.7.1/#Choosing-an-Allocat...
"I'm not mutating or holding onto anything I'm not meant to"
Not really sure Zig can help you with this one. With great power comes great responsibility, or something like that.
"that I've accounted for every exception that I can result from a given call"
Zig does not have exceptions, but it does have error types which functions can return. From the function definition you usually can determine all the errors that can possibly be returned, unless the function definer use'd the catch all ! error type. Regardless, it is still much better than regular exceptions because
- you know by the function def that an error could be thrown, the compiler forces the caller to account for a possible error by "unwrapping" the return value
The compiler infers the errors in an error set even if you don't declare it explicitly (e.g. when returning `!void`). This means that you can use a switch statement to have the compiler tell you what cases it contains.
There's also ZLS, a language server implementation for Zig that I believe can help with that (or if not today, it will in the future).
You can use defer keyword to free right after allocating and it won't be called until the function/program completes. You can use debug or testing allocators to ensure no memory is left unfree'd or double free'd. The std lib has a large selection of custom allocators that you can use depending on your needs. One great one is an "Arena Allocator" which is just a linked-list of allocations that can be free'd at one time, versus tracking all these individual allocations. And if none of these allocators fit your needs, the interface to define one is pretty easy to implement. https://ziglang.org/documentation/0.7.1/#Choosing-an-Allocat...
"I'm not mutating or holding onto anything I'm not meant to"
Not really sure Zig can help you with this one. With great power comes great responsibility, or something like that.
"that I've accounted for every exception that I can result from a given call"
Zig does not have exceptions, but it does have error types which functions can return. From the function definition you usually can determine all the errors that can possibly be returned, unless the function definer use'd the catch all ! error type. Regardless, it is still much better than regular exceptions because
- you know by the function def that an error could be thrown, the compiler forces the caller to account for a possible error by "unwrapping" the return value
- an error happening just passes back a different type to the caller and in combination with the above, you can never "miss" an error https://ziglang.org/documentation/0.7.1/#Errors
Also Zig switch statements without an else ensure you handle every possible value so if you forget to handle one possible error (based on the type), it will throw a compile error. https://ziglang.org/documentation/0.7.1/#toc-Exhaustive-Swit...