> On Dec 28, 2015, at 8:49 AM, Matthew Johnson via swift-evolution 
> <[email protected]> wrote:
> 
> I have brought up the idea of a non-covarying Self a few times.  
> 
> I was surprised to realize that Self is actually non-covarying when used for 
> parameters in protocol declarations!
> 
> Here is an example demonstrating this:
> 
> protocol P {
>    func foo(s: Self)
> }
> protocol Q {
>    func bar() -> Self
> }
> 
> class C: P {
>    // this works!  Self as an argument type in the protocol declaration does 
> not covary
>    func foo(c: C) {}
> }
> 
> class D: C {}
> 
> extension C: Q {
>    // method ‘bar()’ in non-final class ‘C’ must return ‘Self’ to conform to 
> protocol ‘Q'
>    func bar() -> C { return self } 
> }
> 
> 
> It doesn’t make sense to allow a co-varying Self for parameters so I can 
> understand how the current state might have arisen.  At the same time, using 
> Self to mean two different things is inconsistent, confusing and it doesn’t 
> allow us to specify a non-covarying Self as a return type in protocol 
> requirements.  
> 
> As I have pointed out before, the ability to specify a non-covarying Self as 
> a return type would make it possible to design a protocol that can be 
> retroactively conformed to by non-final classes (such as those in Apple’s 
> frameworks).
> 
> I think it would be a very good idea to introduce a non-covarying Self which 
> would specify the type that adds conformance to the protocol and require this 
> Self to be used in places where covariance is not possible, such as parameter 
> types.  It would also be allowed elsewhere, such as return types, making it 
> easier to conform non-final classes when covariance is not required by the 
> protocol.
> 
> One possible name is `ConformingSelf`.  One thing I like about this name is 
> that it makes it very clear that it is the type that introduces protocol 
> conformance.
> 
> I’m interested in hearing thoughts on this.

I proposed this a while back — see "controlling protocol conformance 
inheritance" from a while back. The current rules preserve inheritability of 
the protocol conformance in all cases. `Self` in argument positions maps to the 
root class of the conformance, since a method taking `Base` can also take any 
`Derived` class and thereby satisfy the conformance for `Derived`. In return 
positions, the derived type must be produced. I think there's value in 
controlling this behavior, but the control belongs on the conformer's side, not 
the protocol's. For some class hierarchies, the subclasses are intended to be 
API themselves in order to extend behavior. Every UIView subclass is 
interesting independently, for example, and ought to satisfy `NSCoding` and 
other requirements independently. In other class hierarchies, the base class is 
intended to be the common API, and subclasses are just implementation details. 
NSString, NSURL, etc. exemplify this—for most purposes the common `NSCoding` 
implementation is sufficient for all NSStrings. Likewise, you probably want 
NSURL to conform to `StringLiteralConvertible` but don't particularly care what 
subclass you get out of the deal. I had proposed the idea of modifying a 
class's conformance declaration to allow it control whether the conformance is 
inherited:

extension NSString: static NSCoding { } // NSCoding conformance statically 
applies to only NSString, Self == NSString
extension UIView: required NSCoding { } // NSCoding conformance is required of 
all subclasses, Self <= UIView

-Joe
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to