1. 26

  2. 7

    Interesting. What about iterator invalidation? That tends to be one of the more pernicious types of memory safety bugs IMO.

    1. 10

      Hare solves that by not having iterators, or the generics or closures you’d use to implement iterators. 🙃

      1. 12

        If you can have a pointer into an array then you can have iterator invalidation, even if you call it something else! :P

        …though every example I can find on the website uses for (let i = 0z; i < len(some_list); i += 1) { ... }, so maybe it can’t do that? Or at least it’s considered bad form.

        1. 3

          An index is effectively a logical pointer into an array (or, rather, into an array space, with may be realised by any number of actual arrays or functions at any given point in time), following which you can have ‘iterator invalidation’ problems any time someone mutates an array and you’re still holding onto an index corresponding to the previous state of the array.

          Like all ‘memory safety’ issues, it is irresponsible not to deal with it at the language level, but it will show up at the application level regardless.

          1. 2

            It’s a matter of degree. If you hold an index to an item in an array and the array mutates out from under you, that’s a bug, but bounds checking will catch the worst cases for it. If you hold a pointer to an item in an array and the array moves out from under you (say because it’s been reallocated), you’re now reading or writing unallocated memory and your life is hell.

            1. 2

              And preventing any of those bugs is the intent of the ownership and borrowing rules in safe Rust. Which can indeed be a pain to learn and work with for real-world code. I think the trade-off is worth it, but it will take a long time to persuade the rest of the industry.

              Not that you can’t generate a stale index into an array with safe Rust. For example, you can take a read-only reference, store the index of a desired array element, and then give up the read-only reference. If your code later takes another read-only reference, there’s no guarantee the previously saved index is valid. So if you find an index, and later want to do something at that index, it is best to maintain a read-only reference the entire time.

              1. 1

                Referential transparency is good, but rust’s encouragement of ‘functional in place updates’ is hardly conducive to effective treatment of this sort of thing. SQL and the relational algebra can be seen as an attempt to model this properly.

                1. 1

                  I don’t quite understand this comment. Do you mean that every thread should have its own view of the shared data, a la PostgreSQL’s MVCC and that they are all isolated from each other during a transaction? I really don’t understand.

                  1. 2

                    Ah, heh, I didn’t think at all about concurrency and transaction safety. The nominal (modulo abstraction) explication of access to shared resources does seem to give rust a slightly better showing here, doesn’t it?

                    I was mainly thinking of intra-thread concerns: the existence of relations means that items (rows) are identified by key, not index or (strong) pointer, so it is much harder to end up looking at a different row than you thought you were going to look at.

        2. 4

          I call this ‘the Go way of solving thorny language questions’ 🙃

          EDIT: I say this as someone who wrote the whole backend for his startup in Go.

          1. 1

            There are always more problems to be solved, I guess people just differ in where they draw the line.

        3. 2

          It definitely doesn’t solve everything, another problem not addressed is returning the address of a stack local variable. I guess I would say the solutions don’t have to be perfect and are not necessarily as out of control as some people would have you believe.