struct Protect<T: ~Copyable>: ~Copyable {
let locker: NSLock = NSLock()
var storedValue: T
init(_ storedValue: consuming T) {
self.storedValue = storedValue
}
@discardableResult
mutating func safe<R: ~Copyable>(_ execute: (inout T) throws -> sending R) rethrows -> sending R {
locker.lock()
defer {
locker.unlock()
}
let result = try execute(&self.storedValue)
// Returning task-isolated 'result' risks causing data races since the caller assumes that 'result' can be safely sent to other isolation domains
return result
}
}
I don't understand why I got the error as result is disconnected.
Anecdotally, I have also been having a lot of trouble with sending and understanding when I can/can't/should/shouldn't use it. Honestly, just marking everything I can as Sendable and using nonisolated(unsafe)/@unchecked Sendable when necessary has been a lot easier than trying to figure out why I can't make it work right.
Well I just checked, and this code compiles error-free with the 6.1 snapshot. So it looks like this was indeed a bug/limitation that has been addressed.
The implementation was quite conservative in 6.0, but it is improving a lot with 6.1. Many of my own issues have been resolved in that release as well.