Oh yep, I accidentally read that section as ‘Alternatives Considered’. I still find this a little bit of a hack, so I hope this approach doesn’t get used too much, certainly not in the standard library. Is this only useful for factory or other static methods? It would just be a shame to see protocols become defensive for use cases like this.
I believe the protocol should remain ‘pure’, and the conforming types then decide on which way they want to go. If they use a static type (or label the method final), then its particular protocol requirements change. Anyway, nice resolution! > On 19 May 2016, at 1:06 PM, Matthew Johnson <[email protected]> wrote: > > > > Sent from my iPad > > On May 18, 2016, at 9:57 PM, Patrick Smith <[email protected] > <mailto:[email protected]>> wrote: > >> I think the distinction between StaticSelf and Self will be very confusing >> to newcomers. >> >> So the only reason why we must use StaticSelf instead of Self here is >> because we want NSURL to conform, and it isn’t final? >> >> protocol StringCreatable { >> static func createWithString(s: String) -> StaticSelf >> } >> >> I find it a code smell that this would affect the protocol and not the class. >> >> Why couldn’t you have this? >> >> protocol StringCreatable { >> static func createWithString(s: String) -> Self >> } >> >> 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 { >> // ... >> } >> } >> > > You can't do this because the Self return type in the protocol requirement > specifically *requires* all subclasses to override the method and return an > instance of the subclass type. > > Nevertheless, we have identified a workaround that is similar enough to > StaticSelf that we have abandoned the proposal. Please see The last couple > posts in this thread if you're interested in the details. > >> >> >>> On 19 May 2016, at 3:37 AM, Erica Sadun via swift-evolution >>> <[email protected] <mailto:[email protected]>> wrote: >>> >>> As a wrap-up of the topic, I've updated our original draft with Nicola S's >>> resolution. >>> >>> https://gist.github.com/erica/995af96a0de2f2f3dc419935e8140927 >>> <https://gist.github.com/erica/995af96a0de2f2f3dc419935e8140927> >>> >>> -- E >>> >>> >>>> On May 14, 2016, at 8:35 AM, Matthew Johnson via swift-evolution >>>> <[email protected] <mailto:[email protected]>> wrote: >>>> >>>>> >>>>> On May 14, 2016, at 12:55 AM, Nicola Salmoria via swift-evolution >>>>> <[email protected] <mailto:[email protected]>> wrote: >>>>> >>>>> Matthew Johnson via swift-evolution <swift-evolution@...> writes: >>>>> >>>>>> I agree it’s a bit tricky. But that’s better than not possible at all. >>>>> You just need a typealias and a same type constraint to make this work as >>>>> expected / desired: >>>>>> >>>>>> >>>>>> protocol Makable { >>>>>> >>>>>> typealias RootMakable = StaticSelf >>>>>> static func make(value: Int) -> StaticSelf >>>>>> } >>>>>> >>>>>> func makeWithZero<T: Makable where T == T.RootMakable>(x: Int) -> T { >>>>>> return T.make(value: 0) // works now >>>>>> } >>>>>> >>>>>> >>>>>> Now that we have a typealias we can refer to the binding of StaticSelf >>>>>> and >>>>> constrain it as necessary for whatever purpose we have in mind. In some >>>>> cases that will be a same type constraint so that our code works properly >>>>> with class clusters. I don’t have concrete examples of other use cases >>>>> but >>>>> can imagine use cases constraining the typealias to a protocol, for >>>>> example. >>>>> >>>>> You can do that today: >>>>> >>>>> protocol Makable { >>>>> associatedtype MadeType >>>>> static func make(value: Int) -> MadeType >>>>> } >>>>> >>>>> func makeWithZero<T: Makable where T == T.MadeType>(x: Int) -> T { >>>>> return T.make(value: 0) >>>>> } >>>>> >>>>> You can't currently constrain MadeType to be the same as the conforming >>>>> type, but, does it matter? What kind of extra guarantees would that give, >>>>> since you need to add the extra constraint anyway in generic code? >>>> >>>> Wow, this is pretty cool. Thank you very much for pointing this out >>>> Nicola! >>>> >>>> I haven’t seen this approach to solving the problem. Given the amount of >>>> discussion this problem has received I am surprised nobody has shared this >>>> solution yet. I just checked in Xcode 7.3 and it works there. It isn’t >>>> dependent on any pre-release features. >>>> >>>> Instead of using StaticSelf under the current proposal: >>>> >>>> protocol StringInitializable { >>>> static func initializeWith(string: String) -> StaticSelf >>>> } >>>> >>>> We just add an associatedtype defaulted to Self: >>>> >>>> protocol StringInitializable { >>>> associatedtype Initialized = Self // where Self: Initialized >>>> static func initializeWith(string: String) -> Initialized >>>> } >>>> >>>> extension NSURL: StringInitializable { >>>> static func initializeWith(string: String) -> NSURL { >>>> return NSURL() >>>> } >>>> } >>>> >>>> func makeWith<T: StringInitializable where T == T.Initialized>(string: >>>> String) -> T { >>>> return T.initializeWith(string: string) >>>> } >>>> >>>> There are two minor downsides to this approach: >>>> >>>> 1. You can’t copy and paste the method signature. >>>> 2. You can theoretically conform a type completely unrelated to >>>> `Initialized` to the protocol, thus violating the semantics. >>>> >>>> I think we can live with these downsides. Maybe the `Self: Initialized` >>>> will be possible someday. That would be pretty close to StaticSelf. The >>>> only difference would be that subclasses still have flexibility to >>>> override with their own type. >>>> >>>> Now that a reasonable way to do this with existing language features has >>>> been identified I will withdraw this proposal. If this approach doesn’t >>>> address use cases others have in mind for StaticSelf please speak up! >>>> >>>> Doug, if you’re reading this, does the `where Self: Initialized` (i.e. >>>> arbitrary subclass constraints) fall into the scope of your “completing >>>> generics” manifesto? This is a concrete use case that would utilize >>>> subclass constraints. >>>> >>>> -Matthew >>>> >>>> >>>>> >>>>> Nicola >>>>> _______________________________________________ >>>>> 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] <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] <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
