[RFC] #Self

> No, class would not need to be final to conform to a requirement returning self. The difference is that with Self covaries and self does not. This means you *do not need* to guarantee that all subclasses override a requirement that returns self, while you do need to guarantee that all subclasses override a requirement that returns Self.

I'm probably slow these day, but I(and probably someone else) just can't understand this. Thank you for your patience in explaining this:
Just after you conforms *base* class to *any* protocol, any possible subclass *must* (you *have to* guarantee this) conform the same protocol.

class A {..}
class B:A {..}
class C:A {..}
protocol D {..}
extension A: D {}
-> now B&C and any other existed and *possible* subclass *must* conforms to the same protocol D just because of inheritance. As soon as they are subclass of A, they *must* be `is D` and *must* have the methods that return self. No?

Yes, they must and will conform. The distinction is that if the protocol has requirements returning Self all subclasses must override those requirements and to return their type because the inherited implementation returns their supertype. With self (or Type as we're now calling it) they would not need to override those requirements because the ancestor that initially declared conformance provides an inherited implementation that remains valid for all of its descendants.

···

Sent from my iPad

On May 11, 2016, at 1:22 AM, Vladimir.S <svabox@gmail.com> wrote:

On 10.05.2016 22:04, Matthew Johnson wrote:

On May 10, 2016, at 1:38 PM, Vladimir.S <svabox@gmail.com> wrote:

On 10.05.2016 20:50, Matthew Johnson wrote:

No, the whole point is that D.f() returns C because C is the requirement
of 'f' is declared to return self which is C where the protocol
conformance is declared and implemented. If you want a covariant
requirement you would use Self as the return type, not self.

I just followed your example with NSURL.. Probably I don't understand the point, but you said you want to conform a non-final class to protocol with method -> self.

---------------------<

protocol A { static func createWithString(s: String) -> Self }
extension NSURL: A { // cannot conform because NSURL is non-final }

If we could define a protocol requirement that didn't covary (using
self or whatever) we would be able to write the desired conformance.

---------------------<

And I don't understand how do you want to achieve the target, as even if we 'invent' self, this (as I understand) can't work as class is not final. Just like with 'simple' Self - class must be final to conform. Thank you for clarification.

No, class would not need to be final to conform to a requirement returning self. The difference is that with Self covaries and self does not. This means you do not need to guarantee that all subclasses override a requirement that returns self, while you do need to guarantee that all subclasses override a requirement that returns Self.

The requirement to guarantee that all subclasses provide this override is the reason you cannot declare conformance in the case of requirements returning Self. Since this isn’t necessary for self (will probably have a different name) the class does not need to be final in order to conform.

-Matthew

.

I think Type fits really well. Because every class, struct, and enum gets a static member called ‘Type’. But you can only use it outside the declaration (String.Type), not inside.

So similar to how types declared inside can be referenced:

struct A {
  enum Kind {
    case cat
    case dog
  }

  var kind: Kind // Use nested type here; I don’t have to write A.Kind
}

We could use Type in a similar way:

struct B {
  // This gets created automatically for every type, and is accessible today from B.Type
  //metatype Type { … }

  var children: [Type] // Use here in the same way as Kind above
}

···

On 11 May 2016, at 8:32 AM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPad

On May 10, 2016, at 5:24 PM, Hooman Mehr <hooman@mac.com <mailto:hooman@mac.com>> wrote:

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

That said, I’m not sure I understand the concrete use-cases. When is this concept important? When is “Self” not good enough?

The only case where there is new functionality is when this is used in a protocol requirement. I gave an example earlier today.

This functionality is the key: Ability of an open (non-final) class to conform to a protocol that lets it return an instance of the conforming type (itself). Self does not work for that and we can’t change its behavior (or can we?) So one solution seems to be Matt’s proposal. This functionality is important for me and an example use case is class clusters. For the client code it is sealed and acts just like a final class, but internally it may return a subclass that is an implementation detail. We should be able to do this.

Agree and this is why I am willing to write the proposal for this. There was a discussion a few months ago about this problem and a few solutions were kicked around. The biggest problem with this approach at the time was lack of a good name, which I believe we now have in Type.

I'm going to let the discussion continue for a day or two and will write a proposal if no significant counter arguments arise.

-Matthew

Hooman

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

That explanation is succinct and cogent. I can see the need for this
proposed behavior. Having just played around with conforming classes to
protocols, I think self is rather clear, but Type would be a little
mystifying.

···

On Wed, May 11, 2016 at 08:43 Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

Sent from my iPad

> On May 11, 2016, at 1:22 AM, Vladimir.S <svabox@gmail.com> wrote:
>
> > No, class would not need to be final to conform to a requirement
returning self. The difference is that with Self covaries and self does
not. This means you *do not need* to guarantee that all subclasses
override a requirement that returns self, while you do need to guarantee
that all subclasses override a requirement that returns Self.
>
> I'm probably slow these day, but I(and probably someone else) just can't
understand this. Thank you for your patience in explaining this:
> Just after you conforms *base* class to *any* protocol, any possible
subclass *must* (you *have to* guarantee this) conform the same protocol.
>
> class A {..}
> class B:A {..}
> class C:A {..}
> protocol D {..}
> extension A: D {}
> -> now B&C and any other existed and *possible* subclass *must* conforms
to the same protocol D just because of inheritance. As soon as they are
subclass of A, they *must* be `is D` and *must* have the methods that
return self. No?

Yes, they must and will conform. The distinction is that if the protocol
has requirements returning Self all subclasses must override those
requirements and to return their type because the inherited implementation
returns their supertype. With self (or Type as we're now calling it) they
would not need to override those requirements because the ancestor that
initially declared conformance provides an inherited implementation that
remains valid for all of its descendants.

>
>> On 10.05.2016 22:04, Matthew Johnson wrote:
>>
>>> On May 10, 2016, at 1:38 PM, Vladimir.S <svabox@gmail.com> wrote:
>>>
>>> On 10.05.2016 20:50, Matthew Johnson wrote:
>>>> No, the whole point is that D.f() returns C because C is the
requirement
>>>> of 'f' is declared to return self which is C where the protocol
>>>> conformance is declared and implemented. If you want a covariant
>>>> requirement you would use Self as the return type, not self.
>>>
>>> I just followed your example with NSURL.. Probably I don't understand
the point, but you said you want to conform a non-final class to protocol
with method -> self.
>>>
>>>> ---------------------<
>>> protocol A { static func createWithString(s: String) -> Self }
>>> extension NSURL: A { // cannot conform because NSURL is non-final }
>>>
>>> If we could define a protocol requirement that didn't covary (using
>>> self or whatever) we would be able to write the desired conformance.
>>>> ---------------------<
>>>
>>> And I don't understand how do you want to achieve the target, as even
if we 'invent' self, this (as I understand) can't work as class is not
final. Just like with 'simple' Self - class must be final to conform. Thank
you for clarification.
>>
>> No, class would not need to be final to conform to a requirement
returning self. The difference is that with Self covaries and self does
not. This means you do not need to guarantee that all subclasses override
a requirement that returns self, while you do need to guarantee that all
subclasses override a requirement that returns Self.
>>
>> The requirement to guarantee that all subclasses provide this override
is the reason you cannot declare conformance in the case of requirements
returning Self. Since this isn’t necessary for self (will probably have a
different name) the class does not need to be final in order to conform.
>>
>> -Matthew
>>
>> .
>>

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

With self (or Type as we're now calling it) they would not need to
override those requirements because the ancestor that initially declared
conformance provides an inherited implementation that remains valid for
all of its descendants.

OK.. I see your point, thank you. But probably we thinks differently about the self 'behavior' and how it should be treated in case of protocol conformance.

First of all, the initial proposal (which I base all my understanding on):
>----------------------------------<
To focus SE-0068 and narrow its scope, I removed the `#Self` part of the proposal. This offered compile-time substitution of the defining type for a related self literal:

     A further static identifier, self expands to static type of the code it appears within, completing the ways code may want to refer to the type it is declared in.

         self expands to the static type of the code it is declared within. In value types, this is always the same as Self. In reference types, it refers to the declaring type. self will offer a literal textual replacement just like #file, etc.
>----------------------------------<

So, again, we have protocol

protocol A {
   func f()->#Self
}

What does it mean for me? : Each class C, conformed to protocol A, should have func f() that returns exactly this class.

so, let's have

class B: A {
   func f()->B {} // conforms to protocol
// or could be written as(the same):
//func f()->#Self {} // conforms to protocol
}

class C: A {
   func f()->C {} // conforms to protocol
}

class D: A {
   func f()->D {} // conforms to protocol
}

and now, you want to conform some existed non-final class to A protocol:

class E {
   func f()->E {} // just has such method
}

extension E: A {} // seems like OK at this step

after this, what's the state of some existed derived from E classes ?

class F: E {}
class G: F {}

You conformed the base class E to A protocol. This automatically *reuqire* that F & G also conforms to A protocol. They *must* be `is A`.
But I insist, they does not conform to A protocol as I understand the self proposal.

F().f() *must*(because of protocol A) return instance of F, but F only has f()->C from base class

G().f() *must*(because of protocol A) return instance of G, but G only has f()->C from base class

This is why I don't understand how self could help to achieve the target with NSURL conformance.
These are my points. Please point if I'm wrong somewhere.

···

On 11.05.2016 16:42, Matthew Johnson wrote:
On 10.05.2016 16:15, Erica Sadun via swift-evolution wrote:

If the use case is to support certain protocol requirements rather than avoiding the recitation of long names, then it doesn't have to be short. IMO, `Type` is problematic because there's nothing in the meaning of the word to distinguish from `Self`, and in any case it's already used for the metatype type. `StaticSelf` is unambiguous.

I think both are valid uses so short is better but I agree that the distinction from Self is more readily apparent with StaticSelf. I could live with either one.

···

Sent from my iPad

On May 10, 2016, at 5:42 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

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

Sent from my iPad

On May 10, 2016, at 5:24 PM, Hooman Mehr <hooman@mac.com> wrote:

On May 10, 2016, at 2:49 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:
That said, I’m not sure I understand the concrete use-cases. When is this concept important? When is “Self” not good enough?

The only case where there is new functionality is when this is used in a protocol requirement. I gave an example earlier today.

This functionality is the key: Ability of an open (non-final) class to conform to a protocol that lets it return an instance of the conforming type (itself). Self does not work for that and we can’t change its behavior (or can we?) So one solution seems to be Matt’s proposal. This functionality is important for me and an example use case is class clusters. For the client code it is sealed and acts just like a final class, but internally it may return a subclass that is an implementation detail. We should be able to do this.

Agree and this is why I am willing to write the proposal for this. There was a discussion a few months ago about this problem and a few solutions were kicked around. The biggest problem with this approach at the time was lack of a good name, which I believe we now have in Type.

I'm going to let the discussion continue for a day or two and will write a proposal if no significant counter arguments arise.

-Matthew

Hooman

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

I think Type fits really well. Because every class, struct, and enum gets
a static member called ‘Type’. But you can only use it outside the
declaration (String.Type), not inside.

So similar to how types declared inside can be referenced:

struct A {
  enum Kind {
    case cat
    case dog
  }

  var kind: Kind // Use nested type here; I don’t have to write A.Kind
}

We could use Type in a similar way:

struct B {
  // This gets created automatically for every type, and is accessible
today from B.Type
  //metatype Type { … }

  var children: [Type] // Use here in the same way as Kind above
}

That's neat! My issue with it is that the analysis breaks down with
protocols. If we extend it there, it's difficult to rationalize why Type
has to mean the static type of the conforming class and Self has to mean
the dynamic type.

···

On Tue, May 10, 2016 at 8:45 PM, Patrick Smith via swift-evolution < swift-evolution@swift.org> wrote:

On 11 May 2016, at 8:32 AM, Matthew Johnson via swift-evolution < > swift-evolution@swift.org> wrote:

Sent from my iPad

On May 10, 2016, at 5:24 PM, Hooman Mehr <hooman@mac.com> wrote:

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

That said, I’m not sure I understand the concrete use-cases. When is this
concept important? When is “Self” not good enough?

The only case where there is new functionality is when this is used in a
protocol requirement. I gave an example earlier today.

This functionality is the key: Ability of an open (non-final) class to
conform to a protocol that lets it return an instance of the conforming
type (itself). Self does not work for that and we can’t change its behavior
(or can we?) So one solution seems to be Matt’s proposal. This
functionality is important for me and an example use case is class
clusters. For the client code it is sealed and acts just like a final
class, but internally it may return a subclass that is an implementation
detail. We should be able to do this.

Agree and this is why I am willing to write the proposal for this. There
was a discussion a few months ago about this problem and a few solutions
were kicked around. The biggest problem with this approach at the time was
lack of a good name, which I believe we now have in Type.

I'm going to let the discussion continue for a day or two and will write a
proposal if no significant counter arguments arise.

-Matthew

Hooman

_______________________________________________
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

With self (or Type as we're now calling it) they would not need to
override those requirements because the ancestor that initially declared
conformance provides an inherited implementation that remains valid for
all of its descendants.

OK.. I see your point, thank you. But probably we thinks differently about the self 'behavior' and how it should be treated in case of protocol conformance.

First of all, the initial proposal (which I base all my understanding on):
>----------------------------------<
To focus SE-0068 and narrow its scope, I removed the `#Self` part of the proposal. This offered compile-time substitution of the defining type for a related self literal:

   A further static identifier, self expands to static type of the code it appears within, completing the ways code may want to refer to the type it is declared in.

       self expands to the static type of the code it is declared within. In value types, this is always the same as Self. In reference types, it refers to the declaring type. self will offer a literal textual replacement just like #file, etc.
>----------------------------------<

So, again, we have protocol

protocol A {
func f()->#Self
}

What does it mean for me? : Each class C, conformed to protocol A, should have func f() that returns exactly this class.

so, let's have

class B: A {
func f()->B {} // conforms to protocol
// or could be written as(the same):
//func f()->#Self {} // conforms to protocol
}

class C: A {
func f()->C {} // conforms to protocol
}

class D: A {
func f()->D {} // conforms to protocol
}

and now, you want to conform some existed non-final class to A protocol:

class E {
func f()->E {} // just has such method
}

extension E: A {} // seems like OK at this step

after this, what's the state of some existed derived from E classes ?

class F: E {}
class G: F {}

You conformed the base class E to A protocol. This automatically *reuqire* that F & G also conforms to A protocol. They *must* be `is A`.
But I insist, they does not conform to A protocol as I understand the self proposal.

F().f() *must*(because of protocol A) return instance of F, but F only has f()->C from base class

G().f() *must*(because of protocol A) return instance of G, but G only has f()->C from base class

I think you meant E here, not C.

This is why I don't understand how self could help to achieve the target with NSURL conformance.
These are my points. Please point if I'm wrong somewhere.

You are describing the behavior of Self, not self.

       self expands to the static type of the code it is declared within. In value types, this is always the same as Self. In reference types, it refers to the declaring type.

For implementations of protocol requirements the declaring type is the type that declares conformance.

Self is covariant, self (or Type) is invariant. That is the difference.

···

Sent from my iPad

On May 11, 2016, at 9:33 AM, Vladimir.S <svabox@gmail.com> wrote:

On 11.05.2016 16:42, Matthew Johnson wrote:

On 10.05.2016 16:15, Erica Sadun via swift-evolution wrote:

You are describing the behavior of Self, not self.

Well.. Yes :-) I.e. I wanted to show that `->#Self` requirement in protocol(from my point of view) will produce issues just like `->Self`

       self expands to the static type of the code it is declared
within. In value types, this is always the same as Self. In reference
types, it refers to the *declaring* type.

For implementations of protocol requirements the declaring type is the type
that declares conformance.

Self is covariant, self (or Type) is invariant. That is the difference.

There is some misunderstanding between us.
Most likely this is because of my terrible English. (Btw, sorry for this)

I just can't understand, how do you understand the `A` protocol conformance for F & G classes in my examples?

In your word, with implemented self, F & G `is A` ? If so, how exactly they conform to protocol that says F & G *must* have `f` that returns self. What is self for F & G classes that should be returned in f()?
Right now I think that your idea just can not be implemented at all based on *initial* self proposal.

Probably you(we) need another proposal, like BaseSelf (or SuperSelf) that means "this class or any its base class", then I understand how such a `f()->BaseSelf` protocol requirement can be applied to E class and also be true for F&G classes (as f() inherited from base class will return instance of E which is base for both).

···

On 11.05.2016 17:42, Matthew Johnson wrote:

You are describing the behavior of Self, not self.

Well.. Yes :-) I.e. I wanted to show that `->#Self` requirement in protocol(from my point of view) will produce issues just like `->Self`

      self expands to the static type of the code it is declared
within. In value types, this is always the same as Self. In reference
types, it refers to the *declaring* type.

For implementations of protocol requirements the declaring type is the type
that declares conformance.

Self is covariant, self (or Type) is invariant. That is the difference.

There is some misunderstanding between us.
Most likely this is because of my terrible English. (Btw, sorry for this)

I just can't understand, how do you understand the `A` protocol conformance for F & G classes in my examples?

In your word, with implemented self, F & G `is A` ? If so, how exactly they conform to protocol that says F & G *must* have `f` that returns self. What is self for F & G classes that should be returned in f()?
Right now I think that your idea just can not be implemented at all based on *initial* self proposal.

'f' would return E for E, F and G. Because the conformance is declared by E the requirement to return self is fixed as an invariant requirement to return E for all potential subclasses.

Probably you(we) need another proposal, like BaseSelf (or SuperSelf) that means "this class or any its base class", then I understand how such a `f()->BaseSelf` protocol requirement can be applied to E class and also be true for F&G classes (as f() inherited from base class will return instance of E which is base for both).

This is exactly what self (or Type) does. The behavior you have been describing is the behavior of Self which already exists.

···

Sent from my iPad

On May 11, 2016, at 10:43 AM, Vladimir.S <svabox@gmail.com> wrote:

On 11.05.2016 17:42, Matthew Johnson wrote:

Well, I believe I understand now what *you mean* under self. OK. Thank you for clarifications.
In my terminology 'this' could be called BaseSelf. Your "thing" just can not be called self.
IMO in initial proposal self means not more than placeholder for the concrete type name(inside type declaration or inside protocol).

You propose just something different, more advanced than initial self, you propose not some static "thing" but extended behavior if self is a return type of protocol requirement.

I strictly against to couple the initial proposal of self and your proposal for extended features (for protocol conformance of `->#Self`).
Please be clear and obvious regarding the name of that feature. I really think the behavior you propose can not be called self(or Type)

What I suggest: de-couple these proposals to:

a) initial proposal of self as placeholder for concrete type name. Choose the name for it. Probably StaticSelf, or Type, or somehting else

b) your proposal for BaseSelf feature. I'll definitely support it with just name changed to clearly reflect its propose.

···

On 11.05.2016 18:58, Matthew Johnson wrote:

'f' would return E for E, F and G. Because the conformance is declared
by E the requirement to return self is fixed as an invariant
requirement to return E for all potential subclasses.

Probably you(we) need another proposal, like BaseSelf (or SuperSelf)
that means "this class or any its base class", then I understand how
such a `f()->BaseSelf` protocol requirement can be applied to E
class and also be true for F&G classes (as f() inherited from base
class will return instance of E which is base for both).

This is exactly what self (or Type) does. The behavior you have been
describing is the behavior of Self which already exists.

Well, I believe I understand now what *you mean* under self. OK. Thank you for clarifications.
In my terminology 'this' could be called BaseSelf. Your "thing" just can not be called self.
IMO in initial proposal self means not more than placeholder for the concrete type name(inside type declaration or inside protocol).

You propose just something different, more advanced than initial self, you propose not some static "thing" but extended behavior if self is a return type of protocol requirement.

I strictly against to couple the initial proposal of self and your proposal for extended features (for protocol conformance of `->#Self`).
Please be clear and obvious regarding the name of that feature. I really think the behavior you propose can not be called self(or Type)

What I suggest: de-couple these proposals to:

a) initial proposal of self as placeholder for concrete type name. Choose the name for it. Probably StaticSelf, or Type, or somehting else

b) your proposal for BaseSelf feature. I'll definitely support it with just name changed to clearly reflect its propose.

I don't believe the initial proposal stated how it would behave in a protocol. However I do believe the feature I am talking about covers all of the use cases Erica had in mind while also providing useful semantics when used in a protocol requirement. Erica, please correct me if I'm wrong.

You want to make the semantics of self / Type be covariant when used in a protocol requirement. This makes no sense to me as it is explicitly *not* covariant when used within a class declaration. We already have a covariant construct (Self) and the proposal is to introduce an invariant construct (self or Type). The invariant semantic should be consistent regardless of whether it is used in a protocol requirement or a type declaration.

IMO BaseSelf is a poor choice of name for something that is supposed to be valid syntax in value types as well as classes.

···

Sent from my iPad

On May 11, 2016, at 11:43 AM, Vladimir.S <svabox@gmail.com> wrote:

On 11.05.2016 18:58, Matthew Johnson wrote:
'f' would return E for E, F and G. Because the conformance is declared
by E the requirement to return self is fixed as an invariant
requirement to return E for all potential subclasses.

Probably you(we) need another proposal, like BaseSelf (or SuperSelf)
that means "this class or any its base class", then I understand how
such a `f()->BaseSelf` protocol requirement can be applied to E
class and also be true for F&G classes (as f() inherited from base
class will return instance of E which is base for both).

This is exactly what self (or Type) does. The behavior you have been
describing is the behavior of Self which already exists.

Inline

Sent from my iPad

Well, I believe I understand now what *you mean* under self. OK.
Thank you for clarifications. In my terminology 'this' could be called
BaseSelf. Your "thing" just can not be called self. IMO in initial
proposal self means not more than placeholder for the concrete type
name(inside type declaration or inside protocol).

You propose just something different, more advanced than initial
self, you propose not some static "thing" but extended behavior if
self is a return type of protocol requirement.

I strictly against to couple the initial proposal of self and your
proposal for extended features (for protocol conformance of
`->#Self`). Please be clear and obvious regarding the name of that
feature. I really think the behavior you propose can not be called
self(or Type)

What I suggest: de-couple these proposals to:

a) initial proposal of self as placeholder for concrete type name.
Choose the name for it. Probably StaticSelf, or Type, or somehting
else

b) your proposal for BaseSelf feature. I'll definitely support it with
just name changed to clearly reflect its propose.

I don't believe the initial proposal stated how it would behave in a
protocol. However I do believe the feature I am talking about covers
all of the use cases Erica had in mind while also providing useful
semantics when used in a protocol requirement. Erica, please correct me
if I'm wrong.

Well.. Yes, I also don't see statements regarding how `->#Self` would behave in a protocol in initial proposal. *This is why* I suggest to de-couple what *was* in initial proposall, and what you are suggesting as *addition* to the proposal.

Again. I fully support the behavior you suggest, but I strongly feel like 'that' self can't be named self, as some derived(from conformed class) class X does not return 'self'. It return 'self or one of base classes'. Let's call it 'SelfOrBase' for now.

What we have now:

protocol A {
   func f1() -> Self
   func f2(s: Self)
}

struct S: A {
   func f1() -> S/*self*/ {return self}
   func f2(s: S/*self*/) {}
}

class C: A {
   func f1() -> Self /*only Self, can't write C here*/ {return self}
   func f2(s: C/*self*/) {}
}

final class FC: A {
   func f1() -> Self /*can write FC here, ==#Self*/ {return self}
   func f2(s: FC/*self*/) {}
}

I believe, for clarity, after we introduce self(or whatever name it will have) we need to require `#Self` in protocol as type of method parameter:

protocol A {
   func f1() -> Self // this could be Self and could be self
   func f2(s: self) // this always will be self in implementation

   // this should not be allowed any more
   //func f2(s: Self)
}

struct S: A {
   // as you see we'd have `->#Self` in implementation
   func f1() -> self {return self}
   func f2(s: self) {}
}

class C: A {
   func f1() -> Self /*only Self, can't write C here*/ {return self}
   func f2(s: self) {}
}

final class FC: A {
   func f1() -> Self /*can write FC here, ==#Self*/ {return self}
   func f2(s: self) {}
}

The above is what *I think* was in initial proposal regarding self.

About your suggestion. I just trying to understand it in details.
Please point me where I understand your suggestion incorrectly.

Do you think about such start points? :

class Base {
   func f() -> Base {return Base()}
}

class Derived1: Base {
   override func f() -> Derived1 {return Derived1()}
}

class Derived2: Base {
   override func f() -> Derived2 {return Derived2()}
}

If so, do you want to introduce such a protocol:

protocol A {
     func f() -> self
}

and then conforms Base class to it? :

extension Base : A {}

To be able to use :

let a : A = Derived2()
let some = a.f() // you expect some.dynamicType is Derived2

I understand correctly?

At this point you say that all is OK and self works as expected, each class returns really self and protocol conformation applied.
But I believe this is not true. We *can* have this:

class Derived3: Base {
   // no override for f(). will be used from base class
}

Now. What does Derived3().f() returns? It returns instance of Base.
Is self for Derived3 equals to `Base` ? No.
Does Derived3 conforms to protocol `A` in this case? No.
But it *must* conform as you think you can conform its base class.
This is the problem I see.

This is why I think it must be something separate from self, like SelfOrBase - in this case, protocol will looks like:

protocol A {
     func f() -> SelfOrBase
}

then you can conform Base to A,

extension Base : A {}

and Derived3 fully conforms to this protocol(it returns instance of base class), all is OK and all is consistent.

If I'm wrong somewhere please point me with clarification. Thank you.

···

On 11.05.2016 21:31, Matthew Johnson wrote:

On May 11, 2016, at 11:43 AM, Vladimir.S <svabox@gmail.com> wrote:

You want to make the semantics of self / Type be covariant when used in
a protocol requirement. This makes no sense to me as it is explicitly
*not* covariant when used within a class declaration. We already have a
covariant construct (Self) and the proposal is to introduce an invariant
construct (self or Type). The invariant semantic should be consistent
regardless of whether it is used in a protocol requirement or a type
declaration.

IMO BaseSelf is a poor choice of name for something that is supposed to
be valid syntax in value types as well as classes.

On 11.05.2016 18:58, Matthew Johnson wrote: 'f' would return E for
E, F and G. Because the conformance is declared by E the
requirement to return self is fixed as an invariant requirement to
return E for all potential subclasses.

Probably you(we) need another proposal, like BaseSelf (or
SuperSelf) that means "this class or any its base class", then I
understand how such a `f()->BaseSelf` protocol requirement can
be applied to E class and also be true for F&G classes (as f()
inherited from base class will return instance of E which is
base for both).

This is exactly what self (or Type) does. The behavior you have
been describing is the behavior of Self which already exists.

Inline

Sent from my iPad

Well, I believe I understand now what *you mean* under self. OK.
Thank you for clarifications. In my terminology 'this' could be called
BaseSelf. Your "thing" just can not be called self. IMO in initial
proposal self means not more than placeholder for the concrete type
name(inside type declaration or inside protocol).

You propose just something different, more advanced than initial
self, you propose not some static "thing" but extended behavior if
self is a return type of protocol requirement.

I strictly against to couple the initial proposal of self and your
proposal for extended features (for protocol conformance of
`->#Self`). Please be clear and obvious regarding the name of that
feature. I really think the behavior you propose can not be called
self(or Type)

What I suggest: de-couple these proposals to:

a) initial proposal of self as placeholder for concrete type name.
Choose the name for it. Probably StaticSelf, or Type, or somehting
else

b) your proposal for BaseSelf feature. I'll definitely support it with
just name changed to clearly reflect its propose.

I don't believe the initial proposal stated how it would behave in a
protocol. However I do believe the feature I am talking about covers
all of the use cases Erica had in mind while also providing useful
semantics when used in a protocol requirement. Erica, please correct me
if I'm wrong.

Well.. Yes, I also don't see statements regarding how `->#Self` would behave in a protocol in initial proposal. *This is why* I suggest to de-couple what *was* in initial proposall, and what you are suggesting as *addition* to the proposal.

Again. I fully support the behavior you suggest, but I strongly feel like 'that' self can't be named self, as some derived(from conformed class) class X does not return 'self'. It return 'self or one of base classes'. Let's call it 'SelfOrBase' for now.

What we have now:

protocol A {
func f1() -> Self
func f2(s: Self)
}

struct S: A {
func f1() -> S/*self*/ {return self}
func f2(s: S/*self*/) {}
}

class C: A {
func f1() -> Self /*only Self, can't write C here*/ {return self}
func f2(s: C/*self*/) {}
}

final class FC: A {
func f1() -> Self /*can write FC here, ==#Self*/ {return self}
func f2(s: FC/*self*/) {}
}

I believe, for clarity, after we introduce self(or whatever name it will have) we need to require `#Self` in protocol as type of method parameter:

protocol A {
func f1() -> Self // this could be Self and could be self

What in the original proposal makes you think Self and self would be interchangeable here? Again, the proposal was for self to be invariant. Self is covariant. Those are very different things.

The semantics in the original proposal were unspecified with regards to protocols. I am simply extending it to retain the invariant semantics that the proposal *did* specified when it is used as a protocol requirement.

func f2(s: self) // this always will be self in implementation

// this should not be allowed any more
//func f2(s: Self)
}

struct S: A {
// as you see we'd have `->#Self` in implementation
func f1() -> self {return self}
func f2(s: self) {}
}

class C: A {
func f1() -> Self /*only Self, can't write C here*/ {return self}
func f2(s: self) {}
}

final class FC: A {
func f1() -> Self /*can write FC here, ==#Self*/ {return self}
func f2(s: self) {}
}

The above is what *I think* was in initial proposal regarding self.

About your suggestion. I just trying to understand it in details.
Please point me where I understand your suggestion incorrectly.

Do you think about such start points? :

class Base {
func f() -> Base {return Base()}
}

class Derived1: Base {
override func f() -> Derived1 {return Derived1()}
}

class Derived2: Base {
override func f() -> Derived2 {return Derived2()}
}

If so, do you want to introduce such a protocol:

protocol A {
   func f() -> self
}

and then conforms Base class to it? :

extension Base : A {}

To be able to use :

let a : A = Derived2()
let some = a.f() // you expect some.dynamicType is Derived2

The protocol specifies self (or Type, which we are not calling it). It is conformed to by Base. This means the return type of `f` is only guaranteed to be Base. It *may* be Derived2, but it need not be. Obviously given this example we know it is Derived2 because we can see the implementation but the type system does not. This means `some` has type of Base. Its dynamicsType *may* be Derived2 (and again in this case we can see that it will be) but that is not guaranteed by the type system.

I understand correctly?

At this point you say that all is OK and self works as expected, each class returns really self and protocol conformation applied.
But I believe this is not true. We *can* have this:

class Derived3: Base {
// no override for f(). will be used from base class
}

Now. What does Derived3().f() returns? It returns instance of Base.
Is self for Derived3 equals to `Base` ? No.
Does Derived3 conforms to protocol `A` in this case? No.
But it *must* conform as you think you can conform its base class.
This is the problem I see.

What you are missing is that self is not the same as Self. It is invariant. A was originally conformed to by Base. The requirement is invariant and becomes fixed by the conformance declaration. In this case it is fixed to Base.

You have not explained why you think self should be invariant when used in a type context and covariant when used in a protocol context. This expectation is what is confusing you. If you really what that semantic I think the burden is on you to make the case that we need something with this mixed semantic. I think it is much more confusing than having separate constructs for covariant and invariant semantics.

This is why I think it must be something separate from self, like SelfOrBase - in this case, protocol will looks like:

protocol A {
   func f() -> SelfOrBase
}

then you can conform Base to A,

extension Base : A {}

and Derived3 fully conforms to this protocol(it returns instance of base class), all is OK and all is consistent.

If I'm wrong somewhere please point me with clarification. Thank you.

Again, what you are calling SelfOrBase is *exactly* what I am calling Type (or self). It has consistent invariant semantics in all contexts.

···

On May 12, 2016, at 10:19 AM, Vladimir.S <svabox@gmail.com> wrote:
On 11.05.2016 21:31, Matthew Johnson wrote:

On May 11, 2016, at 11:43 AM, Vladimir.S <svabox@gmail.com> wrote:

You want to make the semantics of self / Type be covariant when used in
a protocol requirement. This makes no sense to me as it is explicitly
*not* covariant when used within a class declaration. We already have a
covariant construct (Self) and the proposal is to introduce an invariant
construct (self or Type). The invariant semantic should be consistent
regardless of whether it is used in a protocol requirement or a type
declaration.

IMO BaseSelf is a poor choice of name for something that is supposed to
be valid syntax in value types as well as classes.

On 11.05.2016 18:58, Matthew Johnson wrote: 'f' would return E for
E, F and G. Because the conformance is declared by E the
requirement to return self is fixed as an invariant requirement to
return E for all potential subclasses.

Probably you(we) need another proposal, like BaseSelf (or
SuperSelf) that means "this class or any its base class", then I
understand how such a `f()->BaseSelf` protocol requirement can
be applied to E class and also be true for F&G classes (as f()
inherited from base class will return instance of E which is
base for both).

This is exactly what self (or Type) does. The behavior you have
been describing is the behavior of Self which already exists.

Inline

I believe, for clarity, after we introduce self(or whatever name it will
have) we need to require `#Self` in protocol as type of method parameter:

protocol A {
func f1() -> Self // this could be Self and could be self

What in the original proposal makes you think Self and self would be
interchangeable here? Again, the proposal was for self to be invariant.
Self is covariant. Those are very different things.

Just incorrect comment for my code. Please add in mind *in implementation* to the end of the comment. I don't mean that they can be interchangeable in protocol definition, no, I mean at the moment of implementation `->Self` could became `->Self` or `->#Self` depending on where it will be implemented. Examples of implementation was below.

The semantics in the original proposal were unspecified with regards to
protocols. I am simply extending it to retain the invariant semantics that
the proposal *did* specified when it is used as a protocol requirement.

IMO your suggestion can not be coupled with initial proposal.
And I mean the recent(last) proposal in email I quoted in one of previous message, where nothing was said regarding protocols.

...

let a : A = Derived2()
let some = a.f() // you expect some.dynamicType is Derived2

The protocol specifies self (or Type, which we are not calling it). It is
conformed to by Base. This means the return type of `f` is only guaranteed
to be Base. It *may* be Derived2, but it need not be. Obviously given
this example we know it is Derived2 because we can see the implementation
but the type system does not. This means `some` has type of Base. Its
dynamicsType *may* be Derived2 (and again in this case we can see that it
will be) but that is not guaranteed by the type system.

I'm tired ;-)
You are trying to couple two IMO different things.
`#Self` as parameter's type in protocol and inside class/struct means 'placeholder for exactly this concrete type name in implementation'. Not base class!
I can't understand how you can extend this meaning to "derived class conforms to ->#Self, but returns some base class".

What you are missing is that self is not the same as Self. It is
invariant. A was originally conformed to by Base. The requirement is
invariant and becomes fixed by the conformance declaration. In this case
it is fixed to Base.

Again. I'm not missing this. It is clear they are no the same. Please point where exactly I missed this.
But you are trying to use the same keyword `#Self`(or Type,not important) in meaning 'this concrete type' and in 'this or base type'.

You have not explained why you think self should be invariant when used in
a type context and covariant when used in a protocol context. This
expectation is what is confusing you. If you really what that semantic I
think the burden is on you to make the case that we need something with
this mixed semantic. I think it is much more confusing than having
separate constructs for covariant and invariant semantics.

Just because of meaning(description) of self in initial proposal and its behavior at the implementation side(inside type body).

If you extend the meaning of your `#Self` to 'any type in hierarchy of that type', that I can understand.

Again, what you are calling SelfOrBase is *exactly* what I am calling Type
(or self). It has consistent invariant semantics in all contexts.

Again ;-), Yes. And I'm against to name your 'thing' with the same name as self(or Type) because they mean different things, different behavior.

Actually I think I got your points, I can't accept them and it seems like there is no some 'common' solution. You think that it is OK to have `->#Self` in protocol requirements in meaning "self of any base class", but I can't accept and understand this.

Thank you for discussion, probably I need to re-think all of this and find out that I was not right. I'll let then know ;-)

···

On 12.05.2016 18:36, Matthew Johnson wrote:

I absolutely share Matthew’s view of self (or whatever it ends up being called) and think this is really needed.

On the other hand I don’t think that a simple placeholder for the defining type is necessary as proposed by Vladimir, especially not if it is the third variant of something Self-like.

-Thorsten

···

Am 12.05.2016 um 17:36 schrieb Matthew Johnson via swift-evolution <swift-evolution@swift.org>:

On May 12, 2016, at 10:19 AM, Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>> wrote:

Inline

On 11.05.2016 21:31, Matthew Johnson wrote:

Sent from my iPad

On May 11, 2016, at 11:43 AM, Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>> wrote:

Well, I believe I understand now what *you mean* under self. OK.
Thank you for clarifications. In my terminology 'this' could be called
BaseSelf. Your "thing" just can not be called self. IMO in initial
proposal self means not more than placeholder for the concrete type
name(inside type declaration or inside protocol).

You propose just something different, more advanced than initial
self, you propose not some static "thing" but extended behavior if
self is a return type of protocol requirement.

I strictly against to couple the initial proposal of self and your
proposal for extended features (for protocol conformance of
`->#Self`). Please be clear and obvious regarding the name of that
feature. I really think the behavior you propose can not be called
self(or Type)

What I suggest: de-couple these proposals to:

a) initial proposal of self as placeholder for concrete type name.
Choose the name for it. Probably StaticSelf, or Type, or somehting
else

b) your proposal for BaseSelf feature. I'll definitely support it with
just name changed to clearly reflect its propose.

I don't believe the initial proposal stated how it would behave in a
protocol. However I do believe the feature I am talking about covers
all of the use cases Erica had in mind while also providing useful
semantics when used in a protocol requirement. Erica, please correct me
if I'm wrong.

Well.. Yes, I also don't see statements regarding how `->#Self` would behave in a protocol in initial proposal. *This is why* I suggest to de-couple what *was* in initial proposall, and what you are suggesting as *addition* to the proposal.

Again. I fully support the behavior you suggest, but I strongly feel like 'that' self can't be named self, as some derived(from conformed class) class X does not return 'self'. It return 'self or one of base classes'. Let's call it 'SelfOrBase' for now.

What we have now:

protocol A {
func f1() -> Self
func f2(s: Self)
}

struct S: A {
func f1() -> S/*self*/ {return self}
func f2(s: S/*self*/) {}
}

class C: A {
func f1() -> Self /*only Self, can't write C here*/ {return self}
func f2(s: C/*self*/) {}
}

final class FC: A {
func f1() -> Self /*can write FC here, ==#Self*/ {return self}
func f2(s: FC/*self*/) {}
}

I believe, for clarity, after we introduce self(or whatever name it will have) we need to require `#Self` in protocol as type of method parameter:

protocol A {
func f1() -> Self // this could be Self and could be self

What in the original proposal makes you think Self and self would be interchangeable here? Again, the proposal was for self to be invariant. Self is covariant. Those are very different things.

The semantics in the original proposal were unspecified with regards to protocols. I am simply extending it to retain the invariant semantics that the proposal *did* specified when it is used as a protocol requirement.

func f2(s: self) // this always will be self in implementation

// this should not be allowed any more
//func f2(s: Self)
}

struct S: A {
// as you see we'd have `->#Self` in implementation
func f1() -> self {return self}
func f2(s: self) {}
}

class C: A {
func f1() -> Self /*only Self, can't write C here*/ {return self}
func f2(s: self) {}
}

final class FC: A {
func f1() -> Self /*can write FC here, ==#Self*/ {return self}
func f2(s: self) {}
}

The above is what *I think* was in initial proposal regarding self.

About your suggestion. I just trying to understand it in details.
Please point me where I understand your suggestion incorrectly.

Do you think about such start points? :

class Base {
func f() -> Base {return Base()}
}

class Derived1: Base {
override func f() -> Derived1 {return Derived1()}
}

class Derived2: Base {
override func f() -> Derived2 {return Derived2()}
}

If so, do you want to introduce such a protocol:

protocol A {
   func f() -> self
}

and then conforms Base class to it? :

extension Base : A {}

To be able to use :

let a : A = Derived2()
let some = a.f() // you expect some.dynamicType is Derived2

The protocol specifies self (or Type, which we are not calling it). It is conformed to by Base. This means the return type of `f` is only guaranteed to be Base. It *may* be Derived2, but it need not be. Obviously given this example we know it is Derived2 because we can see the implementation but the type system does not. This means `some` has type of Base. Its dynamicsType *may* be Derived2 (and again in this case we can see that it will be) but that is not guaranteed by the type system.

I understand correctly?

At this point you say that all is OK and self works as expected, each class returns really self and protocol conformation applied.
But I believe this is not true. We *can* have this:

class Derived3: Base {
// no override for f(). will be used from base class
}

Now. What does Derived3().f() returns? It returns instance of Base.
Is self for Derived3 equals to `Base` ? No.
Does Derived3 conforms to protocol `A` in this case? No.
But it *must* conform as you think you can conform its base class.
This is the problem I see.

What you are missing is that self is not the same as Self. It is invariant. A was originally conformed to by Base. The requirement is invariant and becomes fixed by the conformance declaration. In this case it is fixed to Base.

You have not explained why you think self should be invariant when used in a type context and covariant when used in a protocol context. This expectation is what is confusing you. If you really what that semantic I think the burden is on you to make the case that we need something with this mixed semantic. I think it is much more confusing than having separate constructs for covariant and invariant semantics.

This is why I think it must be something separate from self, like SelfOrBase - in this case, protocol will looks like:

protocol A {
   func f() -> SelfOrBase
}

then you can conform Base to A,

extension Base : A {}

and Derived3 fully conforms to this protocol(it returns instance of base class), all is OK and all is consistent.

If I'm wrong somewhere please point me with clarification. Thank you.

Again, what you are calling SelfOrBase is *exactly* what I am calling Type (or self). It has consistent invariant semantics in all contexts.

You want to make the semantics of self / Type be covariant when used in
a protocol requirement. This makes no sense to me as it is explicitly
*not* covariant when used within a class declaration. We already have a
covariant construct (Self) and the proposal is to introduce an invariant
construct (self or Type). The invariant semantic should be consistent
regardless of whether it is used in a protocol requirement or a type
declaration.

IMO BaseSelf is a poor choice of name for something that is supposed to
be valid syntax in value types as well as classes.

On 11.05.2016 18:58, Matthew Johnson wrote: 'f' would return E for
E, F and G. Because the conformance is declared by E the
requirement to return self is fixed as an invariant requirement to
return E for all potential subclasses.

Probably you(we) need another proposal, like BaseSelf (or
SuperSelf) that means "this class or any its base class", then I
understand how such a `f()->BaseSelf` protocol requirement can
be applied to E class and also be true for F&G classes (as f()
inherited from base class will return instance of E which is
base for both).

This is exactly what self (or Type) does. The behavior you have
been describing is the behavior of Self which already exists.

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