<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Mar 10, 2016 at 12:43 AM, Jonathan Tang <span dir="ltr"><<a href="mailto:jonathan.d.tang@gmail.com" target="_blank">jonathan.d.tang@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>On Wed, Mar 2, 2016 at 5:22 PM, Douglas Gregor via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote: </div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div><div><br></div><div><span style="font-size:14px"><i>Variadic generics</i></span></div><div><br></div><div><div>Currently, a generic parameter list contains a fixed number of generic parameters. If one has a type that could generalize to any number of generic parameters, the only real way to deal with it today involves creating a set of types. For example, consider the standard library’s “zip” function. It returns one of these when provided with two arguments to zip together:</div><div><br></div></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div><font face="Menlo">public struct Zip2Sequence<Sequence1 : Sequence,</font></div><div><font face="Menlo"> Sequence2 : Sequence> : Sequence { … }</font></div></div><div><font face="Menlo"><br></font></div><div><div><font face="Menlo">public func zip<Sequence1 : Sequence, Sequence2 : Sequence>(</font></div><div><font face="Menlo"> sequence1: Sequence1, _ sequence2: Sequence2)</font></div><div><span style="font-family:Menlo"> -> Zip2Sequence<Sequence1, Sequence2> { … }</span></div></div></blockquote><div><div><br></div><div>Supporting three arguments would require copy-paste of those of those:</div><div><br></div><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><font face="Menlo">public struct Zip3Sequence<Sequence1 : Sequence,</font></div><div><font face="Menlo"> Sequence2 : Sequence,</font></div><span style="font-family:Menlo"> Sequence3 : Sequence</span><span style="font-family:Menlo">> : Sequence { … }</span><div><font face="Menlo"><br></font></div><div><div><font face="Menlo">public func zip<Sequence1 : Sequence, Sequence2 : Sequence</font><span style="font-family:Menlo">, Sequence3 : Sequence</span><span style="font-family:Menlo">>(</span></div><div><span style="font-family:Menlo"> sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: sequence3)</span></div><div><font face="Menlo"> -> Zip3Sequence<Sequence1, Sequence2, Sequence3> { … }</font></div></div></blockquote><div></div></div><div><br></div><div>Variadic generics would allow us to abstract over a set of generic parameters. The syntax below is hopelessly influenced by <a href="http://www.jot.fm/issues/issue_2008_02/article2/" target="_blank">C++11 variadic templates</a> (sorry), where putting an ellipsis (“…”) to the left of a declaration makes it a “parameter pack” containing zero or more parameters and putting an ellipsis to the right of a type/expression/etc. expands the parameter packs within that type/expression into separate arguments. The important part is that we be able to meaningfully abstract over zero or more generic parameters, e.g.:</div><div><br></div></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><font face="Menlo">public struct ZipIterator<... <b>Iterators</b> : IteratorProtocol</font><span style="font-family:Menlo">> : Iterator { <i>// zero or more type parameters, each of which conforms to IteratorProtocol</i></span></div><div><span style="font-family:Menlo"> public typealias Element = (<b>Iterators.Element...</b>) <i>// a tuple containing the element types of each iterator in Iterators</i></span></div><div><span style="font-family:Menlo"><br></span></div><div><span style="font-family:Menlo"> var (<b>...iterators</b>): (<b>Iterators...</b>) <i>// zero or more stored properties, one for each type in Iterators</i></span><span style="font-family:Menlo"> </span></div><font face="Menlo"> var reachedEnd: Bool = false</font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"><br></font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"> public mutating func next() -> Element? {</font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"> if reachedEnd { return nil }</font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"><br></font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"> guard let values = (<b>iterators.next()...</b>) { <i>// call “next” on each of the iterators, put the results into a tuple named “values"</i></font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"> reachedEnd = true</font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"> return nil</font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"> }</font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"><br></font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"> return values</font></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"> }<br></font><div><span style="font-family:Menlo">}</span></div><div><span style="font-family:Menlo"><br></span></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div><font face="Menlo">public struct ZipSequence<<b>...Sequences</b> : Sequence</font><span style="font-family:Menlo">> : Sequence {</span></div><div><span style="font-family:Menlo"> public typealias Iterator = ZipIterator<<b>Sequences.Iterator...</b>> <i>// get the zip iterator with the iterator types of our Sequences</i></span></div><div><span style="font-family:Menlo"><i><br></i></span></div><div><div><font face="Menlo"> var (...</font><b><font face="Menlo">sequences</font></b><font face="Menlo">): (<b>Sequences</b></font><b style="font-family:Menlo">...</b><font face="Menlo">) </font><i style="font-family:Menlo">// zero or more stored properties, one for each type in Sequences</i><span style="font-family:Menlo"> </span></div><div><span style="font-family:Menlo"><br></span></div><font face="Menlo"></font></div><div><span style="font-family:Menlo"> <i>// details ...</i></span></div><div><span style="font-family:Menlo">}</span></div></div><div><br></div></blockquote><div><div>Such a design could also work for function parameters, so we can pack together multiple function arguments with different types, e.g.,</div><div><br></div><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><font face="Menlo">public func zip<<b>... Sequences : SequenceType</b>>(<b>... sequences: Sequences...</b>) </font></div><div><span style="font-family:Menlo"> -> ZipSequence<<b>Sequences...</b>> {</span></div><div><span style="font-family:Menlo"> return ZipSequence(<b>sequences...</b>)</span></div><div><span style="font-family:Menlo">}</span></div></blockquote><div></div></div><div><br></div><div>Finally, this could tie into the discussions about a tuple “splat” operator. For example:</div><div><br></div></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div><font face="Menlo">func apply<... Args, Result>(fn: (Args...) -> Result, <i>// function taking some number of arguments and producing Result</i></font></div><div><font face="Menlo"> args: (Args...)) -> Result { <i>// tuple of arguments</i></font></div></div><div><div><font face="Menlo"> return fn(<b>args...</b>) // expand the arguments in the tuple “args” into separate arguments</font></div><div><font face="Menlo">}</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><font face="Menlo"><br></font></blockquote></div></blockquote><div><br></div><div>The application of this to function types is most interesting to me. Right now, when I need client code to register callbacks of potentially different arities, I make the function signature take an Args structure with a method to unpack it by position:<br></div></div><div><br></div><div>struct Args {</div><div> func arg<T>(i: Int) -> T {</div><div> // Bounds-checking and dynamic typecasting/marshalling</div><div> guard let result = myValue as? T else {</div><div> throw TypeConversionError()</div><div> }</div><div> return result</div><div> }</div><div>}</div><div><br></div><div>func addHandler(name: String, handler: Args throws -> AnyObject) {</div><div> ....</div><div>}</div><div><br></div><div>func foo(x: String) { ... }</div><div>func bar(y: Int, z: String) { ... }</div><div><br></div><div>addHandler("foo", { args in try foo(args.arg(0)) })</div><div>addHandler("bar", { args in try bar(args.arg(0), args.arg(1)) })</div><div><br></div><div>If variadics could let the client just do</div><div><br></div><div>addHandler("foo", foo)</div><div>addHandler("bar", bar)</div><div><br></div><div>and then preserve the type signature of foo & bar as they're stored in a dictionary, that'd be great for my library's users. Repeated across the whole library ecosystem, it'd make it much easier for one library's functions to play nice with another library's callbacks, because you wouldn't need proprietary adapter classes that force a dependency on another library just so that client code can use the two together easily.</div><div><br></div><div>But this only works if the type is not erased, i.e. if I can define a dictionary of type [String : (...ParameterType throws -> AnyObject)] and then call a function with apply(handlers["foo"], ["myParam"]). This requires at least three features:</div><div><br></div><div>1. Variadic generics - and not just in function signatures, but also as part of the function *type*, and as structure members, and as associated Element types for Dictionary etc.</div><div>2. An array-splat operator which lets me apply these functions to a data structure, checking the types dynamically as it converts them, <i>or</i></div><div>3. A tuple-splat operator to apply functions to a tuple, <i>plus</i> an array-to-tuple conversion.</div></div></blockquote><div> </div><div>4. Probably "Opening existentials" too, to make the array-to-tuple or array-to-function conversion work. The data in the array is heterogenous, as are the variadic generic parameters. It could work if you could loop over variadic parameters in a type and attempt to unwrap the existential in the array as that type, reporting an error if not.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div></div><div>The actual data that gets passed to the functions is dynamic and subject to error-checking, so it doesn't help if it only works with tuples and not arrays etc.</div><div><br></div><div>Not sure how likely the combination of these happening is, but I think it'd be a big win for Swift's library ecosystem. It's hard to pass callbacks across third-party libraries otherwise, because the type signatures depend upon proprietary types that won't be in the receiving library.</div><div> </div><div><br></div></div>
</blockquote></div><br></div></div>