[swift-evolution] [RFC] #Self
Thorsten Seitz
tseitz42 at icloud.com
Thu May 12 13:10:55 CDT 2016
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 at swift.org>:
>
>>
>> On May 12, 2016, at 10:19 AM, Vladimir.S <svabox at gmail.com <mailto:svabox at 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 at gmail.com <mailto:svabox at 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 at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160512/ca23d82a/attachment.html>
More information about the swift-evolution
mailing list