Reader Mail Bag -- Local Type Inference (JEP 286)

Brian Goetz brian.goetz at oracle.com
Fri Mar 25 19:24:56 UTC 2016


(Please do not respond directly to this mail; if you want to respond, 
please use the follow-up survey.)

As promised yesterday, I'm back to cover some of the more subjective 
responses and questions to the survey.

Overall, the responses were strongly in favor of the feature; given a 
choice of great/ok/bad idea, 74% chose "great idea", 12% chose "OK", and 
10% chose "bad idea".  The written comments had more of a negative bias, 
but this shouldn't be surprising -- people are generally more inclined 
to speak up in disagreement than in agreement.  The positive comments 
were very positive; the negative comments were very negative.  So no 
matter what we do here, some people are going to be very disappointed.

(One interesting observation here is that, while developers frequently 
complain about Java's verbosity, there is at least a silent minority 
that *likes* that verbosity, and complains only when we threaten to take 
some of it away.)


Readability
===========

The biggest category of negative comments regarded concerns for 
readability.  We have always held out "Reading code is more important 
than writing code" as a core value of the language; plenty of folks 
threw this in our face, assuming that this feature would inevitably lead 
to less readable code.

For example, code like the following strawman was offered by several 
commenters:

     var x = y.getFoo()

and offered as evidence of "see, its unreadable, you have no idea what 
'x' is."  The readability problem here, though, stems primarily from the 
fact that 'x' is a silly variable name.

While every situation may be different, we believe that, with judicious 
use of this feature in well-written code, readability can actually be 
*enhanced*.

Consider a block of locals:

     UserModelHandle userDB = broker.findUserDB();
     List<User> users = db.getUsers();
     Map<User, Address> addressesByUser = db.getAddresses();

What is the most important thing on each line?  IMO, in a block like the 
above, the variable *names* are more important than the *types* or their 
initializing expressions -- they describe the role of the variable in 
the current program.  And note that the variables names are not so easy 
to visually pick out from the above code -- they're stuck in the middle 
of each line, and at a different place on each line.

Ideally, we'd like for the most important thing to be front-and-center 
in the reader's view.  (Some languages have us declare variables with 
the syntax "name : type", which also furthers this goal, but that ship 
sailed in 1995.)

If we rewrite the above block with inferred types:

     var userDB = broker.findUserDB();
     var users = db.getUsers();
     var addressesByUser = db.getAddresses();

the true intent of this code pops out much more readily.  The types are 
not needed, because we've chosen good variable names.

Another aspect in which this feature could improve readability (as 
suggested in the JEP) is that users frequently construct complex nested 
and chained expressions not because this is the most readable way to 
write the code, but because the overhead of declaring additional 
temporary variable seems burdensome.  (We all do this.)  By reducing 
this overhead, implementation patterns will likely reequilibrate to a 
less artificially-condensed form, enhancing readability.


A second version of this complaint could be summarized as "bad 
programmers will use this as an excuse to write bad code."  (This is 
sometimes phrased as some form of "I like this feature for me, but am 
not sure other developers can handle the responsibility.")

This may be true, but I think we all know that bad programmers don't 
need excuses to write bad code.

There is always a balance to be found between "preventing bad things" 
and "enabling good things", and reasonable people will reasonably differ 
on which is more important in any given situation or timeframe. 
Ultimately, this comes down to the usual question of "Here's a feature 
that can be used for both good and bad; should we trust developers to 
use it responsibility, or take that choice away from them?"  (And of 
course, proponents on both sides can find precedent in past decisions to 
claim "the spirit of Java" is on their side.)  Recall too that we heard 
all the same arguments about lambdas -- that they were too advanced, 
that Java programmers couldn't handle them, that they'd destroy 
readability (and Java with it) -- in the not-so-distant past.

Further, just because the feature exists, doesn't mean that we can't 
have stylistic guidelines regarding its use -- just like any other 
feature.  (Users can write 1000-line long methods, or pick terrible 
variable names, or store all their state in public static variables, but 
they shouldn't.)


Goals
=====

Many people made assumptions about the goals, such as "this is about 
concision", or "this is about making writing code easier."  But these 
assumptions are incorrect.  The goal here is about *reducing ceremony* 
-- allowing irrelevant details to be elided where appropriate.  In many 
cases, manifest types are not only inconvenient to write, but they get 
in the way of easily seeing what is going on when reading code.

Note that this feature is, quite deliberately, restricted to *pure 
implementation details*.  We don't use inference to determine the types 
of fields or methods; we are willing to accept a higher degree of 
ceremonial overhead for interface contracts than for implementation 
details.  And the body of a method is an implementation detail.

Several users simply expressed the notion that "Java is just fine as it 
is".  Others simply asked "Why?"

Proponents on both sides claimed "simplicity" was on their side :)


First-hand experiences
======================

It's not surprising that many people were quicker to see the bad things 
that such a feature might enable than the good things; this is human 
nature.  But we are inclined to take the comments from those who have 
used this before in other languages most seriously, as they are the most 
informed about the tradeoffs.

Of the respondents who cited first-hand experience, several listed this 
as a major friction point of polyglot projects, or of moving to Java 
from C#, C++, or Groovy (though several did point out that blanket use 
of inferred types everywhere was inadvisable, and that it required some 
judgment to use it correctly.)






More information about the platform-jep-discuss mailing list