> On Dec 28, 2015, at 12:04 PM, Developer <devteam.cod...@gmail.com> 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 <matt...@anandabits.com > <mailto:matt...@anandabits.com>> のメッセージ: > >> >>> On Dec 28, 2015, at 11:19 AM, Developer <devteam.cod...@gmail.com >>> <mailto:devteam.cod...@gmail.com>> 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 >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> のメッセージ: >>> >>>> 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 >>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution