Can a function with parameter packs return a non-generic value for each parameter?

I have this code:

struct Tweak<Value> {
    var name: String
    var value: Value
}

func name<Value>(of tweak: Tweak<Value>) -> String {
    return tweak.name
}

func names<Value1, Value2>(of tweak1: Tweak<Value1>, _ tweak2: Tweak<Value2>) -> (String, String) {
    return (tweak1.name, tweak2.name)
}

Now I want to implement the second function using parameter packs:

func names<each Value>(of tweak: repeat Tweak<each Value>) -> (repeat String) {
    return repeat each tweak.name
}

But that gives this error:

error: pack expansion 'String' must contain at least one pack reference
func names<each Value>(of tweak: repeat Tweak<each Value>) -> (repeat String) {
                                                               ^~~~~~~~~~~~~

What is the correct syntax for doing this? Or is it impossible to spell this?

Thanks,

Marco

Accepted Reply

Of course I found the solution immediately after posting this 🤦‍♂️

The trick is to get the parameter pack into the return value somehow. I did it using a typealias inside the generic type:

struct Tweak<Value> {
    typealias Name = String

    var name: Name
    var value: Value
}

func names<each Value>(of tweak: repeat Tweak<each Value>) -> (repeat Tweak<each Value>.Name) {
    return (repeat (each tweak).name)
}

And now it works as it should 🙂

Add a Comment

Replies

Of course I found the solution immediately after posting this 🤦‍♂️

The trick is to get the parameter pack into the return value somehow. I did it using a typealias inside the generic type:

struct Tweak<Value> {
    typealias Name = String

    var name: Name
    var value: Value
}

func names<each Value>(of tweak: repeat Tweak<each Value>) -> (repeat Tweak<each Value>.Name) {
    return (repeat (each tweak).name)
}

And now it works as it should 🙂

Add a Comment

It should be possible, but at present the compiler only allows implicit repeatable non-generic types, like (repeat String).

Consider the following:

func mirrorString<each M>(_ input: repeat each M) -> String {
      let result = (repeat String(describing: each input))
      return String(describing: result)
    }

The variable result has an implicit type. Option click the variable and see, let result: (repeat String). However it is not possible to explicitly declare (repeat String) as a variable type or a return type. I believe this to be a bug.

  • submitted FB12323957

  • You’re right that this could just be a bug or at least something that hasn’t been implemented yet. After all, functions can only declare a single parameter pack, so there shouldn’t be any ambiguity as to how many times anything should be repeated.

  • The proposal specifically addresses this situation. Type inference is possible for a one-element tuple type like (repeat String), but we are unable to explicitly declare one in source. See Swift Evolution Proposal 0393 Value and Type Parameter Packs.

Add a Comment