Splat

> 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.

Not the result of the splatting operation, but the splatting operation
itself:

let legal = [f, g)
let illegal = [f.apply, g.apply] // But it certainly looks like an
expression that would normally be legal!

Actually nevermind, I see that a list of [f.apply, g.apply] would be legal
(modulo the to: keyword) and has the expected semantics, assuming that the
types match up.

Still find it quite confusing, because I expected x.methodName to be a
bound method and here it's a special syntactic form. What happens if a
protocol defines "func apply(to:)"? Is that legal? Would function types
automatically conform to the protocol?

···

On Wed, Feb 10, 2016 at 9:10 PM, Jonathan Tang <jonathan.d.tang@gmail.com> wrote:

On Wed, Feb 10, 2016 at 8:37 PM, Brent Royal-Gordon < > brent@architechies.com> wrote:

> 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.)

The "..." syntax that's been batted around here looks fine to me as well.

Still find it quite confusing, because I expected x.methodName to be a bound method and here it's a special syntactic form. What happens if a protocol defines "func apply(to:)"? Is that legal? Would function types automatically conform to the protocol?

For `apply(to:)`, it really would just be a method available on function types. You could put an `apply(to:)` method on any other type, and it wouldn't have any effect on things. You could declare a protocol with `apply(to:)`, but it wouldn't do anything to any function types. Conceptually, there would only be a few special things about them:

1. The compiler generates the `apply(to:)` methods automatically. We could, perhaps, have it generate a conformance to an `Applicable` protocol like this one, but that's probably overkill:

  protocol Applicable {
    typealias ReturnValue
    typealias ArgumentTuple
    func apply(to: ArgumentTuple) -> ReturnValue
  }

(Actually, as I think about this, I wonder if `Applicable` could give us the `@splatting` property for free: take a generic parameter on Applicable and someone can specify a bare function, but you can't call it directly, only through its `apply(to:)` method.)

2. If `fn` is overloaded, `fn.apply(x)` will end up selecting an `fn` overload based on the type of `x`. Concrete example: `(+).apply(tupleOfInts)` would give you the `Int, Int` implementation of the `+` operator.

3. There's no way to add your own methods to a function type. (At least, I'm not proposing there would be. There's no particular reason we couldn't have other methods on functions, particularly if there's an `Applicable` protocol to extend.)

But `apply` is not a keyword, `apply(to:)` does not receive any special parsing, and you can still splatter `apply`s all around your code with no consequences whatsoever. Honestly, that's the main virtue of the `apply(to:)` suggestion: that there's really very little to it.

···

--
Brent Royal-Gordon
Architechies

I really like the apply-variant, especially as it moves functions one step into being first class, i.e. allowing them to have methods. Furthermore I like that it does not need new syntax.
The Applicable protocol is a good idea.

-Thorsten

···

Am 11.02.2016 um 08:54 schrieb Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org>:

Still find it quite confusing, because I expected x.methodName to be a bound method and here it's a special syntactic form. What happens if a protocol defines "func apply(to:)"? Is that legal? Would function types automatically conform to the protocol?

For `apply(to:)`, it really would just be a method available on function types. You could put an `apply(to:)` method on any other type, and it wouldn't have any effect on things. You could declare a protocol with `apply(to:)`, but it wouldn't do anything to any function types. Conceptually, there would only be a few special things about them:

1. The compiler generates the `apply(to:)` methods automatically. We could, perhaps, have it generate a conformance to an `Applicable` protocol like this one, but that's probably overkill:

   protocol Applicable {
       typealias ReturnValue
       typealias ArgumentTuple
       func apply(to: ArgumentTuple) -> ReturnValue
   }

(Actually, as I think about this, I wonder if `Applicable` could give us the `@splatting` property for free: take a generic parameter on Applicable and someone can specify a bare function, but you can't call it directly, only through its `apply(to:)` method.)

2. If `fn` is overloaded, `fn.apply(x)` will end up selecting an `fn` overload based on the type of `x`. Concrete example: `(+).apply(tupleOfInts)` would give you the `Int, Int` implementation of the `+` operator.

3. There's no way to add your own methods to a function type. (At least, I'm not proposing there would be. There's no particular reason we couldn't have other methods on functions, particularly if there's an `Applicable` protocol to extend.)

But `apply` is not a keyword, `apply(to:)` does not receive any special parsing, and you can still splatter `apply`s all around your code with no consequences whatsoever. Honestly, that's the main virtue of the `apply(to:)` suggestion: that there's really very little to it.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I really like your suggestion of functions conforming to a protocol. I thought about this a little while and how an extendable FunctionType (or Applicable as you called it) protocol may impact existing code. For that I would even go one step further and add another step of protocol indirection such that the function’s signature is just a specialised form of a protocol SignatureType (this allows even better syntax when extending FunctionType as you can see in my last example).

So this protocol would look like

protocol FunctionSignatureType {
  associatedtype Parameters
  associatedtype ReturnType
}

Parameters will be set to the functions parameters in tuple notation

(((Int, String), secondParameter: Int) -> String).Input == ((Int, String), secondParameter: Int)

FunctionType would then only have one associated type:

protocol FunctionType {
  associatedtype Signature: FunctionSignatureType
}

Signature could for example be ((Int, String), secondParameter: Int) -> String.

We could then declare the apply function as a simple extension to FunctionType just like you suggested

extension FunctionType {
  func apply(tuple: Signature.Parameters) -> Signature.ReturnType {
    // Add some compiler magic here
  }
}

This would make apply another normal Swift function with a special implementation just like print, + and so on. I think that providing the ability to extend FunctionTypes would be a huge win, because several functions that used to be global could now just be methods on FunctionType. For example to execute a function asynchronously via GCD could now be declared as:

extension FunctionType where Signature == (() -> Void) {
  func dispatchAsync(queue: dispatch_queue_t) {
    dispatch_async(queue, self)
  }
}

I don’t know how this fits into the compiler and if functions can be made to conform to a protocol anyway but from the outside this looks like a solution to me that fits very well in the current style of Swift.

- Alex

···

On 11 Feb 2016, at 08:54, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Still find it quite confusing, because I expected x.methodName to be a bound method and here it's a special syntactic form. What happens if a protocol defines "func apply(to:)"? Is that legal? Would function types automatically conform to the protocol?

For `apply(to:)`, it really would just be a method available on function types. You could put an `apply(to:)` method on any other type, and it wouldn't have any effect on things. You could declare a protocol with `apply(to:)`, but it wouldn't do anything to any function types. Conceptually, there would only be a few special things about them:

1. The compiler generates the `apply(to:)` methods automatically. We could, perhaps, have it generate a conformance to an `Applicable` protocol like this one, but that's probably overkill:

  protocol Applicable {
    typealias ReturnValue
    typealias ArgumentTuple
    func apply(to: ArgumentTuple) -> ReturnValue
  }

(Actually, as I think about this, I wonder if `Applicable` could give us the `@splatting` property for free: take a generic parameter on Applicable and someone can specify a bare function, but you can't call it directly, only through its `apply(to:)` method.)

2. If `fn` is overloaded, `fn.apply(x)` will end up selecting an `fn` overload based on the type of `x`. Concrete example: `(+).apply(tupleOfInts)` would give you the `Int, Int` implementation of the `+` operator.

3. There's no way to add your own methods to a function type. (At least, I'm not proposing there would be. There's no particular reason we couldn't have other methods on functions, particularly if there's an `Applicable` protocol to extend.)

But `apply` is not a keyword, `apply(to:)` does not receive any special parsing, and you can still splatter `apply`s all around your code with no consequences whatsoever. Honestly, that's the main virtue of the `apply(to:)` suggestion: that there's really very little to it.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I really like your suggestion of functions conforming to a protocol. I thought about this a little while and how an extendable FunctionType (or Applicable as you called it) protocol may impact existing code. For that I would even go one step further and add another step of protocol indirection such that the function’s signature is just a specialised form of a protocol SignatureType (this allows even better syntax when extending FunctionType as you can see in my last example).

So this protocol would look like

protocol FunctionSignatureType {
  associatedtype Parameters
  associatedtype ReturnType
}

Parameters will be set to the functions parameters in tuple notation

(((Int, String), secondParameter: Int) -> String).Input == ((Int, String), secondParameter: Int)

FunctionType would then only have one associated type:

protocol FunctionType {
  associatedtype Signature: FunctionSignatureType
}

Signature could for example be ((Int, String), secondParameter: Int) -> String.

We could then declare the apply function as a simple extension to FunctionType just like you suggested

extension FunctionType {
  func apply(tuple: Signature.Parameters) -> Signature.ReturnType {
    // Add some compiler magic here
  }
}

I really like the idea of a FuncionType protocol. However, `apply` should be a requirement, not just in an extension. This would allow other types to conform to the protocol.

···

On Feb 11, 2016, at 8:00 AM, Alex Hoppen via swift-evolution <swift-evolution@swift.org> wrote:

This would make apply another normal Swift function with a special implementation just like print, + and so on. I think that providing the ability to extend FunctionTypes would be a huge win, because several functions that used to be global could now just be methods on FunctionType. For example to execute a function asynchronously via GCD could now be declared as:

extension FunctionType where Signature == (() -> Void) {
  func dispatchAsync(queue: dispatch_queue_t) {
    dispatch_async(queue, self)
  }
}

I don’t know how this fits into the compiler and if functions can be made to conform to a protocol anyway but from the outside this looks like a solution to me that fits very well in the current style of Swift.

- Alex

On 11 Feb 2016, at 08:54, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Still find it quite confusing, because I expected x.methodName to be a bound method and here it's a special syntactic form. What happens if a protocol defines "func apply(to:)"? Is that legal? Would function types automatically conform to the protocol?

For `apply(to:)`, it really would just be a method available on function types. You could put an `apply(to:)` method on any other type, and it wouldn't have any effect on things. You could declare a protocol with `apply(to:)`, but it wouldn't do anything to any function types. Conceptually, there would only be a few special things about them:

1. The compiler generates the `apply(to:)` methods automatically. We could, perhaps, have it generate a conformance to an `Applicable` protocol like this one, but that's probably overkill:

  protocol Applicable {
    typealias ReturnValue
    typealias ArgumentTuple
    func apply(to: ArgumentTuple) -> ReturnValue
  }

(Actually, as I think about this, I wonder if `Applicable` could give us the `@splatting` property for free: take a generic parameter on Applicable and someone can specify a bare function, but you can't call it directly, only through its `apply(to:)` method.)

2. If `fn` is overloaded, `fn.apply(x)` will end up selecting an `fn` overload based on the type of `x`. Concrete example: `(+).apply(tupleOfInts)` would give you the `Int, Int` implementation of the `+` operator.

3. There's no way to add your own methods to a function type. (At least, I'm not proposing there would be. There's no particular reason we couldn't have other methods on functions, particularly if there's an `Applicable` protocol to extend.)

But `apply` is not a keyword, `apply(to:)` does not receive any special parsing, and you can still splatter `apply`s all around your code with no consequences whatsoever. Honestly, that's the main virtue of the `apply(to:)` suggestion: that there's really very little to it.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I really like your suggestion of functions conforming to a protocol. I thought about this a little while and how an extendable FunctionType (or Applicable as you called it) protocol may impact existing code. For that I would even go one step further and add another step of protocol indirection such that the function’s signature is just a specialised form of a protocol SignatureType (this allows even better syntax when extending FunctionType as you can see in my last example).

So this protocol would look like

protocol FunctionSignatureType {
  associatedtype Parameters
  associatedtype ReturnType
}

Parameters will be set to the functions parameters in tuple notation

(((Int, String), secondParameter: Int) -> String).Input == ((Int, String), secondParameter: Int)

FunctionType would then only have one associated type:

protocol FunctionType {
  associatedtype Signature: FunctionSignatureType
}

Signature could for example be ((Int, String), secondParameter: Int) -> String.

We could then declare the apply function as a simple extension to FunctionType just like you suggested

extension FunctionType {
  func apply(tuple: Signature.Parameters) -> Signature.ReturnType {
    // Add some compiler magic here
  }
}

I really like the idea of a FuncionType protocol. However, `apply` should be a requirement, not just in an extension. This would allow other types to conform to the protocol.

Good point, it seems like I haven’t completely considered other types conforming to FunctionType.
If we provided a default implementation for apply that uses a special implementation only applicable to real functions we would have to make sure that this implementation is never used for custom types conforming to FunctionType. I can currently think of two options to achieve this:
1. Create a new private protocol in the stdlib extending FunctionType to which the functions actually conform and provide a default implementation for that protocol only
2. Make FunctionType a struct instead of a protocol (and call it Function instead). But I have no idea what implications that poses to the compiler. Making functions conform to FunctionType already seems hard to me and this even harder… If it would be possible I would prefer this option. Functions would then nicely line up along with Int etc.

···

On 11 Feb 2016, at 16:05, Matthew Johnson <matthew@anandabits.com> wrote:

On Feb 11, 2016, at 8:00 AM, Alex Hoppen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This would make apply another normal Swift function with a special implementation just like print, + and so on. I think that providing the ability to extend FunctionTypes would be a huge win, because several functions that used to be global could now just be methods on FunctionType. For example to execute a function asynchronously via GCD could now be declared as:

extension FunctionType where Signature == (() -> Void) {
  func dispatchAsync(queue: dispatch_queue_t) {
    dispatch_async(queue, self)
  }
}

I don’t know how this fits into the compiler and if functions can be made to conform to a protocol anyway but from the outside this looks like a solution to me that fits very well in the current style of Swift.

- Alex

On 11 Feb 2016, at 08:54, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Still find it quite confusing, because I expected x.methodName to be a bound method and here it's a special syntactic form. What happens if a protocol defines "func apply(to:)"? Is that legal? Would function types automatically conform to the protocol?

For `apply(to:)`, it really would just be a method available on function types. You could put an `apply(to:)` method on any other type, and it wouldn't have any effect on things. You could declare a protocol with `apply(to:)`, but it wouldn't do anything to any function types. Conceptually, there would only be a few special things about them:

1. The compiler generates the `apply(to:)` methods automatically. We could, perhaps, have it generate a conformance to an `Applicable` protocol like this one, but that's probably overkill:

  protocol Applicable {
    typealias ReturnValue
    typealias ArgumentTuple
    func apply(to: ArgumentTuple) -> ReturnValue
  }

(Actually, as I think about this, I wonder if `Applicable` could give us the `@splatting` property for free: take a generic parameter on Applicable and someone can specify a bare function, but you can't call it directly, only through its `apply(to:)` method.)

2. If `fn` is overloaded, `fn.apply(x)` will end up selecting an `fn` overload based on the type of `x`. Concrete example: `(+).apply(tupleOfInts)` would give you the `Int, Int` implementation of the `+` operator.

3. There's no way to add your own methods to a function type. (At least, I'm not proposing there would be. There's no particular reason we couldn't have other methods on functions, particularly if there's an `Applicable` protocol to extend.)

But `apply` is not a keyword, `apply(to:)` does not receive any special parsing, and you can still splatter `apply`s all around your code with no consequences whatsoever. Honestly, that's the main virtue of the `apply(to:)` suggestion: that there's really very little to it.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution