On Jun 1, 2016, at 3:29 AM, Brent Royal-Gordon via swift-evolution
<[email protected]> wrote:
>> There's definitely the possibility of going off the deep end with complexity
>> like C++, but since we already have tuples as a primitive language feature,
>> I think there's a straightforward language design that enables the most
>> important use cases for variadics. If we have "tuple splatting" for argument
>> forwarding, and some support for iterating tuples, like we briefly discussed
>> in the context of (4 x Int) fixed-sized homogeneous tuples, that'd probably
>> be enough.
>
> I read the original proposal, started writing up a response along these
> lines, and then scrolled up to see what others had said. I'm glad you agree!
>
> Here's my sketch.
>
> * * *
>
> In general, my preferred direction for this feature would tie variadics
> closely to tuples, and variadic types closely to tuple types. To wit:
>
> 1. We should dust off the old tuple indexing proposal (I actually forgot it
> was never reviewed) and get it through, along with tuple `count`, `map`, and
> probably a few other Collection-like operations which generate fixed
> signatures. (I'm going to use a method-style syntax, but a #function-style
> syntax would work too; we could even introduce a .#method-style syntax.)
Sounds like more compiler magic... rather than trying to reduce it.
>
> let tuple: (Int, Int, Int, Int) = (2, 4, 6, 8)
> print(tuple[tuple.0]) // => 6
> print(tuple.map { $0 / 2 }) // => (1, 2, 3, 4)
>
> 2. We should allow you to use analogous operators on the type of a tuple, too.
>
> let value: (Int, String)[1] = "Hello, world!"
> (Int, String).map { $0.Type } // => (Int.Type, String.Type)
>
> 3. We should change our existing variadic parameters to create tuples, not
> Arrays.
>
> func print(_ items: (Any...), separator: String = "", terminator: String =
> "\n") {
> items.0 // Yes, that's a thing you can do
>
> 4. We should add a splat operator which unpacks tuples into (possibly
> variadic) parameters.
>
> print(tuple...)
>
> 5. We should allow you to define variadic type parameters.
>
> // Note: If you had written `items: Items` instead of `items: Items...`,
> it would've taken a tuple
> // of various LocalizedStringConvertible types.
> func localizedPrint<Items: (LocalizedStringConvertible...)>(_ items:
> Items..., separator: String = "", terminator: String = "\n") {
> print(items.map { $0.localizedDescription }, separator: separator,
> terminator: terminator)
> }
>
> 6. We should extend splat to unpack tuple types into (possibly variadic) type
> parameters.
>
> typealias Pair = (String, Int)
> let table: Dictionary<Pair...> = [:]
>
> (7. Optional pet-peeve fixer, which I will not actually demonstrate: Require
> unconstrained type parameters to be spelled `T: Any`, not just `T`. This will
> remove an asymmetry, in that a variable-length tuple of any type has to be
> spelled `T: (Any...)`, but a single parameter is just spelled `T`.)
>
> What do we end up with here?
>
> Zip:
>
> struct ZipSequence<Sequences: (Sequence...)>: Sequence {
> typealias Iterator: ZipIterator<Sequences.map { $0.Iterator }...>
>
> var sequences: Sequences
>
> func makeIterator() -> ZipIterator<Sequences...> {
> return ZipIterator.init(sequences.map { $0.makeIterator() }...)
> }
>
> init(_ sequences: Sequences...) {
> self.sequences = sequences
> }
> }
>
> struct ZipIterator<Iterators: (IteratorProtocol...)>: IteratorProtocol {
> typealias Element = Iterators.map { $0.Element }
>
> var iterators: Iterators
>
> init(_ iterators: Iterators...) {
> self.iterators = iterators
> }
>
> mutating func next() -> Element? {
> // Note: It may be too difficult to assign a type to this
> reduction;
> // something like the proposal's `#invert` may thus be necessary.
> // If it is added, I would hope that an analogous operation would
> // be added to `Sequence`s of `Optional`s.
> let nextValues = iterators.map { $0.next() }.reduce(Optional( ()
> )) { earlier, this in
> guard let earlier = earlier, this = this else {
> return nil
> }
> return earlier + (this)
> }
> guard let nextValues = nextValues else {
> return nil
> }
> return nextValues
> }
> }
>
> Function application is basically just a use of the splat feature:
>
> // Note that the `args: Args` here is *not* `...`ed, so it takes a tuple.
> // Meanwhile, the `Args` in `(Args...) -> Result` does have `...`, so it's
> looking
> // for arguments which that tuple could be splatted into.
> func apply<Args: (Any...), Return>(_ args: Args, to function: (Args...) ->
> Return) -> Return {
> return function(args...)
> }
>
> func method<Instance, Args: (Args...), Return>(_ name: String, on
> instance: Instance) -> ((Args...) -> Return)? {
> ...
> }
>
> MultiMap:
>
> func multiMap<Sequences: (Sequence...), Return>(_ sequences:
> (Sequences...), transform: (Sequences.map { $0.Iterator.Element }...) ->
> Return) -> [Return] {
> var returns: [Return] = []
>
> // You could do this by manually making iterators, but why bother when
> we already have the right abstraction?
> for elems in zip(sequences...) {
> returns.append(transform(elems...))
> }
>
> return returns
> }
>
> Advantages of this approach, as I see them:
>
> * Variadics are entirely a creature of parameter lists and type parameter
> lists; outside of those, they are always represented as a tuple. That means,
> for instance, that there is no need for variadics to reach into places like
> variables.
>
> * `...` goes in exactly two places: After a type name within the definition
> of a tuple type, and after an expression being splatted into a parameter
> list. There's no proliferation of dots throughout the language or confusing
> leading-vs.-trailing dots thing.
>
> * Many of these features are useful in non-variadic code. For instance,
> Collection-like tuples are a feature people want already.
>
> * We stick closer to already-implemented features, rather than inventing a
> whole lot of completely novel stuff, like `#rest` and `#fold` and `#vector`.
>
> Disadvantages:
>
> * This leans rather heavily on tuple and tuple type features which will
> probably, at least for now, have to be built into the compiler. (You might be
> able to make them macros later.)
>
> * This _may_ raise the grim specter of 1-tuples, but I'm not sure about that.
> (Perhaps even the concrete-tuple members should be hashed, like `#count` and
> `#map`? That would allow them to be applied to single values.)
>
>
> --
> Brent Royal-Gordon
> Architechies
>
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution