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