[HN Gopher] My reference was dropped, why is the compiler compla...
       ___________________________________________________________________
        
       My reference was dropped, why is the compiler complaining about
       multiple borrow
        
       Author : todsacerdoti
       Score  : 34 points
       Date   : 2023-12-21 13:16 UTC (2 days ago)
        
 (HTM) web link (ntietz.com)
 (TXT) w3m dump (ntietz.com)
        
       | kramerger wrote:
       | Currently fighting the borrow checker.
       | 
       | My project has not moved much this last week due to an issue I
       | just can't understand. Have rewritten the offending code 4 times
       | but it always fail to compile somehow.
       | 
       | At this point, I am only staying with Rust because of the
       | ergonomics of enum and iterators. The memory safety stuff is 90%
       | writing safe code then fighting the compiler to agree with you.
       | 
       | :(
        
         | chrismorgan wrote:
         | > _The memory safety stuff is 90% writing safe code then
         | fighting the compiler to agree with you._
         | 
         | This isn't my experience, from a decade of occasionally
         | watching and helping others learn Rust, personally and
         | professionally. Rather, it's normally writing code that you
         | believe is safe, wrestling with the compiler and finally
         | realising that it was right all along, or giving up before
         | reaching this stage but it was still. There _are_ certainly
         | some cases where this isn't the case, and this article talks
         | about the most common and most notorious one, but seriously,
         | the compiler is normally right.
         | 
         | Somewhere along the way, things click and your intuitions
         | subsequently almost always match the compiler's, and you have a
         | much happier time of it, seldom needing to wrestle. And your
         | coding in other languages tends to improve, or at least focus
         | on ownership more in ways that tend to make later maintenance
         | easier.
        
           | kstrauser wrote:
           | Me, writing a thing in Python: La, la-la, la-la.
           | 
           | Me, writing it in C: Grumble, grumble, la-la-la.
           | 
           | Me, writing it in Rust: I HATE THIS THING WHY DO YOU oh hey
           | I'd been thinking about this all wrong.
           | 
           | I go through that cycle all the freaking time. At first, I'm
           | irked that Rust is being such a pain in the neck. Then I give
           | in and do things the way it wants me to, and realize that
           | it's genuinely much better that way, even if I then take that
           | approach back to Python. At the least, now I'm more aware of
           | when I'm counting on the garbage collector to atone for my
           | sins.
        
           | 4death4 wrote:
           | Your "experience" (bias?) is easily falsified. Obviously
           | memory issues happen _all the time_ in unsafe languages, but
           | even then, not nearly at the frequency that a novice Rust
           | user will conflict with the borrow checker. The article we're
           | commenting on is literally about safe code that the borrow
           | checker fails on.
        
         | oconnor663 wrote:
         | If you could put your project up on GitHub or similar, I'd be
         | happy to take a look at the errors. Otherwise without knowing
         | anything about your specific situation, any chance this helps?
         | https://jacko.io/object_soup.html
        
         | yodsanklai wrote:
         | Use OCaml if you can live with a GC.
        
           | dimgl wrote:
           | Why not Go?
        
             | estebank wrote:
             | Because it doesn't have ADTs and pattern matching, which
             | the gp explicitly called out as their reason to use Rust.
             | There are garbage collected languages that have that, but
             | Go isn't one of them.
        
         | armchairhacker wrote:
         | Depending on the issue you could get away with either using
         | unsafe code or just using a RefCell (if you can't convince the
         | compiler a mutable reference isn't being shared, wrap it into a
         | RefCell and then you have a shared reference that you can do
         | mutable operations on.)
        
         | dehrmann wrote:
         | > I am only staying with Rust because of the ergonomics of enum
         | and iterators
         | 
         | Don't other languages have things that are close enough?
        
         | logicchains wrote:
         | Have you tried asking GPT4 for help? It understands Rust fairly
         | well, and can also explain what's going wrong quite clearly.
        
         | dimgl wrote:
         | Is your problem domain relevant to low-level programming?
         | Because if not, I would drop Rust immediately and just go with
         | an easier language.
        
         | tkz1312 wrote:
         | there are many excellent languages that have adts (and much
         | more) without having to deal with the borrow checker.
         | 
         | Maybe give ocaml or haskell a try :)
        
           | estebank wrote:
           | FWIW, you can also write Rust without _having_ to  "deal"
           | with the borrow checker either. A common problem I see from
           | experienced programmers picking up Rust is trying to write
           | code with minimal allocations, _before_ learning enough of
           | the language to properly represent them (or whether the
           | pattern _can_ be represented) in safe Rust. I recall an
           | argument I got into with a colleague who was adamant that
           | boxing closures was the wrong call and spent an inordinate
           | amount of time trying to represent a pattern that wouldn 't
           | work without doing so. Or the time I myself spent a lot of
           | time trying to return borrowed values when in hindsight I
           | should have called .to_owned() once and spared the time I
           | spent looking for an allocation-free alternative. (Cow would
           | have worked in that case, but I didn't have the experience to
           | know that for sure, and today I wouldn't have chosen it
           | because it would have made using the API more cumbersome than
           | needed.)
           | 
           | A lot of the borrow checker problems go away if you're ok
           | with allocations, storing trait objects on the heap, making
           | your ADTs not have references, etc. But getting familiar with
           | the language enough to know "this requires unsafe or for<'a>"
           | takes a while.
        
         | baq wrote:
         | This is not fighting the compiler, this is writing code in a
         | way which can be proved to be safe.
         | 
         | Some code can be safe but is hard to reason about. The compiler
         | tells you that. The solution is, unsurprisingly but perhaps
         | disappointingly, to stop writing code like that.
        
           | Animats wrote:
           | > Some code can be safe but is hard to reason about.
           | 
           | This is a point I made back when I was doing verification.
           | Yes, you can write code for which termination cannot be
           | proven. If termination for your code is theoretically
           | undecidable, it probably won't work right anyway. So don't go
           | there.
           | 
           | Microsoft took a hard line on this with their Static Driver
           | Verifier, a proof of memory correctness system for Windows
           | kernel drivers. If your driver code is so hard to analyze
           | that automatic path analysis can't verify memory correctness,
           | it doesn't get signed to run in kernel space. Driver-caused
           | Windows kernel crashes, formerly a huge problem, mostly went
           | away.
        
         | mcronce wrote:
         | If it's not a project under NDA, like another user, I'd be
         | happy to put eyeballs on it and help you work out the errors
        
         | bsder wrote:
         | Add more braces. Not joking.
         | 
         | I find that a lot of Rust borrow checker problems can be solved
         | by inserting more blocks. At the very least, it helps you
         | isolate _precisely_ where the issue is.
         | 
         | I don't see this recommendation often for how much it seems to
         | help beginners. To be fair, it's a _lot_ less of an issue than
         | it used to be as the borrow checker has gotten quite a bit
         | better.
        
       | jheriko wrote:
       | laughs in "never needed any of these weird mechanisms to manage
       | my own memory"
        
         | recursive wrote:
         | Classic blub programmer looking up.
         | 
         | https://wiki.c2.com/?BlubParadox
        
         | ColonelPhantom wrote:
         | I mean, when coding memory management by hand in C or C++
         | (although C++ of course has things like RAII and smart pointers
         | which simplify life a lot), you do need to have similar
         | mechanisms within your own head. Otherwise you'll get all sorts
         | of fun stuff like pointer aliasing, use-after-free, or what-
         | have-you.
        
         | oconnor663 wrote:
         | Of course not, these mechanisms are so that other people can
         | manage your memory :)
        
         | Tyr42 wrote:
         | What, you never deallocated the bit of memory holding where you
         | put your keys before collecting the keys?
        
           | mtlmtlmtlmtl wrote:
           | Don't forget to zero the memory first. If you don't, the keys
           | may still be there depending on the allocator.
           | 
           | Also, be careful about how you zero it, so the compiler
           | doesn't optimise it out.
        
       | Arnavion wrote:
       | Minor point: `let padding = &mut bytes[..index]; padding[index]`
       | is an out-of-bounds index and will panic even if the borrow
       | checker accepted it. You probably wanted `let padding = &mut
       | bytes[..=index];`
        
       | oneshtein wrote:
       | First example is completely broken. rust:nietz 1:0
        
       | Animats wrote:
       | Right. A local reference is escaping the loop scope at the
       | "return". This is safe but weird, and the current borrow checker
       | isn't smart enough to confirm that it's safe. The fancier
       | "Polonius" borrow checker in development is supposed to be less
       | restrictive.
       | 
       | The code example is Rust written as if it were classic C. In
       | Rust, that example would usually be written like this:
       | /// Find leading zeros in an array of bytes.         fn
       | find_leading_0s(bytes: &mut [u8]) -> Option<&mut [u8]> {
       | if let Some(pos) = bytes.iter().position(|v| *v != 0 ) { //
       | search                 Some(&mut bytes[..pos]) // find
       | } else {                 None // no find             }         }
       | 
       | Rust isn't a fully functional language, but the functional
       | features play well with the lifetime system and are optimized
       | well.
       | 
       | (Rust playground example: https://play.rust-
       | lang.org/?version=stable&mode=debug&editio...)
        
         | angiosperm wrote:
         | A simple "--make-borrow-violations-into-warnings" flag (that
         | for the sake of the panicky would work only on debug builds)
         | would let you get on with your work, and come back before
         | pushing to a shared repository to settle up.
         | 
         | Probably need to release it as a patch so as not to need
         | approval of the purity gatekeepers. People using it get an
         | immediate boost in productivity as it enables exploration with
         | no ultimate reduction in safety.
        
           | cornholio wrote:
           | Sounds like a great way to paint yourself into a corner, and
           | explore solutions that are impossible to be made viable in
           | the general case, even if they happen to work for certain
           | inputs during debug.
        
             | estebank wrote:
             | I would like that mode exclusively for the test suite to
             | use. That way you start writing your tests, and if there's
             | a borrowck error You delay that until the test runs. If it
             | runs, and then it fails when accessing data, you can give
             | more information to the programmer about the failing case.
             | If it runs successfully, you just fail that one test with
             | the borrowck error. I would love it if we could have
             | something akin to prop test for borrowck so that even the
             | test isn't needed.
        
       ___________________________________________________________________
       (page generated 2023-12-23 23:01 UTC)