[Pitch] Light-weight same-type constraint syntax

Generic Protocols

Generic protocols are a major gap in Swift's current generics and opportunistically giving them up in favor of a syntactic sugar for a completely different feature that could be expressed syntactically at a minimal cost using existing syntactic elements via <.T == …> would be a huge mistake, imho.

Unification

That's because the T of Array<T> and Array.Element are two completely different things serving two completely different purposes and roles in the language, which are strictly orthogonal to each other. Of course they are used and spelled differently. It would be bad if they weren't.

  • Generic arguments are passed in by the user of a generic type and provided at the time of its instantiation (i.e. Array<T> -> Array<Int>).
  • Associated types are returned out by the specific instantiation of a generic type at the time of its declaration (i.e. typealias = …).

If generic types/kinds were functions of the type system, mapping from a generic abstract type to a concrete type, then …

  • generic arguments would be the inputs of such a function.
  • associated types would be the outputs of such a function.

So not only would such a unification conflate two orthogonal concepts that cannot be used interchangeably into a single syntax, it also introduces a major inconsistency by doing so:

Every existing use of "instantiate a generic type" (i.e. pass a set of types as its input) in Swift (that I'm aware of) is using <T>.
Every existing use of "constrain a generic type" (i.e. retrieve a set of types as its output) in Swift (that I'm aware of) is using where T == _.


Just imagine for a second a hypothetical and admittedly silly proposal that wanted to unify the passing of inputs and the returning of outputs for a function into a single syntax and went something like this:

We propose that instead of passing values to a function via foo(42, "bar") and obtaining its output via let baz = foo(…) you can now do let foo(42, "bar", baz), where 42 and "bar" are the inputs to foo(…) and baz is its output (i.e. a local binding), resulting in a unified syntax.

A proposal like this would be shut down immediately, if not outright ridiculed, as it would be conflating two orthogonal concepts (inputs vs. outputs) into a shared syntax and effectively would make it impossible to know the semantics implied by (…) without looking up the function signature. Even though it effectively proposes the same thing proposed here: unify syntax of inputs and outputs of a function (on a kind), making them look the same, even though they are orthogonal. It's just that the semantics of "function of types" is familiar to most us, while the semantics of "function of kinds" is somewhat more obscure, yet rally not that different. What's bad in one context is similarly bad in the other.

7 Likes