[swift-evolution] [Idea] Generic associated types

Karl Wagner razielim at gmail.com
Sun Mar 12 03:10:31 CDT 2017


> On 12 Mar 2017, at 08:50, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> 
> On Sun, Mar 12, 2017 at 1:39 AM, Karl Wagner <razielim at gmail.com <mailto:razielim at gmail.com>> wrote:
> 
>> On 12 Mar 2017, at 08:21, Xiaodi Wu <xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>> wrote:
>> 
>> Sorry, I'm confused. The following works:
>> 
>> ```
>> protocol Promise {
>>   associatedtype Result
>> }
>> 
>> protocol Scanner {
>>   associatedtype ScannerPromise : Promise
>>   func frobnicate<T>(_: T) -> ScannerPromise
>>     where ScannerPromise.Result == T
>> }
>> ```
>> 
>> Why does it matter if `ScannerPromise` is generic or not?
>> 
> 
> That’s some pretty strange syntax. I admit I didn’t even try that. ScannerPromise would necessarily have to be generic in this context, because I want to bind one of its associated types to a generic parameter from a function. There is no way a non-generic type could do that.
> 
> That said, even though the compiler accepts your code, it doesn’t seem to actually work:
> 
> protocol Promise {
>   associatedtype Result
>   func await() -> Result
> }
> 
> protocol Scanner {
>   associatedtype ScannerPromise : Promise
>   func frobnicate<T>(_: T) -> ScannerPromise
>     where ScannerPromise.Result == T
> }
> 
> func use<S: Scanner, T>(_ s: S, _ t: T) -> T {
> 	return s.frobnicate(t).await()
> }
> 	    
> 
> 3.0.2: Segfault
> 
> 3.1:
> 
> error: repl.swift:13:14: error: cannot invoke 'frobnicate' with an argument list of type '(T)'
>     return s.frobnicate(t).await()
>              ^
> 
> repl.swift:13:14: note: expected an argument list of type '(T)'
>     return s.frobnicate(t).await()
> 
> That's because your `T` in `use` has no relationship with your `T` in `protocol Scanner`; you just happen to have chosen the same letter of the alphabet. This becomes clear if you rename:
> 
> ```
> func use<S: Scanner, U>(_ s: S, _ t: U) -> U {
>   return s.frobnicate(t).await()
> }
> 
> // cannot invoke 'frobnicate' with an argument list of type '(U)'
> // expected an argument list of type '(T)'
> ```
> 
> However, this works:
> 
> ```
> func use<S: Scanner, T>(_ s: S, _ t: T) -> T
>   where S.ScannerPromise.Result == T {
>   return s.frobnicate(t).await()
> }
> ```
> 
> ...or just this:
> 
> ```
> func use<S: Scanner>(
>   _ s: S, _ t: S.ScannerPromise.Result
> ) -> S.ScannerPromise.Result {
>   return s.frobnicate(t).await()
> }
> ```
> 
> - Karl
> 

I’m pretty sure that the compiler is interpreting the constraint with “reverse emphasis”, so to speak. That is:

func frobnicate<T>(_: T) -> ScannerPromise where ScannerPromise.Result == T

becomes

func frobnicate<T>(_: T) -> ScannerPromise where T == ScannerPromise.Result

becomes

func frobnicate(_: ScannerPromise.Result) -> ScannerPromise

which is why you can’t invoke it with a generic ’T’

- Karl
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170312/0e148a51/attachment.html>


More information about the swift-evolution mailing list