Live data from Hacker News

Rust--: Rust without the borrow checker

github.com

231–240 of 269 posts

Re: Rust--: Rust without the borrow checker

#231

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?

I guess this is like putting an unsafe { } around all your code...

No, unsafe doesn't disable the borrow checker.

Re: Rust--: Rust without the borrow checker

#232
post #214
post #146

Earlier quoted context omitted.

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.

Just FYI rust projects have CVEs as well.

Of course. My sense is there are a lot fewer in of out-of-bounds accesses and use after frees. Maybe a world-class programmer can go several decades without writing a memory error in C/C++, but they will probably eventually falter, meanwhile the other 99.9% of programmers fail more often. Why would you decline a compiler’s help eliminating certain types of bugs almost entirely?

Re: Rust--: Rust without the borrow checker

#233

Earlier quoted context omitted.

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.

> 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 w…

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.

Re: Rust--: Rust without the borrow checker

#234
post #158

Earlier quoted context omitted.

>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 informat…

> 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? Y'know people complain a lot about Rust zealots and how they come into discussions and irrationally talk about how Rust's safety is our lord and savior and can eliminate all bugs or whatever... But your take (and every one like it) is one of the weakest I've h…

I think it comes down to

1. In `c` one have to remember a few, fairly intutive things, and enforce them without fail.

2. In rust, one have to learn, remember ever increasing number of things and constantly deal with non-intutive borrow-checker shenanigans that can hit your project at any point of the development forcing you to re-architecture your project, despite doing everything to ensure "safety". But the borrow-checker can't be convinced.

I have had enough of 2. I might use rust if I want to build a critical system with careless programmers, but who would do such a thing? For open source dependencies, one will have to go by community vouching or auditing themselves. Can't count something to be "Safe" just because it is in rust, right? So what is the point. I just don't see it. I mean, if you look a bit deeper, It just does not make any sense.

Re: Rust--: Rust without the borrow checker

#236

Earlier quoted context omitted.

> 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.

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 , ) -> &'_ String { if let Some(v) = map.get(&22) { return v; } ma…

I don't feel you're quite following what I'm saying unfortunately. In your specific example: couldn't the optimizer just optimize out all the mutations you've written, under the assumption that such a program would not have passed borrow-checking and thus isn't a case it needs to handle? Wouldn't this make it so that if you disabled borrow checking, you would get incorrect codegen vs. what you intended? This seems like an entirely legal and sane optimization; I'm not sure how you're assuming something like this outside the realm of possibility.

You seem to be operating on some (generous) underlying assumptions about what a borrow-checker-violating Rust program really means and what optimizations the compiler has the liberty to make even when borrow-checker assumptions are violated. But are you sure that assumption is well-founded? What is it formally based on?

Re: Rust--: Rust without the borrow checker

#237

Earlier quoted context omitted.

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 , ) -> &'_ String { if let Some(v) = map.get(&22) { return v; } ma…

I don't feel you're quite following what I'm saying unfortunately. In your specific example: couldn't the optimizer just optimize out all the mutations you've written, under the assumption that such a program would not have passed borrow-checking and thus isn't a case it needs to handle? Wouldn't this make it so that if you disabled borrow checking, you would get incorrect codegen vs. what you intended? This seems li…

> I don't feel you're quite following what I'm saying unfortunately.

Disagreeing with your plainly incorrect assertion is not "not following" what you're saying.

> In your specific example: couldn't the optimizer just optimize out all the mutations you've written, under the assumption that such a program would not have passed borrow-checking and thus isn't a case it needs to handle?

No. The borrow checker ensures specific rules are followed, the borrow checker is not the rules themselves, and the optimisations are based on the underlying rules not on the borrow checker.

The program above abides by the underlying rules, it's literally the sort of examples used by people working on the next generation borrow checker, but the current borrow checker is not able to understand that.

> This seems like an entirely legal and sane optimization

It's neither of those things.

> You seem to be operating on some (generous) underlying assumptions about what a borrow-checker-violating Rust program really means and what optimizations the compiler has the liberty to make even when borrow-checker assumptions are violated. But are you sure that assumption is well-founded? What is it formally based on?

They are not assumptions, or generous. They are an understanding of the gap between the capabilities of the NLL borrow checker and "Behavior considered undefined".

They are what anyone working on the borrow checker sees as limitations of the borrow checker (some fixable, others intrinsic).

Re: Rust--: Rust without the borrow checker

#238

Earlier quoted context omitted.

I don't feel you're quite following what I'm saying unfortunately. In your specific example: couldn't the optimizer just optimize out all the mutations you've written, under the assumption that such a program would not have passed borrow-checking and thus isn't a case it needs to handle? Wouldn't this make it so that if you disabled borrow checking, you would get incorrect codegen vs. what you intended? This seems li…

> I don't feel you're quite following what I'm saying unfortunately. Disagreeing with your plainly incorrect assertion is not "not following" what you're saying. > In your specific example: couldn't the optimizer just optimize out all the mutations you've written, under the assumption that such a program would not have passed borrow-checking and thus isn't a case it needs to handle? No. The borrow checker ensures spe…

> Disagreeing with your plainly incorrect assertion is not "not following" what you're saying.

I'm sorry, that particular comment wasn't disagreeing so much as missing my point entirely. It gave an example that would've still suffered from the same problem I was talking about if the optimizer relied on the same borrowing assumptions (hence my subsequent comment clarifying this) and it also diverted the discussion toward explaining the basics of incompleteness and the halting problem to me, neither of which indicated a following of my point at all, and both of which indicated a misunderstanding of where my (mis)understanding was.

But your new comment tracks it now (thanks).

>> This seems like an entirely legal and sane optimization

> It's neither of those things.

Thanks for clarifying.

> They are what anyone working on the borrow checker sees as limitations of the borrow checker (some fixable, others intrinsic).

I understand this, but it (again) doesn't contradict my point. Just because something is a known limitation of an earlier stage like the borrow checker, that doesn't mean that relaxing it would never require a change to later stages of the compiler, which never had to consider other possibilities before. Just like how limitations of the type checker don't imply that relaxing them would automatically cause the backend to generate correct code. It depends how the compiler is written and what the underlying rules and assumptions are for the later stages, and what's actually tested in practice, hence this entire question.

Heck, weren't there literal bugs discovered in LLVM during Rust development (was it noalias?) simply because those patterns weren't seen or tested much prior to Rust, despite being intended to work? It feels quite... optimistic to just change the constraints in one stage and assume they will work correctly for the later stages of a compiler with zero additional work. It makes sense if there's already active work to ensure this in the later stages, and I don't know if that's the case here or not, but if there isn't, then it feels risky.

> the optimisations are based on the underlying rules not on the borrow checker

Is there a link I can follow to these underlying rules so I can see what they are?

Re: Rust--: Rust without the borrow checker

#239

Earlier quoted context omitted.

> I don't feel you're quite following what I'm saying unfortunately. Disagreeing with your plainly incorrect assertion is not "not following" what you're saying. > In your specific example: couldn't the optimizer just optimize out all the mutations you've written, under the assumption that such a program would not have passed borrow-checking and thus isn't a case it needs to handle? No. The borrow checker ensures spe…

> Disagreeing with your plainly incorrect assertion is not "not following" what you're saying. I'm sorry, that particular comment wasn't disagreeing so much as missing my point entirely. It gave an example that would've still suffered from the same problem I was talking about if the optimizer relied on the same borrowing assumptions (hence my subsequent comment clarifying this) and it also diverted the discussion tow…

https://plf.inf.ethz.ch/research/pldi25-tree-borrows.html

(Note that I am an author of that paper, and also that this is just a proposal of the rules and not yet adopted as normative.)

What you seem to be forgetting in this discussion is that unsafe code exists. The example above does not pass the borrow checker, but with a small amount of unsafe code (casting a reference to a pointer and back to erase the lifetime constraints) you can make it compile. But of course with unsafe code it is possible to write programs that have undefined behavior. The question is whether this specific program has undefined behavior, and the answer is no.

Since it does not have undefined behavior, the rest of the compiler already has to preserve its semantics. So one could also tweak the borrow checker to accept this program.

TL;DR unsafe code exists and so you can't just say all programs not passing the borrow checker are UB.

Re: Rust--: Rust without the borrow checker

#240
post #234

Earlier quoted context omitted.

> 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? Y'know people complain a lot about Rust zealots and how they come into discussions and irrationally talk about how Rust's safety is our lord and savior and can eliminate all bugs or whatever... But your take (and every one like it) is one of the weakest I've h…

I think it comes down to 1. In `c` one have to remember a few, fairly intutive things, and enforce them without fail. 2. In rust, one have to learn, remember ever increasing number of things and constantly deal with non-intutive borrow-checker shenanigans that can hit your project at any point of the development forcing you to re-architecture your project, despite doing everything to ensure "safety". But the borrow-c…

Do you have any examples of that?
Post reply on HN