Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type inference in java

Could you please explain why below work in a way is does. It seems to me the java type system is weak to infer the type of R

public class Test {

interface Parser<A,R>{
    R parse(A a);
}

static class ResponseParser implements Parser<String,Integer>{

    public Integer parse(String s) {
        return Integer.parseInt(s) + 1;
    }
}

interface Function<A,R>{
    R with(A a);
}

public static <A,R,P extends Parser<A,R>> Function<P,R> getResult(final A res){
        return new Function<P, R>() {
            public R with(P parser) {
                return parser.parse(res);
            }
        };
}

public static void main(String [] args){
    Function<Parser<String,Integer>, Integer> func = getResult("1");
    //this works
    func.with(new ResponseParser());
    // why this does not work
    getResult("1").with(new ResponseParser());
}


}
like image 348
Abhishek kapoor Avatar asked Sep 01 '15 08:09

Abhishek kapoor


2 Answers

In the getResult("1").with(new ResponseParser()); expression the type of getResult("1") sub-expression cannot be inferred correctly from context. To your opinion it should be Function<? extends Parser<String, Integer>, Integer>, but this subexpression knows nothing about Integer. In the first case you assign the result to the Function<Parser<String,Integer>, Integer>, so the R = Integer type can be resolved, but when you just call some other method, it doesn't work.

You can fix this deferring the necessity to infer the return type. Something like this:

interface ParserFunction<A> {
    <R> R with(Parser<A, R> a);
}

public static <A> ParserFunction<A> getResult(final A res){
        return new ParserFunction<A>() {
            public <R> R with(Parser<A, R> parser) {
                return parser.parse(res);
            }
        };
}

Now getResult("1").with(new ResponseParser()); works.

like image 64
Tagir Valeev Avatar answered Oct 23 '22 15:10

Tagir Valeev


Generics are only used by the compiler to ensure that you do not violate the rules for the type you specify. During run time all generics are converted to Object but the type safety is ensured because the compiler will notify you of any violations or type safety. To achieve this though you need to tell the compiler what try you are using and this is why generics are not inferred.

Check out erasure with java generics https://docs.oracle.com/javase/tutorial/java/generics/genMethods.html

like image 45
Nicholas Robinson Avatar answered Oct 23 '22 13:10

Nicholas Robinson