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.

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.

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