Live data from Hacker News

Rust--: Rust without the borrow checker

github.com

91–100 of 269 posts

Re: Rust--: Rust without the borrow checker

#91
post #59

Earlier quoted context omitted.

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.

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.

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

Re: Rust--: Rust without the borrow checker

#92

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?

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

Re: Rust--: Rust without the borrow checker

#93

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?

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

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

Re: Rust--: Rust without the borrow checker

#94
post #29

To me it feels like rust is barely readable sometimes. When I read some rust cost, I am often incapable to guess what it does, so it does not feel intuitive. I wish they made something simpler. At least C and C++ have a low barrier of entry and any beginner can write code. I don't think the borrow checker forced rust to be such a complicated language.

> To me it feels like rust is barely readable sometimes. [...] C++ have a low barrier of entry and any beginner can write code.

Here's rust code:

    fn main() {
        println!("Hello, world");
    }
Here is the equivalent C++ for the vast majority of its life (any time before C++23, has MS even shipped C++23 support yet?):

    #include 

    int main() {
      std::cout 
C++ initialisation alone is a more complex topic than pretty much any facet of Rust. And it's not hard to find C++ which is utterly inscrutable.

Re: Rust--: Rust without the borrow checker

#95

Earlier quoted context omitted.

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

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

Re: Rust--: Rust without the borrow checker

#96
post #28

I wish I could make the borrow checker give warnings not errors. It would make exploration so much easier, so I don’t have to fight the borrow checker until I know how to build what I want.

Then you have code full of warnings and undefined behavior? I think fighting the borrow checker is more like a rite of passage. Rust is not my favorite language but the borrow checker is great.

This is not a hacker’s take

Re: Rust--: Rust without the borrow checker

#97
I'm assuming it's a meme project. In case it isn't, what's the point? Just trying to understand.

Isn't rust's one of the main selling point is the barrow checker right?

Also how's the memory is handled? I know it'll drop every thing once it's out of scope but it seems you can make copies as much as you want. Looking at the loop example, I feel like this introduces memory leaks & undefined behavior.

Re: Rust--: Rust without the borrow checker

#98

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?

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.

Re: Rust--: Rust without the borrow checker

#99

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?

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

Re: Rust--: Rust without the borrow checker

#100
post #59

Earlier quoted context omitted.

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.

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.

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.

Post reply on HN