public borrowing func withLock<Result: ~Copyable, E: Error>(
_ body: (transferring inout State) throws(E) -> transferring Result
) throws(E) -> transferring Result
But on Darwin platforms the body closure is marked @Sendable preventing non sendable values being transferred in to replace the protected state:
let state = Mutex(NonSendable())
let ns = NonSendable()
state.withLock { $0 = ns } // ❌ Capture of 'ns' with non-sendable type 'NonSendable' in a `@Sendable` closure
On Linux the closure is not marked @Sendable but, but a different error:
error: 'inout sending' parameter '$0' cannot be task-isolated at end of function
This should be fixed in a future version of Xcode.
ns is still accessible outside of the lock. The value in the mutex needs to be uniquely owned or at least not accessible by the rest of the function body:
let state = Mutex(NonSendable())
state.withLock { $0 = NonSendable() }
The escape hatch is to box the non sendable to transfer it in, but its up to the developer to no longer use the original value:
struct Transferring<T>: @unchecked Sendable { .. }
let t = Transferring(ns)
state.withLock {
$0 = t.value
}
I guess its impossible for closures to capture with sending / consuming because the closure can still be executed multiple times even if its not escaping...
state.withLock { [sending ns] in
$0 = ns
}
If closures could be enforced to execute one-time-only then they could
capture with sending — I'm not sure what this feature would be called to search these forums for my own interest.