[swift-evolution] [Idea] Generic associated types

Xiaodi Wu xiaodi.wu at gmail.com
Sun Mar 12 03:11:11 CDT 2017


On Sun, Mar 12, 2017 at 3:02 AM, Karl Wagner <razielim at gmail.com> wrote:

>
> 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> wrote:
>
>>
>> On 12 Mar 2017, at 08:21, Xiaodi Wu <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()
>
>
Hmm, I'm not sure what you're trying to accomplish here. If I have an
instance `s` that conforms to `Scanner`, then it must have a concrete
associated type `ScannerPromise.Result`. `s.frobnicate()` can only take an
argument of type `ScannerPromise.Result`; you want to pass an argument of
arbitrary type `T` and have an existing instance conforming to `Scanner`
retroactively change the type of `ScannerPromise.Result`?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170312/8db7b616/attachment.html>


More information about the swift-evolution mailing list