Output of type type parameters in the method chain

After reading this question , I started thinking about common methods in Java 8 . In particular, what happens to generic type parameters when methods are bound.

In this question I will use some common methods from Guava ImmutableMap , but my question is more general and can be applied to all related common methods.

Consider ImmutableMap.of generic method that has this signature:

 public static <K, V> ImmutableMap<K, V> of(K k1, V v1) 

If we use this generic method to declare a Map , the compiler correctly describes the generic types:

 Map<String, String> map = ImmutableMap.of("a", "b"); 

I know that with Java 8, the mechanism of the compiler output mechanisms has been improved, i.e. it displays the general types of methods from the context, which in this case is the destination.

Context can also be a method call:

 void someMethod(Map<String, String> map) { // do something with map } someMethod(ImmutableMap.of("a", "b")); 

In this case, the generic types ImmutableMap.of are inferred from the generic types of the someMethod argument, i.e. Map<String, String> map .

But when I try to use ImmutableMap.builder() and chain methods to build my map, I get a compilation error:

 Map<String, String> map = ImmutableMap.builder() .put("a", "b") .build(); // error here: does not compile 

Mistake:

 Error:(...) java: incompatible types: ImmutableMap<Object, Object> cannot be converted to Map<String, String> 

(I just deleted the package names from the error message).

I understand the error and why this is happening. The first method in the chain is ImmutableMap.builder() , and the compiler has no context for outputting type parameters, so it discards <Object, Object> . Then, the ImmutableMap.Builder.put method ImmutableMap.Builder.put called with the arguments "a" and "b" and finally, the ImmutableMap.Builder.build() method is ImmutableMap.Builder.build() , which returns ImmutableMap<Object, Object> . This is why I get an incompatible type error: when I try to assign this instance of ImmutableMap<Object, Object> my variable Map<String, String> map , the compiler complains.

I even know how to solve this error: I could either split the method chain into two lines so that the compiler can now output type-type parameters:

 ImmutableMap.Builder<String, String> builder = ImmutableMap.builder(); Map<String, String> map = builder.put("a", "b").build(); 

Or I can explicitly specify type parameters:

 Map<String, String> map = ImmutableMap.<String, String>builder() .put("a", "b") .build(); 

So my question is not how to solve / work around this, but why do I need to explicitly provide type parameters when binding common methods. Or, in other words, why the compiler cannot output type parameters to the method chain, especially when the method chain is on the right side of the task? If it were possible, would it break something else (I mean, related to a system like generics)?

EDIT

Here is a question with a question about the same , however, the only answer it has does not give a clear explanation why the compiler does not output type parameters in the method chain. All it has is a link to a small paragraph in JSR-000335 Lambda Expressions for JavaTM programming for the final version for evaluation (spec part D):

There was some interest in allowing the output of "chain": in a (). b (), passing type information from call b to call a. This adds another dimension to the complexity of the inference algorithm, since partial information must go both ways; it only works when erasing the return type a () is fixed for all instances (e.g. List). This feature does not fit well with the poly expression model, since the type of target cannot be easily obtained; but perhaps with additional improvements that may be added in the future.

So, I can rephrase my original question as follows:

  • What will be these additional improvements?
  • How is it that transferring partial information in both directions will make the output algorithm more complicated?
  • Why will this only work when the erase of the return type () is fixed for all instances (e.g. List)? In fact, what does this mean that erasing the return type of a method is fixed for all instances?
  • Why doesn't this function fit very well into the expression model? In fact, what is a poly-expression model? And why in this case it is impossible to easily obtain the target type?
+8
java generics methods java-8 method-chaining
source share
1 answer

If it really is a comment, let me know and I will break it in separate comments (it probably won't fit in one).

The first poly expression is one that can have different types in different contexts. You declare something in contextA , it has typeA ; one in contextB and has typeB .

What you do with creating a map using ImmutableMap.of("a", "b") or ImmutableMap.of(1,2) is such a thing. To be more precise, Chapter 15.2 in JLS says that it is actually an Expression Expression of an instance of the poly expression class .

So far, we have established that A generic class instance creation is a poly expression . Thus, instantiation can have different types based on the context in which it is used (and this obviously happens).

Now in your example with ImmutableMap.builder not so difficult to draw a conclusion (if you could chain the builder and of , for example) the Builder is declared as follows:

  public static <K, V> Builder<K, V> builder() { return new Builder<K, V>(); } 

and ImmutableMap.of as follows:

  public static <K, V> ImmutableMap<K, V> of() { return ImmutableBiMap.of(); } 

Notice how both declare the same generic types K,V It will probably be easy to move from one method to another. But consider the case where your methods ( let say 10 methods ) declare different boundaries of common types, for example:

 <K,V> of() .... <M extends T, R extends S> build() 

And so on. And you can tie them. Type information needs to be passed from left to right and from right to left for output to work, and as far as I can tell, it will be very difficult to do (besides the fact that you are very complex).

Right now, how it works, each of the poly expressions is compiled according to one of what I see (and your examples seem to prove it).

+2
source share

All Articles