currently, the Mutex
type's locking method has the following signature:
public borrowing func withLock<Result: ~Copyable, E: Error>(
_ body: (inout sending Value) throws(E) -> sending Result
) throws(E) -> sending Result
i'd like to focus on the Result: ~Copyable
generic constraint, as i don't quite understand its motivation, nor the current apparent behavior. my interpretation is that this constraint implies that the value returned from the body
closure must be a ~Copyable
type. would this then preclude the ability to do something like make a copy of the mutex-protected data and return it from the withLock
closure? e.g.
let protectedState = Mutex(1)
let doubled = protectedState.withLock { 2*$0 } // `Result` type is `Int`, which does not conform to `~Copyable`
assuming this assessment is accurate – what is the motivation for the ~Copyable
constraint here?
secondly, is the ~Copyable
constraint on the Result
type in the prior example actually being enforced by the compiler today? it appears to compile without issue, and allows Copyable
types to be returned from the closure. this is somewhat surprising since analogous formulations that require a particular conformance on their generic parameters do not behave analogously. e.g.
func returnSomeNonCopyable<Result: ~Copyable>(
_ body: () -> Result
) -> Result {
body()
}
protocol P {}
func returnSomeP<Result: P>(
_ body: () -> Result
) -> Result {
body()
}
let works = returnSomeNonCopyable { 42 }
let fails = returnSomeP { 42 } // 🛑 Global function 'returnSomeP' requires that 'Int' conform to 'P'