I am of the opinion that it is horses for courses and not a universal better proposition.
Because my needs don’t fit in with Rust’s decisions very well I will use zig for personal projects when needed. I just need linked lists, graphs etc…
While hopefully someone can provide a more comprehensive explanation here are the two huge wins for my use case.
1) In Zig, accessing an array or slice out of bounds is considered detectable illegal behavior.
2) defer[0] allows you to collocate the the freeing of resources with code.
That at least ‘feels’ safer to me than a bunch of ‘unsafe’ rust that is required for my very specific use case.
I was working on some eBPF code in C and did really miss zig.
For me it fits the Pareto principle but zig is also just a sometimes food for me, so take that for what it is worth.
I've written hundreds of thousands of lines of Rust and outside of FFI, I've written I think one line of unsafe Rust.
E.g. look at a Python list. Is it safe? In Python sure, but that's abstracting a C implementation which definitely isn't safe.
If you look at Rust's std::Vec you'll find a very similar story - safe interface over an unsafe implementation.
It isn't as binary as you think.
It's true that safe wrappers around unsafe code sometimes have bugs in them, but it's orders of magnitude easier to get the abstraction right once than to use unsafe correctly in many places sprawled across a large codebase.
His point was that for his programming, he wants to be able to make real pointers and real linked lists with memory unsafe, which Rust makes difficult or opaque. For example with linked list, you could simulate (to avoid unsafe), by either boxing everything (so all refs are actually smart pointers), or you can use a container with scoped memory lifetime, and have integers in an array that are the "next" pointer. In addition to extra complexity, the "integers as edges" doesn't actually solve the complexity, it just means you can't get a bad memory error (you can still have 'pointers' that point to the wrong index if you're rolling your own).
Same with your graph code. Using a COO representation for a graph does in theory make it "memory safe" (albeit more clumsy to use if you are doing pointer-following logic), and it also introduces other subtle bugs if your logic is wrong (e.g. you have edge 100 but actually those nodes were removed, so now you're pointing at the wrong node).
I think the point (which I agree with for things like linked list, graph, compiler) is that depending on your usecase, the "safety" guarantees of rust are just making it harder to write the simplest most understandable code. Now instead of: `Node* next` I have lifetimes, integer references, two collections (nodes and edges) to keep in sync, smart pointers, etc. Previously my complexity was to make sure `next != null`, now its a ton of boilerplate and abstractions, performance hits, or more subtle bugs (like 'next' indices getting out of sync with the array of 'nodes').
If there was a way to explicitly track the lifetime of an arbitrary graph/tree of pointers at compile time, we wouldn't need garbage collection -- its not solvable at compile time, and the complexity has to live somewhere.
What are you asking for exactly?
I guess you are making the point that the user does not have to concern themselves with the unsafe declarations?
You're correcting someone, so it's clear that your understanding isn't universal, and example code is the absolute minimum.
And you can't forget to type defer
The fact that you can explicitly invoke the destructor to happen later is simply syntactic sugar, just like if/else/while, or any other control construct more powerful than a conditional jump instruction.
When you explicitly invoke a "destructor", you do it on many code paths (and miss one or two)
>The fact that you can explicitly invoke the destructor to happen later
You don't specify where the `defer`-red "destructor" will be invoked.
It gives you a few more tools than C - like a debug allocator, bounds checked array slices and so on. But it’s not a memory safe language like rust.
Its an interesting idea. But if you want static memory safety in a low level systems language, its probably much easier to just use rust.
you can make a no-op function that gets compiled out but survives AIR
> rust knows when it can Drop.
and its possible to cause problems if you aren't aware where rust picks to dropp.
> And rust can put noalias everywhere in emitted code.
zig has noalias and it should be posssible to do alias tracking as a refinement.
> But if you want static memory safety in a low level systems language, its probably much easier to just use rust.
don't use that attitude to suck oxygen out of the air. rust comes with its own baggage, so "just using rust because its the only choice" keeps you in a local minimum.
Can you give some examples? I've never ran into problems due to this.
> don't use that attitude to suck oxygen out of the air. rust comes with its own baggage
Yeah, that's a totally fair argument. One nice aspect of the approach you're proposing is it'd give you the opportunity to explore more of the borrow checker design space. I'm convinced there's a giant forest of different ways we could do compile time memory safety. Rust has gone down one particular road in that forest. But there's probably loads of other options that nobody has tried yet. Some of them will probably be better than rust - but nobody has thought them through yet.
I wish you luck in your project! If you land somewhere interesting, I hope you write it up.
If it's doing a drop in the hot loop that may be an unexpected performance regression that could be carefully lifted.
thank you. Unfortunately in the last few weeks i've been too busy with my startup to put as much work into it. We'll see =D
Yeah, I've heard of people being surprised that when they make massive collections of Box'ed entries, then get surprised that it takes a long time to Drop the whole thing. But this would be the same in C or Zig too. Malloc and free are really complex functions. Reducing heap allocations is an essential tool for optimisation.
The solution to this "unexpected performance regression" in rust is the same as it is in C, C++ and Zig: Stop heap allocating so much. Use primitive types, SSO types (SmartString and friends in rust) or memory arenas. Drop isn't the problem.
Zig is still under development and beta. Stability, crashes, and leaks should not be surprising, and even expected. To stick with a beta language, usually companies and developers are philosophically and/or financially aligned with the language. An example is JangaFX and Odin, where they not only have committed to using the language (despite being beta) in their products, but have directly hired GingerBill.
Team Bun appears to have "alignment and relationship issues" with Zig, to the point they have decided to extensively explore their options. Now Bun is rewritten in Rust. They are seeing if Rust solves their requirements. As with any relationship, if one ignores or takes a partner for granted, don't be surprised if they want a divorce or jump to someone else.
This maneuver was arguably obfuscated by the anti-LLM stance and finger pointing at Microsoft, but nevertheless, many still have noticed. Zig, for a long time, had been falling behind and doing poorly on their open to close ratio for resolving issues. It should be embarrassing to leave so many issues open.
Even if not accepting new GitHub issues, they have demonstrated an inability to resolve existing issues, except at an extremely slow pace. Considering there are just about no new issues on their GitHub repo, it is understandable if there are those that find the pace to close and amount of issues unacceptable or questionable, in addition to the clearly bad open to close ratio.