[Pitch] Parameter Packs

You can express a lot of things with parameter packs in their current form if you get creative :slightly_smiling_face: but please continue to bring up pain points here! I have my own list of things I think should be nicer to express, but I'm sure you all will come up with things I haven't thought of.

2 Likes

The developer snapshots use the libswiftCore.dylib from the OS. You need to set DYLD_LIBRARY_PATH to use the runtime from the toolchain:

export DYLD_LIBRARY_PATH=/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2023-06-07-a.xctoolchain/usr/lib/swift/macosx

Your example seems to work with the latest snapshot.

As documented in the proposals, variadic generic functions can backward deploy (there's a small shim to handle heap allocation of type packs for escaping closures), but variadic generic types cannot because they require too much runtime support.

Also note that the only way to build code with a variadic generic type in a developer snapshot is to pass -disable-availability-checking. Otherwise you get the placeholder parameter packs in generic types are only available in macOS 99.99.0 or newer error message (which should read macOS 14).

2 Likes

(EDIT: Oh, but this just tells you if the pack is empty, it doesn't give you the length.)

This is extremely gross and I'm not advocating this as the idiomatic solution, but you can already do this using the trick of try/catch control flow within repeat.

enum E: Error { case e }

struct Tuple<each T> {
  var x: (repeat each T)

  var isEmpty: Bool {
    func f<X>(_: X) throws { throw E.e }

    do {
      repeat try f(each x)
    } catch {
      return false
    }

    return true
  }
}

When compiled with -O all the abstraction is optimized away:

bb0(%0 : $*Tuple<repeat each T>):
  %2 = integer_literal $Builtin.Word, 0           
  %3 = pack_length $Pack{repeat each T}           
  %4 = builtin "cmp_eq_Word"(%3 : $Builtin.Word, %2 : $Builtin.Word) : $Builtin.Int1 
  cond_br %4, bb2, bb1                            

bb1:                                              
  %6 = integer_literal $Builtin.Int1, 0           
  br bb3(%6 : $Builtin.Int1)                      

bb2:                                              
  %8 = integer_literal $Builtin.Int1, -1          
  br bb3(%8 : $Builtin.Int1)                      

bb3(%10 : $Builtin.Int1):                         
  %11 = struct $Bool (%10 : $Builtin.Int1)        
  return %11 : $Bool 
5 Likes

Hmm, I'm only getting that to work for compiling a single file using swiftc when I additionally give it the arguments

-Xlinker -L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib


because otherwise the linker complains about not finding a library for -lSystem.

I haven't managed to build and run a package so far though. Any advice?

Spending some amount of time on parameter packs, I wanted to provide some feedback on the current state of parameter packs in Variadic Generics.

Firstly, I often find myself writing code that looks a bit hacky and may be difficult to read due to the lack of something like "repeat" block. For instance, I end up using nested function like the following:

func someVariadicGenericFunction<each T>(argument: repeat each T) -> Value {
    var result: Value  = Value()
    func update<U>(with argument: U) {
        result = someFunction(argument)
    }
    repeat update(with each argument)
    return result 
}

It would be simpler and cleaner if we had something like repeat block:

var result: Value = Value()
repeat {
    result = someFunction(each argument)
}
return result

Secondly, it is currently not possible to reuse value packs in a variadic function like print(repeat each value) . Although the syntax itself was accepted as part of SE-0393, it requires another proposal before it can be implemented, as mentioned in this comment. I believe this is a small but important improvement, and I hope to see a proposal for it soon.


Lastly, while trying to implement a variadic ChainSequence in Swift Algorithms, I encountered difficulties in conforming to Collection due to the lack of something like a "variadic union type." Specifically, I couldn't implement a variadic version of this section.

Although I don't have a concrete suggestion to enable this kind of variadic generics, I believe it is an issue worth addressing.

2 Likes