4 ms·
I would still consider myself a go novice, but I have been burned a number of times passing simple objects by reference and then that object gets mutated causin
by __turbobrew__ 4y ago
I would still consider myself a go novice, but I have been burned a number of times passing simple objects by reference and then that object gets mutated causing subtle bugs. Also, go is happy to blow your foot off if you take the reference of a loop variable. Although, there is a proposal to fix that.
Generally I find that less bugs get introduced when using copy instead of pass by reference, but I’m sure others have the opposite opinion.
- deleted 4y ago[deleted]
- mcguire 4y agoI have had the same results. Passing by copy is simpler and less bug-prone and reduces the urge to "just set the value since I have a reference to the object" which is a well-paved road to significant pain. And the objects have to get surprisingly large before passing by reference really makes a difference.
- db48x 4y agoThat kind of problem doesn't happen in Rust though, because if all you have is a reference then you cannot mutate anything. You can only mutate things if you have a mutable reference to them, which makes the caller jump through hoops to acquire one for you. They may have to have ownership of the thing, or use a Mutex or RWLock to acquire exclusive access to it, before they can call your method. Nothing can be mutated by accident, or in a surprising place.
- 411111111111111 4y agoThis is about rust though and thats not really possible there (at least to my knowledge). You should get a compiler error if you attempt this. I got very little experience in rust though, so there might be a way (I'm just not aware of) to circumvent this check
- maxbond 4y agoIndeed, you can use interior mutability to accomplish this: https://doc.rust-lang.org/reference/interior-mutability.html https://doc.rust-lang.org/reference/interior-mutability.html Usually (read: near universally) something that provides interior mutability will implement a runtime check to protect you (eg, a lock), but you could make a footgun if you were cavalier about it. And recent I misused a framework (I kept a value returned by the framework around that should've been dropped) without realizing it was holding locks internal to the framework, and ended up with a tricky to diagnose deadlock (though only tricky before I hadn't read the documentation as closely as I should've).
- touisteur 4y agoOuch, I actually feel Ada was right in having the for-loop 'variable' be constant inside the body of the loop. If you want a modifiable loop variable, use a loop/while loop, but at least the first question in peer-review becomes 'why not a for-loop here'?
- throwaway894345 4y agoI don’t think that solves the problem because the loop itself still needs to mutate the variable. The issue often arises when people fork a new goroutine that closes over the loop variable inside the loop body—the loop often completes before any of the threads start running, so many/all of the threads read the loop variable at its max value (e.g., if we are forking 10 goroutines that just print their loop variable and quit, then there’s a good chance every goroutine will print 10 rather than printing 1-10).
- touisteur 4y agoWouldn't any sane fork system capture the value of the loop variable instead of a reference to it? Why would anyone ever want to capture a reference to a loop variable that will be moved under one's feet? I'm sorry I'm struggling to understand what we're doing here and why.
- throwaway894345 4y agoNo, the capturing is done by the closure and as far as I know capturing by reference is pretty standard for closures across languages. The forking system just runs the closure in a thread, agnostic to any capturing details.
- throwaway894345 4y agoYeah, const semantics are one of many things I would have preferred to have in Go over generics. You can sort of emulate them with pass by copy, but (1) that has performance implications and (2) if your data contains a reference, that can still be mutated.