Hi all, I just want to raise an issue. I currently don't have any concrete ideas about it, but I believe we should discuss this before ABI stabilization. Default implementation for mutating methods
Swift protocol extension allows assigning to self in default implementations for mutating methods: protocol Resettable { mutating func reset() init() } extension Resettable { mutating func reset() { self = Self() // Assigning to 'self'. } } And you can: class Foo : Resettable { var value: Int required init() { value = 0 } } In this example, Foo class conforms to Resettable, by the default implementation of mutating func reset(). However, this can cause an unexpected behavior for classes: var ref1 = Foo() let ref2 = ref1 assert(ObjectIdentifier(ref1) == ObjectIdentifier(ref2)) ref1.value = 42 assert(ObjectIdentifier(ref1) == ObjectIdentifier(ref2)) ref1.reset() assert(ObjectIdentifier(ref1) != ObjectIdentifier(ref2)) assert(ref1.value == 0) assert(ref2.value == 42) From the perspective of the caller, I think, this behavior is counterintuitive because we use "reference types" with an expectation: the referencing address would never be changed *unless* we explicitly replace the object by re-assigning to the variable in call sites, e.g., var ref: Foo = Foo() ref = Foo() <https://gist.github.com/rintaro/e9d606e2a6d833a043cf43a9a3e14670#default-implementation-for-initializers>Default implementation for initializers Similar to methods, initializers also have this issue: protocol HasDefault { static var _default: Self { get } init() } extension HasDefault { init() { self = Self._default // Here it is. } } final class Foo : HasDefault { let value: Int init(value: Int) { self.value = value } static var _default = Foo(value: 0) } let obj = Foo() assert(obj.value == 0) This behavior allows us to implement a kind of "factory initializer". protocol Factory { init(factory: () -> Self) } extension Factory { init(factory: () -> Self) { self = factory() } } class Animal { var emoji: Character { return "❓" } } class Cat : Animal { override var emoji: Character { return "🐱" } } class Dog : Animal { override var emoji: Character { return "🐶" } } extension Animal : Factory { convenience init(type: String) { self.init(factory: { switch type { case "dog": return Dog() case "cat": return Cat() default: return Animal() } }) } } assert(Animal(type: "dog").emoji == "🐶") I believe this is *NOT* a right way of implementing factory initializers. We should introduce a proper "factory initializer" syntax, as discussed in this ML before. Any thought? Do we want to leave them AS IS in Swift4?
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution