How much do you think about borrowing

I definitely think about borrowing at the design and signature stage. Honestly, I have to do that in languages like C# too: Is this shared? Is it ok if I modify this object? Should I make this class immutable so I don't need to worry about it? Can I reuse that Stream?

In many ways it's easier in Rust because I can actually make those things explicit in the code. I don't ever need to pass leaveOpen: true because that's phrased as ownership instead, for example. (And for extra fun, you have to be careful that you don't accidentally pass that for append instead -- yay overloading.)

Then in the method body, I certainly forget .copied() on iterators or miss mut in places or whatever sometimes, but I don't really worry about those. I think of those like missing semicolons, where the compiler helps me out if I was inconsistent somewhere.

Admittedly, this does rely on adapting your brain to think of these things for the signature. But sometimes the difficult borrowing errors are a sign that the signature was where the problem was -- there was a nice example of that in Return a reference from the function - #6 by scottmcm

I think the important part is that it's just ignoring it in other languages. If I pass an array to another function in Scala, does it modify it? I don't know. If I'm a class, can I give out an array to a caller? If they might modify it, maybe I can't without copying it.

That leads to either defensive copying -- either from the cache or the user, or worst both -- or the occasional weird error where the value in the cache got updated and now some things

So there's absolutely an advantage from all this, even if it's not immediately obvious. As quoted in https://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/,

My intuition is that code far away from my code might as well be in another thread , for all I can reason about what it will do to shared mutable state.

3 Likes