upvote
Rust's compile times will get faster long before Zig gets safer.
reply
I'm pretty sure Zig has no plans to ever become safe - by any sane sense of the word - so, yes, I would expect...
reply
zig does have plans to give access to IRs when stable so adding a borrow checker to zig will be even easier than it is now
reply
This is cool and will likely enable some cool tooling.

I don't think a borrow checker is likely to be in that tooling. Borrow checking requires shaping the code, and all the dependencies, into easily analyzable (and at least in rust's version annotated) patterns. You can't borrow check arbitrary code not designed for it without false positives.

reply
You can because all allocations are tracked and explicit
reply
That's not sufficient - consider the following pseudocode

    x = malloc();
    if (opaque_cond()) free(x);
    if (other_opaque_cond()) use(x);
Conditions can be opaque and non-analyzable due to rices theorem - in any turing complete language. This code is correct (or at least not memory unsound) if opaque_cond and other_opaque_cond are never both true. Otherwise it isn't.

And functionally compiler analyses of whether conditions hold have to be trivial because using some form of theorem prover to decide of code is correct or not leads to code that is brittle against compiler version changes, and slow compile times. Thus opaque_cond could be as simple as `len == 0` and `other_opaque_cond` could be `len > 0` and it's unlikely you'd want the compiler to realize those are mutually exclusive (at the stage where it accepts programs, obviously during optimization it is very likely to take advantage of this).

Rust solves this by simply rejecting the pattern. Very roughly forcing you to write if opaque_cond() { free(x) } else if other_opaque_cond() { use_x } (or something else where the program structure and not just the logic in the conditions guarantees correctness). Zig simply allows it and leaves it up to the programmer not to make a mistake.

And as onlyrealcuzzo suggests aliases are where this type of analysis (accepting enough programs to be useful but still imposing enough structure you can prove correctness) is really tricky.

reply
Allocations are less of a problem than aliases.

Without affine/linear ownership - solving the aliasing problem is the Halting Problem.

Rust didn't invent Affine Ownership just to make Rust hard. It did it because it's one of the only ways to have memory safety without a GC.

reply
deleted
reply
This is being worked on: https://rust-lang.github.io/rust-project-goals/2026/roadmap-...

Most of the goals on this page are targeted for this year.

reply
Instead of waiting for faster compiler in Rust, how about from the other direction, adding some kind of borrow checker to Zig? That sounds more within reach and practically achievable, possibly even in userland.
reply
That's sort of what I'm doing...

I'm writing a language with Affine Ownership that transpiles to Zig and has a built-in FSM-based Green Fiber runtime.

Affine Ownership gives you memory safety + fearless concurrency + eliminates the need for Go's GC.

It's obviously going to slow down compilation - since you need to do Rust's borrow checking, etc. But I can do this incrementally as well...

reply
It's impossible to add a borrow checker to any existing language.

The reason Rust has a working borrow checker is because every part of the language from structs, enum, traits, generics and all the way to the syntax itself has been designed to support lifetimes and borrow checking.

It's is not something you can just tack on to an existing language without fundamentally changing it.

reply
I wouldn't say it's impossible, rather un-ergonomic. TypeScript can add type information to ordinary JavaScript code via JSDoc comments; the result can both be executed as ordinary JavaScript as-is and type-checked with TypeScript. But it's a huge pain to try to write (and maintain) everything that way, it was supported as a hack to help migrate legacy codebases. You could probably take a similar "the lifetimes are embedded in comments" approach with other languages, and the result would be similarly un-ergonomic.
reply
That is possible (clang has experimental lifetime annotations support), but that is not enough to guarantee memory safety.

As a simple example, Zig has no private fields. That makes encapsulating any unsafety impossible.

reply
no. You don't need private fields. All you have to do is analyze the code, harness the compiler to generate a time-dependent data dependency graph, and map allocation/frees/uses, if you can 'color' branches where data are shared you can also track and check to see there isn't an aliasing violation too.

it is easy to patch the zig compiler to enable this this (export the code graph; about 50 LOC). The analysis is much much harder to get right.

reply
This analysis is undecidable. There is a reason sound static analyzers (including languages like Rust) require in-code annotations.
reply
It is only feasible to do this if the whole of the codebase idea designed to allow it, and it's still going to blow up in odd ways of you don't have a way to describe lifetimes in your interfaces. The magic of rust's design is that it turns this memory tracking into a local problem, such that you can design an interface and be sure that every use case is safe and verifiably so.
reply
It seems like it'd be pretty reasonable to get something akin to polonius. I can write up an engine in zig if it'd help?
reply
> Zig has no private fields

You may have missed the point here. You could add a comment to the struct field that marks the field as private, and build a TypeScript/JSDoc analogue that analyzes all accesses to the field and fails if it finds accesses from functions that aren't part of the struct that owns the field. You don't even need a comment on the field - you could copy Go's convention, add a comment to the struct definition marking it as "follows Go convention", and then fail any access from outside the struct to a field that starts with a lower-case character.

It doesn't prevent you from ignoring that tool and writing Zig code that imports the struct and accesses the field. It is, of course, not part of the Zig language itself. But if you adopted a tool like that, it would be your responsibility to run it across-the-board and pay attention to the results - same as how it is your responsibility to pay attention to the results if you added those JSDoc comments.

reply
I have picked private fields as an example of feature that is needed because it is very simple. You're right that you can build an analyzer (with additional code annotations) to support that, but it's only one example.

Take another example: unsafe traits. They are fundamental to some safety encapsulations, most famously concurrency (`Send`/`Sync`). Here you cannot just build an analyzer to mark something unsafe, because Zig has no traits, its generics are duck-typed.

You can, of course, add traits. But at this point you're essentially creating your own language that compiles to Zig, with all problems this entails (e.g. bad ecosystem support). It's also hard to claim that Zig can be memory safe then.

reply
Exactly.

Every part of the language must support memory safety from first principles.

reply
empirically untrue. several projects exist that bolt on extra safety to unsafe languages or unsafe parts of language. SeL4 for C, MIRI for rust unsafe. i guess ada/spark for ada too, is the OG, spark being added to ada 4 years after its first release
reply
Hardening is definitely possible, we've had sanitizers in C/C++ for a long time. It's not full memory safety though. Miri is the same.

SeL4C is formal verification, and while it can prove memory safety (and much more) it is much more difficult, to the point that you're basically programming in a different language.

Ada/SPARK is your best example, and also the example I know the least of, so I won't comment on.

reply
A better comparison would be Python.

The way Python added types is the most disgusting thing imaginable... but it has type hints now, so I guess that makes some people happy.

reply
Swift, Linear Haskell, Chapel, Ada/SPARK are all counter examples from such claim.
reply
Also OxCaml, from what I hear.
reply
C# was already a very mature language when it had referenes and later "ref safety" added to it.
reply
> It's impossible to add a borrow checker to any existing language.

Why do you say that. Have you tried and failed? It seems to be possible to add a borrow checker to zig, just as you can add MIRI to rust to get extra safety in unsafe blocks.

reply
> how about from the other direction, adding some kind of borrow checker to Zig? That sounds more within reach and practically achievable, possibly even in userland.

It's doable, and as static analysis. see sibling comment.

reply
No, it would fundamentally change how Zig works.
reply
no, it would not. If you do not believe me, you should try out the repo.
reply
the architecture doesn't make sense. MIRI doesn't perform static analysis on MIR. It is, as the name says, an interpreter. The borrow checker is entirely different from miri.

Rust's borrow checker requires lifetime annotations. Zig code doesn't contain any such annotations. How does your design handle this?

reply
Layperson here: what is special about Go's runtime, aside from the GC?
reply
Chief design goals were radically easy concurrency and speed of compilation.
reply
Speed of compilation feels like a distant second in terms of goals given the weird new generic features they keep adding..

I was fine with basic generics they complicated it quite a bit much for my liking.

reply
What weird new generic features? Generic type aliases? Those aren't very complicated.
reply
Is the Go GC that special? Is it even generational yet?
reply
I'm not sure it would ever make sense to be. That makes the assumption tons of allocations get made that don't live long, which was(maybe is still?) more common in some languages. Go is more aggressive about not heap allocating, and has tools to help you avoid them.
reply
Goroutines?
reply
It's literally the most sophisticated scheduling engine in the world.

In practice, Go can typically outperform Rust in throughput (using more memory), despite having a mountain of disadvantages against it in theory.

That's how good the Go scheduler/runtime is.

reply
> n practice, Go can typically outperform Rust in throughput (using more memory), despite having a mountain of disadvantages against it in theory

This is a huge claim that disagrees with both my real-world experience and everything I've seen from artificial comparisons.

Every high performance Go system I've worked on has quickly reached the point where we're optimizing memory management and doing things that would have been explicit in a non-GC language like Rust anyway.

The Go runtime is amazingly optimized, but it comes with overhead over doing the same work directly in a lower level language.

reply
This is the first I've heard anyone claim higher throughput for Go than Rust. Any articles you'd point to to learn more?
reply
I think one of the few performance benefits with a GC is that you can defer allocations. You can do that in Rust too though.
reply
> It's literally the most sophisticated scheduling engine in the world.

That seems unlikely regardless of how good it is. This is a domain where state-of-the-art research is not in the public literature. Scheduling is an AI-complete problem.

reply
I think this is interesting and warrants explanation. There are cases where a GC can be faster (sort of, Arenas get you most of the gains) but "the most sophisticated scheduling engine in the world" should be easy to at least partially support.
reply
What benchmarks are you referring to?

Rust itself doesn't have a scheduler of course, I assume this is comparing against tokio or one of the other async executors?

reply
deleted
reply
What a joke, ignoring Erlang, and the custom schedulers from JVM and CLR runtimes.
reply
Erlang's scheduler is not sophisticated, which is what makes it AWESOME.

but yeah. i would be surprised if the JVM's scheduler is not more sophisticated than go's if for no other reason than it has way more knobs you can tune. you know they put that knob in there because someone (probably Google cough cough) asked for it

reply
> if only somehow we could get Rust's safety with all of Zig's features

i periodically throw my unused codex tokens at this:

https://github.com/ityonemo/clr

reply
deleted
reply