-
-
Save manicaesar/984ea25673b5dc412ce3fb05ea4deaa2 to your computer and use it in GitHub Desktop.
struct StructWithTwoObjects { | |
let object: String | |
/* | |
var object: A { // Stupid, but causes compilation error - OK! | |
return self | |
} | |
*/ | |
} | |
// --------------------- | |
protocol SomeProtocol {} | |
protocol ObjectProviding { | |
associatedtype ObjectType: SomeProtocol | |
var object: ObjectType { get } | |
} | |
extension ObjectProviding where | |
Self: SomeProtocol, // It is not needed, can be commented out | |
Self.ObjectType == Self { | |
var object: ObjectType { | |
return self | |
} | |
} | |
struct ObjectContainer: SomeProtocol, ObjectProviding { | |
let object: String | |
init(object: String) { | |
self.object = object | |
} | |
} | |
struct ObjectPrinter<T: ObjectProviding> { | |
let objectContainer: T | |
init(objectContainer: T) { | |
self.objectContainer = objectContainer | |
} | |
func printTypeOfContainedObject() { | |
return print(type(of: objectContainer.object)) | |
} | |
} | |
let objectContainer = ObjectContainer(object: "string") | |
let printer = ObjectPrinter<ObjectContainer>(objectContainer: objectContainer) | |
print(type(of: objectContainer.object)) // Prints: String | |
printer.printTypeOfContainedObject() // Prints: ObjectContainer |
O wow! That's a super interesting thread, glad you found it ❤️
While it's (a little) reassuring that this is expected and well-defined behavior, I don't think I personally like the potential implications of all of this, especially when we move this discussion to consider cross-framework implications.
Since in your merged sample we see that we can force different value
to be used by giving some hints to the compiler than this becomes possible :
// Assume this is in External Module
protocol Provider {
var value: Int { get }
func fvalue() -> Int
}
extension Provider {
var value: Int { 0 }
}
// -------
// And now in Our Module
struct Struct: Provider {
var value: String { "1" }
// Provider conformance
func fvalue() -> Int { return 1 }
}
func takeInt(_ i: Int) { print(i) }
takeInt(Struct().value)
This can be unexpected from the External Module
consumer perspective - the compiler obviously told them that they need to implement func fvalue()
to fulfil the requirements but in no other way hinted them that there are other requirements that have default values - so they aren't aware that they "silently" have an Int
property and would (rightfully so!) expect this to fail, or maybe assume that there is a conversion happening under the hood (conversion from Int
to String
would be more natural, but still)
Not to mention the samples that Xiaodi Wu and Marc Palmer mentioned in their posts 🤯
It can easily lead to a whole lot of errors that may be confusing to track down.
Ok, I have found this thread: https://forums.swift.org/t/concerned-about-this-protocol-extension-conformance-bug/9687
And I guess we can assume Ben Cohen's response is official explanation (not a bug, if we want to change it, it is a feature request 😀)
https://forums.swift.org/t/concerned-about-this-protocol-extension-conformance-bug/9687/5
Though looks like this never got enough traction to at least provide "near-miss warning" from the compiler.