[swift-evolution] Splat

Jonathan Tang jonathan.d.tang at gmail.com
Wed Feb 10 17:53:29 CST 2016


On Wed, Feb 10, 2016 at 1:21 PM, Brent Royal-Gordon via swift-evolution <
swift-evolution at swift.org> wrote:

> So, since SE-0029 has been accepted, let's think about explicit
> replacements. So far, I've been able to think of three general approaches.
> For the examples below, I'll assume there's a `func concatenate(number:
> Int, to string: String) -> String`, which does the obvious thing. Where
> supported, I will fully qualify names with SE-0021 syntax, but in some
> cases this might not be necessary.
>
>                 1. Special parameter label.
>
> `concatenate` is implicitly overloaded with a `func
> concatenate(parameters: (Int, String)) -> String`.
>
>         concatenate(parameters: tuple)
>         tuples.map(concatenate(parameters:))
>
> Advantages:
> - Does not require any new call-side syntax.
> - Googleable thanks to use of identifiers.
>
> Disadvantages:
> - Could conflict with functions that use `parameters` as an argument label.
> - Not clear how it would distinguish between `concatenate(_:to:)` and e.g.
> `concatenate(_:with:)`.
> - Might reintroduce type checking complexity, since it's adding overloads.
> - A bit wordy.
> - As far as I know, not precedented in other languages.
>
>                 2. Method on functions.
>
> `concatenate` has a method on it called, say, `apply(to:)` which takes a
> tuple of parameters.
>
>         concatenate(_:to:).apply(to: tuple)
>         tuples.map(concatenate(_:to:).apply(to:))
>
> Advantages:
> - You can be sure of the variant you're selecting.
> - Googleable thanks to use of identifiers.
> - Similar to usage in Javascript.
>
> Disadvantages:
> - Rather wordy, with lots of chaining and extra parentheses.
> - Methods on unapplied functions might be a little confusing.
>
>                 3. Splat operator.
>
> An operator like `*` is used to indicate splatting. A tuple can be put to
> the right of the operator to splat it in immediately, or it can be omitted
> to select a splattable version of the function.
>
>         concatenate(_:to: *tuple)
>         tuples.map(concatenate(_:to: *))
>
> Advantages:
> - You can be sure of the variant you're selecting.
> - Similar to usage in Ruby and Perl 6.
> - Fairly short in all forms.
>
> Disadvantages:
> - Not Googleable.
> - New magic syntax.
> - Two slightly different forms depending on whether you're calling or not.
>
> Any thoughts on these, or alternative approaches (as opposed to small
> syntax tweaks)?
>
>
>
> P.S. As for pointers potentially using prefix `*` for memory
> dereferencing, I would instead make them use postfix `!`. `!` could become
> an `unwrapped` pseudo-property that any type can use, democratizing another
> piece of `Optional` magic and working around the vexing problem of what you
> name the `Pointer` property for "that thing you're actually pointing to".
>
>
I'm curious what the type signature of the splat operator would be?  IIUC,
one of the primary reasons the Swift core team accepted SE-0029 (remove
implicit tuple splat) is because it adds a lot of complexity to the
typechecker.  That was my experience too, having implemented a hobby
language several years ago where every function took a single tuple
argument.  It made it very difficult to reason about the types in the
program, because a function type held no intrinsic type information, and
the only way to typecheck it was to know how the function was defined and
see whether that was compatible with how it was invoked.  That, in turn,
made first-class functions and separate module compilation very difficult:
you had to carry around full information about the arity of the tuple, each
of its types, whether the types were generic type variables, whether they
had typeclass (protocol in Swift) constraints, whether the typeclasses
themselves had associated types, etc.  And then when you try to *infer*
types, each of these become cases in the inference engine, and interacted
combinatorially.

I'd start by trying to write down the type of the splat operator.  Can it
be expressed within the normal Swift type system?  I'm not sure...I'm not
familiar enough with the intricacies of Swift tuple types to know.

If it can't, I have a strong preference against the options (#1 & #2) that
look like normal function call syntax.  Because you won't be able to do
several things that you're accustomed to with functions: assign them to
variables, store them in containers, pass them as parameters to other
functions.

This is less of a problem with explicit language syntax, because you could
have a rule in the typechecker that says "If the expression being splatted
is a tuple of type (A, B, x: C), then it must be applied to a function of
type (A, B, C) -> Ret, with the result type of the call being Ret."  I
think you can also get around many of the type inference pitfalls as well,
because in most cases the types of the function and tuple are unlikely to
need inferring (occasionally this will require explicit type annotations on
tuple components, but it seems like most of the time they will have already
been inferred when the tuple was declared).  And it's much easier to do
"partial splat" operations, where, for example, you may want to pass the
first couple arguments of a function explicitly but splat the rest.

Note that there's a loss of expressiveness through *not* making the splat
operator first-class; a number of interesting Haskell combinators come out
of using $ (the function-application operator) as a function that can
itself be passed around.  But it's also a question of how much complexity
you want to add to the language for the sake of conceptual purity.  Python,
Ruby, and Javascript all seem to get along fine with just the ability to
splat lists & dictionaries into the final position of an argument list.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160210/be2930e3/attachment.html>


More information about the swift-evolution mailing list