On Sun, Mar 12, 2017 at 3:23 AM, Karl Wagner <[email protected]> wrote:
> > On 12 Mar 2017, at 09:11, Xiaodi Wu <[email protected]> wrote: > > 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`? > > > Yes, but I may want ScannerPromise.Result to be a generic parameter. I > refer you to my original email: > > Even with SE-0142, this kind of constraint would not be possible. What I > would like to write is something like this: > > protocol Promise { > associatedtype Result > func await() -> Result > } > > protocol Scanner { > associatedtype ScanPromise<X>: Promise where Result == X // (incl. > SE-0142) > > func promiseScan<T>(from: Offset, until: @escaping (Offset, Item) -> > T?) -> ScanPromise<T?> > } > > So, for example, I could write something like this (allowing my > asynchronous Scanners to all automatically implement a synchronous API): > > extension Scanner { > func scan(from f: Offset, until u: (Offset, Item) -> T?) -> T? { > return promiseScan(from: f, until: u).await() > } > } > > A conforming Promise would look like this: > > class MyPromise<Result>: Promise { > func await() -> Result { … } > } > > And a conforming scanner would look like this: > > class Scanner { > typealias ScanPromise<X> = MyPromise<X> // compiler checks where > clause: Result == X > > public func promiseScan<T>(from f: Offset, until u: @escaping (Offset, > Item) -> T?) -> MyPromise<T?> { > return MyPromise(from: f, until: u) > } > } > I see. Makes sense now. I'm out of my depth here, but that does sound like what you want here is higher kinded types.
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
