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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20180314/523c49bc/attachment-0001.html>


More information about the amber-spec-experts mailing list