Preconditions (for records, or otherwise)
Kevin Bourrillion
kevinb at google.com
Wed Mar 14 17:14:12 UTC 2018
This thread was, at first, discussing both records-specific and general
approaches; the records-specific part is now being addressed in other
threads, but I think the following has not yet been engaged with:
On Fri, Mar 9, 2018 at 1:56 PM, Kevin Bourrillion <kevinb at google.com> wrote:
But I don't want to give up too easily on a more *general* approach that
> would apply to records, methods, and constructors. That's been sketched at
> times as
>
> void foo(int num, String unrelated)
> requires (num >= 0) {
> ...
> }
>
> where `requires` takes a boolean expression*, which lives in the same
> scope as the body proper; if it evaluates to false, an exception is thrown
> and the body is never entered.
>
> The main criticism I hear about this is that it feels like a *"method
> with two bodies"*. To that I'd point out that
>
> - it is only an *expression* -- and anything even moderately complex
> ought to be factored out, just like we advise for lambdas
> - this expression isn't implementation; it's contract, so frankly it *belongs
> *in this elevated place more than it does in the body. It is
> information that pertains, not really to the body, but to the communication
> between caller and body - just like the signature does.
> - this way, the preconditions can be *inherited* by default in an
> overriding method, which seems awfully convenient to me right now. (If you
> have some conditions you wouldn't want inherited for some reason, keep
> those in the regular body. I'm not sure whether these are *technically* LSP
> violations, but in pragmatic terms they don't seem to be, to me)
>
> I bring all this up because some of the upsides seem quite compelling to
> me:
>
> - The automatically composed exception *message* will be more useful
> than what 90% of users bother to string together (and the other 10% are
> wasting time and space dealing with it).
> - These expressions can be displayed in generated *documentation* so
> you don't have to write them out a second time in prose.
> - I admit this may feel weird for a core language feature, but you can
> choose the idiomatic exception *type* automatically: if the expression
> involved at least one parameter, it's IAE; otherwise it's probably ISE
> (except in the amusing case of `requires (false)` it is UOE). (Again, maybe
> this is too weird.)
> - Some of these expressions are *verifiable* statically. For example a
> call to `foo(-1, "x")` (using example above) should be caught by javac. I
> suppose we teach it to recognize cases like empty collections through
> compiler plugins.
>
> Note that the other design-by-contract idioms are still addressed well
> enough by `assert`; we only need this one because `assert` disclaims this
> use case (for good reason).
>
> (*why I say it should take one boolean expression, not a comma-separated
> list: I think we might as well let the user choose between short-circuiting
> or not, by using && and & directly, which makes it clear to readers as
> well. Well, that is, charitably assuming that reader remembers the
> difference.)
>
--
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com
More information about the amber-spec-observers
mailing list