On Oct 31, 2015, at 4:17 AM, Remi Forax <fo...@univ-mlv.fr> wrote:
> 
> Hi John,
> I think there is a good reason to not reuse/enhance the requireNonNull prefix,
> requireNonNull here is used to check a precondition or an invariant (a 
> contract), hence a name that starts with 'require' like in Eiffel.
> (BTW re-reading this thread, Brian already said that)

Ah, of course—that's where require came from, from contract terms.  Thanks.

> requireNonNullElseGet is not something that checks a contract and as you 
> said, nonNull is not a good prefix too, so we should starts a new family.

It seems to me that, even so, "require*" makes excellent logical sense for the 
proposed use case.  As I said, it requires a slight adjustment (really, an 
*expansion*) of the contract viewpoint.  I think we should be happy to think of 
the new "require*" logic as an "extended contract" or "contract with 
fallback/repair".

Why shouldn't contract checks (at least in our system) offer repairs?  Why must 
"require", as imported from Eiffel (or some such place) dictate the meaning of 
a family of Java methods?  If I am working on new Java code, and I want to 
enforce a dynamically checked condition P on some value X, I *first* think, "X 
must be (is required to be) P", and then as a *secondary* thought I think, 
"what event E should happen if that fails?"  In this case, X is a reference 
value and P is "must not be null".  E can often be:

- throw NullPointerException
- throw IllegalArgumentException
- throw AssertionError (use assert syntax)
- replace X with an ad hoc fallback value
- replace X with the result of some ad hoc computation (Supplier.get)
- execute some ad hoc logic inline (control flow)

I understand that contract systems (per se) allow a single contract to be 
injected across a range of sites, and so the use of ad hoc local values is 
impossible in those use cases, but (again) we are not designing a contract 
system here.

— John

P.S.  If we did add a contract system, perhaps we would end up with 
double-requires, as:

class Box<T> {
  private T value;
  static require<in value> { Objects.requireNonNull(value); }
  // value null-checked before every storage
  ...
}

This suggests there is only a weak linkage between some hypothetical contract 
system and the present API.

P.P.S.
> what about:
>  <T> T coalesceNull(T, T)
>  <T> T coalesceNullGet(T, Supplier<? extends T>)

(Sorry, not for my bikeshed.)

Reply via email to