> On Dec 28, 2015, at 12:04 PM, Developer <[email protected]> wrote:
>
> That doesn't look like a variance issue to me, that's about the same
> "information" invariant I talked about before. The former works because self
> resolves to an invariant type, the type of the implementing structure, which
> satisfies the requirement Self introduces. The latter does not because Self
> indicates a level of specificity C cannot guarantee. Self is magic, but it
> is also implemented as a generic parameter. So think of it this way:
>
> protocol Q {
> func bar<T>() -> T { return Q() }
> }
>
> You wouldn't expect that to compile, would you?
It actually does work for structs and for final classes because Self becomes
invariant when used in a return type position for them.
protocol Q {
func bar() -> Self
}
final class C: Q {
func bar() -> C { return C() }
}
>
> ~Robert Widmann
>
> 2015/12/28 12:49、Matthew Johnson <[email protected]
> <mailto:[email protected]>> のメッセージ:
>
>>
>>> On Dec 28, 2015, at 11:19 AM, Developer <[email protected]
>>> <mailto:[email protected]>> wrote:
>>>
>>> My understanding of Self is that it is a special generic parameter resolved
>>> by the type system to the type of the implementing structure. That
>>> resolution must be invariant because the implementing structure (here,
>>> non-final classes) can choose to yank the protocol's invariants out from
>>> under you when it is subclassed. Sure, retroactively, you can make things
>>> conform, but you also can't completely guarantee type safety with any kind
>>> of variance in Self in all cases.
>>>
>>> On the other hand, using the protocol itself in either position says that
>>> you only wish to restrict yourself to the protocol itself, not some
>>> specific implementation. You are necessarily specifying an upper bound
>>> (here C) on the amount of "information" you can get out of the type, so it
>>> is possible to introduce variance because you will never violate the
>>> protocol's invariants by returning a subtype with a legal conformance.
>>>
>>> Self doesn't mean two different things, your protocol declarations do!
>>
>> My mind must be a little bit foggy this morning. This works:
>>
>> extension C: Q {
>> func bar() -> Self { return self }
>> }
>>
>> What doesn’t work, regardless of whether C is final or not, is this:
>>
>> extension C: Q {
>> // Cannot convert return expression of type ‘C’ to return type ‘Self'
>> func bar() -> Self { return C() }
>> }
>>
>> In order for classes to meet a protocol requirement with Self in the return
>> position you must specify Self (rather than the conforming type) as the
>> return type for the method. Self in the return position of a method is
>> treated as covariant.
>>
>> In order for classes to meet a protocol requirement with Self in parameter
>> position you must specify the type of the conforming class (you cannot
>> specify Self in an argument position). Obviously the type of the conforming
>> class is invariant.
>>
>> This is the sense in which Self in protocol declarations is inconsistent.
>> The requirements on conforming types are different - invariance for Self
>> parameters and covariance for Self return types.
>>
>> IMO it would be much more clear if this distinction was explicit rather than
>> implicit based on the location of Self. It would also be extremely useful
>> in some cases to be able to specify an invariant `ConformingSelf` return
>> type.
>>
>>
>>>
>>> ~Robert Widmann
>>>
>>> 2015/12/28 11:49、Matthew Johnson via swift-evolution
>>> <[email protected] <mailto:[email protected]>> のメッセージ:
>>>
>>>> I have brought up the idea of a non-covarying Self a few times.
>>>>
>>>> I was surprised to realize that Self is actually non-covarying when used
>>>> for parameters in protocol declarations!
>>>>
>>>> Here is an example demonstrating this:
>>>>
>>>> protocol P {
>>>> func foo(s: Self)
>>>> }
>>>> protocol Q {
>>>> func bar() -> Self
>>>> }
>>>>
>>>> class C: P {
>>>> // this works! Self as an argument type in the protocol declaration
>>>> does not covary
>>>> func foo(c: C) {}
>>>> }
>>>>
>>>> class D: C {}
>>>>
>>>> extension C: Q {
>>>> // method ‘bar()’ in non-final class ‘C’ must return ‘Self’ to conform
>>>> to protocol ‘Q'
>>>> func bar() -> C { return self }
>>>> }
>>>>
>>>>
>>>> It doesn’t make sense to allow a co-varying Self for parameters so I can
>>>> understand how the current state might have arisen. At the same time,
>>>> using Self to mean two different things is inconsistent, confusing and it
>>>> doesn’t allow us to specify a non-covarying Self as a return type in
>>>> protocol requirements.
>>>>
>>>> As I have pointed out before, the ability to specify a non-covarying Self
>>>> as a return type would make it possible to design a protocol that can be
>>>> retroactively conformed to by non-final classes (such as those in Apple’s
>>>> frameworks).
>>>>
>>>> I think it would be a very good idea to introduce a non-covarying Self
>>>> which would specify the type that adds conformance to the protocol and
>>>> require this Self to be used in places where covariance is not possible,
>>>> such as parameter types. It would also be allowed elsewhere, such as
>>>> return types, making it easier to conform non-final classes when
>>>> covariance is not required by the protocol.
>>>>
>>>> One possible name is `ConformingSelf`. One thing I like about this name
>>>> is that it makes it very clear that it is the type that introduces
>>>> protocol conformance.
>>>>
>>>> I’m interested in hearing thoughts on this.
>>>>
>>>> Matthew
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> [email protected] <mailto:[email protected]>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution