Results 1 to 6 of 6
  1. #1
    ranma173 is offline Member
    Join Date
    Sep 2010
    Posts
    4
    Rep Power
    0

    Default Generic return type is not inferred in for-each loop

    Hello,

    I've come across this situation where I need to use a method with generic return type inside a for-each (enhanced for) loop.

    The generic method is this:
    Java Code:
    	/** Returns an Iterable for a IDfList */
    	public static <E> Iterable<E> getIterable(IDfList list) {
    		return new IterableIDfList<E>(list);
    	}
    Then, I can use it this way:
    Java Code:
    	Iterable<IDfCopyNode> copyNodes = DfcUtil.getIterable(copyOp.getNodes()); // Infers the return type
    	for ( IDfCopyNode node : copyNodes ) ...
    But I can't inline the copyNodes variable:
    Java Code:
    	for ( IDfCopyNode node : DfcUtil.getIterable(copyOp.getNodes()) ) ... // WON'T COMPILE; doens't infer type
    To do it, I must explicitly put the generic type:
    Java Code:
    	for ( IDfCopyNode node : DfcUtil.<IDfCopyNode>getIterable(copyOp.getNodes()) ) ...
    Do you know why? Shouldn't the compiler infer the generic type in the for-each like in the simple assignation? After all, I suppose the for-each loop performs a simple assignation behind the scenes.

    Thank you!
    Fran

  2. #2
    ranma173 is offline Member
    Join Date
    Sep 2010
    Posts
    4
    Rep Power
    0

    Default

    Do you have any idea?

  3. #3
    rc_coder is offline Member
    Join Date
    Sep 2010
    Posts
    11
    Rep Power
    0

    Default

    I'm not a 100% sure what you're asking, I think you're more curious than needing to actually fix a problem right!?

    And I'm also not a 100% sure of the answer but I'll give it a bash,
    Java Code:
    	Iterable<IDfCopyNode> copyNodes = DfcUtil.getIterable(copyOp.getNodes()); // Infers the return type
    	for ( IDfCopyNode node : copyNodes ) ...
    In this segment of code you are helping the type get inferred by explicitly stating the type of the iterable on the left hand side, i.e. Iterable<IDfCopyNode>.

    However in this code
    Java Code:
    	for ( IDfCopyNode node : DfcUtil.getIterable(copyOp.getNodes()) ) ... // WON'T COMPILE; doens't infer type
    you skip that step of inferring it, you simply call DfcUtil.getIterable(copyOp.getNodes()) which will give a generic Iterator.

    If you were to rewrite the above snippet as two seperate statements(just like the 1st snippet) I believe the code would be like so
    Java Code:
    	Iterable copyNodes = DfcUtil.getIterable(copyOp.getNodes()); // Infers the return type
    	for ( IDfCopyNode node : copyNodes ) ...
    Note the generic creation of an Iterable object with no type inferred.
    If the other bit doesn't compile, I would imagine this would also not compile because of not inferring the type, although I'm not sure!

  4. #4
    ranma173 is offline Member
    Join Date
    Sep 2010
    Posts
    4
    Rep Power
    0

    Default

    Quote Originally Posted by rc_coder View Post
    I'm not a 100% sure what you're asking, I think you're more curious than needing to actually fix a problem right!?
    Right, but I'm curious because maybe I'm doing something wrong, or Java itself is doing something wrong. :)

    Quote Originally Posted by rc_coder View Post
    If you were to rewrite the above snippet as two seperate statements(just like the 1st snippet) I believe the code would be like so
    Java Code:
    	Iterable copyNodes = DfcUtil.getIterable(copyOp.getNodes()); // Infers the return type
    	for ( IDfCopyNode node : copyNodes ) ...
    Well, I think it would (or should) be:
    Java Code:
    	Iterable<IDfCopyNode> copyNodes = DfcUtil.getIterable(copyOp.getNodes()); // Infers the return type
    	for ( IDfCopyNode node : copyNodes ) ...
    since the "for" knows that the element type is IDfCopyNode.

    I think the problem is that the "for" doesn't tell the iterable_part what the element_type is:
    Java Code:
    for( element_type var : iterable_part ) ...
    so the iterable_part can't infer the type like in a simple assignation.

    In that case, the assignation DOES tell the value_part what the assignation_type is:
    Java Code:
    assignation_type var = value_part;
    Do you know what I mean?

    Thanks for your help!

  5. #5
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,585
    Rep Power
    12

    Default

    According to Angelika Langer (who has a lot of detail about generics online) inWhat happens if a type parameter does not appear in the method parameter list?:

    If the type parameter does not appear in the types of the method arguments, then the compiler cannot infer the type arguments by examining the types of the actual method arguments. If the type parameter appears in the method's return type, then the compiler takes a look at the context in which the return value is used. If the method call appears as the righthand side operand of an assignment, then the compiler tries to infer the method's type arguments from the static type of the lefthand side operand of the assignment.

    ...

    An invocation context other than an assignment is not considered for type inference. The result of the method call might be passed as an argument to another method, for instance. The compiler does not try to perform any special type inference in that case. Instead the compiler handles the method call as though it would appear in no context. No context means that the compiler performs the type inference algorithm as though the method result was assigned to a variable of type Object.

    This would explain why this type inference is not done in the case of a for loop. I tried to get the detailed bassis for this from the JLS - 15.12.2.7 Inferring Type Arguments Based on Actual Arguments - but couldn't understand a word of it!

  6. #6
    rc_coder is offline Member
    Join Date
    Sep 2010
    Posts
    11
    Rep Power
    0

    Default

    Quote Originally Posted by ranma173 View Post
    Right, but I'm curious because maybe I'm doing something wrong, or Java itself is doing something wrong. :)
    I don't think either is the case :)

    Quote Originally Posted by ranma173 View Post
    Well, I think this
    for ( IDfCopyNode node : DfcUtil.getIterable(copyOp.getNodes()) ) ... // WON'T COMPILE; doens't infer type
    would (or should) be:
    Java Code:
    	Iterable<IDfCopyNode> copyNodes = DfcUtil.getIterable(copyOp.getNodes()); // Infers the return type
    	for ( IDfCopyNode node : copyNodes ) ...
    since the "for" knows that the element type is IDfCopyNode.
    Well as far as I see all Java/the for loop knows(in the first snippet) is that there is a call being maid to retrieve an object from an generic iterator (i.e. copyNodes) and the object is expected to be of type IDfCopyNode, this doesn't mean the iterator(which is still generic) has all IDfCopyNodes in it!
    Consider the case that there are different types of objects in a generic iterator, if the compiler assumed the coder was correct in specifying the type on the left then it would crash depending what you tried to do in the loop.
    For example consider
    Java Code:
    		ArrayList test = new ArrayList();
    		test.add(new Integer(1));
    		test.add(new String("s"));
    
    		for(Integer i : test){
    			i.byteValue();
    		}
    If the for loop assumed my generic ArrayList was indeed of type Integer then it would crash when it called byteValue() on the second element which is a string! Of course you could still force it to go through the loop by explicitly coding it, like if you did something like this.
    Java Code:
    	public static <E> Iterable<E> getIterable(ArrayList list) {
    		return new Vector<E>(list);
    	}
    	ArrayList test = new ArrayList();
    	test.add(new Integer(1));
    	test.add(new String("s"));
    
    	for(Integer i : GeneralTest.<Integer>getIterable(test)){
    		i.byteValue();
    	}
    but then that's your fault and not the compiler :)

    If a for loop was to just assume the iterator was of type whatever element you specify they it could cause all sorts of problems! what if I did this
    Java Code:
    ArrayList<String> list = new ArrayList<String>();
    list.add("a")...
    ...
    ...
    for(MyOwnCrazyType c : list){
     c.doACrazyMethod();
    }
    I'd get another crash :)

    Quote Originally Posted by ranma173 View Post
    Thanks for your help!
    No probs! :) It may feel more like I'm working but I'm still procrastinating from real work :p

Similar Threads

  1. Generic collection type
    By dreuzel in forum Advanced Java
    Replies: 7
    Last Post: 12-23-2009, 07:05 PM
  2. Static String Return Type
    By Java_Developer in forum New To Java
    Replies: 17
    Last Post: 10-03-2009, 07:07 PM
  3. Method return type problem
    By McChill in forum New To Java
    Replies: 7
    Last Post: 05-05-2009, 10:21 PM
  4. Replies: 1
    Last Post: 05-17-2008, 12:06 AM
  5. The return type
    By Marcus in forum New To Java
    Replies: 1
    Last Post: 07-05-2007, 07:28 AM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •