[swift-evolution] [Draft] Introducing StaticSelf, an Invariant Self

Matthew Johnson matthew at anandabits.com
Fri May 13 10:18:19 CDT 2016



Sent from my iPad

> On May 12, 2016, at 9:21 PM, Joe Groff <jgroff at apple.com> wrote:
> 
> 
>> On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> The invariant StaticSelf identifier will always refer to A, unlike Self, which is covarying and refers to
>> the type of the actual instance. Since multiple inheritance for non-protocol types is disallowed,
>> this establishes this invariant type identifier with no possibility for conflict.
>> 
>> Consider the following example, under the current system:
>> 
>> protocol StringCreatable 
>> {
>> 
>> static func createWithString(s: String) -> Self
>> 
>> }
>> 
>> 
>> extension NSURL: StringCreatable 
>> {
>> 
>> // cannot conform because NSURL is non-final
>> 
>> 
>> // error: method 'createWithString' in non-final class 'NSURL' must return `Self` to conform to protocol 'A'
>> 
>> }
>> 
>> Introducing a static, invariant version of Self permits the desired conformance:
>> 
>> protocol StringCreatable 
>> {
>> 
>> static func createWithString(s: String) -> StaticSelf
>> 
>> }
>> 
>> 
>> extension NSURL: StringCreatable 
>> {
>> 
>> // can now conform conform because NSURL is fixed and matches the static
>> 
>> 
>> // type of the conforming construct. Subclasses need not re-implement
>> 
>> 
>> // NOTE: the return type can be declared as StaticSelf *or* as NSURL
>> 
>> 
>> //       they are interchangeable
>> 
>> 
>> static func createWithString(s: String) -> StaticSelf
>> { 
>> 
>> // ...
>> 
>> }
>> }
> 
> As I've noted before, I don't think this makes sense to encode in the protocol. `Self` is already effectively invariant within a protocol.
> 
> As I've noted before, I don't think this makes sense to encode in the protocol. `Self` is already effectively invariant within a protocol.

'Self' is not invariant when used as a return type so I'm not sure what you mean.

> If a protocol doesn't have the foresight to use StaticSelf, then you still have the same problems retroactively conforming class hierarchies to the protocol.

True, but in many use cases we are in control of the protocol.  This has always been the case when I have personally encountered this problem.

> Whether a conformance is inherited or not feels more natural as a property of a conformance, not something that can be legislated a priori by a protocol definition.

This proposal does not allow protocols to legislate whether conformance is inherited or not.  It just allows the protocol to specify more precisely how requirements are inherited.   

When I write a class Base with non-final methods that return instances of Base I can choose whether to state the return type as Self (covariant) or Base (invariant, under this proposal StaticSelf would also be an alternative way to state this).  If I choose to specify Base as the return type derived classes *may* override the method but are not required to.  Further, if they *do* override the method they are allowed to choose whether their implementation returns Base or Derived.

I believe protocols should have the same flexibility.  If superclasses can control the variance of the return types of their inherited methods why shouldn't protocols be able to do so as well?  The weaker requirement can be very useful in some cases.

I think the case for StaticSelf is:

1. It is useful as a general substitute for the name of the containing type.
2. It solves real world use cases of providing protocol conformance.
3. It is a small change (on the surface, I can't speak to implementation) and may have a chance at making it into Swift 3.
4. The previous discussion about controlling conformance at the usage site didn't really seem to reach any conclusions.  My impression is that this is a feature that is difficult to design well and probably isn't going to be a priority, at least for a while.
5. StaticSelf is perfectly compatible with such a feature if it is introduced in the future.  

> 
> Something like StaticSelf might still be useful as shorthand within a class definition with a long-winded name, though `StaticSelf` feels kind of long as a shortcut to me.

That's a fair criticism for that use case.  Chris also mentioned that.  'Type' is the best shorter option we came up with.  We didn't go that route in the proposal because feels like it could be more confusing for those first learning it.  That said, we are willing to go with whatever the community decides on.  

If you like one of the alternatives better or have any new ideas please let us know...

> 
> -Joe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160513/272d6991/attachment.html>


More information about the swift-evolution mailing list