On Sat, Jan 7, 2017 at 4:00 PM, Braeden Profile via swift-evolution <
swift-evolution@swift.org> wrote:

> * One could workaround the problem and use final, but what if the class
> ** meant to be subtypeable? Self simply does not work in this scenario.
> *
> It works exactly as it should in this scenario. If A isn't final, then by
> definition it's impossible for A to make a copy of type Self. I see,
> however, what you mean, which is that you wish you could write a protocol
> requirement for a function that returns #Self.
>
> What do you mean?  Even with the limited `Self` support in Swift 3, I can
> write a very effective copying paradigm.
>

That was poor writing on my part. What I meant was that, exactly as you
show below, `Building.copy()` needs to invoke a method on a subclass to
obtain an instance of type `Self`. There is nothing that `Building` can do
without relying on its subclasses in order to obtain such an instance (I
can't imagine a use case _why_ one couldn't do that, but I understood
Adrian as saying that he has that problem).

protocol Copyable
> {
>       func copy() -> Self
> }
>
> class Building: Copyable
> {
>       var floors = 1
>       
>       required init()
>               {  }
>       
>       func copy() -> Self
>       {
>               let dynamicType = type(of: self)
>               let newObject = dynamicType.init()
>               newObject.floors = self.floors
>               
>               return newObject
>       }
> }
>
> class Mansion: Building
> {
>       var butlers = 3
>       
>       override func copy() -> Self
>       {
>       //      let newObject = super.copy()
>               let newObject = super.copy() as! Mansion
>               
>               newObject.butlers = self.butlers
>               
>       //      return newObject
>               return unsafeBitCast(newObject, to: type(of: self))
>       }
> }
>
>
> let hoboHouse = Building()
> hoboHouse.floors = 0
>
> let beggarHouse = hoboHouse.copy()
> print(beggarHouse.floors)  // "0"
>
>
> let myHouse = Mansion()
> myHouse.floors = 4
>
> let yourHouse = myHouse.copy()
> print(yourHouse.floors)  // “4”
>
> Besides the poor support for `Self` in the function body (SE–0068 fixes
> that), it seems like an acceptable way of doing it.
>

Agree, it's a shame that one needs to jump through that hoop with
`unsafeBitCast`. With SE-0068, I'd hope that `super.copy() as! Self` would
be sufficient.


> Of course, I would love being able to use an initializer setup, but there
> are serious bugs in the implementation.
>
> protocol Clonable
> {
>       init(other: Self)
> }
>
> extension Clonable
> {
>       func clone() -> Self
>               { return type(of: self).init(other: self) }
> }
>
>
> class Base: Clonable
> {
>       var x: Int
>       
>       init(x: Int)
>               { self.x = x }
>       
>       required init(other: Base)
>               { self.x = other.x }
> }
>
> class Derived: Base
> {
>       var y: String
>       
>       init(x: Int, y: String)
>       {
>               self.y = y
>               super.init(x: x)
>       }
>       
>       // Should be required by the Clonable protocol, but it isn't.
>       required init(other: Derived)
>       {
>               self.y = other.y
>               super.init(other: other)
>       }
>       
>       // Required because it was `required` in Base.  Even a `Derived` calls 
> this initializer to clone, which is wrong.  Bugs abound.
>       required init(other: Base)
>               { fatalError("init(other:) is wrong.") }
> }
>
>
>
> let me = Derived(x: 1, y: "food")
> let alienClone = me.clone() // "init(other:) is wrong."
>
>
Agree. That seems wrong. Great example.

_______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to