Reader Mail Bag for Thursday (original) (raw)

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.

  1. 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.

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

Almost certainly yes.

  1. Can I say "final val"?

Silly, but probably yes as well.

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

No.

  1. 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.)

  1. 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.

  1. 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.)

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

Yes.

  1. 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.

  1. 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.

  1. 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.

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

Yes.

  1. 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
  1. 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.

  1. 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.

  1. When do we get this?

When it's ready.

  1. Can I have feature X too?

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



More information about the platform-jep-discuss mailing list