[swift-evolution] Splat

Brent Royal-Gordon brent at architechies.com
Wed Feb 10 22:37:56 CST 2016


> Ah, I see, at least for #1.  I'm assuming that to get the function that takes a tuple, you'd have to explicitly use the parameters: overload:

Probably; otherwise this doesn't actually save the type checker much.

There's a bit of a complication when talking about type signatures. Currently, the fact that a function operates on a tuple is embedded in our type syntax, and the parentheses around the argument list are optional and represent a tuple—`(Int, String) -> String` is equivalent to `TupleOfIntAndString -> String`. This might now need a change, or at least a clarification. For the purposes of this post, I'll say that `(Int, String) -> String` is the type of a function taking an Int and String, while `((Int, String)) -> String` is the type of a function taking a tuple.

For the `concatenate(_:to:)` example, the original function has a signature of `(Int, String) -> String` (once argument labels are fully part of the name, which seems to be the trend). For each of the syntaxes I proposed, the type of this expression is `((Int, String)) -> String`:

	concatenate(parameters:)
	concatenate(_:to:).apply(to:)
	concatenate(_:to: *)

> let f = concatenate(_:to:).apply(to:)  // I assume this has type (Int, String) -> String
> var g = f.apply(to:)  // Is this legal?  What's the type?

That's an interesting question. Swift does not have 1-tuples, so unary functions might not have an `apply(to:)` method.

> // This type signature is wrong, g takes an arbitrary argument list...but how do I write that?
> func compose<Params, Intermediate, Result>(f: Intermediate -> Result , g: Params -> Intermediate) -> Result {
>   return { args in f.apply(to: g.apply(to: args)) }
> }

Without something along the lines of the `@splatting` annotation in a parameter list, it would not be possible to write a `compose(_:_:)` function which could operate on non-unary functions directly. Instead of writing `compose(f, g)`, you'd have to write `compose(f.apply, g.apply)`.

If you think that's kind of ugly, I don't disagree.

> // Here's a function that takes an Array of functions and applies them one after another...
> // I don't really know where to start with this...the types of all of its arguments seem inexpressible
> func composeMany</* ...arbitrary many intermediate params... */>(functions: [/* What type for arbitrary function? */]) {
>   reduce(compose, functions, identity)
> }

Even with the current implicit splatting, this is impossible to express unless all functions have the same argument and return type. The generics system is simply not equipped to handle arbitrarily many generic types.

> But then if it looks like a method, people are going to wonder why they can't pass it to a function or store it in a data-structure.

I'm not sure why you think it can't be stored. I think it can.

> I saw that, briefly.  I hope that something like that makes it in, but it has similar issues with "What's the type signature of this operator, and if the only way it can exist is as compiler-supported syntax, how do we make it clear to users that this is a compiler language feature and not a first-class function call?"  IIRC the syntax suggested there made use of the #thisIsACompilerDirective naming convention.  I wonder if that might be appropriate here:
> 
> f(#splat(tuple))
> concatenate(_: #splat)
> 
> The latter form also suggests a way this could be used for partial application:
> 
> concatenate(2, #splat) returns a closure where the first argument is always 2, but any remaining arguments are pulled from the provided tuple.

I don't really think # is a good fit here. I think it's best used in places where it's performing a relatively straightforward textual substitution; in the `concatenate(_: #splat)` case, that's not really what's being done here.

(To tell the truth, in my head I imagine that when we finally get a macro system in Swift N, all macros are marked by a leading #. So I tend to get a little squeamish about # uses which draw heavily from context instead of relying on what you "pass" to them.)

-- 
Brent Royal-Gordon
Architechies



More information about the swift-evolution mailing list