7 ms·
Turning off Rust's borrow checker completely (2022)
- withinboredom 3y ago[flagged]
- Alifatisk 3y agoSo the borrow checker is not necessary in Rust?
- trklausss 3y agoNot at all, you can encase everything on an “unsafe” block and live happy. However you won’t have Rust’s guarantees of fearless concurrency and you expose yourself to other defects related to memory (free after use etc.) If you understand the language, you even program much of the std libraries with unsafe code in them. For more info you can consult the Rustonomicon.
- pests 3y agoTechnically the borrow checker only limits the set of valid programs and is not involved with compilation. So if you can write perfectly correct code then you never have to deal with it. Just like when you write perfectly correct syntax you never have to work with the syntax checker.
- steveklabnik 3y agoTo be a bit more precise: the borrow checker does not change the code generation part of the compiler. If you modified rustc to skip borrow checking, and you passed it a valid Rust program, you would get identical output. However, that doesn't mean that you can disregard the semantic rules that it enforces. It is "involved in compilation" in that sense. Even when writing unsafe code, you are expected to keep up the invariants that the language requires, and the rules of the borrow checker are one part of those invariants.
- pests 3y agoYes thank you. That was my underlying point without explicitly saying it. That the borrow checker does not influence compilation and just determines if a program is valid or not. Just like you can ignore the syntax checker of languages as long as you never give it incorrect syntax. I guess my core concept is that you wouldn't do these things because they provide value. And that removing the rust borrow checker without restricting what programs you write does not make sense just like trying to pass incorrect syntax to a compiler with the syntax checker removed. That to remove the borrow checker would still require you to still follow all the rules of the borrow checker! Now you just don't know if you did it correctly or not.
- withinboredom 3y agoSometimes, especially when debugging, you don’t care about being “correct,” freeing memory properly, or any other safeties. You just want to narrow down where a bug is in the code so you can start stepping through the right parts and see what is going on.
- nickm12 3y agoYou're putting "correctness" in quotes as though it is a matter of being polite to the machine. The Rust compilation process depends on these invariants so that the code actually executes as written (specifically, has no undefined behavior). I'd argue there is never a very good time to expose your program to undefined behavior, but when you're trying to debug an issue is a particularly bad time. Rust as a language aims to move bugs "to the left" through a stricter compiler. The promise is an environment where building things takes longer, but the things you build are more reliable and the net amount of time debugging (and being exposed to production bugs) is lower.
- withinboredom 3y agoIt is a matter of being polite when it comes to semantics. Weird is English written in obtuse grammar, but it is still legible. Undefined behavior still compiles into _something_, and if it’s after the code I care about observing, it doesn’t matter. The very first C++ templates compilation was observed through undefined behavior and errors. If you don’t have some way to “escape” from proper semantics, just to experiment, then the language is useless unless you know exactly what you are building before you build it. I guess that makes sense, now that I think about it. I see lots of “rewrite in rust!” But not a lot of new (from whole cloth, innovative) projects from rust. Then again, I’m not really in the rust community or do much in rust except a PR every year or so.
- Klonoar 3y agoYou can’t really hate something that you profess to not deeply understand.
- austinjp 3y agoSure, but you can think you hate it, and practically speaking what's the difference?
- withinboredom 3y agoI can hate something for any reason I wish. They are my feelings that I wield. Who are you to tell me what I can and cannot feel?
- Klonoar 3y agoYou certainly can, though I submit that's a hollow emotion at best.
- josephg 3y agoOf course you can. In fact, I think it’s often much easier to hate something when you don’t understand it fully. But in this case, the GP was describing their experience programming with the borrow checker as a new rust programmer. Hatred is an emotion. It’s not up to you or me to decide if that feeling is present in someone else’s brain.
- Klonoar 3y agoI would classify that emotion as anger or frustration. Hatred is something deeper, and I don't think you can be there without deep understanding of what you're hating. But it's ultimately whatever.
- deleted 3y ago[deleted]
- justincredible 3y ago[dead]
- dvt 3y agoI found the source code of the macro cited[1][2] way more interesting than the article. It's not that big of a deal to find where compilation error counts are incremented in the compiler and just, you know, not increment them. The macro is pretty cool though (turning bounded into unbounded lifetimes). [1] https://docs.rs/you-can-build-macros/0.0.14/src/you_can_build_macros/lib.rs.html#33 https://docs.rs/you-can-build-macros/0.0.14/src/you_can_buil... [2] https://docs.rs/you-can/latest/src/you_can/lib.rs.html#17-25 https://docs.rs/you-can/latest/src/you_can/lib.rs.html#17-25
- YetAnotherNick 3y agoI have limited experience with Rust and the combination of slow compile time and borrow checker is irritating. My rust code was less than a thousand lines and it takes like 10-20 seconds to compile. Rust really made me appreciate garbage collection after the number of times I resorted to things like Arc<Box<..>>.
- PartiallyTyped 3y agoCompiling clippy certainty doesn’t take that long and it’s a substantially larger project. What you describe is pretty weird to be honest.
- Fiahil 3y ago> after the number of times I resorted to things like Arc<Box<..>>. ... What are you doing ? It's definitively unusual.
- dvt 3y ago> ... What are you doing ? It's definitively unusual. No it's not, it's extremely common. `Arc<Box<...>>` or `Arc<Mutex<Box<...>>>` or similar is used all the time when you want to share a mutable reference (on the heap, in the case of Box); especially in the case of interior mutability[1]. It's pretty annoying, but I have learned to love the borrow checker (although lifetime rules still confuse me). It really does make my code extremely clear, knowing exactly what parts of every struct is shareable (Arc) & mutable (Mutex). [1] https://doc.rust-lang.org/book/ch15-05-interior-mutability.html https://doc.rust-lang.org/book/ch15-05-interior-mutability.h...
- Fiahil 3y ago> No it's not, it's extremely common. Arc-Mutex yes, Arc-Box no. It's like "I want a shared, immutable reference to something recursive, or unsized". The heap part makes no sense because it's already allocated there if you use an Arc : https://doc.rust-lang.org/std/sync/struct.Arc.html https://doc.rust-lang.org/std/sync/struct.Arc.html > The type Arc<T> provides shared ownership of a value of type T, allocated in the heap. Moreover, you don't even need the box for a dyn : https://gist.github.com/rust-play/f19567f8ad4cc00e3ef17ae6b3c76d2d https://gist.github.com/rust-play/f19567f8ad4cc00e3ef17ae6b3...
- olvy0 3y agoIt's been a while since I've programmed in Rust, and I was initially surprised that the get() call returned garbage. Could anyone explain why that is? I mostly program in C++ and C#. After thinking about it, my intuition is that: - the Vec was passed by value to the function, which in Rust means something different than passing a std::vector in c++ to a function, due to... - Due to the language semantics, its reference counter remained 1 while inside the function, but decreased to 0 when returning to main, since in Rust if it isn't a borrow (ref) then it's a "steal" - the callee "steals" the Vec completely from the caller. Or something like that. - Since the reference counter is 0 when returning to main, the Vec is released, akin to calling its destructor if this was C++. - SOMETHING changed the value of either the internal pointer to the heap inside the stack-allocated Vec (so now it points to garbage), OR something overwrote the Vec's content with some garbage. I'm not sure what that something is, and why would it do that. I apologize if my explanation/intuition above is garbage in itself, like I said it's been a while since I programmed in Rust. Edit: formatting
- deleted 3y ago[deleted]
- needlesslygrim 3y agoYou're mostly correct, it is moved into the function (pass by value), and then, at the end of the function's scope, the destructor is called automatically (as the compiler inserts a call to `drop()` at the end of the function) which de-allocates the vec, causing the reference obtained in `main()` become a dangling pointer.
- olvy0 3y agoThank you!
- zamalek 3y agoAn alternative, more correct but less interesting, explanation: you really need to look at the disassembly (with your specific build of the Rust compiler with the same flags) to see what's really happening. This is why UB (undefined behavior) is dangerous. For example, the compiler could decide that the entire allocation is unnecessary and elide it, if it's known that the Vec is very small. The compiler could also decide to pass it by ref. Remember that the compiler merely has to preserve your intent, beyond that it is allowed to do whatever it pleases. https://rust.godbolt.org/ https://rust.godbolt.org/
- miki123211 3y agoI wonder if you could actually write a compiler that does this for compilation speed. Have one mode where the compiler is super fast, has no error checking and can compile some malformed programs, and another mode where the compiler does all the checks. This would be useful for dependencies for example, in most circumstances you can safely assume that dependency code doesn't contain compilation errors, so any passes that check for them are just pure and unnecessary overhead. I don't know how practical this is, I don't have much experience in compiler design (beyond very small and toy compilers).
- eropple 3y ago> This would be useful for dependencies for example, in most circumstances you can safely assume that dependency code doesn't contain compilation errors, so any passes that check for them are just pure and unnecessary overhead. It's not an identical case, but TypeScript offers this with `skipLibCheck`. Most people use it. It's generally good--until it's really not good and you eat half a day unwinding a deceptively broken dependency.
- gloryjulio 3y agoSounds like if the code is in JavaScript, it would be already broken anyway
- markusde 3y agoYes... Rust! I don't know if you can toggle it from the front-end, but the Polonius borrow checker includes a "location insensitive" mode which is faster but accepts fewer programs.
- estebank 3y agoI think the GP had something else in mind. You're mentioning a mode where the rules are more stringent, allowing for a faster check and consequently faster compile times. The GP is pictuting a mode where the checks are skipped altogether, only the necessary transformations occur with an assumption that everything is already correct. I'm weary of having something like that outside of nightly, unless cargo publish had more checks than it does today.