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.
···
On Sun, Mar 12, 2017 at 3:23 AM, Karl Wagner <razielim@gmail.com> wrote:
On 12 Mar 2017, at 09:11, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
On Sun, Mar 12, 2017 at 3:02 AM, Karl Wagner <razielim@gmail.com> wrote:
On 12 Mar 2017, at 08:50, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
On Sun, Mar 12, 2017 at 1:39 AM, Karl Wagner <razielim@gmail.com> wrote:
On 12 Mar 2017, at 08:21, Xiaodi Wu <xiaodi.wu@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`?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 == Xpublic func promiseScan<T>(from f: Offset, until u: @escaping (Offset,
Item) -> T?) -> MyPromise<T?> {
return MyPromise(from: f, until: u)
}
}