Disallow assertions in in-header primary constructors
The primary constructor proposal lets you define a constructor right in the header of a class declaration.
Because there is already a lot of stuff going on up there (type parameters, extends, implements, etc.), it is somewhat restricted in what the constructor can have. It doesn't allow a body or an initializer list.
But, curiously, it does allow assertions. I can't say I find them readable in the header:
class Interval<T extends num>(T min, T max)
: assert(min >= 0),
assert(min <= max),
assert(max >= 0)
implements Comparable<Interval<T>> {
// ...
}
I think there was an argument for allowing in-header assertions to avoid a usability cliff when the proposal was first written. Without support for assertions, if you wanted to add an assert, you had to convert the in-header primary constructor all the way to an in-body normal constructor and explicitly declare all the fields.
But the proposal now supports in-body primary constructors too. If you want a primary constructor with assertions, I think you should use an in-body primary constructor:
class Interval<T extends num> implements Comparable<Interval<T>> {
this(T min, T max):
assert(min >= 0),
assert(min <= max),
assert(max >= 0);
// ...
}
I find this much easier to read, and it means we don't have to introduce users to the idea of a thing that's sort of like a constructor initializer list but one that only allows assert() and not other kinds of initializers.
Then in-header primary constructors are reserved for the simplest cases where all you need is the parameter list.
If the in-body syntax is easy enough to use, you should use it for anything that is not a plain value-type constructor.
(And you shouldn't use assert for checking correctness, then you can have incorrectness in production.)
I feel like this could just be a lint?
I feel like this could just be a lint?
In general, I dislike shipping language features that we simultaneously discourage users from using. If we do all the work to add a capability and then also add lint saying "no", then... why did we spend all that time designing and implementing the capability in the first place?
If we think asserts inside class headers are a bad idea (and, personally, I do think they're a bad idea), then I'd rather just not support them at all.
why did we spend all that time designing and implementing the capability in the first place?
If it's more work to support it, I understand, but from the way the original proposal was formulated I understood it as adding an exception to the rule.
Having asserts etc there is probably very cluttered, but if it's not any extra effort to support it, I'd like the consistency that all constructors are the same better than imposing an arbitrary restriction (especially if it's just for stylistic reasons)
If it's more work to support it
It's almost always more work to support. It's new syntax in a new location, so it has to be specified, parsed, compiled, tested, etc. We get surprisingly little for free when it comes to programming language implementation.
Closing. We allow asserts in the in-body constructor. This is how it'd be written with a header and a body constructor:
// Current syntax.
class Point {
int x;
int y;
Point(this.x, this.y): assert(0 <= x && x <= y * y);
}
// Using a primary constructor.
class Point(var int x, var int y) {
this : assert(0 <= x && x <= y * y);
}
// Using a declaring body constructor.
class Point {
this(var int x, var int y): assert(0 <= x && x <= y * y);
}