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