Local type inference against instance

I tried to scan the JEP-286 for a local type. I see that this only works for local variables - understood. So this really works:

public class TestClass { public static void main(String [] args){ var list = new ArrayList<>(); list.add("1"); System.out.println(list.get(0)); // 1 } } 

I see that this, on the other hand, does not compile:

 public class TestClass { public var list = new ArrayList<>(); public static void main(String [] args){ } } 

Obviously, this is not so, as JEP says so. Now my question is:

This means that a public / protected member declared as var fails, at least IMO. But why doesn't it compile even if it's private ? I can only assume that you can still capture this variable through reflection (and I can’t get local fields like this) ... And to get this variable you need to cast, well, maybe a very confusing listing.

+7
type-inference java-10
source share
5 answers

The motivation to disable type inference for fields and return methods is that the APIs must be stable; field access and method invocation are associated with a descriptor at runtime, so anything that causes subtle changes in the output types can cause existing compiled clients to be broken badly if a change in implementation causes a change in the intended type (modulo erase). Therefore, using this for implementation, but not for the API, is a reasonable guideline.

It’s reasonable to ask, “so what about private fields and methods?” And indeed, we could very well do that. Like all design decisions, this is a compromise; this will allow the use of output in other places in exchange for a more complex user model. (I don’t care about the complexity in the specification or the compiler, about our problem.) It’s easier to talk about “output for local variables yes, there are no fields and methods” than to add various epicyclic considerations, such as “but, the fields and methods are in order, if they are private. " Drawing the line in which we did this also means that the consequences of compatibility with changing a field or method from private to unvaccinated do not have random interactions with conclusions.

So the short answer is to do it this way by simplifying the language without making this function much less useful.

+14
source share

Various reasons:

  • Visibility and type are orthogonal - you cannot influence another. If private variables can be initialized with var , you would have to change this to make them protected or public.

  • Since var uses the right side to type in, such private fields always had to be initialized right away. If you move initialization to the constructor, you need to make the type explicit.

  • With var compiler can infer types that you currently cannot express in Java (for example, intersection types such as Comparable & Serializable ). Of course, you certainly rely on these specific types, and when for some reason you need to stop using var , you may need to refactor enough for your code to work.

+5
source share

Not like it was impossible to turn these variables into fields that can be checked with Reflection. For example, you can do

 var l = new ArrayList<String>(); l.add("text"); System.out.println(l); System.out.println( new Object(){ { var x = l; } }.getClass().getDeclaredFields()[0].getGenericType() ); 

In the current version, it simply prints an ArrayList , so the actual generic type was not stored in the class file of the anonymous inner class, and it is unlikely that this will change, since support for this introspection is not the actual target. This is also a special case when the type is denoted as ArrayList<String> . To illustrate another case:

 var acs = true? new StringBuilder(): CharBuffer.allocate(10); acs.append("text"); acs.subSequence(1, 2); System.out.println( new Object(){ { var x = acs; } }.getClass().getDeclaredFields()[0].getGenericType() ); 

The acs type is the intersection type of Appendable and CharSequence , as shown by invoking a method on any interface on it, but since it is not specified whether the compiler #1 extends Appendable&CharSequence or #1 extends CharSequence&Appendable , it is not specified whether the code will print java.lang.Appendable or java.lang.CharSequence .

I do not think that this is a problem for a synthetic field, but for an explicitly declared field it could be.

However, I doubt that the expert group considered such consequences in detail. Instead, a decision that does not support field declarations (and therefore, skip a long thought about the consequences) was made from the very beginning, since local variables were always the intended purpose for this function. The number of local variables is much higher than the number of field declarations, so the template reduction for local variables has the greatest impact.

+5
source share

It would be a smart decision to allow var for private fields (IMO). But omission of this simplifies the function.

It can also be added to some future release after there is more experience with the method of outputting only a local type, while deleting a function is much more complicated.

+3
source share

In developing Nicolai's answer (in particular, his argument No. 2), the proposed JLS 10 project states that as var e; , so var g = null; are illegal for local variables, and for good reason; from the right part (or its absence) it is not visible what type to deduce for var .

Currently, instance variables of the final instance are automatically initialized depending on their type (primitives to 0 and false ) and references to null , as I am sure you already know). The inferred type of the instance variable remains unclear if it is not initialized during the declaration or in its constructor (s) of the corresponding class.

For this reason, I support the possibility of using var only when the variable is private and final , so we can guarantee that it will be initialized by the time the class is created. Although, I can’t say how difficult it is to implement it.

+3
source share

All Articles