Skip to content

Instantly share code, notes, and snippets.

@manicaesar
Created September 24, 2021 19:10
Show Gist options
  • Save manicaesar/984ea25673b5dc412ce3fb05ea4deaa2 to your computer and use it in GitHub Desktop.
Save manicaesar/984ea25673b5dc412ce3fb05ea4deaa2 to your computer and use it in GitHub Desktop.
Swift property overloading
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
@manicaesar
Copy link
Author

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.

@Losiowaty
Copy link

Losiowaty commented Sep 26, 2021

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment