Protocol types cannot be retroactively marked `Sendable`. now what?

well, i’ve run into a dilemma:

websocket.swift:176:13: warning: stored property 'channel' of 
'Sendable'-conforming generic struct 'Session' has non-sendable 
type 'Channel'
        let channel:Channel 
            ^
.build/checkouts/swift-nio/Sources/NIOCore/Channel.swift:105:17: note: protocol 'Channel' does not conform to the 'Sendable' protocol
public protocol Channel: AnyObject, ChannelOutboundInvoker {

of course, Channel is a protocol existential type, so the usual solution - adding an :@unchecked Sendable extension doesn’t work.

this issue cropped up while using SwiftNIO, but it probably affects all libraries that expect users to pass around protocol existential types across concurrency domains. do we need a new solution for this?

1 Like

You can use a wrapper type:

@propertyWrapper
struct UnsafeTransfer<Wrapped> : @unchecked Sendable {
  var wrappedValue: Wrapped
  init(wrappedValue: Wrapped) {
    self.wrappedValue = wrappedValue
  }
}

Ref: swift-evolution/0302-concurrent-value-and-concurrent-closures.md at main · apple/swift-evolution · GitHub

3 Likes

We raised this issue with @Douglas_Gregor and @beccadax, and they have a strategy for managing this using the @predatesConcurrency attribute. This will likely need further enhancements, but they can speak to the approach.

1 Like

@preconcurrency makes sense for a protocol that should always imply Sendable, which Channel is a good candidate for. Until that happens, client code could use Channel & Sendable.

Doug

Terms of Service

Privacy Policy

Cookie Policy