[Draft] Introducing StaticSelf, an Invariant Self


(Matthew Johnson) #1

Erica Sadun and I have written a proposal are following up the recent discussion thread "[RFC] #Self” with a proposal to introduce StaticSelf, an invariant Self.

The recent discussion can be found here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

The proposal can be found here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

We look forward to continuing the discussion. We plan to submit a PR in the near future after incorporating your final feedback.

Thanks,
Matthew
Introducing StaticSelf, an Invariant Self

Proposal: TBD
Authors: Matthew Johnson <https://github.com/anandabits>, Erica Sadun <https://github.com/erica>
Status: TBD
Review manager: TBD
Introduction

This proposal introduces a new keyword that provides consistent invariant type semantics in all contexts.

The Swift-evolution thread about this topic can be found here: [RFC] #Self <http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565>
Motivation

The distinction between covariant and non-covariant type references come into play when
conforming non-final classes to protocols. Fixing a protocol requirement to a covarying type
means that a method returning Self must be overriden by all subclasses in order to return
the correct, matching type.

This proposal builds on the covariant construct Self accepted in SE–0068 <https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md>
to introduce an invariant type identifier. It enables protocol declarations to consistently
refer to a type that is fixed at compile time. This ensures that subclasses can inherit
protocol implementations without having to re-implement that code at each level of
inheritance.

Under this proposal, a new identifier keyword is fixed in use at the point of protocol conformance
to the static type of that construct.

class A: MyProtocol
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 {
     // ...
}
}
Additional Utility

The utility of StaticSelf is not limited to protocols. A secondary use enables code to refer to the lexical context’s current type without explicitly mentioning its name. This provides a useful shortcut when referencing static type members with especially long names and when re-purposing code between types.

class StructWithAVeryLongName {
    static func foo() -> String {
      // ...
    }
    func bar() {
      // ...
      let s = StaticSelf.foo()
      //
    }
}
Detailed Design

This proposal introduces StaticSelf, a new keyword that may be used in protocols to refer to the invariant static type of a conforming construct. StaticSelf may also be used in the lexical context of any type declaration. In such use, the keyword is identical to spelling out the full name of that type.

Impact on existing code

Being additive, there should be no impact on existing code.

Alternatives considered

The keyword is not fixed at this time. Alternatives that have been discussed include StaticType, InvariantSelf, SelfType, or Type. The community is welcome to bikeshed on the most clear and concise name for this keyword.


(Joe Groff) #2

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. 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. 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.

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.

-Joe

···

On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@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
{
     
// ...

}
}


(Xiaodi Wu) #3

I like the way the motivation for this feature has been explained here. Now
that the reasoning behind it is evident, I have to say I'm leaning towards
the "InvariantSelf" name--after all, you describe this feature in the title
as "an invariant self."

···

On Thu, May 12, 2016 at 7:49 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

Erica Sadun and I have written a proposal are following up the recent
discussion thread "[RFC] #Self” with a proposal to introduce StaticSelf, an
invariant Self.

The recent discussion can be found here:
http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

The proposal can be found here:
https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

We look forward to continuing the discussion. We plan to submit a PR in
the near future after incorporating your final feedback.

Thanks,
Matthew
Introducing StaticSelf, an Invariant Self

   - Proposal: TBD
   - Authors: Matthew Johnson <https://github.com/anandabits>, Erica Sadun
   <https://github.com/erica>
   - Status: TBD
   - Review manager: TBD

Introduction

This proposal introduces a new keyword that provides consistent invariant
type semantics in all contexts.

*The Swift-evolution thread about this topic can be found here: [RFC]
#Self <http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565>*
Motivation

The distinction between covariant and non-covariant type references come
into play when
conforming non-final classes to protocols. Fixing a protocol requirement
to a covarying type
means that a method returning Self must be overriden by all subclasses in
order to return
the correct, matching type.

This proposal builds on the covariant construct Self accepted in SE–0068
<https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md>
to introduce an invariant type identifier. It enables protocol
declarations to consistently
refer to a type that is fixed at compile time. This ensures that
subclasses can inherit
protocol implementations without having to re-implement that code at each
level of
inheritance.

Under this proposal, a new identifier keyword is fixed in use *at the
point of protocol conformance*
to the static type of that construct.

class A: MyProtocol

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 {
     // ...
}
}

Additional Utility

The utility of StaticSelf is not limited to protocols. A secondary use
enables code to refer to the lexical context’s current type without
explicitly mentioning its name. This provides a useful shortcut when
referencing static type members with especially long names and when
re-purposing code between types.

class StructWithAVeryLongName {
    static func foo() -> String {
      // ...
    }
    func bar() {
      // ...
      let s = StaticSelf.foo()
      //
    }
}

Detailed Design

This proposal introduces StaticSelf, a new keyword that may be used in
protocols to refer to the invariant static type of a conforming construct.
StaticSelf may also be used in the lexical context of any type
declaration. In such use, the keyword is identical to spelling out the full
name of that type.
Impact on existing code

Being additive, there should be no impact on existing code.
Alternatives considered

The keyword is not fixed at this time. Alternatives that have been
discussed include StaticType, InvariantSelf, SelfType, or Type. The
community is welcome to bikeshed on the most clear and concise name for
this keyword.

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


(Thorsten Seitz) #4

+1

Good description of the motivating problem!

As for bikeshedding: ConformingSelf, ConformingType, BaseSelf, BaseType

-Thorsten

···

Am 13.05.2016 um 02:49 schrieb Matthew Johnson via swift-evolution <swift-evolution@swift.org>:

Erica Sadun and I have written a proposal are following up the recent discussion thread "[RFC] #Self” with a proposal to introduce StaticSelf, an invariant Self.

The recent discussion can be found here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

The proposal can be found here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

We look forward to continuing the discussion. We plan to submit a PR in the near future after incorporating your final feedback.

Thanks,
Matthew
Introducing StaticSelf, an Invariant Self

Proposal: TBD
Authors: Matthew Johnson, Erica Sadun
Status: TBD
Review manager: TBD
Introduction

This proposal introduces a new keyword that provides consistent invariant type semantics in all contexts.

The Swift-evolution thread about this topic can be found here: [RFC] #Self

Motivation

The distinction between covariant and non-covariant type references come into play when
conforming non-final classes to protocols. Fixing a protocol requirement to a covarying type
means that a method returning Self must be overriden by all subclasses in order to return
the correct, matching type.

This proposal builds on the covariant construct Self accepted in SE–0068
to introduce an invariant type identifier. It enables protocol declarations to consistently
refer to a type that is fixed at compile time. This ensures that subclasses can inherit
protocol implementations without having to re-implement that code at each level of
inheritance.

Under this proposal, a new identifier keyword is fixed in use at the point of protocol conformance
to the static type of that construct.

class A: MyProtocol
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 {
     // ...
}
}
Additional Utility

The utility of StaticSelf is not limited to protocols. A secondary use enables code to refer to the lexical context’s current type without explicitly mentioning its name. This provides a useful shortcut when referencing static type members with especially long names and when re-purposing code between types.

class StructWithAVeryLongName {
    static func foo() -> String {
      // ...
    }
    func bar() {
      // ...
      let s = StaticSelf.foo()
      //
    }
}
Detailed Design

This proposal introduces StaticSelf, a new keyword that may be used in protocols to refer to the invariant static type of a conforming construct. StaticSelf may also be used in the lexical context of any type declaration. In such use, the keyword is identical to spelling out the full name of that type.

Impact on existing code

Being additive, there should be no impact on existing code.

Alternatives considered

The keyword is not fixed at this time. Alternatives that have been discussed include StaticType, InvariantSelf, SelfType, or Type. The community is welcome to bikeshed on the most clear and concise name for this keyword.

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


(David Hart) #5

Totally agree. It feels weird to have protocols decide on how "Self" conformance a are inherited. It should a decision for the conforming type.

···

On 13 May 2016, at 04:21, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@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. 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. 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.

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.

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


(Nicola Salmoria) #6

Matthew Johnson via swift-evolution <swift-evolution@...> writes:

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
}

I'm not convinced by this example.

I think the problem to solve here is the interaction of protocols with
classes.
A related issue was illustrated by Tony Allevato here
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502
/016294.html

I think that before attempting to solve this specific problem introducing a
new notation, the general design of the interaction between protocols and
class inheritance should be reviewed.

Nicola


(Vladimir) #7

How about BaseType? (as just `Type` can not be used here) Or ThisType?

And, do you think we actually should use `#` here in analogue to #file as this `StaticSelf` will be pre-processed on compilation stage to be replaced with actual type name?

···

On 13.05.2016 5:21, Joe Groff via swift-evolution wrote:

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.


(Matthew Johnson) #8

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...

···

Sent from my iPad

On May 12, 2016, at 9:21 PM, Joe Groff <jgroff@apple.com> wrote:

On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

-Joe


(Vladimir) #9

Why did you decide to drop the `#` ? As `StaticSelf` will be resolved on compilation time like #file etc ? I feel like this is inconsistent solution.

Also, do you expect this will work:

protocol A {
   func g()->StaticSelf
}

class B: A {
   func g()->StaticSelf {return B()}
}

class C: B {
   //func f(s: C) {}
}

func x(a: A ){
     var xx : A = a.g() // ?
     print(xx)
}

func z<T: A>(t: T) {
     let u = t.g() // ?
     print(u)
}

let c = C()
z(c)
x(c)

···

On 13.05.2016 3:49, Matthew Johnson via swift-evolution wrote:

Erica Sadun and I have written a proposal are following up the recent
discussion thread "[RFC] #Self” with a proposal to introduce StaticSelf, an
invariant Self.

The recent discussion can be found
here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

The proposal can be found
here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

We look forward to continuing the discussion. We plan to submit a PR in
the near future after incorporating your final feedback.

Thanks,
Matthew

  Introducing StaticSelf, an Invariant Self

  * Proposal: TBD
  * Authors: Matthew Johnson <https://github.com/anandabits>, Erica Sadun
    <https://github.com/erica>
  * Status: TBD
  * Review manager: TBD

    Introduction

This proposal introduces a new keyword that provides consistent invariant
type semantics in all contexts.

/The Swift-evolution thread about this topic can be found here: [RFC] #Self
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565>/

    Motivation

The distinction between covariant and non-covariant type references come
into play when
conforming non-final classes to protocols. Fixing a protocol requirement to
a covarying type
means that a method returning |Self| must be overriden by all subclasses in
order to return
the correct, matching type.

This proposal builds on the covariant construct |Self| accepted in SE–0068
<https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md>
to introduce an invariant type identifier. It enables protocol declarations
to consistently
refer to a type that is fixed at compile time. This ensures that subclasses
can inherit
protocol implementations without having to re-implement that code at each
level of
inheritance.

Under this proposal, a new identifier keyword is fixed in use /at the point
of protocol conformance/
to the static type of that construct.

>class A: MyProtocol|

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 { // ... } }|

      Additional Utility

The utility of |StaticSelf| is not limited to protocols. A secondary use
enables code to refer to the lexical context’s current type without
explicitly mentioning its name. This provides a useful shortcut when
referencing static type members with especially long names and when
re-purposing code between types.

>class StructWithAVeryLongName { static func foo() -> String { // ... } func
bar() { // ... let s = StaticSelf.foo() // } }|

    Detailed Design

This proposal introduces |StaticSelf|, a new keyword that may be used in
protocols to refer to the invariant static type of a conforming
construct. |StaticSelf| may also be used in the lexical context of any type
declaration. In such use, the keyword is identical to spelling out the full
name of that type.

    Impact on existing code

Being additive, there should be no impact on existing code.

    Alternatives considered

The keyword is not fixed at this time. Alternatives that have been
discussed include |StaticType|, |InvariantSelf|, |SelfType|, or |Type|. The
community is welcome to bikeshed on the most clear and concise name for
this keyword.

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


(Patrick Smith) #10

I didn’t really understand some of the lead in discussion examples regarding protocols A and B each being interwoven, but I would prefer to see StaticSelf only used for concrete types, and protocols only to use Self. If Self has problems with non-final classes, then maybe how it works in protocols could change. A class could interpret a protocol’s ‘Self’ as ‘myself or my subclasses’?

Maybe instead of introducing StaticSelf it could be renamed simply Self, and ‘Self’ as used in protocols could change to something else? ‘Instance’ perhaps?

···

On 13 May 2016, at 12:21 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@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. 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. 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.

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.

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


(Austin Zheng) #11

I'm not quite sure I understand the 'Additional Utility' section. A given class hierarchy can only have one implementation of a given static method; static methods are effectively final. Therefore, the 'Self' introduced in the previous proposal should be completely sufficient for invoking a static method on a class. (Likewise, for moving around code.) In fact, the previous proposal for 'Self' used a very similar example.

I think the example would make more sense if it involved class methods. However, *without considering the protocol applications* I wouldn't consider that a compelling enough use case, by itself, to add StaticSelf.

As for StaticSelf's impact on protocols, I defer to the opinions of the other folks who've commented on the thread.

Austin

···

On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

Erica Sadun and I have written a proposal are following up the recent discussion thread "[RFC] #Self” with a proposal to introduce StaticSelf, an invariant Self.

The recent discussion can be found here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

The proposal can be found here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

We look forward to continuing the discussion. We plan to submit a PR in the near future after incorporating your final feedback.

Thanks,
Matthew
Introducing StaticSelf, an Invariant Self

Proposal: TBD
Authors: Matthew Johnson <https://github.com/anandabits>, Erica Sadun <https://github.com/erica>
Status: TBD
Review manager: TBD
Introduction

This proposal introduces a new keyword that provides consistent invariant type semantics in all contexts.

The Swift-evolution thread about this topic can be found here: [RFC] #Self <http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565>
Motivation

The distinction between covariant and non-covariant type references come into play when
conforming non-final classes to protocols. Fixing a protocol requirement to a covarying type
means that a method returning Self must be overriden by all subclasses in order to return
the correct, matching type.

This proposal builds on the covariant construct Self accepted in SE–0068 <https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md>
to introduce an invariant type identifier. It enables protocol declarations to consistently
refer to a type that is fixed at compile time. This ensures that subclasses can inherit
protocol implementations without having to re-implement that code at each level of
inheritance.

Under this proposal, a new identifier keyword is fixed in use at the point of protocol conformance
to the static type of that construct.

class A: MyProtocol
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 {
     // ...
}
}
Additional Utility

The utility of StaticSelf is not limited to protocols. A secondary use enables code to refer to the lexical context’s current type without explicitly mentioning its name. This provides a useful shortcut when referencing static type members with especially long names and when re-purposing code between types.

class StructWithAVeryLongName {
    static func foo() -> String {
      // ...
    }
    func bar() {
      // ...
      let s = StaticSelf.foo()
      //
    }
}
Detailed Design

This proposal introduces StaticSelf, a new keyword that may be used in protocols to refer to the invariant static type of a conforming construct. StaticSelf may also be used in the lexical context of any type declaration. In such use, the keyword is identical to spelling out the full name of that type.

Impact on existing code

Being additive, there should be no impact on existing code.

Alternatives considered

The keyword is not fixed at this time. Alternatives that have been discussed include StaticType, InvariantSelf, SelfType, or Type. The community is welcome to bikeshed on the most clear and concise name for this keyword.

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


(Joe Groff) #12

Sent from my iPad

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.

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

That's a property of a conformance. Class conformances are inherited, so they have to satisfy a protocol's requirements . Within the protocol definition, or in a protocol extension, `Self` is a generic parameter bound to a specific conforming type. When you conform a base class to a type, that means `Self == Base` and `Self == Derived` must be possible, but `Self` is never simultaneously `Base` and `Derived`.

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.

That will likely change once resilient Swift frameworks start to exist. Changing `Self` to `StaticSelf` or back would also be a nonresilient change, so if frameworks get this wrong, they wouldn't be able to fix it without breaking ABI, which makes this even more problematic.

-Joe

···

On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On May 12, 2016, at 9:21 PM, Joe Groff <jgroff@apple.com> wrote:

On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:


(Joe Groff) #13

`StaticSelf` requirements by themselves don't even save you from covariance. If Base conforms to a protocol (with Self == Base), Derived inherits that conformance and also conforms (with Self == Derived). If `StaticSelf` always refers to the conforming type, then it must also be bindable to Base and Derived, so a base class must still use a covariant-returning method to satisfy the `StaticSelf` requirement.

-Joe

···

On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:

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.


(Vladimir) #14

In this case I propose to call it BaseType (or BaseSelf) as actually this 'thing' in meaning `->StaticSelf` means 'self or any base class'

···

On 13.05.2016 7:56, Thorsten Seitz via swift-evolution wrote:

+1

Good description of the motivating problem!

As for bikeshedding: ConformingSelf, ConformingType, BaseSelf, BaseType

-Thorsten

Am 13.05.2016 um 02:49 schrieb Matthew Johnson via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

Erica Sadun and I have written a proposal are following up the recent
discussion thread "[RFC] #Self” with a proposal to introduce StaticSelf,
an invariant Self.

The recent discussion can be found
here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

The proposal can be found
here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

We look forward to continuing the discussion. We plan to submit a PR in
the near future after incorporating your final feedback.

Thanks,
Matthew

  Introducing StaticSelf, an Invariant Self

  * Proposal: TBD
  * Authors: Matthew Johnson <https://github.com/anandabits>, Erica Sadun
    <https://github.com/erica>
  * Status: TBD
  * Review manager: TBD

    Introduction

This proposal introduces a new keyword that provides consistent invariant
type semantics in all contexts.

/The Swift-evolution thread about this topic can be found here: [RFC]
#Self <http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565>/

    Motivation

The distinction between covariant and non-covariant type references come
into play when
conforming non-final classes to protocols. Fixing a protocol requirement
to a covarying type
means that a method returning |Self| must be overriden by all subclasses
in order to return
the correct, matching type.

This proposal builds on the covariant construct |Self| accepted
in SE–0068
<https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md>
to introduce an invariant type identifier. It enables protocol
declarations to consistently
refer to a type that is fixed at compile time. This ensures that
subclasses can inherit
protocol implementations without having to re-implement that code at each
level of
inheritance.

Under this proposal, a new identifier keyword is fixed in use /at the
point of protocol conformance/
to the static type of that construct.

>class A: MyProtocol|

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 {
// ... } }|

      Additional Utility

The utility of |StaticSelf| is not limited to protocols. A secondary use
enables code to refer to the lexical context’s current type without
explicitly mentioning its name. This provides a useful shortcut when
referencing static type members with especially long names and when
re-purposing code between types.

>class StructWithAVeryLongName { static func foo() -> String { // ... }
func bar() { // ... let s = StaticSelf.foo() // } }|

    Detailed Design

This proposal introduces |StaticSelf|, a new keyword that may be used in
protocols to refer to the invariant static type of a conforming
construct. |StaticSelf| may also be used in the lexical context of any
type declaration. In such use, the keyword is identical to spelling out
the full name of that type.

    Impact on existing code

Being additive, there should be no impact on existing code.

    Alternatives considered

The keyword is not fixed at this time. Alternatives that have been
discussed include |StaticType|, |InvariantSelf|, |SelfType|, or |Type|.
The community is welcome to bikeshed on the most clear and concise name
for this keyword.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(Vladimir) #15

The proposed StaticSelf when used as `->StaticSelf` in protocol means ‘myself or my some *base* class’. I.e. if this requirement was implemented in one of base classes, any subclass automatically conforms to the protocol as it has `->(myself or some base class)` in his hierarchy.

This is the difference with `->Self` in protocol which requires 'myself'.

···

On 13.05.2016 7:21, Patrick Smith via swift-evolution wrote:

I didn’t really understand some of the lead in discussion examples
regarding protocols A and B each being interwoven, but I would prefer to
see StaticSelf only used for concrete types, and protocols only to use
Self. If Self has problems with non-final classes, then maybe how it
works in protocols could change. A class could interpret a protocol’s
‘Self’ as ‘myself or my subclasses’?

Maybe instead of introducing StaticSelf it could be renamed simply Self,
and ‘Self’ as used in protocols could change to something else?
‘Instance’ perhaps?

On 13 May 2016, at 12:21 PM, Joe Groff via swift-evolution >> <swift-evolution@swift.org> wrote:

On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution >>> <swift-evolution@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.
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. 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.

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.

-Joe _______________________________________________ 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


(Matthew Johnson) #16

Totally agree. It feels weird to have protocols decide on how "Self" conformance a are inherited. It should a decision for the conforming type.

Do you have any suggestions on how we allow the conforming type to make that decision? Last time we had that discussion it didn’t produce clear answer. It turns out there is quite a bit of complexity involved in doing this.

···

On May 13, 2016, at 1:26 AM, David Hart <david@hartbit.com> wrote:

On 13 May 2016, at 04:21, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@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. 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. 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.

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.

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


(Vladimir) #17

I don't feel that InvariantSelf reflects the fact that class conformed to protocol with `f()->InvariantSelf` requirement will actually return
'self or some base class'. Especially when this `InvariantSelf` means `exactly this concrete static type name` inside type declaration.

Probably the better name is BaseType (BaseSelf, ThisType.. #Type ?)

But actually I don't fully understand how this would work in generic functions:

protocol A {
   func g()->StaticSelf
}

class B: A {
   func g()->StaticSelf {return B()}
}

class C: B {
}

func x(a: A ){
     var xx : A = a.g() // will this work? as g returns *some in hierarchy*
     print(xx)
}

func z<T: A>(t: T) {
     let u = t.g() // will this work?
     print(u)
}

let c = C()
z(c)
x(c)

···

On 13.05.2016 4:59, Xiaodi Wu via swift-evolution wrote:

I like the way the motivation for this feature has been explained here. Now
that the reasoning behind it is evident, I have to say I'm leaning towards
the "InvariantSelf" name--after all, you describe this feature in the title
as "an invariant self."

On Thu, May 12, 2016 at 7:49 PM, Matthew Johnson via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

    Erica Sadun and I have written a proposal are following up the recent
    discussion thread "[RFC] #Self” with a proposal to introduce
    StaticSelf, an invariant Self.

    The recent discussion can be found
    here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

    The proposal can be found
    here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

    We look forward to continuing the discussion. We plan to submit a PR
    in the near future after incorporating your final feedback.

    Thanks,
    Matthew

      Introducing StaticSelf, an Invariant Self

      * Proposal: TBD
      * Authors: Matthew Johnson <https://github.com/anandabits>, Erica
        Sadun <https://github.com/erica>
      * Status: TBD
      * Review manager: TBD

        Introduction

    This proposal introduces a new keyword that provides consistent
    invariant type semantics in all contexts.

    /The Swift-evolution thread about this topic can be found here: [RFC]
    #Self <http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565>/

        Motivation

    The distinction between covariant and non-covariant type references
    come into play when
    conforming non-final classes to protocols. Fixing a protocol
    requirement to a covarying type
    means that a method returning |Self| must be overriden by all
    subclasses in order to return
    the correct, matching type.

    This proposal builds on the covariant construct |Self| accepted
    in SE–0068
    <https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md>
    to introduce an invariant type identifier. It enables protocol
    declarations to consistently
    refer to a type that is fixed at compile time. This ensures that
    subclasses can inherit
    protocol implementations without having to re-implement that code at
    each level of
    inheritance.

    Under this proposal, a new identifier keyword is fixed in use /at the
    point of protocol conformance/
    to the static type of that construct.

    >class A: MyProtocol|

    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 {
    // ... } }|

          Additional Utility

    The utility of |StaticSelf| is not limited to protocols. A secondary
    use enables code to refer to the lexical context’s current type without
    explicitly mentioning its name. This provides a useful shortcut when
    referencing static type members with especially long names and when
    re-purposing code between types.

    >class StructWithAVeryLongName { static func foo() -> String { // ... }
    func bar() { // ... let s = StaticSelf.foo() // } }|

        Detailed Design

    This proposal introduces |StaticSelf|, a new keyword that may be used
    in protocols to refer to the invariant static type of a conforming
    construct. |StaticSelf| may also be used in the lexical context of any
    type declaration. In such use, the keyword is identical to spelling out
    the full name of that type.

        Impact on existing code

    Being additive, there should be no impact on existing code.

        Alternatives considered

    The keyword is not fixed at this time. Alternatives that have been
    discussed include |StaticType|, |InvariantSelf|, |SelfType|, or |Type|.
    The community is welcome to bikeshed on the most clear and concise name
    for this keyword.

    _______________________________________________
    swift-evolution mailing list
    swift-evolution@swift.org <mailto: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


(Matthew Johnson) #18

Sent from my iPad

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.

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

That's a property of a conformance. Class conformances are inherited, so they have to satisfy a protocol's requirements . Within the protocol definition, or in a protocol extension, `Self` is a generic parameter bound to a specific conforming type. When you conform a base class to a type, that means `Self == Base` and `Self == Derived` must be possible, but `Self` is never simultaneously `Base` and `Derived`.

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.

That will likely change once resilient Swift frameworks start to exist. Changing `Self` to `StaticSelf` or back would also be a nonresilient change, so if frameworks get this wrong, they wouldn't be able to fix it without breaking ABI, which makes this even more problematic.

You can say this about many things. It seems less problematic than having no way to express this. Frameworks would not be required to use it if the authors have concerns about ABI.

···

On May 13, 2016, at 10:39 AM, Joe Groff <jgroff@apple.com> wrote:

On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On May 12, 2016, at 9:21 PM, Joe Groff <jgroff@apple.com> wrote:

On May 12, 2016, at 5:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

-Joe


(Matthew Johnson) #19

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.

`StaticSelf` requirements by themselves don't even save you from covariance. If Base conforms to a protocol (with Self == Base), Derived inherits that conformance and also conforms (with Self == Derived). If `StaticSelf` always refers to the conforming type, then it must also be bindable to Base and Derived, so a base class must still use a covariant-returning method to satisfy the `StaticSelf` requirement.

We are specifying that `StaticSelf` refers to the type that explicitly declares conformance. If a class inherits conformance it refers to the base class which explicitly declared the conformance it is inheriting.

···

On May 13, 2016, at 10:55 AM, Joe Groff <jgroff@apple.com> wrote:

On May 13, 2016, at 8:18 AM, Matthew Johnson <matthew@anandabits.com> wrote:

-Joe


(L Mihalkovic) #20

Considering the precedent of using ! and ? in swift, could it be that:

Self! would designate what is known for sure, the invariant compile time type of self

Self? Would designate the yet unknown (*optional* if you will) covariant type of self

Regards
LM
(From mobile)

···

On May 13, 2016, at 3:59 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

I like the way the motivation for this feature has been explained here. Now that the reasoning behind it is evident, I have to say I'm leaning towards the "InvariantSelf" name--after all, you describe this feature in the title as "an invariant self."

On Thu, May 12, 2016 at 7:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:
Erica Sadun and I have written a proposal are following up the recent discussion thread "[RFC] #Self” with a proposal to introduce StaticSelf, an invariant Self.

The recent discussion can be found here: http://thread.gmane.org/gmane.comp.lang.swift.evolution/16565

The proposal can be found here: https://github.com/anandabits/swift-evolution/blob/static-self/proposals/NNNN-static-self.md

We look forward to continuing the discussion. We plan to submit a PR in the near future after incorporating your final feedback.

Thanks,
Matthew
Introducing StaticSelf, an Invariant Self

Proposal: TBD
Authors: Matthew Johnson, Erica Sadun
Status: TBD
Review manager: TBD
Introduction

This proposal introduces a new keyword that provides consistent invariant type semantics in all contexts.

The Swift-evolution thread about this topic can be found here: [RFC] #Self

Motivation

The distinction between covariant and non-covariant type references come into play when
conforming non-final classes to protocols. Fixing a protocol requirement to a covarying type
means that a method returning Self must be overriden by all subclasses in order to return
the correct, matching type.

This proposal builds on the covariant construct Self accepted in SE–0068
to introduce an invariant type identifier. It enables protocol declarations to consistently
refer to a type that is fixed at compile time. This ensures that subclasses can inherit
protocol implementations without having to re-implement that code at each level of
inheritance.

Under this proposal, a new identifier keyword is fixed in use at the point of protocol conformance
to the static type of that construct.

class A: MyProtocol
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 {
     // ...
}
}
Additional Utility

The utility of StaticSelf is not limited to protocols. A secondary use enables code to refer to the lexical context’s current type without explicitly mentioning its name. This provides a useful shortcut when referencing static type members with especially long names and when re-purposing code between types.

class StructWithAVeryLongName {
    static func foo() -> String {
      // ...
    }
    func bar() {
      // ...
      let s = StaticSelf.foo()
      //
    }
}
Detailed Design

This proposal introduces StaticSelf, a new keyword that may be used in protocols to refer to the invariant static type of a conforming construct. StaticSelf may also be used in the lexical context of any type declaration. In such use, the keyword is identical to spelling out the full name of that type.

Impact on existing code

Being additive, there should be no impact on existing code.

Alternatives considered

The keyword is not fixed at this time. Alternatives that have been discussed include StaticType, InvariantSelf, SelfType, or Type. The community is welcome to bikeshed on the most clear and concise name for this keyword.

_______________________________________________
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