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

Reply via email to