I don't think it's a big problem to have two different syntaxes to accomplish the same thing. After all, that's exactly what some P
in parameter position does:
func example1<C: Collection>(collection: C) {}
// This is the same thing as example 1
func example2(collection: some Collection) {}
These are both roughly equally verbose, so the benefit is not primarily about reducing the number of characters the user needs to type. Rather, the benefit is increased clarity; we don't have to introduce a generic parameter and then use it separately. It feels analogous to how in early versions of C, you had to declare all your variables at the beginning of the function block:
void sillyExampleInC() {
int x = 0;
printf("x is zero\n");
// This was illegal! Variables declarations had to come before all expressions
int y = 3;
printf("y is three\n");
}
Thankfully, C moved on from that requirement, and you're now allowed to declare variables at the point where you need them. What I like about some P
syntax is that it allows the same thing for generic function signatures:
// I can introduce the generic parameter at the point where
// it is used
func example3(a: Int, b: String, c: Float, d: some Collection) {}
// I don't have to do this, which requires generic parameters
// to be declared up front, even though it won't be used until the end.
func example4<C: Collection>(a: Int, b: String, c: Float, d: C) {}
Now, there are still cases where it makes sense to declare a parameter up front, but those are primarily cases where I want to constrain multiple parameters to have the same type:
// These all need to be the same type
func example5<C: Collection>(one: C, two: C, three: C) {}
In that case, declaring the generic parameter up front feels reasonable, because it is being used in multiple places. But when a generic parameter is only used in one position, declaring it inline feels reasonable.
Wrapping this all up, I like this proposed syntax:
func proposed(one: some Collection A, two: some Collection B)
where A.Element == B.Element
and it doesn't feel like a problem to me that the same thing could also be done using angle brackets:
func current<A: Collection, B: Collection>(one: A, two: B)
where A.Element == B.Element
The proposed way seems significantly clearer to me, but if someone is comfortable with the angle brackets, that's fine too.