Fwd: no good default responsibility
Brian Goetz
brian.goetz at oracle.com
Sat Aug 1 15:01:34 UTC 2020
This was received on the -spec-comments list but wasn't really on-topic
for that list. Moving to amber-dev. (It is technically slightly
outside the charter for -dev too, but it is such a reasonable and
constructively asked question, that it is better to allow it.)
One of the reasons this conversation has been so difficult is that it is
not always obvious where the boundary of responsibility between VM,
language, and developer ought to be.
<digression>
C took the position of not initializing variables for you. You can
imagine the discussion; "why should the compiler overwrite this with
zeros, when it is really the developer's responsibility to put valid
data there? And it would be inefficient to write it with zeros, and
then have the developer immediately overwrite it 99.9% of the time.
Let's make this the developer's responsibility."
In 1972, this might have been a reasonable position; computers were
pretty slow, and redundantly initializing memory just because some lazy
programmer forgot to initialize their variables was viewed as an
unaffordable luxury. (Worse, you can easily imagine someone arguing the
moral hazard here: "this will just encourage programmers to be lazy,
knowing that the language will save them!") And, there were only about
six (exaggerating for effect) programmers in the world, and they were
all super-careful, since they had learned to program by writing their
programs on Fortran coding sheets and quadruple-checking them at the
desk before they dared to consume any machine time.
In hindsight, this didn't go very well (e.g., buffer overruns.) The
moral of the story is, it's easy to convince oneself that the
responsibility belongs on one specific side of the line, but sometimes
things have a way of not staying within the boxes you draw for them.
</digression>
It is easy to call these "business logic constraints" and say that it is
not the VMs (or languages) problem, but if the language becomes so
unreliable that it is hard to code correctly, then we will have the same
problem C has with buffer overruns; while it is theoretically possible
to prevent them by good practices, in practice, it does not seem to be,
and so C gets tarred with the "C is insecure" brush. We don't want Java
tarred with that brush, so it is worth spending what might seem like an
exorbitant amount of time puzzling through the right way to handle
this. And our thinking may evolve over time, as it has here.
Let's say we have a class:
inline record StringHolder(String s) {
String s;
int length() { return s.length(); }
}
If we have an uninitialized StringHolder, and someone passes that to
some other method, and then that method calls lenght() on it, it will
NPE. Just as with the buffer overrun, it is unreasonable to expect that
every developer will remember to check for nulls in methods like
length(). (And, we wouldn't want them to; that would be a waste.)
What we want to do is help developers model their domains accurately.
For many domains (e.g., numbers), a zero default is entirely sensible,
and our job is done. But for some domains, there really is no good
default. So what should happen? Let the nulls fly, and assume that
they will be caught by an NPE eventually? As much as `null` is
considered by many to be a mistake, Java's fail-fast behavior with null
dereference is clearly a feature, not a bug. Having an exception at the
precise point where the bad data was consumed is a good thing, rather
than letting it flow into some other calculation and maybe blow up far
away. So the question being considered is whether we should work harder
to align (in the case that the default is considered no good)
default-dereference with null-dereference, and catch the error in the
above code before the call to length().
Your conclusion: "maybe it is best to just keep the zero default", might
in fact be the right answer in the end. But enough people are
uncomfortable enough about this, that it's worth discussing it more.
-------- Forwarded Message --------
Subject: no good default responsibility
Date: Fri, 31 Jul 2020 23:25:04 -0400
From: Jack Ammo <jackammo77 at gmail.com>
To: valhalla-spec-comments at openjdk.java.net
i have a question about the issue. is it the jvm's responsibility to deal
with initializing inline objects to a "valid" state or is it the compiler's
responsibility to enforce the business logic of what is and isnt a valid
state for the inline object?
in my view, the "good default" problem is really the language's problem and
by extension, the language's compilers' problem. the jvm doesn't define
what the purpose or usage is for a Date object or a String object or an
int. it doesn't say if an empty String is valid for a name field or if -1
is valid for count field. Those are business logic constraints, no?
Maybe it's best for the jvm to just keep the all zero default, and if the
compiler wishes, it can immediately reassign the appropriate default as
needed. As long the inline object can be re-assigned cheaply, maybe that's
as far as the jvm needs to go?
More information about the valhalla-dev
mailing list