3 ms·
What's the equivalent in rust of defer? E.g. this code in Go is buggy: mu.Lock(); fmt.Print(someoneElsesObject);mu.Unlock();return You need to get into the ha
by knorker 6y ago
What's the equivalent in rust of defer? E.g. this code in Go is buggy:
mu.Lock(); fmt.Print(someoneElsesObject);mu.Unlock();return
You need to get into the habit of writing:
mu.Lock(); defer mu.Unlock(); fmt.Print(someoneElsesObject);return
And this gets extra complicated by the fact that in Go defer runs at end of function, not end of scope. This makes every single for-loop that needs to lock anything hard to read and annoying to write.
for _, a := range stuff { if err:=func()error { mu.Lock();defer mu.Unlock(); return a.stuff()}(); err != nil {return err}}
- steveklabnik 6y agoYou use RAII, to put it in C++ terms. To use your variable names, someoneElsesObject is inside mu, and is returned by mu.lock. When it goes out of scope, it will unlock. You can also use defer if you want, but I've never seen it in real code, it's more error-prone and not as flexible. You can build it on top of RAII.
- knorker 6y agoI'm not following what you're saying. I'm saying "mu.Unlock()" except when deferred, is essentially always a bug. At the very least it's a bug waiting to happen. You need to prove that everything between Lock and Unlock is exception-safe. And that's rarely possible. As I've said elsewhere you cannot rely on panic triggering program exit, since e.g. HTTP handlers swallow panics. The fact that you seem to be saying you never see an Unlock deferred proves my point that saying "Go doesn't have exceptions" hurts Go programming. And Go code is in fact full of bugs because there's all this exception-unsafe code. C++ is naturally exception safe, because RAII. Where it's not exception safe it's because RAII was not used. Even something as simple as: mu.Lock() stats[metricName]++ mu.Unlock() will throw if there's a path where stats[] map was not inited, and if called in an HTTP handler will leave the lock in place, leading to probably a deadlock of the server. Not great.
- steveklabnik 6y agoThe Rust code would be, roughly (I tried to keep names similar even though Rust would use a slightly different naming scheme) let someoneElsesObject = mu.lock(); println!("{}", someoneElsesObject); return; when someoneElsesObject goes out of scope, the mutex is unlocked. This happens no matter how it goes out of scope. You cannot forget to do it, because the only way to get access to someoneElsesObject in the first place is locking the mutex, because mutexes wrap the data that they are protecting. https://crates.io/crates/defer https://crates.io/crates/defer exists, but it would be weird to try and use it here, because it can't really be combined directly with this. I guess in theory you could put drop(someoneElsesObject) in the defer block, but like... that already happens for free.
- knorker 6y agoAh, that looks neat. Among my huge backlog project list, learning Rust is on there. Yeah looks more RAII, and looks like it would not have the problem Go has. Thanks.
- fxtentacle 6y agoIn go, you can just inline a lambda to force defer to adhere to any scope that you the programmer decide upon. func(){ Code for lock and deferred unlock here }()
- knorker 6y agoWell, no you can't, because that leaves no way to directly return from the function. Hence my example where the lambda has to return an error, and the loop has to check for the error. It's A LOT of boilerplate. Edit: Actually now I don't know what you mean. You clearly replied to my comment that gave a clear example with a return from within the lambda, so what did you think that I didn't know? You took my example and removed extremely commonly needed functionality. So… huh?