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
([email protected]) schrieb:
On Sat, Jan 7, 2017 at 5:33 PM, Braeden Profile <[email protected]> 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
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution