On Sun, Mar 12, 2017 at 3:02 AM, Karl Wagner <[email protected]> wrote:
> > On 12 Mar 2017, at 08:50, Xiaodi Wu <[email protected]> wrote: > > On Sun, Mar 12, 2017 at 1:39 AM, Karl Wagner <[email protected]> wrote: > >> >> On 12 Mar 2017, at 08:21, Xiaodi Wu <[email protected]> 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`?
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
