participate


Generics - no unique maximal instance exists for type variable A [Locked]
This topic is locked
<<   Back to Forum  |   Give us Feedback
This topic has 19 replies on 2 pages.    1 | 2 | Next »
Plouf
Posts:6
Registered: 11/6/00
no unique maximal instance exists for type variable A   
Apr 18, 2006 12:34 PM

 
I'm migrating a project from Eclipse to Ant. While the following code compiles using Eclipse, it fails using JDK 1.5.0_06 with the following error:
type parameters of <B>B cannot be determined; no unique maximal instance exists for type variable B with upper bounds A,java.lang.Object

  private <B> B getOtherValue()
  {
    return null;
  }
  
  private <A> A getValue()
  {
    return getOtherValue();
  }


The compiler seems to have troubles infering the type of the generic <B> parameter in getOtherValue, based on the return type of getValue.

Could somebody explain me what's wrong with that code?
 
lord_pixel
Posts:252
Registered: 10/21/97
Re: no unique maximal instance exists for type variable A   
Apr 19, 2006 6:05 AM (reply 1 of 19)  (In reply to original post )

 
  private <B> B getOtherValue()
  {
    return null;
  }
  
  private <A> A getValue()
  {
    return getOtherValue();
  }

Let's substitute some concrete types:

private String getOtherValue() {
    return null;
}
 
private Integer getValue() {
     return getOtherValue();
}


Now do you see what's wrong? OK, so it's a silly example, but it illustrates how you have not told the compiler anything about the relationship between A and B. If A is Object then B can be anything, but if at runtime A turned out to be Integer, and B turned out to be String, clearly we'd have a problem. The compiler has no way of knowing what A and B will be, so intuitively it must disallow this.

It's not that there's no possible correct answer, obviously, there's always Object, but it can't know whether the code is correct or not because it can't know if A and B are compatible.
 
Plouf
Posts:6
Registered: 11/6/00
Re: no unique maximal instance exists for type variable A   
Apr 19, 2006 10:29 AM (reply 2 of 19)  (In reply to #1 )

 
I don't get it: as soon as I fix the value of A as being Integer, it becomes very clear that B is Integer as well. There is strictly no ambiguity here: whatever A, B is equal to A. The compiler has no problem with

  private <B> B getOtherValue()
  {
    return null;
  }
  
  private Integer getValue()
  {
    return getOtherValue();
  }


There is no reason for the compiler to decide that B is Object when it is called from an Integer context. So why can't it perform exactly the same inference when 'Integer' is replaced by 'A'?

And once again, Eclipse has no trouble compiling the initial code.
 
lord_pixel
Posts:252
Registered: 10/21/97
Re: no unique maximal instance exists for type variable A   
Apr 19, 2006 5:27 PM (reply 3 of 19)  (In reply to #2 )

 
I don't get it: as soon as I fix the value of A as
being Integer, it becomes very clear that B is
Integer as well. There is strictly no ambiguity here:
whatever A, B is equal to A. The compiler has no
problem with

  private <B> B getOtherValue()
  {
    return null;
  }
  
  private Integer getValue()
  {
    return getOtherValue();
  }

Yes... though that code is useless, because I don't think you can ever return anything other than null from getOtherValue(). Nothing else will compile...?

There is no reason for the compiler to decide that B
is Object when it is called from an Integer context.
So why can't it perform exactly the same inference
when 'Integer' is replaced by 'A'?

And once again, Eclipse has no trouble compiling the
initial code.

Well, both Javac and Eclipse have bugs. The question is, which has a bug in this case (always assuming the Java Lang Spec isn't ambiguous).

Unfortunately I'm not an expert on this stuff - my gut feeling is this should not compile as you originally posted it. But I may well be wrong.

It might help to reason about it if you can give us a bigger piece of your original program so we can think about what you are trying to achieve. Right now it is difficult to see why this code is useful. Not than I'm doubting that it is useful.

Another thought experiment... what if you added another method to the class:

  private <C> C getValue()
  {
    return getOtherValue();
  }


Now, you've told the compiler you have two methods, one returning an A and one returning a C. They both call getOtherValue() which returns a B.

Clearly there are cases where this could work. If A and C and compatible types. But the compiler can't prove this.

It must consider the case where A and C are not compatible, e.g. if A were Integer and C was String, then no B exists that can satisfy that contract (the bounds). B would have to be String sometimes and Integer other times - there's no unique instance that can do it.

You can say maybe it should compile when there is only the one method returning A - but then that would mean that if you later changed the source code of the class to add the method that returns C, the method that returns B would suddenly no longer compile even though you didn't change it.

So, should it be allowed? What do you think?
 
Plouf
Posts:6
Registered: 11/6/00
Re: no unique maximal instance exists for type variable A   
Apr 20, 2006 11:16 AM (reply 4 of 19)  (In reply to #3 )

 
Once again, I don't see your point about the compatibility between A and C. The compiler never has to decide, once for all, what is the value for A or C. It depends on the context.
Take the following code (that builds using both Eclipse and Sun):
  private <A> A getValue()
  {
    return null;
  }
  
  public String getStringValue()
  {
    return getValue();
  }
  
  public Integer getIntegerValue()
  {
    return getValue();
  }


What's the value for A? Well, it depends on the context. In the first context, A is a String, in the second A is an Integer. There is no context-less value for A. That's the purpose of this "method-level" generic parameter, unless I'm completely lost.

My actual code is rather complex and involves several classes, but I found a less trivial example:
  public <A> A getValue(Class<A> clazz,String name)
  {
    A result=null;
    if(name.equals("User"))
    {
      result=(A)"Plouf";
    }
    else if(name.equals("Age"))
    {
      result=(A)new Integer(26);
    }
    if(result.getClass()!=clazz) throw new RuntimeException();
    return result;
  }
  
  public String getUserName()
  {
    return getValue(String.class,"User");
  }
  
  public int getUserAge()
  {
    return getValue(Integer.class,"Age");
  }


This code is safe and compiles using both Eclipse and Sun. Now let say that you want to refactor this getValue method, and split the actual value extraction from the type verification:
  public <B> B getValueUnsafe(String name)
  {
    B result=null;
    if(name.equals("User"))
    {
      return (B)"Plouf";
    }
    else if(name.equals("Age"))
    {
      return (B)new Integer(26);
    }
    return null;
  }
 
  public <A> A getValue(Class<A> clazz,String name)
  {
    A result=getValueUnsafe(name);
    if(result.getClass()!=clazz) throw new RuntimeException();
    return result;
  }
  
  public String getUserName()
  {
    return getValue(String.class,"User");
  }
  
  public int getUserAge()
  {
    return getValue(Integer.class,"Age");
  }


Now this code does not compile anymore using Sun JDK! I agree this code is a little bit far-fetched, but this is all I found both usefull and still small enough for this forum.
 
Plouf
Posts:6
Registered: 11/6/00
Re: no unique maximal instance exists for type variable A   
Apr 20, 2006 11:28 AM (reply 5 of 19)  (In reply to #4 )

 
What is funny is that the following code just compiles OK:
  private <B> B getOtherValue()
  {
    return null;
  }
  
  private <A> A getValue()
  {
    return (A)getOtherValue();
  }
 
lord_pixel
Posts:252
Registered: 10/21/97
Re: no unique maximal instance exists for type variable A   
Apr 20, 2006 12:30 PM (reply 6 of 19)  (In reply to #4 )

 
Once again, I don't see your point about the
compatibility between A and C. The compiler never has
to decide, once for all, what is the value for A or
C. It depends on the context.
Take the following code (that builds using both
Eclipse and Sun):
  private <A> A getValue()
  {
    return null;
  }
  
  public String getStringValue()
  {
    return getValue();
  }
  
  public Integer getIntegerValue()
  {
    return getValue();
  }


What's the value for A? Well, it depends on the
context. In the first context, A is a String, in the
second A is an Integer. There is no context-less
value for A. That's the purpose of this
"method-level" generic parameter, unless I'm
completely lost.

Granted, you can use it that way. You gain in that you don't have to insert unsafe casts to String and Integer - the compiler infers them for you from the calling context. However, you only have no casts in the code above because you are returning null. If you wanted to actually return a value you have to cast to (A) as you do in the examples below, so you still have an unsafe cast. You've saved a bit of typing but not much else.

Now let say that you want to refactor this
getValue method, and split the actual value
extraction from the type verification:
  public <B> B getValueUnsafe(String name)
  {
    B result=null;
    if(name.equals("User"))
    {
      return (B)"Plouf";
    }
    else if(name.equals("Age"))
    {
      return (B)new Integer(26);
    }
    return null;
  }
 
  public <A> A getValue(Class<A> clazz,String name)
  {
    A result=getValueUnsafe(name);
if(result.getClass()!=clazz) throw new
new RuntimeException();
    return result;
  }
  
  public String getUserName()
  {
    return getValue(String.class,"User");
  }
  
  public int getUserAge()
  {
    return getValue(Integer.class,"Age");
  }


Now this code does not compile anymore using Sun JDK!
I agree this code is a little bit far-fetched, but
this is all I found both usefull and still small
enough for this forum.

OK... now I see what you're doing This is how I'd write that example:

public Object getValueUnsafe(String name) {
    if ( "User".equals(name) )  {
      return "Plouf";
    } else if ( "Age".equals(name) )  {
      return new Integer(26);
    }
    return null;
  }
 
  public <A> A getValue(Class<A> clazz, String name) {
      return clazz.cast(getValueUnsafe(name));
  }
  
  public String getUserName() {
    return getValue(String.class, "User");
  }
  
  public int getUserAge() {
    return getValue(Integer.class, "Age");
  }


The method Class.cast() hides the unsafe cast inside of it, so you do not get a warning. The getValueUnsafe() just returns an Object - which is all it ever did when it was declared to return a 'B' as B was unconstrained. Hopefully this is applicable to your real code and it may make it simpler. Class.cast() throws ClassCastException - if you want a different exception you'll have to catch that and wrap it.

As to whether it's a bug that Javac doesn't accept the original code, or a bug that Eclipse does, I still do not know, but I'd suggest something like the above as an alternative.
 
Plouf
Posts:6
Registered: 11/6/00
Re: no unique maximal instance exists for type variable A   
Apr 20, 2006 12:57 PM (reply 7 of 19)  (In reply to #6 )

 
Well that does not really apply because my method is actually something like this:

public <A extends Serializable,B> A convertFromNetwork(B param)
{
  return _converterImpl.convertFromNetwork(param);
}


With _converterImpl having its method like this
public <A extends Serializable,B> A convertFromNetwork(B param);


But I managed to fix my problem by doing an explicit cast:
public <A extends Serializable,B> A convertFromNetwork(B param)
{
  return (A)_converterImpl.convertFromNetwork(param);
}


That's not the most clean thing ever, but that'll do the job... The only drawback is that previously the only location where I had to do the cast was in the _convertImpl instance, and not a little bit everywhere as it is now... Funnily enough, I now have MORE casts than if I didn't use generics...
 
lord_pixel
Posts:252
Registered: 10/21/97
Re: no unique maximal instance exists for type variable A   
Apr 20, 2006 4:51 PM (reply 8 of 19)  (In reply to #7 )

 
It's really hard to say without seeing more complete code, but if that's the case maybe you shouldn't be using generics.

If there really no relationship between the return type A and the param type B?

It looks like you're using unsafe casts in the convertFromNetwork code, to hide the need to cast from your client code that calls convertFromNetwork(). This can be good or bad, but without knowing the whole shape of the problem it's hard to say.

This looks like it could possibly be similar to the FAQ in this forum where someone asks: "given a Map, how can I make it so if the key is a String the value is known to be a StringFoo and if the key is an Integer, the value is known to be an IntegerFoo?" (you can't with generics)

I'm curious, if you're willing to talk more, but as you've found a solution...
 
Plouf
Posts:6
Registered: 11/6/00
Re: no unique maximal instance exists for type variable A   
Apr 21, 2006 11:54 AM (reply 9 of 19)  (In reply to #8 )

 
It is true that there is no relationship between A and B and that it is impossible for the compiler to be 100% certain that everything will work at compile-time.

The generics here allow me not to do castings all over the place. Some might argue that I'm trying to emulate dynamic-typing in Java using generics.

With generics, you can do things like
public <A> A getValue(Object key)
{
  return (A)_map.get(key);
}


That's not safe at all, but heh, not more that doing the explicit cast when doing the getValue call... and now you can write something like

String name=getValue("name");
int age=getValue("age");
 
realbuzz
Posts:1
Registered: 4/26/06
Re: no unique maximal instance exists for type variable A   
Apr 26, 2006 3:43 AM (reply 10 of 19)  (In reply to #9 )

 
We have exactly the same problem here. Our project compiles smoothly with the eclipse java compiler. But with javac it don't.

Please, if anyone solved this issue we would be pleased to see a post here.

Mirko Dietrich, Distributed Genetic Programming Framework http://dgpf.sourceforge.net
 
lord_pixel
Posts:252
Registered: 10/21/97
Re: no unique maximal instance exists for type variable A   
Apr 26, 2006 9:46 AM (reply 11 of 19)  (In reply to #10 )

 
I actually filed a new bug, but it appears it will be a duplicate of this one:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
 
vgarmash
Posts:34
Registered: 25.11.2004
Re: no unique maximal instance exists for type variable A   
May 1, 2008 12:46 PM (reply 12 of 19)  (In reply to #11 )

 
Yep. By the way - workaraund the offering there works!
 
mauriziocima
Posts:4
Registered: 6/27/01
Re: no unique maximal instance exists for type variable A   
May 20, 2008 7:56 AM (reply 13 of 19)  (In reply to #12 )

 
Hi everybody
I'm Maurizio Cimadamore, the type-system engineer of javac. I just tried to compiled your example and I found no problems.
I tried this using the latest version of the openjdk-6 compiler. Which release of javac are you using? Btw, the suggested workaround
works whenever the compiler is wrong in inferring method type arguments, since it basically disables type-inference.

Maurizio
 
paul.miner
Posts:2,841
Registered: 10/8/07
Re: no unique maximal instance exists for type variable A   
May 20, 2008 8:21 AM (reply 14 of 19)  (In reply to #13 )

 
mauriziocima wrote:
Hi everybody

Apr 18, 2006 2:34 PM

Thanks for the speedy response.
 
This topic has 19 replies on 2 pages.    1 | 2 | Next »
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics
    Users Online : 63
  • Guests : 118

About Sun forums
  • Sun Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

    Check out our guide on Getting started with Sun Forums for a full walkthrough of how to best leverage the benefits of this community.

Powered by Jive Forums