[swift-evolution] [Idea] Generic associated types

Karl Wagner razielim at gmail.com
Sun Mar 12 03:02:40 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

No, what you’ve done is something different. “frobnicate” is itself a generic function, so it should work if you rename the parameter to “U". You’ve just punted the constraint down the abstraction hierarchy.

This becomes clear if you try to continue working at the protocol-level:

extension Scanner {
	func synchronised_frob<T>(_ t: T) -> T {
	    return frobnicate(t).await()
	}
}

error: repl.swift:14:16: error: cannot invoke 'frobnicate' with an argument list of type '(T)'
        return frobnicate(t).await()
               ^

repl.swift:14:16: note: expected an argument list of type '(T)'
        return frobnicate(t).await()

- Karl

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


More information about the swift-evolution mailing list