<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="">I was thinking of making a new thread for this, but since this discussion’s basically over I thought I’d ask a quick question about generic closures.</div><div class=""><br class=""></div><div class="">Basically, I would like to express something like the following (without type-erasing via AnyCollection):</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><font face="Courier" class="">func vendsGenericBytes(callback: <T: Collection>(_: T) -> Void where T.Iterator.Element == UInt8) {</font></div></div></div></blockquote><span class="Apple-tab-span" style="font-family: Courier; white-space: pre;">        </span><span style="font-family: Courier;" class="">callback([1, 2, 3, 4, 5])</span><br class=""><span class="Apple-tab-span" style="font-family: Courier; white-space: pre;">        </span><span style="font-family: Courier;" class="">callback(DispatchData.empty)</span><br class=""><span class="Apple-tab-span" style="font-family: Courier; white-space: pre;">        </span><span style="font-family: Courier;" class="">callback(UnsafeRawBufferPointer(start: nil, count: 0))</span><br class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><font face="Courier" class="">}</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""><br class=""></font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">// type of vendsGenericBytes is "(<T>(T)->Void where ...)->Void"</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""><br class=""></font></div></div></div><div class=""><div class=""><font face="Courier" class="">func takesGenericBytes<T: Collection>(_: T) where T.Iterator.Element == UInt8 {</font></div></div></blockquote><span class="Apple-tab-span" style="font-family: Courier; white-space: pre;">        </span><span style="font-family: Courier;" class="">// ...</span><br class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Courier" class="">}</font></div><div class=""><span style="font-family: Courier;" class="">// type of takesGenericBytes is: "<T>(T)->Void where …”</span></div><div class=""><font face="Courier" class="">vendsGenericBytes(takesGenericBytes)</font></div><div class=""><br class=""></div></div><div class=""><br class=""></div><div class=""><div class=""><div class=""><font face="Courier" class="">vendsGenericBytes {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> if let idx = index(where: { $0 == 0x04 }) {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> //...</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> }</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">}</font></div></div></div><div class=""><div class=""><div class=""><br class=""></div></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">For functions and closures, you sometimes want to refer to them as an unbound generic because you intend to invoke them with a multitude of types within the same scope, and you want to invoke a specialised function/closure for each type of argument.</div><div class=""><br class=""></div><div class="">For example, vendsGenericBytes might decide to call the callback with a ReversedCollection (if the bytes are coming in reverse), or a LazyMapCollection, FilterCollection or any other kind of collection of UInt8s. You can write a generic function which handles that, but you can’t use it as a callback.</div><div class=""><br class=""></div><div class="">Would this kind of thing ever be supported in Swift? If so, could I (or somebody) add it to the generics manifesto so we don't forget?</div><div class=""><br class=""></div><div class="">- Karl</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 13 Mar 2017, at 17:50, John McCall <<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class="">On Mar 12, 2017, at 5:00 PM, Matthew Johnson via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class="">On Mar 12, 2017, at 3:23 PM, Karl Wagner <<a href="mailto:razielim@gmail.com" class="">razielim@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 12 Mar 2017, at 14:32, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="auto" class=""><div class="">This is a really important feature IMO, but as others have pointed out it basically amounts to higher-kinded types. I would love to be wrong about this but I am reasonably sure this is out of scope for Swift 4 (otherwise I would be working on a proposal already).<br class=""><br class="">Sent from my iPad</div><div class=""><br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">I’m not an expert on this stuff, but are they still higher-kinded types if we don’t express a relationship between Self and the associated type? I don’t think it’s quite the same conceptual leap as HKT.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">I’m no expert either but it sure seems to me like it enables the things usually discussed in the context of higher-kinder types. Maybe someone from the core team can comment on whether there is a meaningful difference</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Yes, it's a way of getting some of the behavior of higher-kinded types. Kind of a well-known trick in a number of languages. It's significantly simpler to handle in the type system because the higher-kinded entities stay "second class" — you don't necessarily have to deal with, say, higher-kinded type variables in the constraint solver or in type inference. Of course, that limits some of the code you can write, or at least the simplicity of that code.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">and whether this is something that could fit into Swift 4.</div></div></div></div></blockquote><div class=""><br class=""></div>No.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">John.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><br class=""></div><div class="">Consider that every associated type must be backed by a typealias (explicit or inferred) in the conforming type. We can already have generic typealiases. This would be a more targeted thing which required those associatedtype-implementing-typealiases to contain generic parameters. It would also extend the constraints from SE-0142 to allow constraints to refer to those parameters and bind them to other associated types.</div><div class=""><br class=""></div><div class="">The workaround is basically to erase and dynamic-cast your way out:</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Yes, there are workarounds, none of which are desirable. </div><div class=""><br class=""></div><div class="">I ran into a case last year where there was a significant performance impact caused by the need to perform type erasure as a workaround. The type erasing wrapper required an allocation and type information that could have been used by the optimizer was lost. This was frustrating and convinced me that we definitely need HKT in Swift eventually. There are very useful generic libraries that cannot be implemented efficiently without them.</div><div class=""><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><br class=""></div><div class=""><span class="" style="font-family: Courier;"> //NOTE: dynamic type of ScanPromise.Result *must* be same as closure result. No static enforcement though :(</span></div><div class=""><span class="" style="font-family: Courier;"><br class=""></span></div></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class=""><div class=""><font face="Courier" class="">extension Scanner where ScanPromise.Result == Any? {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> func scan<T>(from f: Offset, until u: (Offset, Item) -> T?) -> T? {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> return withoutActuallyEscaping(u) { _u -> T? in</font></div></div></div></blockquote><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class=""><div class=""><font face="Courier" class=""> return promiseScan(from: f, until: _u).await() as? T // downcast from Any? to T?</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> }</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> }</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">}</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""><br class=""></font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">class MyPromise<R>: Promise {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> typealias Result = R?</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> let offset: Offset</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> let block: (Offset, Item) -> R?</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">}</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""><br class=""></font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">class MyScanner: Scanner {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> typealias ScanPromise = MyPromise<Any> // want this to be “typealias ScanPromise<X> = MyPromise<X>"</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""><br class=""></font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> func promiseScan<T>(from: Offset, until: @escaping (Offset, Item) -> T?) -> ScanPromise {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> return MyPromise(offset: from, block: until) // upcast from T? to Any?</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class=""> }</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">}</font></div></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">- Karl</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="auto" class=""><div class="">On Mar 11, 2017, at 11:49 PM, Karl Wagner via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class="">I have a model like this:<div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><font face="Courier" class="">protocol Promise {</font></div><div class=""><font face="Courier" class=""> associatedtype Result</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">protocol Scanner {</font></div><div class=""><font face="Courier" class=""> associatedtype ScanPromise: Promise</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class=""> func promiseScan<T>(from: Offset, until: (Offset, Item) -> T?) -> ScanPromise // where Result == T?</font></div><div class=""><font face="Courier" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">The thing that I’m trying to express is: whichever type implements the associated type ‘ScanPromise’ must be generic, and that parameter must be its result (i.e. something it got as a result of calling the “until” closure).</div><div class=""><br class=""></div><div class="">Even with SE-0142, this kind of constraint would not be possible. What I would like to write is something like this:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Courier" class="">protocol Promise {</font></div><div class=""><font face="Courier" class=""> associatedtype Result</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">protocol Scanner {</font></div><div class=""><font face="Courier" class=""> associatedtype ScanPromise<T>: Promise // now generic. [SE-0142]: where Result == T</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class=""> func promiseScan<T>(from: Offset, until: (Offset, Item) -> T?) -> ScanPromise<T></font></div><div class=""><font face="Courier" class="">}</font></div></div><div class=""><br class=""></div><div class="">Thoughts?</div><div class=""><br class=""></div><div class="">- Karl</div></div></blockquote><blockquote type="cite" class=""><div class=""><span class="">_______________________________________________</span><br class=""><span class="">swift-evolution mailing list</span><br class=""><span class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a></span><br class=""><span class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br class=""></div></blockquote></div></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div></div></blockquote></div><br class=""></div></div></body></html>