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

Reply via email to