Top
Best
New

Posted by ravenical 1/1/2026

Rust--: Rust without the borrow checker(github.com)
139 points | 260 commentspage 2
gspr 1/1/2026|
Tangentially related: the opposite, Rust's borrow checker sans the compiler, is actually very useful. As far as I understand, the borrow checker is a significant part of the work of writing a Rust compiler. Therefore, having the official borrow checker available as a standalone program can make alternative compilers (e.g. for exotic hardware) feasible faster, because they won't need a borrow checker of their own from the get-go.
tialaramex 1/1/2026||
Why would this matter? The borrowck is (a) not needed during bring-up because as its name suggests it is merely a check, so going without it just means you can write nonsense and then unbounded undefined behaviour results, but (b) written entirely in Rust so you can just compile it with the rest of this "exotic hardware" Rust compiler you've built.
gspr 1/1/2026||
Yeah, you're right, I'm misremembering something here. Thanks for the correction.
bananaflag 1/1/2026||
I get your point, but still you haven't identified a use for the borrow checker sans the compiler.
accelbred 1/1/2026||
I've been thinking of writing a language with Rust's ergonomics but less of the memory safety stuff. I prefer using no dynamic allocations, in which case the only memory safety feature I need is leaking references to locals into outer scopes. As for the thread safety stuff, most of my stuff is single-threaded.
adastra22 1/2/2026||
…then just use Rust? I’m confused. Most of this stuff never comes up if you aren’t doing things where memory safety would be an issue.
accelbred 1/5/2026||
The code I have in C is often code that does't fit in Rusts safety model. Dealing with ffi is annoying because slices have no defined layout. `dyn` is limited compared to what I can do with a manual vtable. I have seriously attempted porting my personal stuff to Rust, but theres enough papercuts that I go back to C. I want the parts of Rust I find to be helpful without those parts I don't.
giancarlostoro 1/1/2026||
I've been wishing for Rust to become more ergonomic, what ergonomics does Rust currently have that other languages lack?
zeroxfe 1/1/2026|||
If Go had rust-style ADTs and pattern matching, and some parallel of "?" to short-circuit error handling, I'd be thrilled.
maxbond 1/1/2026||||
To add to the sibling comments, a world-class LSP enabling you to get a great experience in any editor/IDE out of the box. This is not at all exclusive to Rust of course, most strongly typed languages have one at this point, but I've been working in Python lately and this is what I miss the most. (I'm using an LSP in Python, but it isn't as good at the best of times, and it seems like no matter how many times I fix it's configuration it's broken again the next day.)
Null-Set 1/1/2026||||
I love how everything is an expression with a value. And match expressions are quite nice, especially with the option type. I really miss those when working in javascript.
accelbred 1/1/2026||||
For me its everything being an expression, macro_rules, dyn, automatic conversions (the few that it does have), traits, and the ? operator.
masklinn 1/1/2026|||
Affine types / destructive moves, type-level safety signal (sync/send), container-type locks.

I really miss these when doing concurrent stuff in other languages.

indigoabstract 1/1/2026||
My controversial opinion:

If Rust were to "borrow" something from the C/C++ spirit, then disabling the borrow checker should be available as a compiler option.

As in, you're an adult: if you want it, you can have it, instead of "we know better".

whatshisface 1/1/2026||
If you could disable the borrow checker globally, projects would do it, and it would become impossible to compile anything with it enabled.

You can already disable it locally: the unsafe keyword is for that.

gpm 1/1/2026||
The unsafe keyword doesn't disable the borrow checker... it lets you interact with different pointer types that aren't borrow checked, but if you're using the normal reference types in rust the same guardrails are still in place.
pornel 1/1/2026|||
That's not the spirit Rust wants to have. You can already disable borrow checker selectively by using "raw" pointers in places where you think you know better, and this is used very commonly. Every String in Rust has such raw pointer inside.

It doesn't make much sense to globally relax restrictions of Rust's references to be like C/C++ pointers, because the reference types imply a set of guarantees: must be non-null (affects struct layout), always initialized, and have strict shared/immutable vs exclusive access distinction. If you relax these guarantees, you'll break existing code that relies on having them, and make the `--yolo` flag code incompatible with the rest. OTOH if you don't remove them, then you still have almost all of borrow checker's restrictions with none of the help of upholding them. It'd be like a flag that disables the sign bit of signed integers. It just makes an existing type mean something else.

klysm 1/1/2026|||
Doesn’t work - you need the borrow checker guarantees to implement downstream compilation steps. You can just turn off assumptions
gpm 1/1/2026||
> you need the borrow checker guarantees to implement downstream compilation steps.

You don't technically. The borrow checker doesn't effect the semantics of the program (like, for example, type inference does) and the rest of the compiler doesn't need to (and in fact, doesn't) use its analysis to figure out how to compile the code.

The downstream compiler does assume that the code followed the rules for accessing references - i.e. didn't violating aliasing rules. The borrow checker guarantees this, but it's fundamentally a conservative check. It rejects programs it can't guarantee are correct, and rice's theorem proves that there are always correct programs that it can't guarantee are correct.

That said if you just treat rust-references like C-pointers you will run into issues. The aliasing rules for rust references are stricter. Also not fully agreed upon yet - the currently closest to accepted definition is in the "tree borrows" paper but it has yet to be adopted as the official one by the rust team.

MangoToupe 1/1/2026||
Is rust simple aesthetics to you? Why use rust, or any language at all really, at all then? The whole point of formal languages is to point a gun at the people who refuse to be adults.

If we can't have this, C itself offers zero benefit over assembly.

indigoabstract 1/1/2026|||
I think it's more in the spirit of playfulness, like in "don't take yourself too seriously". It's why people want to mod Minecraft and Doom for example.

Because it's fun.

I can totally understand why you wouldn't want to do this though - the plethora of incompatible lisp dialects come to mind. That's why I said it was controversial.

Wowfunhappy 1/1/2026|||
You don't think assembly is more tedious to write than C? I don't think that's because of what C does/doesn't "allow" you to do.
yazaddaruvala 1/1/2026||
Of course it is. C does allow named functions and variables. C doesn’t allow arbitrary jumps.

Those are two reasons why C is less tedious than assembly.

1718627440 1/1/2026||
> C doesn’t allow arbitrary jumps.

Have you heard of longjmp?

fithisux 1/1/2026||
This should be called trust, because it does view the developer as evil.
fithisux 1/1/2026|
I meant "it does not view"
boxed 1/1/2026||
A motivation section in the readme seems like it is needed.
poly2it 1/1/2026|
https://github.com/buyukakyuz/corroded/issues/11#issuecommen...
corrode2711 1/1/2026||
Yes, that was my motivation.
mistivia 1/2/2026||
I don't want a Rust language without a borrow checker. I want a C language with a Borrow Checker. Rust's complexity is already approaching C++, and removing the Borrow Checker would turn it into a similar disaster. Austral looks like a good option to me, but it's not mature enough yet, and the Pascal-like syntax is also difficult to get used to.
kace91 1/1/2026||
I’m not picturing how it works.

In rust you don’t have a garbage collector and you don’t manually deallocate - if the compiler is not certain of who drops memory and when, what happens with those ambiguous drops ?

In other words, are the silenced errors guaranteed to be memory leaks/use after frees?

gliptic 1/1/2026||
The borrow checker doesn't decide when things are dropped. It only checks reference uses and doesn't generate any code. This will work exactly the same as long as your program doesn't violate any borrowing rules.
kace91 1/1/2026||
No, I get that from an architectural perspective they are separate processes. The point is, unlike in other languages, the compiler is developed assuming the input has been borrow checked, right? So it is surprising to me that it doesn’t blow up somewhere when that invariant doesn’t hold.
andrewaylett 1/1/2026|||
In a correct program, the borrow checker has no effect.

Languages like C compile code with the understanding that if the compiler can't prove the code is incorrect, it'll assume it's correct. Rust compiles with the expectation that unless the compiler can prove the code correct (according to the language rules), it won't compile it. In C, all programs that only perform defined behaviour are valid, but many programs which exhibit undefined behaviour are also valid. In safe Rust, all programs which exhibit undefined behaviour are invalid. But as a trade-off, many programs which would actually execute perfectly well are also considered invalid.

In both cases, once you get past the layers that check stuff, you may normally assume that whatever you have has already been shown to be OK and you probably don't have enough information to re-check while compiling. It might blow up at runtime, it might not.

masklinn 1/1/2026||||
> So it is surprising to me that it doesn’t blow up somewhere when that invariant doesn’t hold.

The final program may be broken in various manners because you don't respect the language's prescribed semantics, in about the same way they do in C and C++. From the compiler's perspective the borrow checker validates that rules it assumes are upheld are actually upheld.

mrustc already compiles rust code without having a borrow checker (well IIRC recent-ish versions of mrustc have some borrow checking bits, but for the most part it still assumes that somebody else has done all the borrow checking).

pornel 1/1/2026|||
The compiler has deep assumptions about exclusive ownership and moves, which affects destructors and deallocation of objects.

It doesn't actually depend on the borrow checker. All lifetime labels are discarded after being checked. Code generation has no idea about borrow checking. Once the code is checked, it is compiled just like C or C++ would, just assuming the code is valid and doesn't use dangling pointers.

Borrow checker doesn't affect program behavior. It either stops compilation or does nothing at all. It's like an external static analysis tool.

antonvs 1/1/2026|||
> In other words, are the silenced errors guaranteed to be memory leaks/use after frees?

No, not at all. The examples at the beginning of the article show this - they'll execute correctly. The borrow checker is quite conservative, and rules out all sorts of code that won't (normally!) cause runtime errors.

It's fairly easy to see this if you think about the core of Rust's ownership model: every value in Rust has a single owner. The compiler enforces that for any value, there's either one mutable reference or any number of immutable references to it at a time.

This model has the advantage of being simple, easy to reason about, and ruling out large classes of errors. But like most static checks, including e.g. traditional type checks, it also rules out a great deal of otherwise valid code.

It's easy to think of examples in which you have multiple mutable references to a value that won't cause errors. Aside from trivial examples like in the article, in C-like languages you can have many concurrent mutable references to the same mutable value. You can safely (with some caveats) manage access to it via locks, protocols, documentation, or just being careful. Rust with the borrow checker simply doesn't allow multiple concurrent mutable references to the same value to exist. Rust without the borrow checker, as in the article, would allow this.

juliangoldsmith 1/1/2026|||
The silenced errors aren't guaranteed to be memory leaks or use after frees. There are some situations where memory is being handled properly, but the borrow checker isn't able to prove it.

One example might be a tree-like struct where a parent and child have references to each other. Even if everything is cleaned up properly, the borrow checker has no way to know that when the struct is created. Solving it requires unsafe at some point, usually through something like RefCell.

gpm 1/1/2026|||
I'm pretty sure that every example except example-3 in the readme intentionally invokes undefined behavior - if that helps you picture how it works ;)
eru 1/1/2026|||
I don't think so, I don't think Rust's borrow checker is free of false negatives.
MangoToupe 1/1/2026||
Rust's concept of lifetime and scopes exists independently of the borrow checker
joelthelion 1/1/2026||
I would actually enjoy that for certain small projects. Rust without the borrow checker is a very elegant language. The borrow checker is great, of course, but it can be a pain to deal with. So, for small projects it would be nice to be able to disable it.
estebank 1/1/2026|
Instead of disabling the borrow checker what should be possible is to promote borrows to Rc/Arc as needed. I would want to restrict this mode to one where it can only work locally, never publishable to crates.io. It would be particularly useful when running tests, then instead of a compile error you can also get a runtime error with better information about the cases the borrow checker was actually encountering.
w4rh4wk5 1/1/2026|
I am wondering whether this would actually be a helpful compile option in upstream rustc for quick prototyping. I don't want prod code to use this, but if I want to try things out during development, this could substantially shorten the dev cycle.
Philpax 1/1/2026||
After a while, you just don't write code that would cause substantial borrow-checker problems, even when prototyping. I'd say the slow compile times are much more of an impediment for a practicing Rust prototyper than the borrow checker.
0xdeafbeef 1/1/2026||
What the point, though? You will get compiling code, but later you would need to reachitecture code to avoid violating rust rules.
withinboredom 1/1/2026||
Sometimes, you just need to know if an idea will even work or what it would look like. If you have to refactor half the codebase (true story for me once), it makes the change a much harder sell without showing some benefits. IE, it keeps you from discovering better optimizations because you have to pay the costs upfront.
LoganDark 1/1/2026|||
In Rust, it's a lot easier to refactor half the codebase than it would be in another language. Once you're done fighting the compiler, you're usually done! instead of NEVER being sure if you did enough testing.
withinboredom 1/1/2026||
I can’t tell if you missed the whole point of “exploratory”…
LoganDark 1/2/2026||
I don't know either. Personally I can spend days or more on exploratory efforts that end up scrapped. My source code is usually version controlled, so I never have to worry about messing things up. But I suppose not everyone has this kind of time for stuff that isn't guaranteed to pan out.

Sometimes I will prototype an exploration in another crate or module so I can see if there are performance gains in a more limited application. Sometimes these explorations will grow into a full rewrite that ends up better than if I had refactored.

aw1621107 1/1/2026||||
> Sometimes, you just need to know if an idea will even work or what it would look like.

I think what GP is trying to say is that the value of such exploration might be limited if you end up with something incompatible with "proper" Rust anyways.

I suppose it depends on how frequently "transition through invalid Rust while experimenting and end up with valid Rust" happens instead of "transition through invalid Rust while experimenting and end up with invalid Rust", as well as how hard it is to fix the invalid Rust in the latter case.

withinboredom 1/2/2026||
In my case, I was adding a new admin api endpoint, which meant pulling through a bunch of stuff that was never meant for the api and got in a fight with the borrow checker. For me, I just wanted to see if I broke something on a feature level (it was never meant to be exposed by the api after all), and I didn’t care about memory safety at that point. Refactoring it properly just to get memory safety just to see what would have broke, ended up breaking out of my time-box, so it never saw the light of a merge request. Had I been able to prove the concept worked, I would have opened a PR and against the open issue to find out the best way to refactor it “properly” into a right way. As it was, I would need to completely guess what the right way was without ever even knowing if the idea would work in the first place.
aw1621107 1/2/2026||
I guess that doesn't neatly fall into the categories I described, though I think it's closer to the former than the latter.

That being said, I think what you describe sounds like a case where relaxed checks could be beneficial. It's the eternal tradeoff of requiring strong static checks, I suppose.

eru 1/1/2026|||
Can't you usually just throw some quick referenced counted cells in there, to make the borrow checker happy enough for a prototype without refactoring the whole code base?
More comments...