(inline, again) On Mon, May 30, 2016 at 5:44 AM, plx via swift-evolution < [email protected]> wrote:
> I’ll keep this quick since I see upthread you have already revised the > proposal. > > On May 29, 2016, at 12:36 PM, Austin Zheng <[email protected]> wrote: > > …something like the above is definitely a "nice to have", but not having > it will close off certain use cases. > > > Oh, this is interesting. So a way to specify an equality relationship > between "adjacent" sets of associated types? > > > Right, that was what I had in mind, and I can think of uses for such > neighbor-to-neighbor type relationships. > > There may be uses for other relationships—both beyond equality and beyond > neighbor-to-neighbor—but I can’t think of any offhand. > > One other pack-level constraint came to mind: > > - can you enforce (T…) is *exactly* (T,T,T,…) N times? (e.g. T0 == T1, > etc., not just "conforms to same protocols” or “have identical associated > types”) > Yes, this makes sense. #allequal(T...), maybe? > > …along with some “pack-to-pack” constraints: > > - if you have e.g. 2+ packs, can you enforce (T…) and (U…) have the same > arity? > - if you have e.g. 2+ packs, could you enforce e.g. T.Foo… == U.Bar ? > Yes, an explicit "same length" constraint makes sense. Otherwise, if a pack is derived from another pack they are implied to have the same length. I think the second constraint should be possible already? I'll double-check. > > …as always nice-to-have, but throwing them out there for consideration. > > I'll write something up. > > for index in 0..<#count(T…) { > if let v = tables[index][key] { > valueCache[key] = v > return v > } > } > > I assume this is all compile time code generation (unroll the loop in the > source #count(T...) times for each arity that T... is instantiated as, with > a different 'tables' pack member value for each unrolled loop iteration). > > > I’d assume so too, but thinking it through I think it needs some > alternative way of being expressed. > > If you look @ the “obvious” implementation for the above as written, it > unrolls into something like this: > > if let v = tables[0][key] { … } // assume returns out of here on success > if let v = tables[1][key] { … } // assume returns out of here on success > //…etc... > > …but b/c tuples aren’t directly subscriptable, those `tables[index][key]` > expressions themselves would perhaps get expanded into the equivalent of, > e.g.: > > private func __subscriptTables(index index: Int, key: K) -> V? { > switch index { > case 0: return tables.0[key] > case 1: return tables.1[key] > // etc... > default: fatalError(“Invalid subscript into variadic…blah blah”) > } > } > > …and so the original expansion would be more like: > > if let v = __subscriptTables(index:0, key: key) { … } // assume returns > out of here on success > if let v = __subscriptTables(index:1, key: key) { … } // assume returns > out of here on success > //…etc... > > ….which repeats the switch at each line. In theory the optimizer can know > to inline `__subscriptTables`, notice `index` is known at compile-time, > replace the switch with direct access, and arrive at the code you “really > want”: > > if let v = tables.0[key] { … } // assume returns out of here on success > if let v = tables.1[key] { … } // assume returns out of here on success > > …but that’s obviously putting a lot of pressure on the compiler to convert > the `for index in #count(tables) { … }` code into something > equivalent-but-reasonable. > > I’ll be sure to look @ at the proposed `fold` in this light. > I'm not sure if 'fold' as currently expressed is powerful enough to do something like this. I suppose a variant of fold that took its parameter 'inout' would work, especially if your 'fold' type was a (isFinished, desiredValue) tuple (or maybe even just "desiredValue?" as an optional). > > This is interesting. Might it be possible with to accomplish this with > existentials (this is sort of a cross-reference to a different proposal > from the generics manifest)? An existential type as described below would > work for any pack where all the elements were constrained in the same way. > Not sure if it could be made to work in the case where the types in the > pack are related to each other (as proposed earlier). > > struct ChainSequenceIterator<E, S… where S:Sequence, S.Iterator.Element == > E> { > > // A single variable that contains each iterator in turn; specific type > doesn't matter as long as the element is E > private var iterator : Any<Iterator where .Element == E>? > > // ... > } > > > Actually yes, I hadn’t thought of that and you could make it work in this > case (although perhaps with some indirection overhead? and it seems also > with some additional state tracking to know which iterator you actually > have). > > Where I’m not as sure is for something like a `ChainCollectionIndex` (same > `stuff from A, then stuff from B, etc” concept, but for A, B collections, > and so on). > > That’s more clearly a case where what you *want* ideally is something like > this: > > struct ChainCollection2<A:Collection,B:Collection> { > let a: A; let b: B > } > > struct ChainCollectionIndex2<A:Comparable,B:Comparable> { > private var sourceIndex: Sum2<A,B> // e.g. (A | B) > } > > …since to implement the APIs you need A and A.Index and B and B.Index to > "match up". It’s probably possible here to do something like this instead: > > struct ChainCollectionIndex2<A:Comparable,B:Comparable> { > private var boxedIndex: Box<Any> // actually either Box<A> or Box<B> > private var whichIndex: AOrB // (E.G. enum ilke IndexFromA | > IndexFromB) > } > > …with a lot of casting and so on, and perhaps also with existentials > (and/or casting and open-as), but it’d be *cleaner* with the sum, still. > > Either way you’re right that e.g. existentials and similar + state flags > can cover a lot of these uses. > I think union types (the A | B | C anonymous type commonly requested) would naturally complement this sort of functionality. You could have something like #union(T...), which is a scalar value whose type is T1 | T2 | ... | Tn. Like you said, a lot of things are possible with even the simple model, when dynamic casting is taken into account. It's just more difficult to read and possibly slower to execute. > > > > D: Make Parameter-Packs Named > > I understand the appeal of the `…T`-style syntax, but I’d at least > consider giving parameter-packs a more-concrete existence, e.g. something > like this: > > // strawman declaration syntax: > struct Foo<I,J,K#ParameterPack> { > > // `K` here will refer to the variadic parameter-pack itself; > // cf the `typealias` below , but basically K ~ the tuple of its types > > typealias KValueTuple = #tuple(K) // == tuple of values of type K.0, > K.1, etc.) > typealias KTypeTyple - #typeTuple(K) // == tuple of types like K.0, K.1 > typealias FirstK = #first(K) > typealias LastK = #last(K) > static var kArity: Int { return #count(K) } > // and so on > > } > > // straw man point-of-use syntax, can be adjusted of course: > let concreteFoo = Foo<I,J,K:(K0,K1,K2,…,Kn)> > > …which complicates the grammar, but IMHO feels a lot nicer than having a > lot of "implicit rules" about what `…` means and so on. > > > I think it makes sense to make pack usage explicit. I think the dots at > site of declaration don't really cause trouble, though, and are a little > nicer to read than T#ParameterPack. > > > I agree #ParameterPack is awful and that T… at the declaration site is not > a big deal. > > What I don’t like is not having a way to refer to the pack itself other > than via its “placeholder type” with some dots. > > It also seems nicer to express things like a pack fusion with names for > packs, but again in fairness it’s not terrible: > > struct Foo<T…> { > } > > func +++<T…,U…>(lhs: Foo<T…>, rhs: Foo<U…>) -> Foo<#fuse(T…,U…)> > > …so I’m not sure what I think on this. > I'll keep on thinking about this. > > > > On May 28, 2016, at 3:03 PM, Austin Zheng via swift-evolution < > [email protected]> wrote: > > Hello swift-evolution, > > > _______________________________________________ > 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 > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
