There are a few good points made here. It’s an interesting workaround to use 
type(of:) to get a similar behavior I wanted. My point is, that Current or call 
it static Self should exist to fill some gaps in our design patterns. Using 
Self in protocols should not always mean that you shall use the dynamic 
behavior. Yes on value types the dynamic type is the same conforming type.

// All these protocol do not compile
// This is not real world example, but IMO should be possible
protocol P : class {
     
    associatedtype StaticSelf : AnyObject
    func castOrTrap<T : StaticSelf>() -> T
}

protocol P : class {
     
    associatedtype StaticSelf : Self
    func castOrTrap<T : StaticSelf>() -> T
}

protocol P : class {
     
    func castOrTrap<T : Self>() -> T
}
The absence of static Self does hurt the flexibility of the language to design 
a specific but yet clear behavior. The P protocol is meant to have a static 
Self, where conforming to it would result in a shorthand version using 
StaticSelf/Current or the conforming type:

class A : P {
     
    func castOrTrap<T : Current>() -> T { … }
    // or
    func castOrTrap<T : A>() -> T { … }
}
I cannot think of a possible workaround here except of defining that method on 
the base type itself. If other not derived classes need to have this pattern, I 
cannot create an ancestor protocol as I might would like.

The forced required init might be a good workaround for the issue from some 
previous post, but is it really what we always wanted? This restriction lives 
only on the non-final classes because Self there is dynamic, which feels kinda 
inconsistent. As I already mentioned, I’d be happy if we could drop the 
restriction on the conforming type to allow the user to decide if we want to 
follow the contract of using self (lowercased) and type(of: self) or could 
simply override Self with ContainingTypeName. That would solve that issue, if 
I’m not totally missing here something.

But the issue from above remans unsolved. Furthermore, does dynamic Self make 
any sense on non-final classes as a parameter type? Can anyone show me a 
plausible code snippet for that?

Sure my arguments are more like might, want etc. and not that much of a weight, 
but that’s my honest opinion that some restrictions makes the language less 
flexible as it could be.

Self is exactly like .Type which might also be magically .Protocol. The static 
and dynamic behaviors are baked into one place. :/



-- 
Adrian Zubarev
Sent with Airmail

Am 8. Januar 2017 um 00:51:32, Xiaodi Wu via swift-evolution 
(swift-evolution@swift.org) schrieb:

On Sat, Jan 7, 2017 at 5:33 PM, Braeden Profile <jhaezhy...@gmail.com> wrote:

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.

So, is this odd behavior intentional, a bug, or a design deficiency?  I would 
think that when a protocol has a method or initializer has `Self` 
parameters—like in Clonable—every subclass would be required to implement its 
own specialized version (much like a required initializer).  That would be a 
special case of the protocol system, though.

As it sits, even fixing the calling behavior of my example leaves us with the 
problem of subclasses inheriting inapplicable required initializers from 
superclasses that actually don’t make any sense.

Does this deserve its own thread?

Dunno, maybe best to have its own thread. It's not mentioned as part of 
SE-0068, but IMO a complete design that respects the spirit of that proposal 
*should* involve allowing you to write:

```
class Base : Clonable {
  required init(other: Self) { ... }
}

class Derived : Base {
  required init(other: Self) { ... }
}
```


_______________________________________________
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