Top
Best
New

Posted by ravenical 9 hours ago

Rust--: Rust without the borrow checker(github.com)
107 points | 164 comments
sakisv 16 minutes ago|
As someone who's only did a couple of small toy-projects in rust I was never annoyed by the borrow checker. I find it nothing but a small mental shift and I kinda like it.

What I _do_ find annoying though and I cannot wrap my head around are lifetimes. Every time I think I understand it, I end up getting it wrong.

QuaternionsBhop 28 minutes ago||
Fighting the borrow checker is something you do when you're learning Rust. After you learn how to design things that way in the first place, it's just there to keep you honest.
accelbred 49 minutes ago||
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.
giancarlostoro 45 minutes ago|
I've been wishing for Rust to become more ergonomic, what ergonomics does Rust currently have that other languages lack?
zeroxfe 7 minutes ago|||
If Go had rust-style ADTs and pattern matching, and some parallel of "?" to short-circuit error handling, I'd be thrilled.
Null-Set 28 minutes ago|||
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.
dataflow 8 hours ago||
This can't possibly be guaranteed to work just by disabling the checker, can it? If Rust optimizes based on borrow-checker assumptions (which I understand it can and does) then wouldn't violating them be UB, unless you also mess with the compiler to disable those optimizations?
Sytten 55 minutes ago||
Correct, I was reading a very interesting blog post [1] on how the rust compiler will change the LLVM annotaions like sending noalias for mutable pointer. This changes a lot the generated machine code. Disabling the borrow checker won't enable those LLVM flags.

[1] https://lukefleed.xyz/posts/who-owns-the-memory-pt1/

tialaramex 7 hours ago|||
If you write correct Rust code it'll work, the borrowck is just that, a check, if the teacher doesn't check your homework where you wrote that 10 + 5 = 15 it's still correct. If you write incorrect code where you break Rust's borrowing rules it'll have unbounded Undefined Behaviour, unlike the actual Rust where that'd be an error this thing will just give you broken garbage, exactly like a C++ compiler.

Evidently millions of people want broken garbage, Herb Sutter even wrote a piece celebrating how many more C++ programmers and projects there were last year, churning out yet more broken garbage, it's a metaphor for 2025 I guess.

lordgroff 1 hour ago|||
The attitude expressed here and that tends to surface in any Rust discussion is the reason I completely lost interest in the language.
maxbond 46 minutes ago|||
Rust isn't a one true language, no one necessarily needs to learn it, and I'm sure your preffered language is excellent. C and C++ are critical languages with legitimate advantages and use cases. Don't learn Rust of you aren't interested.

But Rust, its community, and language flame wars are separate concerns. When I talk shop with other Rust people, we talk about our projects, not about hating C++.

Maxatar 30 minutes ago||||
So don't use it. Rust is not intended to be used by everyone. If you are happy using your current set of tools and find yourself productive with them then by all means be happy with it.
tempodox 1 hour ago|||
You’re expressing the same attitude here, just in reverse. Some users not thinking highly of C++ doesn’t make Rust a worse or less interesting language.
ozgrakkurt 7 hours ago||||
I have been using kde for years now without a single problem. Calling cpp garbage sounds wrong.
LtWorf 1 hour ago||
People who can't do something, sometimes assume nobody else possibly could.
zzrrt 50 minutes ago||
I’m sure some people could tiptoe through minefields daily for years, until they fail. Nobody is perfect at real or metaphorical minefields, and hubris is probably the only reason to scoff at people suggesting alternatives.
jjgreen 4 hours ago||||
It is possible to like something without hating people who like something else, can't people just live and let live?
tialaramex 2 hours ago||
Did I write that I hated somebody? I don't think I wrote anything of the sort. I can't say my thoughts about Bjarne for example rise to hatred, nobody should have humoured him in the 1980s, but we're not talking about what happened when rich idiots humoured The Donald or something as serious as that - nobody died, we just got a lot of software written in a crap programming language, I've had worse Thursdays.

And although of course things could have been better they could also have been worse. C++ drinks too much OO kool aid, but hey it introduced lots of people to generic programming which is good.

jjgreen 1 hour ago||
Correct me if I'm wrong, but I don't think you think that C++ programmers actually want to write "broken garbage", so when you say "millions of people want broken garbage" the implication is that a) they do write broken garbage, b) they're so stupid don't even know that is what they are doing. I can't really read else than in the same vein as an apartheid-era white South-African statement starting "all blacks ...", i.e., an insult to a large class of people simply for their membership in that class. Maybe that's not your intent, but that's how it reads to me, sorry.
dminik 4 minutes ago||
Considering how many people will defend C++ compilers bending over backwards to exploit some accidental undefined behaviour with "but it's fast though" then yeah, that's not an inaccurate assessment.
ada0000 3 hours ago||||
herb sutter and the c++ community as a whole have put a lot of energy into improving the language and reducing UB; this has been a primary focus of C++26. they are not encouraging people to “churn out more broken garbage”, they are encouraging people to write better code in the language they have spent years developing libraries and expertise in.
lordgroff 1 hour ago||
And for which there's often no serious alternative to in many domains anyway.
nemetroid 50 minutes ago|||
Yes, many or even most domains where C++ sees a large market share are domains with no other serious alternative. But this is an indictment of C++ and not praise. What it tells us is that when there are other viable options, C++ is rarely chosen.

The number of such domains has gone down over time, and will probably continue to do so.

ada0000 57 minutes ago|||
even when there are alternatives, sometimes it makes sense to use a library like Qt in its native language with its native documentation rather than a binding - if you can do so safely
amelius 7 hours ago||||
People don't want garbage. But in any case, they don't want straightjackets like the borrow checker.

Hence, they use GC'd languages like Go whenever they can.

eru 7 hours ago|||
Straightjackets can be very useful.

Haskell (and OCaml etc) give you both straightjackets and a garbage collector. Straightjackets and GC are very compatible.

Compared to C, which has neither straightjackets nor a GC (at least not by default).

qsera 4 hours ago|||
>Haskell (and OCaml etc) give you both straightjackets..

Haskell's thing with purity and IO does not feel like that. In fact Haskell does it right (IO type is reflected in type). And rust messed it up ("safety" does not show up in types).

You want a global mutable thing in Haskell? just use something like an `IORef` and that is it. It does not involve any complicated type magic. But mutations to it will only happen in IO, and thus will be reflected in types. That is how you do it. That is how it does not feel like a straight jacket.

Haskell as a language is tiny. But Rust is really huge, with endless behavior and expectation to keep in mind, for some some idea of safety that only matter for a small fraction of the programs.

And that I why I find that comment very funny. Always using rust is like always wearing something that constrains you greatly for some idea of "safety" even when it does not really matter. That is insane..

gpm 58 minutes ago|||
> "safety" does not show up in types

It does in rust. An `unsafe fn()` is a different type than a (implicitly safe by the lack of keyword) `fn()`.

The difference is that unsafe fn's can be encapsulated in safe wrappers, where as IO functions sort of fundamentally can't be encapsulated in non-IO wrappers. This makes the IO tagged type signatures viral throughout your program (and as a result annoying), while the safety tagged type signatures are things you only have to think about if you're touching the non-encapsulated unsafe code yourself.

qsera 27 minutes ago||
>The difference is that unsafe fn's can be encapsulated in safe wrappers

This is the koolaid I am not willing to drink.

If you can add safety very carefully on top of unsafe stuff (without any help from compiler), why not just use `c` and add safety by just being very careful?

> IO tagged type signatures viral throughout your program (and as a result annoying)..

Well, that is what good type systems do. Carry information about the types "virally". Anything short is a flawed system.

gpm 19 minutes ago||
> This is the koolaid I am not willing to drink.

> If you can add safety very carefully on top of unsafe stuff (without any help from compiler), why not just use `c` and add safety by just being very careful?

There is help from the compiler - the compiler lets the safe code expose an interface that creates strict requirements about how it is being called with and interacted with. The C language isn't expressive enough to define the same safe interface and have the compiler check it.

You can absolutely write the unsafe part in C. Rust is as good at encapsulating C into a safe rust interface as it is at encapsulating unsafe-rust into a safe rust interface. Just about every non-embedded rust program depends on C code encapsulated in this manner.

> Well, that is what good type systems do. Carry information about the types "virally". Anything short is a flawed system.

Good type systems describe the interface, not every implementation detail. Virality is the consequence of implementation details showing up in the interface.

Good type systems minimize the amount of work needed to use them.

IO is arguably part of the interface, but without further description of what IO it's a pretty useless detail of the interface. Meanwhile exposing a viral detail like this as part of the type system results in lots of work. It's a tradeoff that I think is generally not worth it.

qsera 1 minute ago||
>the compiler lets the safe code expose an interface that creates strict requirements about how it is being called with and interacted with..

The compiler does not and cannot check if these strict requirements are enough for the intended "safety". Right? It is the judgement of the programmer.

And what is stopping a `c` function with such requirements to be wrapped in some code that actually checks these requirements are met? The only thing that the rust compiler enables is to include a feature to mark a specific function as unsafe.

In both cases there is zero help from the compiler to actually verify that the checks that are done on top are sufficient.

And if you want to mark a `c` function as unsafe, just follow some naming convention...

>but without further description of what IO it's a pretty useless detail of the interface..

Take a look at effect-system libraries which can actually encode "What IO" at the type level and make it available everywhere. It is a pretty basic and widely used thing.

elbear 58 minutes ago|||
When I started learning Haskell, it did feel like coding with a straightjacket.
qsera 23 minutes ago||
I think that is because when you start learning Haskell, you are not typically told about state monads, `IORefs` and likes that enables safe mutability.

It might be because Monads could have a tad bit advanced type machinery. But IORefs are straightforward, but typically one does not come across it until a bit too late into their Haskell journey.

reactordev 6 hours ago||||
>Straitjackets can be very useful.

Only if you’re insane.

qsera 6 hours ago|||
Damn! This is the funniest HN comment that I have ever come across...
josephg 6 hours ago||||
How dare you. C is a fine language.

Just don't accidentally step on any of these landmines and we'll all get along great.

reactordev 2 hours ago||
Not to mention your sidearm is a Sig P365. We like to call them footguns.
imtringued 6 hours ago|||
The meaning of straightjacket here is inherently subjective and not to be meant literally.
127 1 hour ago||||
You call it a straightjacket, I call it a railroad track for reliably delivering software.
Spivak 48 minutes ago||||
How are we still having the same trade off discussion being argued so black and white when reality has shown that both options are preferred by different groups.

Rust says that all incorrect programs (in terms of memory safety) are invalid but the trade is that some correct programs will also be marked as invalid because the compiler can't prove them correct.

C++ says that all correct programs are valid but the trade is that some incorrect programs are also valid.

You see the same trade being made with various type systems and people still debate about it but ultimately accept that they're both valid and not garbage.

Maxatar 26 minutes ago||
>C++ says that all correct programs are valid but the trade is that some incorrect programs are also valid.

C++ does not say this, in fact no statically typed programming language says this, they all reject programs that could in principle be correct but get rejected because of some property of the type system.

You are trying to present a false dichotomy that simply does not exist and ignoring the many nuances and trade-offs that exist among these (and other) languages.

pron 51 minutes ago|||
For all its faults, and it has many (though Rust shares most of them), few programming languages have yielded more value than C++. Maybe only C and Java. Calling C++ software "garbage" is a bonkers exaggeration and a wildly distorted view of the state of software.
masklinn 6 hours ago|||
> This can't possibly be guaranteed to work just by disabling the checker, can it?

It works in the sense that the borrow checker stops bothering you and the compiler will compile your code. It will even work fine as long as you don't write code which invokes UB (which does include code which would not pass the borrow checker, as the borrow checker necessarily rejects valid programs in order to forbid all invalid programs).

dataflow 6 hours ago||
> It will even work fine as long as you don't write code which invokes UB (which does include code which would not pass the borrow checker, as the borrow checker necessarily rejects valid programs in order to forbid all invalid programs).

To be clear, by "this" I meant "[allowing] code that would normally violate Rust's borrowing rules to compile and run successfully," which both of us seem to believe to be UB.

masklinn 5 hours ago||
Not quite, there is code which fails borrow checking but is safe and sound.

That is part of why a number of people have been waiting for Polonius and / or the tree borrows model, most classic are relatively trivial cases of "check then update" which fail to borrow check but are obviously non-problematic e.g.

    pub fn get_or_insert (
        map: &'_ mut HashMap<u32, String>,
    ) -> &'_ String
    {
        if let Some(v) = map.get(&22) {
            return v;
        }
        map.insert(22, String::from("hi"));
        &map[&22]
    }
Though ultimately even if either or both efforts bear fruits they will still reject programs which are well formed: that is the halting problem, a compiler can either reject all invalid programs or accept all valid programs, but it can not do both, and the former is generally considered more valuable, so in order to reject all invalid programs compilers will necessarily reject some valid programs.
CGamesPlay 6 hours ago|||
Yes. An analog would be uninitialized memory. The compiler is free to make optimizations that assume that uninitialized memory holds every value and no value simultaneously (because it is undefined behavior to ever read it).

In the following example, z is dereferenced one time and assigned to both x and y, but if z and x are aliased, then this is an invalid optimization.

    fn increment_by(x: &mut i32, y: &mut i32, z: &i32) {
        *x = *z;
        *y = *z;
    }
https://rust.godbolt.org/z/Mc6fvTzPG
MangoToupe 6 hours ago||
> If Rust optimizes based on borrow-checker assumptions

This is a binary assumption that you can understand to evaluate to "true" in the absence of a borrow checker. If it is "false" it halts the compiler

indigoabstract 2 hours ago||
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".

pornel 1 hour ago||
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.

whatshisface 1 hour ago|||
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 54 minutes ago||
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.
klysm 1 hour ago|||
Doesn’t work - you need the borrow checker guarantees to implement downstream compilation steps. You can just turn off assumptions
gpm 27 minutes ago||
> 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 hour ago||
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.

Wowfunhappy 23 minutes ago|||
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.
indigoabstract 1 hour ago|||
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.

raluk 8 hours ago||
What are protental issues with compiler, by just disabling borrow checker? If I recall correctly some compiler optimisations for rust can not be done in C/C++ because of restrictions implied by borrow checker.
0xdeafbeef 8 hours ago||
Rust can set restricts to all pointers, because 1 mut xor many shared refs rule. Borrow checker empowers this. https://en.wikipedia.org/wiki/Restrict
imtringued 6 hours ago||
The crazy part about this is that (auto) vectorization in Rust looks something like this: iter.chunks(32).map(vectorized)

Where the vectorized function checks if the chunk has length 32, if yes run the algorithm, else run the algorithm.

The compiler knows that the chunk has a fixed size at compile time in the first block, which means it can now attempt to vectorize the algorithm with a SIMD size of 32. The else block handles the scalar case, where the chunk is smaller than 32.

vanviegen 7 hours ago||
Without the borrow checker, how should memory be managed? Just never deallocate?
masklinn 6 hours ago|||
The borrow checker does not deal with ownership, which is what rust’s memory management leverages. The borrow checker validates that borrows (references) are valid aka that they don’t outlive their sources and that exclusive borrows don’t overlap.

The borrow checker does not influence codegen at all.

eptcyka 1 hour ago||||
The same as C++, destructors get called when an object goes out of scope.
flohofwoe 6 hours ago|||
It would be the same as in any language with manual memory management, you'd simply get a dangling pointer access. The 'move-by-default' semantics of Rust just makes this a lot trickier than in a 'copy-by-default' language though.

It's actually interesting to me that the Rust borrow checker can 'simply' be disabled (e.g. no language- or stdlib-features really depending on the borrow checker pass) - not that it's very useful in practice though.

xlii 8 hours ago||

    > In addition to meeting the Open Source Definition, the following standards apply to new licenses:
    > (...) The license does not have terms that structurally put the licensor in a more favored position than any licensee.
    https://opensource.org/licenses/review-process

That's a funfact I learned from IP lawyer when discussing possibility of open-source but otherwise LLVM-extempt license. If there is extemption (even in LLM) such license is most likely OSI-incompatible.
corrode2711 2 hours ago||
I'm the author of this repo. I see some really angry comments, some of them even personal. Obviously I didn't think that just by tinkering with a compiler, I'd get personally attacked, but anyway, fair enough.

For those of you confused: yes, this started as a satirical project with the corroded lib. Then I thought "why not just remove the borrow checker?" without any real motivation. Then I just went ahead and did it. To my surprise, it was really simple and easy. I thought it would be heavily tangled into the rustc compiler, but once I figured out where the error emitter is, it was pretty straightforward.

I'm not sure about my long-term goals, but besides the joke, I genuinely think for debugging and prototyping purposes, I'd like the borrow checker to shut up. I'm the kind of guy that prints everything while debugging and prototyping. Maybe you're using a debugger, okay, but I don't. I don't like debuggers. It's just more convenient for me. So what constantly happens is I run into issues like: does this implement Debug? Can I print this after it moved? The borrow checker won't let me access this because of some other borrow. Stuff like that.

Another point is, as you guys are well aware, the borrow checker will reject some valid programs in order to never pass any invalid program. What if I'm sure about what I'm doing and I don't want that check to run?

In the repo there's a doubly linked list example. Without the borrow checker it's fairly simple and easy to implement. With it, you know how complicated and ugly it gets.

Anyway, have a good new year, and don't get angry over compilers, you know.

CodeMage 1 hour ago||
> Then I thought "why not just remove the borrow checker?" without any real motivation.

Reminds me of a chemistry kit I had as a kid. None of this tame, safe stuff you can buy these days. Mine was a gift from my dad and I never thought of asking him where he dug it up, but it had stuff like pure sulfuric acid in it.

One day, when I was done with all of the experiments I had planned to do, I decided to mix a few things and heat them up, just for fun, without any real motivation other than "let's see what happens".

Let's just say I was lucky we only had to replace some of the clothes my mom had left out for me to put away. ;)

> Another point is, as you guys are well aware, the borrow checker will reject some valid programs in order to never pass any invalid program. What if I'm sure about what I'm doing and I don't want that check to run?

Then you do it using the "unsafe" keyword, and you think long and hard about how to design and structure the code so that the unsafe code is small in scope, surface, and blast radius.

That's precisely what unsafe code is for: to get around the borrow checker and assert you know what you're doing. Of course, if you're wrong, that means your program will blow up, but at least you know that the culprit is hiding in one of those unsafe areas, rather than literally anywhere in the whole codebase.

Alternately, you can switch to a language with a different ethos.

The ethos of Rust is caring for memory safety so much that you willingly limit yourself in terms of what kind of code you write and you only step out of those limits reluctantly and with great care. That's something that resonates with a lot of people and Rust has been built on top of that for years.

If you suddenly take the product of those years of hard work, strip out the foundation it has been built on, and unironically offer it as a good idea, a lot of people won't like it and will tell you so. Mind, I'm not excusing the personal attacks, I'm just explaining the reaction.

corrode2711 43 minutes ago||
Anything fun is dangerous. Or anything dangerous is fun. Something like that.
whatshisface 1 hour ago|||
I think there is probably a way to do what you're doing with unsafe. You could write a library that copies handles and can dump potentially freed memory afterwards.
g-mork 1 hour ago|||
Some kind of cargo plugin that transforms all references in the project into pointers and casts prior to feeding to rustc would probably be the best practice and highly maintainable route I'd go. like "cargo expand" but with a fancy catchier name that encourages new users to rely on it. "cargo autofix" might work
jvanderbot 1 hour ago|||
There's definitely a way to do it without unsafe! It just isn't as simple as dropping one println out so.... Lets alter the compiler?

I gotta applaud that level of my-way-or-the-highway

npalli 56 minutes ago|||
You just need to master one package managed in depth and you will get what you really want with Modern C++.
linolevan 1 hour ago||
[dead]
JoelJacobson 1 hour ago||
Rust without async maybe?
joelthelion 4 hours ago|
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 34 minutes ago|
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.
More comments...