Description
The (most recently) proposed syntax for primary constructors puts type parameters after the name of a named constructor:
// Allow `C.name` to occur together.
class C.name<X extends List<Y>, ... /*lots of stuff*/>(Y y) {...}
This has the advantage that C.name
is easily findable and readable, and the constructor name is not split from the class name by a potentially large type parameter list.
However, it doesn't match the call site of the constructor, where type parameters go on the class name, and more worrisome to me, it would conflict with having generic constructors (#647) as primary constructors, where you would want to put a second type parameter list at that position.
I suggest putting the type parameters on the class name, same place they occur in non-primary-constructor classes, and place the named constructor identifier with the parameter list:
// Follow the constructor invocations.
class C<X extends List<Y>, ... /*lots of stuff*/>.name(Y y) {...}
That way the logic is that:
class Name<TypeParams> extends/implements... {
fieldsForArgs;
Name.foo(args);
...
}
can be rewritten as:
class Name<TypeParams>.foo(args) extends/implements... {
// ^^^^^^^^^^ -- inserted part
...
}
which moves the part of the constructor after Name
into the class declaration line, just before any extends or implements clause.
If we put the name before the type parameters, and the arguments after, it's instead:
class Name.foo<TypeParams>(args) extends/implements... {
// ^^^^ ^^^^^^ -- inserted parts
...
}
Not a big difference, but still slightly more complicated.
Both options have readability issues, because primary constructors stuff a lot of information into very little syntax, with some of it being used for more than one thing.
Some of those issue are avoided by plain constructors by not having type parameters in the declaration at all (but #1899 would allow that).