haven't used zig...(only used rust)
but zig doesn't solve those problems?
haven't used zig...(only used rust)
but zig doesn't solve those problems?
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.
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.
This is not actually a different kind of bug; it's just use-after-free, which you can of course get when using pointers instead of indices.
Actually it's slightly safer than pointer use-after-free because it is type safe and there's no UB.
Also some of the Rust arenas give you keys (equivalent to pointers) which can check for this. There's a good list here (see "ABA mitigation"):
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?
Yes, in the same way that there's a difference between using `std::Vec` (which uses `unsafe`), and writing an unsafe Vec class yourself.
Or even the difference between using Python (which wraps an unsafe CPython implementation), and doing everything in unsafe Python code.
The difference is that widely used code like CPython and `std::Vec` are much much better tested and audited than anything I would write myself, because so many people use them. This is a continuum so something like petgraph is going to be not as well tested as std::Vec but still way better tested than anything I've written.
You're correcting someone, so it's clear that your understanding isn't universal, and example code is the absolute minimum.
Many garbage collection algorithms can deal with cycles.
And you can't forget to type defer
If I open a file, eventually I want to close it. If I allocate some memory, eventually I want to deallocate it.
Any programming language design that intentionally puts the onus BY DEFAULT on the user to *not forget to manually do something* is honestly asinine.
Defer has a place (I do use defer in C++, in fact you can implement it with RAII, proving that RAII is strictly more powerful/more flexible), but the default should be the safest and most straightforward option.
Also "magic-sauce that does a lot for you" is just false. It's literally a function call injected at the end of a scope.
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.
defer is a perfectly general structured flow concept; it only cares about when you do something, and is completely orthogonal to what you need to accomplish.
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.
Unless, of course, you do it inside a defer block.
> You don't specify where the `defer`-red "destructor" will be invoked.
Yes, actually, you do. It is patently obvious, by code inspection, where the destructor, or anything else specified in a deferred block, will be invoked. defer is a perfectly cromulent part of structured control flow, allowing for easy reasoning about when things occur without having to calculate an insane number of permutations of conditional branch instructions.
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.
I understand zig's philosophy here. But I prefer rust's default behaviour.
MSVC has a debug allocator since at least Visual Studio 5.
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.