Issue
Could someone please have a look at the following code and tell me whether this is a bug or expected behavior?
Based on my knowledge of Swift it doesn't seem like this should be happening, but perhaps I'm misunderstanding something.
Protocols
Given the following protocols:
public protocol LogWriter {
func write<T: LogEvent>(_ logEvent: @autoclosure () -> T)
}
public protocol LogEvent {
var write: ((LogWriter) -> Void)? { get }
}
public protocol DefaultEvent: LogEvent {}
Implementations
And given the following basic implementations of the protocols:
public struct Writer: LogWriter {
public init() {}
}
public struct DefaultLogEvent: DefaultEvent {
public init() {
self.write = { [self] (logWriter: LogWriter) in
logWriter.write(self)
}
}
public var write: ((LogWriter) -> Void)? = nil
}
Extensions
And given the following extension of LogWriter
protocol:
extension LogWriter {
public func write<T: LogEvent>(_ logEvent: @autoclosure () -> T) {
print("logEvent: \(T.self)")
}
public func write<T: DefaultEvent>(_ logEvent: @autoclosure () -> T) {
print("defaultEvent: \(T.self)")
}
}
The Problem
Given all the above, when I run the following code:
let writer = Writer()
let defaultEvent = DefaultLogEvent()
defaultEvent.write?(writer)
... then I would expect that write<T: DefaultEvent>(...)
above would run and print "defaultEvent: defaultLogEvent" to the console.
However, instead, write<T: LogEvent>(...)
runs and prints "logEvent: DefaultLogEvent".
Why? This is a bug, right?
I mean, DefaultLogEvent
clearly conforms to DefaultEvent
, which is a sub-protocol of LogEvent
, so why is the compiler ignoring write<T: DefaultEvent>(...)
?
It Gets Weirder...
Note that if we add the following extension:
extension LogWriter {
public func write(_ logEvent: @autoclosure () -> DefaultLogEvent) {
print("DefaultLogEvent! WTAF")
}
}
Then it gets called as expected (instead of write<T: LogEvent>(...)
).
So why does overloading the generic function with a more specialized protocol fail, while overloading the generic function with a non-generic function succeeds?
Current workaround
UPDATE: I found a workaround, which is to change the declaration of LogWriter
to just be an empty protocol:
public protocol LogWriter {}
Now, the correct function func write<T: DefaultEvent>(...)
gets called in the extension on LogWriter
.
But why does this workaround work?
I do not understand.