[Pitch] One-Element Tuples

As a rule, generic code with T == Int dynamically should behave like it would as concrete code with T replaced with Int. (The eternal caveat to this is overloading, but otherwise, this is how it is.) This is just as true with variadic generics.

The fact that a type is a tuple is significant in the type system; tuples behave differently from non-tuples in some ways, and there are things you can with tuple values that you generally cannot do with element values and vice-versa. And that set of operations is likely to grow; for example, we will probably find it useful with variadic generics to add an “expand” operator, usable on tuples in contexts that can take a list of values, which produces the sequence of the elements of that tuple. (This could be used concretely to e.g. conveniently concatenate two tuples; in variadic generics it is important as a way to “escape the tuple trap” if you e.g. need to store all the elements of a value pack somewhere that cannot be a pack, like in a stored property.)

Because tuple-ness is significant in the type system, and generic code is type-checked without knowing the values of the generic arguments, unsubstituted generic code must treat (T…) as a tuple type; and because substitution should not by itself change behavior, substitution with a single-element pack must keep it as a tuple, which means single-element tuples must exist in the type system. Even if the tuple-ness were implicitly converted away when working directly with single-element tuples, they would still exist in secondary positions.

I do think there’s a possibility that this will be annoying for certain patterns and we’ll want to consider implicit injection and projection. Hopefully we’ll be in a position to evaluate that before there’s a significant amount of code relying on single-element tuple behavior.

17 Likes