As I mentioned above, what I have now is something like this:
public protocol CallType: Sendable {
associatedtype Callback: Sendable
}
public enum SyncCall: CallType {
public typealias Callback = @Sendable () throws -> Void
}
public enum AsyncCall: CallType {
public typealias Callback = @Sendable () async throws -> Void
}
struct Container<Call: CallType> {
let description: String
let block: Call.Callback
init(_ description: String, executing block: @escaping Call.Callback)
where Call == SyncCall {
self.description = description
self.block = block
}
init(_ description: String, executing block: @escaping Call.Callback)
where Call == AsyncCall {
self.description = description
self.block = block
}
}
@escaping
is required there since I'm storing the callback, but I can only use it if the type I'm talking about is known by the compiler to be a function type. Thus I have to have two copies of the initializer, differing only in the where
clause, so the compiler knows I'm talking about SyncCall.Callback
and AsyncCall.Callback
which are function types.
But if we had a built-in protocol for that - let's pretend it's called FunctionType
- then I'm thinking I could do it this way:
public protocol CallType: Sendable {
associatedtype Callback: Sendable, FunctionType
}
// same SyncCall and AsyncCall as above
struct Container<Call: CallType> {
let description: String
let block: Call.Callback
// Just one version of the initializer because Call.Callback conforms
// to FunctionType and so @escaping can be applied.
init(_ description: String, executing block: @escaping Call.Callback) {
self.description = description
self.block = block
}
}