• calcopiritus@lemmy.world
    link
    fedilink
    arrow-up
    4
    ·
    edit-2
    12 hours ago

    There is no reference counting if the count is always one.

    The defining feature of reference counting is that its a runtime check. Which in turn results in a runtime performance.

    If there is no in memory counter at runtime, nobody calls that reference counting.

    • Log in | Sign up@lemmy.world
      link
      fedilink
      arrow-up
      2
      ·
      11 hours ago

      It’s not as simple as that.

      Roc does static reference counting too, otherwise it wouldn’t be able to do opportunistic in place mutation. It can do static reference counting up to a known compile time bound, whereas rust can only count to one. Both of them can do runtime reference counting, but it’s implicit in roc and explicit with Rc and Arc in rust.

      For example, consider the pseudocode
      {
      h = "Hello, "
      hw = h + "world."
      hm = h + "Mum!"
      }

      In real life, this could be something less swervable.

      Roc counts, at compile time, 1,2,3,0, drop. No problem.

      Depending on how you declare these variables (with what additional keywords, symbols, string types and concepts), rust counts, at compile time, 1,release,1,2! No no no stop broken! Bad programmer! This was in this case an unnecessary premature optimisation. That’s what I mean by rust counts references, but only counts up to 1.

      The borrow checker is a static reference counter with an arbitrary number of immutable references that you must declare explicitly and a maximum of one mutable reference that you declare explicitly with mut or let under different circumstances. Arc and Rc are runtime reference counters that you declare explicitly. This is essentially all tracked in the type system.

      Roc does the static reference counting and if the total doesn’t rise above rust’s maximum of 1, uses in place mutation (as opposed to the default immutability). If it is bounded it can use static (compile time) reference counting so that when, for example, all four local references fall out of scope, the memory is dropped. If the number is unbounded (eg parameter passing recursion that can’t be tail-cpseudocode ilarly removed), runtime reference counting is used. This is all essentially tracked in the runtime system, but calls to clone are automated in roc. A beginner absolutely can write a memory hog in roc, but the same beginner is likely to overuse clone in rust and write a similar memory hog.

      • calcopiritus@lemmy.world
        link
        fedilink
        arrow-up
        2
        ·
        9 hours ago

        I don’t know whatever that language is doing is called, but it’s not reference counting. It’s doing some kind of static code analysis, and then it falls back to reference counting.

        If you call that reference counting, what stops you from calling garbage collectors reference counting too? They certainly count references! Is the stack a reference count too? It keeps track of all the data in a stack frame, some of it might be references!

        • Log in | Sign up@lemmy.world
          link
          fedilink
          arrow-up
          1
          ·
          3 hours ago

          Garbage collection is pausing the main thread while you go searching the heap for memory to free up. It’s slow and unpredictable about when it’ll happen or how long it’ll take. That’s a very different process indeed and roc doesn’t do it.

          Whether you call it static reference counting or not, when roc chooses in-place mutation it’s because it would have satisfied the borrow checker. It can do a wider class of such things when stuff goes out of scope. There’s a webserver platform that does arena allocation, often swerving cache misses as a result, but crucially frees the entire arena in one step. Freeing up all the tiny little bits of memory for lots of individual stuff as you go along as rust would do would be far slower.

          Calling that kind of thing garbage collection is I think very misleading indeed.

          Optimising your memory management for each problem domain/platform actually give you memory management efficiencies.

    • Log in | Sign up@lemmy.world
      link
      fedilink
      arrow-up
      1
      ·
      10 hours ago

      runtime check. Which in turn results in a runtime performance.

      If you’re calling drop on a mutable string that’s been extended repeatedly, you’re recursively dropping all kinds of mess all over the heap. Checking for zero beforehand has an insignificant impact. Those cache misses you had because rust pays less attention to “where” than it does to “whether”, they cost you a lot more than the reference count check. In the real world, in practice, under profiling of real code, the cache misses and the branch misses are more expensive than the reference counting.

      You sound a little bit like a C programmer who claims his code is fast because his arrays don’t do bounds checking. That’s not why C is fast. Similarly rust isn’t fast because it never does runtime reference counting. It does sometimes, but that code isn’t pathologically slow.

      Also, rust isn’t just fast because of the borrow checker, primarily it’s memory safe because of the borrow checker.

      If it’s any consolation, afaik, most of the roc platforms are written in rust. Also afaik only application specific code is written in roc. There are no memory management primitives in roc code unless a platform author exposes them in their api/interface, and I don’t think anyone is working on implementing C on top of roc.

      • calcopiritus@lemmy.world
        link
        fedilink
        arrow-up
        2
        ·
        10 hours ago

        I don’t know what you read on my reply. But your reply makes no sense.

        Let me rephrase it if you prefer:

        Claiming that Rusty’s borrow checker is reference counting is hugely misleading. Since the borrow checker was made specifically to prevent the runtime cost of garbage collection and reference counting while still being safe.

        To anyone unaware, it may read as “rust uses reference counting to avoid reference counting, but they just call it borrow checking”. Which is objectively false, since rust’s solution doesn’t require counting references at runtime.

        I don’t know what mutable string or any of the other rant has to do with reference counting. Looks like you’re just looking to catch a “rust evangelist” in some kind of trap. Without even reading what I said.

        • Log in | Sign up@lemmy.world
          link
          fedilink
          arrow-up
          1
          ·
          2 hours ago

          A boolean is a non-negative integer with a maximum of one, often literally, but I see that calling the borrow checker a static reference counter with a maximum of one is frustrating you in the same way that you calling roc’s reference counting a garbage collector is frustrating me.

          The string example is because the thing you’re calling runtime overhead is cheap compared to freeing up a string that’s been extended even just a couple of times. It’s not a trap. It’s an example where freeing the string itself could be considerably more expensive than the DEC c and BRZ that you’re calling overhead.

          It’s a bit hypocritical to tell me off for not reading what you said when you haven’t bothered to figure out the relevance of the memory management examples I gave and just dismissed them out of hand as “rant” and a “trap”.