<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: &lt;T: Collection&gt;(_: T) -&gt; 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 "(&lt;T&gt;(T)-&gt;Void where ...)-&gt;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&lt;T: Collection&gt;(_: 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: "&lt;T&gt;(T)-&gt;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="">&nbsp; &nbsp; if let idx = index(where: { $0 == 0x04 }) {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; &nbsp; &nbsp; //...</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; }</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 &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; 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 &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; 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 &lt;<a href="mailto:razielim@gmail.com" class="">razielim@gmail.com</a>&gt; 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 &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>&gt; 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. &nbsp;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. &nbsp;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. &nbsp;Kind of a well-known trick in a number of languages. &nbsp;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. &nbsp;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. &nbsp;</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. &nbsp;The type erasing wrapper required an allocation and type information that could have been used by the optimizer was lost. &nbsp;This was frustrating and convinced me that we definitely need HKT in Swift eventually. &nbsp;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;">&nbsp; &nbsp; &nbsp; //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="">&nbsp; &nbsp; func scan&lt;T&gt;(from f: Offset, until u: (Offset, Item) -&gt; T?) -&gt; T? {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; &nbsp; &nbsp; return withoutActuallyEscaping(u) { _u -&gt; 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="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 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="">&nbsp; &nbsp; &nbsp; &nbsp; }</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; }</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&lt;R&gt;: Promise {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; typealias Result = R?</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; let offset: Offset</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; let block: (Offset, Item) -&gt; 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="">&nbsp; &nbsp; typealias ScanPromise = MyPromise&lt;Any&gt; // want this to be “typealias ScanPromise&lt;X&gt; = MyPromise&lt;X&gt;"</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="">&nbsp; &nbsp; func promiseScan&lt;T&gt;(from: Offset, until: @escaping (Offset, Item) -&gt; T?) -&gt; ScanPromise {</font></div></div></div><div class=""><div class=""><div class=""><font face="Courier" class="">&nbsp; &nbsp; &nbsp; &nbsp; 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="">&nbsp; &nbsp; }</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 &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; 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="">&nbsp; &nbsp; 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="">&nbsp; &nbsp; associatedtype ScanPromise: Promise</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; func promiseScan&lt;T&gt;(from: Offset, until: (Offset, Item) -&gt; T?) -&gt; 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="">&nbsp; &nbsp; 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="">&nbsp; &nbsp; associatedtype ScanPromise&lt;T&gt;: 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="">&nbsp; &nbsp; func promiseScan&lt;T&gt;(from: Offset, until: (Offset, Item) -&gt; T?) -&gt; ScanPromise&lt;T&gt;</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>