Reader Mail Bag for Thursday

Brian Goetz brian.goetz at oracle.com
Thu Mar 10 15:07:54 UTC 2016


PLEASE DO NOT RESPOND DIRECTLY TO THIS MAIL -- SEE BELOW FOR HOW TO 
PROVIDE FEEDBACK.

The first ~1000 survey responses are in.  We'll publish the full results 
when the survey closes, but I'll take this opportunity to answer some of 
the questions from the "Questions for the Java Language Team" section.  
(I've paraphrased / generalized a lot of the questions.)  I'll answer 
more as they come in.

***
If you want to respond, please do it through the survey! If you've 
already taken the survey, don't worry, there'll be a follow-up survey 
where you can provide additional feedback.

The survey link is: https://www.surveymonkey.com/r/KGPTHCG
***

We'll also be posting a prototype soon, which will answer a lot of the 
"what would happen in this case..." questions.


1.  What about multiple assignments?

If we have

     var x = new Foo();
     ...
     x = new Bar();

we compute the type of x based solely on the type of the initializer.  
So the above code is equivalent to:

     Foo x = new Foo();
     ...
     x = new Bar();

If Bar is a subtype of Foo, then this code is fine, otherwise it is a 
type error -- just like before.  Local variable type inference is purely 
local; we compute the type of x from its initializer, and thereafter, it 
is as if it were manifestly typed.


2.  If the type of the initializer is ArrayList, can you infer List 
instead, as we probably would have written by hand?

This would be confusing type inference with mind reading.


3.  Can I say "final var", even if we have "val"?

Almost certainly yes.


4.  Can I say "final val"?

Silly, but probably yes as well.


5.  Will this interfere with existing uses of "var" and "val" as 
identifiers, package names, or method names?

No.


6.  Will this interfere with existing uses of "var" and "val" as a class 
name?

Yes.  We consider this to be an acceptable source-compatibility 
violation, because these are likely to be quite rare as class names (the 
naming conventions for Java code, which are almost universally accepted, 
say that class names should start with an uppercase letter.)


7.  Why is it not possible to use var when the initializer is an array 
initializer, as in:

     var ints = { 1, 2, 3 }

The rule is: we derive the type of the variable by treating the 
initializer as a standalone expression, and deriving its type. However, 
array initializers, like lambdas and method refs, are *poly expressions* 
-- they need a target type in order to compute their type.  So they are 
rejected.

Could we *make* this work?  We probably could.  But it would add a lot 
of complexity to the feature, for the benefit of a mostly corner case.  
We'd like for this to be a simple feature.


8.  How do we debug programs with inferred types?

We expect tooling will evolve to help here.  In languages that have this 
feature, IDEs will show you the type as you hover over the variable name 
(most Java IDEs already do this).  We are also considering providing a 
javac option to produce a source file that shows all inferred types 
(lambda formals, generic method type parameters, diamond constructor 
args, inferred locals.)


9.  Won't bad developers misuse this feature to write terrible code?

Yes.


10.  What do you mean by "action at a distance"?

Type inference is constraint solving.  The main choices a language 
designer gets to make in designing a type inference algorithm are where 
to get the constraints, and when (over what scope) to solve.  We could, 
if we chose, let all assignments to a variable contribute constraints, 
and solve globally; while this produces nice sharp types (though 
sometimes surprising types) when it works, it produces extremely 
confusing error messages when it doesn't, and means that a change 
anywhere in a program could affect things far away in the program.

For example, if we followed the approach of using all assignments to 
constrain the type of an implicitly typed variable, if we had:

    var x = "";
    ...
    x = anInteger;

the compiler might compute the type of x by taking the least upper bound 
of String and Integer.  (You might think this would be Object, but 
really is something more like Object&Serializable&Comparable, if not 
more complicated.)

Action-at-a-distance refers to the fact that a use of x several hundred 
lines away could change the type of x, and cause confusing errors 
nowhere near where the change occurred.


11.  What is the reasoning behind not inferring types for variables that 
use the C-style "int x[]" convention?

In part, this would be asking for half-inference; "I want x to be an 
array with a given rank, but infer the component type please." Valid, 
but that's basically a different feature.  Besides, this convention is, 
at this point, mostly vestigial.


12.  You ran the prototype over the JDK as a corpus, and gathered 
statistics.  Can you run it over a larger source base?

The JDK is pretty large, but yes, we already did this over a corpus of 
~100 popular OSS projects including Eclipse, NetBeans, and many Apache 
projects.  We got essentially the same numbers.


13.  Will this work for the index variable of a for loop or foreach loop?

Yes.


14.  What happens if we ask for inference on both sides, as in:

     var x = new ArrayList<>()

In most cases, you'll get an informative compiler error telling you that 
you're asking for your mind to be read.  In some cases, we'll fall back 
to inferring Object, as we currently do with:

     Object o = new ArrayList<>()  // always inferred ArrayList<Object> here


15.  Isn't this opposed to static typing?

No.  Variables are still statically typed, as they have always been (and 
the inference algorithm used here ensures that we always produce a 
denotable type, meaning that there is an equivalent manifestly typed 
program.)  What's happening here is that you have the opportunity to let 
the compiler figure out the type.


16.  Why exclude field declarations?

Field and method declarations are part of a classes interface contract, 
and may be referenced from other classes (meaning their type descriptors 
will be copied into other classfiles, and dynamically linked by exact 
descriptor match at runtime.)  This means that small changes to the 
program implementation could silently turn into binary compatibility 
issues, if the type changes subtle and the client is not recompiled.

The operating theory here is that local variables are *implementation 
details* -- they are part of the method implementation, not part of the 
classes interface contract.  They cannot be referenced from other 
compilation units or other methods.  Therefore, a lower degree of 
ceremony is needed than when specifying interface contracts across 
compilation units.


17.  When do we get this?

When it's ready.


18.  Can I have feature X too?

Let's do one thing at a time, OK?





More information about the platform-jep-discuss mailing list