3 ms·
The database transaction example has another good reason to use a closure or callback: many databases can fail a transaction with an error saying it should be r
by amluto 3y ago
The database transaction example has another good reason to use a closure or callback: many databases can fail a transaction with an error saying it should be retried (due to a deadlock being detected). If the body is a closure or other callback, the wrapper can call it again.
- timmb 3y agoSounds like a cause for impossible to find bugs if the wrapper decides to reuse the callback in rare cases likely only existing in production. Might be better to let the end user handle this scenario in case they have side effects in their callback, like std::move.
- amluto 3y agoThis type of use case is why I wish more mainstream languages would have stricter concepts of purity and side effects. Conceptually, a function implementing the body of a database transaction should be idempotent. If a language had a function type that did not mutate global or closed-over variables and only affected the world by calling methods on its parameter, it would be difficult to mess up. Haskell can do this. Rust’s Fn(&mut txn) -> Ret is kind of close, but it doesn’t express that the function may not have mutable captures, and it does nothing about interior mutability or calling impure functions.