<div dir="ltr"><div>On Wed, Mar 2, 2016 at 5:22 PM, Douglas Gregor via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</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&lt;Sequence1 : Sequence,</font></div><div><font face="Menlo">                           Sequence2 : Sequence&gt; : Sequence { … }</font></div></div><div><font face="Menlo"><br></font></div><div><div><font face="Menlo">public func zip&lt;Sequence1 : Sequence, Sequence2 : Sequence&gt;(</font></div><div><font face="Menlo">              sequence1: Sequence1, _ sequence2: Sequence2)</font></div><div><span style="font-family:Menlo">            -&gt; Zip2Sequence&lt;Sequence1, Sequence2&gt; { … }</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&lt;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">&gt; : Sequence { … }</span><div><font face="Menlo"><br></font></div><div><div><font face="Menlo">public func zip&lt;Sequence1 : Sequence, Sequence2 : Sequence</font><span style="font-family:Menlo">, Sequence3 : Sequence</span><span style="font-family:Menlo">&gt;(</span></div><div><span style="font-family:Menlo">              sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: sequence3)</span></div><div><font face="Menlo">            -&gt; Zip3Sequence&lt;Sequence1, Sequence2, Sequence3&gt; { … }</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&lt;... <b>Iterators</b> : IteratorProtocol</font><span style="font-family:Menlo">&gt; : 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() -&gt; 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&quot;</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&lt;<b>...Sequences</b> : Sequence</font><span style="font-family:Menlo">&gt; : Sequence {</span></div><div><span style="font-family:Menlo">  public typealias Iterator = ZipIterator&lt;<b>Sequences.Iterator...</b>&gt;   <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&lt;<b>... Sequences : SequenceType</b>&gt;(<b>... sequences: Sequences...</b>) </font></div><div><span style="font-family:Menlo">            -&gt; ZipSequence&lt;<b>Sequences...</b>&gt; {</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&lt;... Args, Result&gt;(fn: (Args...) -&gt; Result,    <i>// function taking some number of arguments and producing Result</i></font></div><div><font face="Menlo">                           args: (Args...)) -&gt; 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&lt;T&gt;(i: Int) -&gt; 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 -&gt; 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(&quot;foo&quot;, { args in try foo(args.arg(0)) })</div><div>addHandler(&quot;bar&quot;, { 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(&quot;foo&quot;, foo)</div><div>addHandler(&quot;bar&quot;, bar)</div><div><br></div><div>and then preserve the type signature of foo &amp; bar as they&#39;re stored in a dictionary, that&#39;d be great for my library&#39;s users.  Repeated across the whole library ecosystem, it&#39;d make it much easier for one library&#39;s functions to play nice with another library&#39;s callbacks, because you wouldn&#39;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 -&gt; AnyObject)] and then call a function with apply(handlers[&quot;foo&quot;], [&quot;myParam&quot;]).  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><br></div><div>The actual data that gets passed to the functions is dynamic and subject to error-checking, so it doesn&#39;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&#39;d be a big win for Swift&#39;s library ecosystem.  It&#39;s hard to pass callbacks across third-party libraries otherwise, because the type signatures depend upon proprietary types that won&#39;t be in the receiving library.</div><div> </div><div><br></div></div>