The proposed new call-me-anything-except-a-real-tuple type seems a bit complicated to me. Someone earlier in the thread suggested that variadic tuples - on which variadic generics could be built - would be more straightforward, and I agree. They also seem more broadly useful and to require less change to the language (at least from a Swift user’s perspective - I have no idea what it means for the compiler’s implementation).
An example is the proposed overloading of the .
operator to mean map
only on these special not-a-real-tuple-tuples. That’s a bit magical to me - why is that necessary? Why not just have these new things (whether tuples or whatever) just have a map
method, so that they are more consistent with existing Sequence
s. In fact, my (perhaps naive) question is why can’t these collections - tuples or otherwise - of metatypes genuinely conform to Collection
, and support all the normal methods?
Or alternatively, if we want some syntactic sugar that translates .map { $0.foo }
to something shorter, how about a proper new operator that then also applies anywhere else, e.g. self.values..foo
or somesuch? (riffing, syntactically, on the pointwise operators introduced for SIMD recently, which have defined .
as also an operator modifier, essentially, so the prior example reads as “self.values pointwise .foo”) That avoids ambiguity to the reader as to whether “.foo” is referring to a property of the tuple itself.
If it helps for understanding where I’m coming from, I’ve been doing a lot of metaprogramming in Python lately, and for all Python’s warts I do find its metatyping system to actually be pretty elegant, particularly w.r.t. to the fact that its metatypes (by which I mean instances of the type
type) can be treated just like any other object. Maybe something, in Swift, like:
// “T” becomes a tuple of 0 or more Metatypes, each of which represent
// a type that conforms to Sequence (but are not necessarily the same
// types).
struct Zipped<variadic T: Sequence> {
private let values: T // used as a type here, in a property declaration...
// ... and here in a function signature
init(_ values: T) {
self.values = values
}
// Used here directly as an object.
static var typeName {
return “Zipped<“ + “, “.join(T.map { “\($0)” }) + “>“
}
var description {
return self.typeName + “(“ + “, “.join(self.values.map { “\($0)” }) + “)”
}
}
Maybe it makes more sense if you presume constexpr support too… e.g. if you think of the variadic types as constexpr tuples.