Why can java not infer a supertypeWhy is lambda return type not checked at compile timeIs Java “pass-by-reference” or “pass-by-value”?What is a serialVersionUID and why should I use it?How do I read / convert an InputStream into a String in Java?When to use LinkedList over ArrayList in Java?How do I generate random integers within a specific range in Java?Creating a memory leak with JavaWhy is subtracting these two times (in 1927) giving a strange result?Why don't Java's +=, -=, *=, /= compound assignment operators require casting?Why is char[] preferred over String for passwords?Why is processing a sorted array faster than processing an unsorted array?

What does "speed checked" mean?

Precious Stone, as Clear as Diamond

Why combine commands on a single line in a Bash script?

What does a single quote inside a C# date time format mean?

Are there any spells that aren't on any class's spell list?

Migrate foreign key type from char to binary - ways to deal with the fallout?

How does an aircraft descend without its nose pointing down?

Why is the past tense of vomit generally spelled 'vomited' rather than 'vomitted'?

Travel with Expired Greek Passport from UK to Greece and Return

Are the Properties of the EM Spectrum Fluid?

Alternatives to boxes

What are some examples of three-mora atamadaka verbs besides 帰る?

Why is the Falcon Heavy center core recovery done at sea?

Explanation of tac --before

Why does the passage the Letwin amendment "scrap the possibility of a meaningful vote on Johnson's deal"?

C function to check the validity of a date in DD.MM.YYYY format

More optional xx_use:N and xx_new:N functions than documented?

Multiple devices with one IPv6 to the Internet?

On the finite simple groups with an irreducible complex representation of a given dimension

Why is my Windows 7 recovery folder 53% of my disk

What is a word for the feeling of constantly wanting new possessions?

Is it possible to have a healthy work-life balance as a professor?

What would be the best propulsion system for this aircraft carrier?

Can someone help explain what this FFT workflow is doing to my signal, and why it works?



Why can java not infer a supertype


Why is lambda return type not checked at compile timeIs Java “pass-by-reference” or “pass-by-value”?What is a serialVersionUID and why should I use it?How do I read / convert an InputStream into a String in Java?When to use LinkedList over ArrayList in Java?How do I generate random integers within a specific range in Java?Creating a memory leak with JavaWhy is subtracting these two times (in 1927) giving a strange result?Why don't Java's +=, -=, *=, /= compound assignment operators require casting?Why is char[] preferred over String for passwords?Why is processing a sorted array faster than processing an unsorted array?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;









16

















We all know Long extends Number. So why does this not compile. And how to define the method "with" so that the program compiles without any manual cast.




import java.util.function.Function;

public class Builder<T>
static public interface MyInterface
Number getNumber();
Long getLong();


public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)
return null;//TODO


public static void main(String[] args)
// works:
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// works:
new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
// works:
new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
// works:
new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, Long.valueOf(4));
// compiles but also involves typecast (and Casting Number to Long is not even safe):
new Builder<MyInterface>().with( myInterface->(Long) myInterface.getNumber(), 4L);
// compiles but also involves manual conversion:
new Builder<MyInterface>().with(myInterface -> myInterface.getNumber().longValue(), 4L);
// compiles (compiler you are kidding me?):
new Builder<MyInterface>().with(castToFunction(MyInterface::getNumber), 4L);


static <X, Y> Function<X, Y> castToFunction(Function<X, Y> f)
return f;







  • Cannot infer type argument(s) for <F, R> with(F, R)

  • The type of getNumber() from the type Builder.MyInterface is Number, this is incompatible with the descriptor's return type: Long



For usecase see: Why is lambda return type not checked at compile time










share|improve this question




























  • Can you post MyInterface?

    – Maurice Perry
    Oct 14 at 13:42











  • its already inside the class

    – jukzi
    Oct 14 at 13:42











  • Hmm I tried <F extends Function<T, R>, R, S extends R> Builder<T> with(F getter, S returnValue) but got java.lang.Number cannot be converted to java.lang.Long), which is surprising because I don't see where the compiler gets the idea that the return value from getter will need to be converted to returnValue.

    – jingx
    Oct 14 at 14:56











  • @jukzi OK. Sorry, I missed that.

    – Maurice Perry
    Oct 15 at 4:58











  • Changing Number getNumber() to <A extends Number> A getNumber() makes stuff work. No idea whether this is what you wanted. As others have said the issue is that MyInterface::getNumber could be a function that returns Double for example and not Long. Your declaration does not allow the compiler to narrow the return type based on other information present. By using a generic return type you allow the compiler to do so, hence it works.

    – Giacomo Alzetta
    Oct 15 at 9:19


















16

















We all know Long extends Number. So why does this not compile. And how to define the method "with" so that the program compiles without any manual cast.




import java.util.function.Function;

public class Builder<T>
static public interface MyInterface
Number getNumber();
Long getLong();


public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)
return null;//TODO


public static void main(String[] args)
// works:
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// works:
new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
// works:
new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
// works:
new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, Long.valueOf(4));
// compiles but also involves typecast (and Casting Number to Long is not even safe):
new Builder<MyInterface>().with( myInterface->(Long) myInterface.getNumber(), 4L);
// compiles but also involves manual conversion:
new Builder<MyInterface>().with(myInterface -> myInterface.getNumber().longValue(), 4L);
// compiles (compiler you are kidding me?):
new Builder<MyInterface>().with(castToFunction(MyInterface::getNumber), 4L);


static <X, Y> Function<X, Y> castToFunction(Function<X, Y> f)
return f;







  • Cannot infer type argument(s) for <F, R> with(F, R)

  • The type of getNumber() from the type Builder.MyInterface is Number, this is incompatible with the descriptor's return type: Long



For usecase see: Why is lambda return type not checked at compile time










share|improve this question




























  • Can you post MyInterface?

    – Maurice Perry
    Oct 14 at 13:42











  • its already inside the class

    – jukzi
    Oct 14 at 13:42











  • Hmm I tried <F extends Function<T, R>, R, S extends R> Builder<T> with(F getter, S returnValue) but got java.lang.Number cannot be converted to java.lang.Long), which is surprising because I don't see where the compiler gets the idea that the return value from getter will need to be converted to returnValue.

    – jingx
    Oct 14 at 14:56











  • @jukzi OK. Sorry, I missed that.

    – Maurice Perry
    Oct 15 at 4:58











  • Changing Number getNumber() to <A extends Number> A getNumber() makes stuff work. No idea whether this is what you wanted. As others have said the issue is that MyInterface::getNumber could be a function that returns Double for example and not Long. Your declaration does not allow the compiler to narrow the return type based on other information present. By using a generic return type you allow the compiler to do so, hence it works.

    – Giacomo Alzetta
    Oct 15 at 9:19














16












16








16


3






We all know Long extends Number. So why does this not compile. And how to define the method "with" so that the program compiles without any manual cast.




import java.util.function.Function;

public class Builder<T>
static public interface MyInterface
Number getNumber();
Long getLong();


public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)
return null;//TODO


public static void main(String[] args)
// works:
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// works:
new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
// works:
new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
// works:
new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, Long.valueOf(4));
// compiles but also involves typecast (and Casting Number to Long is not even safe):
new Builder<MyInterface>().with( myInterface->(Long) myInterface.getNumber(), 4L);
// compiles but also involves manual conversion:
new Builder<MyInterface>().with(myInterface -> myInterface.getNumber().longValue(), 4L);
// compiles (compiler you are kidding me?):
new Builder<MyInterface>().with(castToFunction(MyInterface::getNumber), 4L);


static <X, Y> Function<X, Y> castToFunction(Function<X, Y> f)
return f;







  • Cannot infer type argument(s) for <F, R> with(F, R)

  • The type of getNumber() from the type Builder.MyInterface is Number, this is incompatible with the descriptor's return type: Long



For usecase see: Why is lambda return type not checked at compile time










share|improve this question

















We all know Long extends Number. So why does this not compile. And how to define the method "with" so that the program compiles without any manual cast.




import java.util.function.Function;

public class Builder<T>
static public interface MyInterface
Number getNumber();
Long getLong();


public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)
return null;//TODO


public static void main(String[] args)
// works:
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// works:
new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
// works:
new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
// works:
new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, Long.valueOf(4));
// compiles but also involves typecast (and Casting Number to Long is not even safe):
new Builder<MyInterface>().with( myInterface->(Long) myInterface.getNumber(), 4L);
// compiles but also involves manual conversion:
new Builder<MyInterface>().with(myInterface -> myInterface.getNumber().longValue(), 4L);
// compiles (compiler you are kidding me?):
new Builder<MyInterface>().with(castToFunction(MyInterface::getNumber), 4L);


static <X, Y> Function<X, Y> castToFunction(Function<X, Y> f)
return f;







  • Cannot infer type argument(s) for <F, R> with(F, R)

  • The type of getNumber() from the type Builder.MyInterface is Number, this is incompatible with the descriptor's return type: Long



For usecase see: Why is lambda return type not checked at compile time







java type-inference






share|improve this question
















share|improve this question













share|improve this question




share|improve this question








edited Oct 14 at 16:12







jukzi

















asked Oct 14 at 13:38









jukzijukzi

3792 silver badges14 bronze badges




3792 silver badges14 bronze badges















  • Can you post MyInterface?

    – Maurice Perry
    Oct 14 at 13:42











  • its already inside the class

    – jukzi
    Oct 14 at 13:42











  • Hmm I tried <F extends Function<T, R>, R, S extends R> Builder<T> with(F getter, S returnValue) but got java.lang.Number cannot be converted to java.lang.Long), which is surprising because I don't see where the compiler gets the idea that the return value from getter will need to be converted to returnValue.

    – jingx
    Oct 14 at 14:56











  • @jukzi OK. Sorry, I missed that.

    – Maurice Perry
    Oct 15 at 4:58











  • Changing Number getNumber() to <A extends Number> A getNumber() makes stuff work. No idea whether this is what you wanted. As others have said the issue is that MyInterface::getNumber could be a function that returns Double for example and not Long. Your declaration does not allow the compiler to narrow the return type based on other information present. By using a generic return type you allow the compiler to do so, hence it works.

    – Giacomo Alzetta
    Oct 15 at 9:19


















  • Can you post MyInterface?

    – Maurice Perry
    Oct 14 at 13:42











  • its already inside the class

    – jukzi
    Oct 14 at 13:42











  • Hmm I tried <F extends Function<T, R>, R, S extends R> Builder<T> with(F getter, S returnValue) but got java.lang.Number cannot be converted to java.lang.Long), which is surprising because I don't see where the compiler gets the idea that the return value from getter will need to be converted to returnValue.

    – jingx
    Oct 14 at 14:56











  • @jukzi OK. Sorry, I missed that.

    – Maurice Perry
    Oct 15 at 4:58











  • Changing Number getNumber() to <A extends Number> A getNumber() makes stuff work. No idea whether this is what you wanted. As others have said the issue is that MyInterface::getNumber could be a function that returns Double for example and not Long. Your declaration does not allow the compiler to narrow the return type based on other information present. By using a generic return type you allow the compiler to do so, hence it works.

    – Giacomo Alzetta
    Oct 15 at 9:19

















Can you post MyInterface?

– Maurice Perry
Oct 14 at 13:42





Can you post MyInterface?

– Maurice Perry
Oct 14 at 13:42













its already inside the class

– jukzi
Oct 14 at 13:42





its already inside the class

– jukzi
Oct 14 at 13:42













Hmm I tried <F extends Function<T, R>, R, S extends R> Builder<T> with(F getter, S returnValue) but got java.lang.Number cannot be converted to java.lang.Long), which is surprising because I don't see where the compiler gets the idea that the return value from getter will need to be converted to returnValue.

– jingx
Oct 14 at 14:56





Hmm I tried <F extends Function<T, R>, R, S extends R> Builder<T> with(F getter, S returnValue) but got java.lang.Number cannot be converted to java.lang.Long), which is surprising because I don't see where the compiler gets the idea that the return value from getter will need to be converted to returnValue.

– jingx
Oct 14 at 14:56













@jukzi OK. Sorry, I missed that.

– Maurice Perry
Oct 15 at 4:58





@jukzi OK. Sorry, I missed that.

– Maurice Perry
Oct 15 at 4:58













Changing Number getNumber() to <A extends Number> A getNumber() makes stuff work. No idea whether this is what you wanted. As others have said the issue is that MyInterface::getNumber could be a function that returns Double for example and not Long. Your declaration does not allow the compiler to narrow the return type based on other information present. By using a generic return type you allow the compiler to do so, hence it works.

– Giacomo Alzetta
Oct 15 at 9:19






Changing Number getNumber() to <A extends Number> A getNumber() makes stuff work. No idea whether this is what you wanted. As others have said the issue is that MyInterface::getNumber could be a function that returns Double for example and not Long. Your declaration does not allow the compiler to narrow the return type based on other information present. By using a generic return type you allow the compiler to do so, hence it works.

– Giacomo Alzetta
Oct 15 at 9:19













6 Answers
6






active

oldest

votes


















9


















This expression :



new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


can be rewritten as :



new Builder<MyInterface>().with(myInterface -> myInterface.getNumber(), 4L);


Taking into account method signature :



public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)



  • R will be inferred to Long


  • F will be Function<MyInterface, Long>

and you pass a method reference which will be infered as Function<MyInterface, Number> This is the key - how should compiler predict that you actually want to return Long from a function with such signature? It will not do the downcasting for you.



Since Number is superclass of Long and Number is not necessairly a Long (this is why it does not compile) - you would have to cast explicitly on your own :



new Builder<MyInterface>().with(myInterface -> (Long) myInterface.getNumber(), 4L);


making F to be Function<MyIinterface, Long> or pass generic arguments explicitly during method call as you did :



new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);


and know R will be seen as Number and code will compile.






share|improve this answer




























  • Thats an interesting typecast. But still i am searching for a definition of the method "with" which will make the caller compile without any cast. Anyway thanks for that idea.

    – jukzi
    Oct 14 at 14:12











  • @jukzi You can't. It does not matter how your with is written. You have MJyInterface::getNumber has type Function<MyInterface, Number> so R=Number and then you also have R=Long from the other argument (remember that Java literals are not polymorphic!). At this point the compiler stops because it's not always possible to convert a Number to a Long. The only way to fix this is to change MyInterface to use <A extends Number> Number as return type, this makes the compiler have R=A and then R=Long and since A extends Number it can substitute A=Long

    – Giacomo Alzetta
    Oct 15 at 9:27


















4


















The key to your error is in the generic declaration of the type of F: F extends Function<T, R>. The statement that does not work is: new Builder<MyInterface>().with(MyInterface::getNumber, 4L); First, you have a new Builder<MyInterface>. The declaration of the class therefore implies T = MyInterface. As per your declaration of with, F must be a Function<T, R>, which is a Function<MyInterface, R> in this situation. Therefore, the parameter getter must take a MyInterface as parameter (satisfied by the method references MyInterface::getNumber and MyInterface::getLong), and return R, which must be the same type as the second parameter to the function with. Now, let's see if this holds for all of your cases:



// T = MyInterface, F = Function<MyInterface, Long>, R = Long
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// T = MyInterface, F = Function<MyInterface, Number>, R = Number
// 4L explicitly widened to Number
new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
// T = MyInterface, F = Function<MyInterface, Number>, R = Number
// 4L implicitly widened to Number
new Builder<MyInterface>().<Function<MyInterface, Number>, Number>with(MyInterface::getNumber, 4L);
// T = MyInterface, F = Function<MyInterface, Number>, R = Number
// 4L implicitly widened to Number
new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
// T = MyInterface, F = Function<MyInterface, Number>, R = Long
// F = Function<T, not R> violates definition, therefore compilation error occurs
// Compiler cannot infer type of method reference and 4L at the same time,
// so it keeps the type of 4L as Long and attempts to infer a match for MyInterface::getNumber,
// only to find that the types don't match up
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


You can "fix" this problem with the following options:



// stick to Long
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// stick to Number
new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
// explicitly convert the result of getNumber:
new Builder<MyInterface>().with(myInstance -> (Long) myInstance.getNumber(), 4L);
// explicitly convert the result of getLong:
new Builder<MyInterface>().with(myInterface -> (Number) myInterface.getLong(), (Number) 4L);


Beyond this point, it's mostly a design decision for which option reduces code complexity for your particular application, so choose whatever fits you best.



The reason that you cannot do this without casting lies in the following, from the Java Language Specification:




Boxing conversion treats expressions of a primitive type as expressions of a corresponding reference type. Specifically, the following nine conversions are called the boxing conversions:



  • From type boolean to type Boolean

  • From type byte to type Byte

  • From type short to type Short

  • From type char to type Character

  • From type int to type Integer

  • From type long to type Long

  • From type float to type Float

  • From type double to type Double

  • From the null type to the null type



As you can clearly see, there is no implicit boxing conversion from long to Number, and the widening conversion from Long to Number can only occur when the compiler is sure that it requires a Number and not a Long. As there is a conflict between the method reference that requires a Number and the 4L that provides a Long, the compiler (for some reason???) unable to make the logical leap that Long is-a Number and deduce that F is a Function<MyInterface, Number>.



Instead, I managed to resolve the problem by slightly editing the function signature:



public <R> Builder<T> with(Function<T, ? super R> getter, R returnValue) 
return null;//TODO



After this change, the following occurs:



// doesn't work, as it should not work
new Builder<MyInterface>().with(MyInterface::getLong, (Number), 4L);
// works, as it always did
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// works, as it should work
new Builder<MyInterface>().with(MyInterface::getNumber, (Number)4L);
// works, as you wanted
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


Edit:

After spending some more time on it, it's annoyingly difficult to enforce getter-based type safety. Here's a working example that uses setter methods to enforce a builder's type-safety:



public class Builder<T> 

static public interface MyInterface
//setters
void number(Number number);
void Long(Long Long);
void string(String string);

//getters
Number number();
Long Long();
String string();

// whatever object we're building, let's say it's just a MyInterface for now...
private T buildee = (T) new MyInterface()
private String string;
private Long Long;
private Number number;
public void number(Number number)

this.number = number;

public void Long(Long Long)

this.Long = Long;

public void string(String string)

this.string = string;

public Number number()

return this.number;

public Long Long()

return this.Long;

public String string()

return this.string;

;

public <R> Builder<T> with(BiConsumer<T, R> setter, R val)

setter.accept(this.buildee, val); // take the buildee, and set the appropriate value
return this;


public static void main(String[] args)
// works:
new Builder<MyInterface>().with(MyInterface::Long, 4L);
// works:
new Builder<MyInterface>().with(MyInterface::number, (Number) 4L);
// compile time error, as it shouldn't work
new Builder<MyInterface>().with(MyInterface::Long, (Number) 4L);
// works, as it always did
new Builder<MyInterface>().with(MyInterface::Long, 4L);
// works, as it should
new Builder<MyInterface>().with(MyInterface::number, (Number)4L);
// works, as you wanted
new Builder<MyInterface>().with(MyInterface::number, 4L);
// compile time error, as you wanted
new Builder<MyInterface>().with(MyInterface::number, "blah");




Provided the type-safe ability to construct an object, hopefully at some point in the future we'll be able to return an immutable data object from the builder (maybe by adding a toRecord() method to the interface, and specifying the builder as a Builder<IntermediaryInterfaceType, RecordType>), so you don't even have to worry about the resulting object being modified. Honestly, it's an absolute shame that it requires so much effort to get a type-safe field-flexible builder, but it's probably impossible without some new features, code generation, or an annoying amount of reflection.






share|improve this answer




























  • Thanks for all your work but i do not see any improvement towards avoiding the manual typecast. My naive understanding is that a compiler should be able to infer (i.e. typecast) everything that a human can.

    – jukzi
    Oct 14 at 14:24











  • @jukzi My naive understanding is the same, but for whatever reason it doesn't work that way. I've come up with a workaround that pretty much achieves the desired effect, though

    – Avi
    Oct 14 at 14:39











  • Thanks again. But your new proposal is too wide (see stackoverflow.com/questions/58337639) since it allows compilation of ".with(MyInterface::getNumber, "I AM NOT A NUMBER")";

    – jukzi
    Oct 14 at 14:42












  • your sentence "Compiler cannot infer type of method reference and 4L at the same time" is cool. But i just want it the other way arround. the compiler should try Number based on the first parameter and do a widening to Number of the second parameter.

    – jukzi
    Oct 14 at 14:45






  • 1





    WHAAAAAAAAAAAT? Why does BiConsumer work as intended while Function does not? I do not get the idea. I admit this is exactly the typesafety i wanted but unfortunatlly does not work with getters. WHY WHY WHY.

    – jukzi
    Oct 14 at 16:22


















1


















It seems the compiler has used the value 4L to decide that R is Long, and getNumber() returns a Number, which is not necessarily a Long.



But I'm not sure why the value takes precedence over the method...






share|improve this answer

































    0


















    The Java compiler is in general not good at inferring multiple/nested generic types or wildcards. Often I cannot get something to compile without using a helper function to capture or infer some of the types.



    But, do you really need to capture the exact type of Function as F? If not, maybe the following works, and as you can see, also seems to work with subtypes of Function.



    import java.util.function.Function;
    import java.util.function.UnaryOperator;

    public class Builder<T>
    public interface MyInterface
    Number getNumber();
    Long getLong();


    public <R> Builder<T> with(Function<T, R> getter, R returnValue)
    return null;


    // example subclass of Function
    private static UnaryOperator<String> stringFunc = (s) -> (s + ".");

    public static void main(String[] args)
    // works
    new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
    // works
    new Builder<String>().with(stringFunc, "s");








    share|improve this answer


























    • "with(MyInterface::getNumber, "NOT A NUMBER")" should not compile

      – jukzi
      Oct 15 at 8:20


















    0


















    The most interesting part lies in the difference between those 2 lines, I think:



    // works:
    new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
    // compilation error: Cannot infer ...
    new Builder<MyInterface>().with(MyInterface::getNumber, 4L);



    In the first case, the T is explicitly Number, so 4L is also a Number, no problem. In the second case, 4L is a Long, so T is a Long, so your function is not compatible, and Java cannot know if you meant Number or Long.






    share|improve this answer

































      0


















      With the following signature:



      public <R> Test<T> with(Function<T, ? super R> getter, R returnValue)


      all your examples compile, except the third, which explicitly requires the method to have two type variables.



      The reason that your version doesn't work, is because Java's method references do not have one specific type. Instead, they have the type which is required in the given context. In your case, R is inferred to be Long because of the 4L, but the getter cannot have the type Function<MyInterface,Long> because in Java, generic types are invariant in their arguments.






      share|improve this answer


























      • Your code would compile with( getNumber,"NO NUMBER") which is not desired. Also it is not true that generics are always invariant (see stackoverflow.com/a/58378661/9549750 for a prove that generics of setters behave other then those of getters)

        – jukzi
        Oct 15 at 13:33











      • @jukzi Ah, my solution was already proposed by Avi. Too bad... :-). By the way, it is true that we can assign a Thing<Cat> to a Thing<? extends Animal> variable, but for real covariance I would expect that a Thing<Cat> can be assigned to a Thing<Animal>. Other languages, such as Kotlin, do allow to define co- and contravariant type variables.

        – Hoopje
        Oct 15 at 14:36












      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );














      draft saved

      draft discarded
















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58378037%2fwhy-can-java-not-infer-a-supertype%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown


























      6 Answers
      6






      active

      oldest

      votes








      6 Answers
      6






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      9


















      This expression :



      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      can be rewritten as :



      new Builder<MyInterface>().with(myInterface -> myInterface.getNumber(), 4L);


      Taking into account method signature :



      public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)



      • R will be inferred to Long


      • F will be Function<MyInterface, Long>

      and you pass a method reference which will be infered as Function<MyInterface, Number> This is the key - how should compiler predict that you actually want to return Long from a function with such signature? It will not do the downcasting for you.



      Since Number is superclass of Long and Number is not necessairly a Long (this is why it does not compile) - you would have to cast explicitly on your own :



      new Builder<MyInterface>().with(myInterface -> (Long) myInterface.getNumber(), 4L);


      making F to be Function<MyIinterface, Long> or pass generic arguments explicitly during method call as you did :



      new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);


      and know R will be seen as Number and code will compile.






      share|improve this answer




























      • Thats an interesting typecast. But still i am searching for a definition of the method "with" which will make the caller compile without any cast. Anyway thanks for that idea.

        – jukzi
        Oct 14 at 14:12











      • @jukzi You can't. It does not matter how your with is written. You have MJyInterface::getNumber has type Function<MyInterface, Number> so R=Number and then you also have R=Long from the other argument (remember that Java literals are not polymorphic!). At this point the compiler stops because it's not always possible to convert a Number to a Long. The only way to fix this is to change MyInterface to use <A extends Number> Number as return type, this makes the compiler have R=A and then R=Long and since A extends Number it can substitute A=Long

        – Giacomo Alzetta
        Oct 15 at 9:27















      9


















      This expression :



      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      can be rewritten as :



      new Builder<MyInterface>().with(myInterface -> myInterface.getNumber(), 4L);


      Taking into account method signature :



      public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)



      • R will be inferred to Long


      • F will be Function<MyInterface, Long>

      and you pass a method reference which will be infered as Function<MyInterface, Number> This is the key - how should compiler predict that you actually want to return Long from a function with such signature? It will not do the downcasting for you.



      Since Number is superclass of Long and Number is not necessairly a Long (this is why it does not compile) - you would have to cast explicitly on your own :



      new Builder<MyInterface>().with(myInterface -> (Long) myInterface.getNumber(), 4L);


      making F to be Function<MyIinterface, Long> or pass generic arguments explicitly during method call as you did :



      new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);


      and know R will be seen as Number and code will compile.






      share|improve this answer




























      • Thats an interesting typecast. But still i am searching for a definition of the method "with" which will make the caller compile without any cast. Anyway thanks for that idea.

        – jukzi
        Oct 14 at 14:12











      • @jukzi You can't. It does not matter how your with is written. You have MJyInterface::getNumber has type Function<MyInterface, Number> so R=Number and then you also have R=Long from the other argument (remember that Java literals are not polymorphic!). At this point the compiler stops because it's not always possible to convert a Number to a Long. The only way to fix this is to change MyInterface to use <A extends Number> Number as return type, this makes the compiler have R=A and then R=Long and since A extends Number it can substitute A=Long

        – Giacomo Alzetta
        Oct 15 at 9:27













      9














      9










      9









      This expression :



      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      can be rewritten as :



      new Builder<MyInterface>().with(myInterface -> myInterface.getNumber(), 4L);


      Taking into account method signature :



      public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)



      • R will be inferred to Long


      • F will be Function<MyInterface, Long>

      and you pass a method reference which will be infered as Function<MyInterface, Number> This is the key - how should compiler predict that you actually want to return Long from a function with such signature? It will not do the downcasting for you.



      Since Number is superclass of Long and Number is not necessairly a Long (this is why it does not compile) - you would have to cast explicitly on your own :



      new Builder<MyInterface>().with(myInterface -> (Long) myInterface.getNumber(), 4L);


      making F to be Function<MyIinterface, Long> or pass generic arguments explicitly during method call as you did :



      new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);


      and know R will be seen as Number and code will compile.






      share|improve this answer
















      This expression :



      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      can be rewritten as :



      new Builder<MyInterface>().with(myInterface -> myInterface.getNumber(), 4L);


      Taking into account method signature :



      public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)



      • R will be inferred to Long


      • F will be Function<MyInterface, Long>

      and you pass a method reference which will be infered as Function<MyInterface, Number> This is the key - how should compiler predict that you actually want to return Long from a function with such signature? It will not do the downcasting for you.



      Since Number is superclass of Long and Number is not necessairly a Long (this is why it does not compile) - you would have to cast explicitly on your own :



      new Builder<MyInterface>().with(myInterface -> (Long) myInterface.getNumber(), 4L);


      making F to be Function<MyIinterface, Long> or pass generic arguments explicitly during method call as you did :



      new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);


      and know R will be seen as Number and code will compile.







      share|improve this answer















      share|improve this answer




      share|improve this answer








      edited Oct 14 at 14:49

























      answered Oct 14 at 14:03









      michalkmichalk

      6,0732 gold badges11 silver badges24 bronze badges




      6,0732 gold badges11 silver badges24 bronze badges















      • Thats an interesting typecast. But still i am searching for a definition of the method "with" which will make the caller compile without any cast. Anyway thanks for that idea.

        – jukzi
        Oct 14 at 14:12











      • @jukzi You can't. It does not matter how your with is written. You have MJyInterface::getNumber has type Function<MyInterface, Number> so R=Number and then you also have R=Long from the other argument (remember that Java literals are not polymorphic!). At this point the compiler stops because it's not always possible to convert a Number to a Long. The only way to fix this is to change MyInterface to use <A extends Number> Number as return type, this makes the compiler have R=A and then R=Long and since A extends Number it can substitute A=Long

        – Giacomo Alzetta
        Oct 15 at 9:27

















      • Thats an interesting typecast. But still i am searching for a definition of the method "with" which will make the caller compile without any cast. Anyway thanks for that idea.

        – jukzi
        Oct 14 at 14:12











      • @jukzi You can't. It does not matter how your with is written. You have MJyInterface::getNumber has type Function<MyInterface, Number> so R=Number and then you also have R=Long from the other argument (remember that Java literals are not polymorphic!). At this point the compiler stops because it's not always possible to convert a Number to a Long. The only way to fix this is to change MyInterface to use <A extends Number> Number as return type, this makes the compiler have R=A and then R=Long and since A extends Number it can substitute A=Long

        – Giacomo Alzetta
        Oct 15 at 9:27
















      Thats an interesting typecast. But still i am searching for a definition of the method "with" which will make the caller compile without any cast. Anyway thanks for that idea.

      – jukzi
      Oct 14 at 14:12





      Thats an interesting typecast. But still i am searching for a definition of the method "with" which will make the caller compile without any cast. Anyway thanks for that idea.

      – jukzi
      Oct 14 at 14:12













      @jukzi You can't. It does not matter how your with is written. You have MJyInterface::getNumber has type Function<MyInterface, Number> so R=Number and then you also have R=Long from the other argument (remember that Java literals are not polymorphic!). At this point the compiler stops because it's not always possible to convert a Number to a Long. The only way to fix this is to change MyInterface to use <A extends Number> Number as return type, this makes the compiler have R=A and then R=Long and since A extends Number it can substitute A=Long

      – Giacomo Alzetta
      Oct 15 at 9:27





      @jukzi You can't. It does not matter how your with is written. You have MJyInterface::getNumber has type Function<MyInterface, Number> so R=Number and then you also have R=Long from the other argument (remember that Java literals are not polymorphic!). At this point the compiler stops because it's not always possible to convert a Number to a Long. The only way to fix this is to change MyInterface to use <A extends Number> Number as return type, this makes the compiler have R=A and then R=Long and since A extends Number it can substitute A=Long

      – Giacomo Alzetta
      Oct 15 at 9:27













      4


















      The key to your error is in the generic declaration of the type of F: F extends Function<T, R>. The statement that does not work is: new Builder<MyInterface>().with(MyInterface::getNumber, 4L); First, you have a new Builder<MyInterface>. The declaration of the class therefore implies T = MyInterface. As per your declaration of with, F must be a Function<T, R>, which is a Function<MyInterface, R> in this situation. Therefore, the parameter getter must take a MyInterface as parameter (satisfied by the method references MyInterface::getNumber and MyInterface::getLong), and return R, which must be the same type as the second parameter to the function with. Now, let's see if this holds for all of your cases:



      // T = MyInterface, F = Function<MyInterface, Long>, R = Long
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L explicitly widened to Number
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L implicitly widened to Number
      new Builder<MyInterface>().<Function<MyInterface, Number>, Number>with(MyInterface::getNumber, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L implicitly widened to Number
      new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Long
      // F = Function<T, not R> violates definition, therefore compilation error occurs
      // Compiler cannot infer type of method reference and 4L at the same time,
      // so it keeps the type of 4L as Long and attempts to infer a match for MyInterface::getNumber,
      // only to find that the types don't match up
      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      You can "fix" this problem with the following options:



      // stick to Long
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // stick to Number
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
      // explicitly convert the result of getNumber:
      new Builder<MyInterface>().with(myInstance -> (Long) myInstance.getNumber(), 4L);
      // explicitly convert the result of getLong:
      new Builder<MyInterface>().with(myInterface -> (Number) myInterface.getLong(), (Number) 4L);


      Beyond this point, it's mostly a design decision for which option reduces code complexity for your particular application, so choose whatever fits you best.



      The reason that you cannot do this without casting lies in the following, from the Java Language Specification:




      Boxing conversion treats expressions of a primitive type as expressions of a corresponding reference type. Specifically, the following nine conversions are called the boxing conversions:



      • From type boolean to type Boolean

      • From type byte to type Byte

      • From type short to type Short

      • From type char to type Character

      • From type int to type Integer

      • From type long to type Long

      • From type float to type Float

      • From type double to type Double

      • From the null type to the null type



      As you can clearly see, there is no implicit boxing conversion from long to Number, and the widening conversion from Long to Number can only occur when the compiler is sure that it requires a Number and not a Long. As there is a conflict between the method reference that requires a Number and the 4L that provides a Long, the compiler (for some reason???) unable to make the logical leap that Long is-a Number and deduce that F is a Function<MyInterface, Number>.



      Instead, I managed to resolve the problem by slightly editing the function signature:



      public <R> Builder<T> with(Function<T, ? super R> getter, R returnValue) 
      return null;//TODO



      After this change, the following occurs:



      // doesn't work, as it should not work
      new Builder<MyInterface>().with(MyInterface::getLong, (Number), 4L);
      // works, as it always did
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // works, as it should work
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number)4L);
      // works, as you wanted
      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      Edit:

      After spending some more time on it, it's annoyingly difficult to enforce getter-based type safety. Here's a working example that uses setter methods to enforce a builder's type-safety:



      public class Builder<T> 

      static public interface MyInterface
      //setters
      void number(Number number);
      void Long(Long Long);
      void string(String string);

      //getters
      Number number();
      Long Long();
      String string();

      // whatever object we're building, let's say it's just a MyInterface for now...
      private T buildee = (T) new MyInterface()
      private String string;
      private Long Long;
      private Number number;
      public void number(Number number)

      this.number = number;

      public void Long(Long Long)

      this.Long = Long;

      public void string(String string)

      this.string = string;

      public Number number()

      return this.number;

      public Long Long()

      return this.Long;

      public String string()

      return this.string;

      ;

      public <R> Builder<T> with(BiConsumer<T, R> setter, R val)

      setter.accept(this.buildee, val); // take the buildee, and set the appropriate value
      return this;


      public static void main(String[] args)
      // works:
      new Builder<MyInterface>().with(MyInterface::Long, 4L);
      // works:
      new Builder<MyInterface>().with(MyInterface::number, (Number) 4L);
      // compile time error, as it shouldn't work
      new Builder<MyInterface>().with(MyInterface::Long, (Number) 4L);
      // works, as it always did
      new Builder<MyInterface>().with(MyInterface::Long, 4L);
      // works, as it should
      new Builder<MyInterface>().with(MyInterface::number, (Number)4L);
      // works, as you wanted
      new Builder<MyInterface>().with(MyInterface::number, 4L);
      // compile time error, as you wanted
      new Builder<MyInterface>().with(MyInterface::number, "blah");




      Provided the type-safe ability to construct an object, hopefully at some point in the future we'll be able to return an immutable data object from the builder (maybe by adding a toRecord() method to the interface, and specifying the builder as a Builder<IntermediaryInterfaceType, RecordType>), so you don't even have to worry about the resulting object being modified. Honestly, it's an absolute shame that it requires so much effort to get a type-safe field-flexible builder, but it's probably impossible without some new features, code generation, or an annoying amount of reflection.






      share|improve this answer




























      • Thanks for all your work but i do not see any improvement towards avoiding the manual typecast. My naive understanding is that a compiler should be able to infer (i.e. typecast) everything that a human can.

        – jukzi
        Oct 14 at 14:24











      • @jukzi My naive understanding is the same, but for whatever reason it doesn't work that way. I've come up with a workaround that pretty much achieves the desired effect, though

        – Avi
        Oct 14 at 14:39











      • Thanks again. But your new proposal is too wide (see stackoverflow.com/questions/58337639) since it allows compilation of ".with(MyInterface::getNumber, "I AM NOT A NUMBER")";

        – jukzi
        Oct 14 at 14:42












      • your sentence "Compiler cannot infer type of method reference and 4L at the same time" is cool. But i just want it the other way arround. the compiler should try Number based on the first parameter and do a widening to Number of the second parameter.

        – jukzi
        Oct 14 at 14:45






      • 1





        WHAAAAAAAAAAAT? Why does BiConsumer work as intended while Function does not? I do not get the idea. I admit this is exactly the typesafety i wanted but unfortunatlly does not work with getters. WHY WHY WHY.

        – jukzi
        Oct 14 at 16:22















      4


















      The key to your error is in the generic declaration of the type of F: F extends Function<T, R>. The statement that does not work is: new Builder<MyInterface>().with(MyInterface::getNumber, 4L); First, you have a new Builder<MyInterface>. The declaration of the class therefore implies T = MyInterface. As per your declaration of with, F must be a Function<T, R>, which is a Function<MyInterface, R> in this situation. Therefore, the parameter getter must take a MyInterface as parameter (satisfied by the method references MyInterface::getNumber and MyInterface::getLong), and return R, which must be the same type as the second parameter to the function with. Now, let's see if this holds for all of your cases:



      // T = MyInterface, F = Function<MyInterface, Long>, R = Long
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L explicitly widened to Number
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L implicitly widened to Number
      new Builder<MyInterface>().<Function<MyInterface, Number>, Number>with(MyInterface::getNumber, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L implicitly widened to Number
      new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Long
      // F = Function<T, not R> violates definition, therefore compilation error occurs
      // Compiler cannot infer type of method reference and 4L at the same time,
      // so it keeps the type of 4L as Long and attempts to infer a match for MyInterface::getNumber,
      // only to find that the types don't match up
      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      You can "fix" this problem with the following options:



      // stick to Long
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // stick to Number
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
      // explicitly convert the result of getNumber:
      new Builder<MyInterface>().with(myInstance -> (Long) myInstance.getNumber(), 4L);
      // explicitly convert the result of getLong:
      new Builder<MyInterface>().with(myInterface -> (Number) myInterface.getLong(), (Number) 4L);


      Beyond this point, it's mostly a design decision for which option reduces code complexity for your particular application, so choose whatever fits you best.



      The reason that you cannot do this without casting lies in the following, from the Java Language Specification:




      Boxing conversion treats expressions of a primitive type as expressions of a corresponding reference type. Specifically, the following nine conversions are called the boxing conversions:



      • From type boolean to type Boolean

      • From type byte to type Byte

      • From type short to type Short

      • From type char to type Character

      • From type int to type Integer

      • From type long to type Long

      • From type float to type Float

      • From type double to type Double

      • From the null type to the null type



      As you can clearly see, there is no implicit boxing conversion from long to Number, and the widening conversion from Long to Number can only occur when the compiler is sure that it requires a Number and not a Long. As there is a conflict between the method reference that requires a Number and the 4L that provides a Long, the compiler (for some reason???) unable to make the logical leap that Long is-a Number and deduce that F is a Function<MyInterface, Number>.



      Instead, I managed to resolve the problem by slightly editing the function signature:



      public <R> Builder<T> with(Function<T, ? super R> getter, R returnValue) 
      return null;//TODO



      After this change, the following occurs:



      // doesn't work, as it should not work
      new Builder<MyInterface>().with(MyInterface::getLong, (Number), 4L);
      // works, as it always did
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // works, as it should work
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number)4L);
      // works, as you wanted
      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      Edit:

      After spending some more time on it, it's annoyingly difficult to enforce getter-based type safety. Here's a working example that uses setter methods to enforce a builder's type-safety:



      public class Builder<T> 

      static public interface MyInterface
      //setters
      void number(Number number);
      void Long(Long Long);
      void string(String string);

      //getters
      Number number();
      Long Long();
      String string();

      // whatever object we're building, let's say it's just a MyInterface for now...
      private T buildee = (T) new MyInterface()
      private String string;
      private Long Long;
      private Number number;
      public void number(Number number)

      this.number = number;

      public void Long(Long Long)

      this.Long = Long;

      public void string(String string)

      this.string = string;

      public Number number()

      return this.number;

      public Long Long()

      return this.Long;

      public String string()

      return this.string;

      ;

      public <R> Builder<T> with(BiConsumer<T, R> setter, R val)

      setter.accept(this.buildee, val); // take the buildee, and set the appropriate value
      return this;


      public static void main(String[] args)
      // works:
      new Builder<MyInterface>().with(MyInterface::Long, 4L);
      // works:
      new Builder<MyInterface>().with(MyInterface::number, (Number) 4L);
      // compile time error, as it shouldn't work
      new Builder<MyInterface>().with(MyInterface::Long, (Number) 4L);
      // works, as it always did
      new Builder<MyInterface>().with(MyInterface::Long, 4L);
      // works, as it should
      new Builder<MyInterface>().with(MyInterface::number, (Number)4L);
      // works, as you wanted
      new Builder<MyInterface>().with(MyInterface::number, 4L);
      // compile time error, as you wanted
      new Builder<MyInterface>().with(MyInterface::number, "blah");




      Provided the type-safe ability to construct an object, hopefully at some point in the future we'll be able to return an immutable data object from the builder (maybe by adding a toRecord() method to the interface, and specifying the builder as a Builder<IntermediaryInterfaceType, RecordType>), so you don't even have to worry about the resulting object being modified. Honestly, it's an absolute shame that it requires so much effort to get a type-safe field-flexible builder, but it's probably impossible without some new features, code generation, or an annoying amount of reflection.






      share|improve this answer




























      • Thanks for all your work but i do not see any improvement towards avoiding the manual typecast. My naive understanding is that a compiler should be able to infer (i.e. typecast) everything that a human can.

        – jukzi
        Oct 14 at 14:24











      • @jukzi My naive understanding is the same, but for whatever reason it doesn't work that way. I've come up with a workaround that pretty much achieves the desired effect, though

        – Avi
        Oct 14 at 14:39











      • Thanks again. But your new proposal is too wide (see stackoverflow.com/questions/58337639) since it allows compilation of ".with(MyInterface::getNumber, "I AM NOT A NUMBER")";

        – jukzi
        Oct 14 at 14:42












      • your sentence "Compiler cannot infer type of method reference and 4L at the same time" is cool. But i just want it the other way arround. the compiler should try Number based on the first parameter and do a widening to Number of the second parameter.

        – jukzi
        Oct 14 at 14:45






      • 1





        WHAAAAAAAAAAAT? Why does BiConsumer work as intended while Function does not? I do not get the idea. I admit this is exactly the typesafety i wanted but unfortunatlly does not work with getters. WHY WHY WHY.

        – jukzi
        Oct 14 at 16:22













      4














      4










      4









      The key to your error is in the generic declaration of the type of F: F extends Function<T, R>. The statement that does not work is: new Builder<MyInterface>().with(MyInterface::getNumber, 4L); First, you have a new Builder<MyInterface>. The declaration of the class therefore implies T = MyInterface. As per your declaration of with, F must be a Function<T, R>, which is a Function<MyInterface, R> in this situation. Therefore, the parameter getter must take a MyInterface as parameter (satisfied by the method references MyInterface::getNumber and MyInterface::getLong), and return R, which must be the same type as the second parameter to the function with. Now, let's see if this holds for all of your cases:



      // T = MyInterface, F = Function<MyInterface, Long>, R = Long
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L explicitly widened to Number
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L implicitly widened to Number
      new Builder<MyInterface>().<Function<MyInterface, Number>, Number>with(MyInterface::getNumber, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L implicitly widened to Number
      new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Long
      // F = Function<T, not R> violates definition, therefore compilation error occurs
      // Compiler cannot infer type of method reference and 4L at the same time,
      // so it keeps the type of 4L as Long and attempts to infer a match for MyInterface::getNumber,
      // only to find that the types don't match up
      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      You can "fix" this problem with the following options:



      // stick to Long
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // stick to Number
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
      // explicitly convert the result of getNumber:
      new Builder<MyInterface>().with(myInstance -> (Long) myInstance.getNumber(), 4L);
      // explicitly convert the result of getLong:
      new Builder<MyInterface>().with(myInterface -> (Number) myInterface.getLong(), (Number) 4L);


      Beyond this point, it's mostly a design decision for which option reduces code complexity for your particular application, so choose whatever fits you best.



      The reason that you cannot do this without casting lies in the following, from the Java Language Specification:




      Boxing conversion treats expressions of a primitive type as expressions of a corresponding reference type. Specifically, the following nine conversions are called the boxing conversions:



      • From type boolean to type Boolean

      • From type byte to type Byte

      • From type short to type Short

      • From type char to type Character

      • From type int to type Integer

      • From type long to type Long

      • From type float to type Float

      • From type double to type Double

      • From the null type to the null type



      As you can clearly see, there is no implicit boxing conversion from long to Number, and the widening conversion from Long to Number can only occur when the compiler is sure that it requires a Number and not a Long. As there is a conflict between the method reference that requires a Number and the 4L that provides a Long, the compiler (for some reason???) unable to make the logical leap that Long is-a Number and deduce that F is a Function<MyInterface, Number>.



      Instead, I managed to resolve the problem by slightly editing the function signature:



      public <R> Builder<T> with(Function<T, ? super R> getter, R returnValue) 
      return null;//TODO



      After this change, the following occurs:



      // doesn't work, as it should not work
      new Builder<MyInterface>().with(MyInterface::getLong, (Number), 4L);
      // works, as it always did
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // works, as it should work
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number)4L);
      // works, as you wanted
      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      Edit:

      After spending some more time on it, it's annoyingly difficult to enforce getter-based type safety. Here's a working example that uses setter methods to enforce a builder's type-safety:



      public class Builder<T> 

      static public interface MyInterface
      //setters
      void number(Number number);
      void Long(Long Long);
      void string(String string);

      //getters
      Number number();
      Long Long();
      String string();

      // whatever object we're building, let's say it's just a MyInterface for now...
      private T buildee = (T) new MyInterface()
      private String string;
      private Long Long;
      private Number number;
      public void number(Number number)

      this.number = number;

      public void Long(Long Long)

      this.Long = Long;

      public void string(String string)

      this.string = string;

      public Number number()

      return this.number;

      public Long Long()

      return this.Long;

      public String string()

      return this.string;

      ;

      public <R> Builder<T> with(BiConsumer<T, R> setter, R val)

      setter.accept(this.buildee, val); // take the buildee, and set the appropriate value
      return this;


      public static void main(String[] args)
      // works:
      new Builder<MyInterface>().with(MyInterface::Long, 4L);
      // works:
      new Builder<MyInterface>().with(MyInterface::number, (Number) 4L);
      // compile time error, as it shouldn't work
      new Builder<MyInterface>().with(MyInterface::Long, (Number) 4L);
      // works, as it always did
      new Builder<MyInterface>().with(MyInterface::Long, 4L);
      // works, as it should
      new Builder<MyInterface>().with(MyInterface::number, (Number)4L);
      // works, as you wanted
      new Builder<MyInterface>().with(MyInterface::number, 4L);
      // compile time error, as you wanted
      new Builder<MyInterface>().with(MyInterface::number, "blah");




      Provided the type-safe ability to construct an object, hopefully at some point in the future we'll be able to return an immutable data object from the builder (maybe by adding a toRecord() method to the interface, and specifying the builder as a Builder<IntermediaryInterfaceType, RecordType>), so you don't even have to worry about the resulting object being modified. Honestly, it's an absolute shame that it requires so much effort to get a type-safe field-flexible builder, but it's probably impossible without some new features, code generation, or an annoying amount of reflection.






      share|improve this answer
















      The key to your error is in the generic declaration of the type of F: F extends Function<T, R>. The statement that does not work is: new Builder<MyInterface>().with(MyInterface::getNumber, 4L); First, you have a new Builder<MyInterface>. The declaration of the class therefore implies T = MyInterface. As per your declaration of with, F must be a Function<T, R>, which is a Function<MyInterface, R> in this situation. Therefore, the parameter getter must take a MyInterface as parameter (satisfied by the method references MyInterface::getNumber and MyInterface::getLong), and return R, which must be the same type as the second parameter to the function with. Now, let's see if this holds for all of your cases:



      // T = MyInterface, F = Function<MyInterface, Long>, R = Long
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L explicitly widened to Number
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L implicitly widened to Number
      new Builder<MyInterface>().<Function<MyInterface, Number>, Number>with(MyInterface::getNumber, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Number
      // 4L implicitly widened to Number
      new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
      // T = MyInterface, F = Function<MyInterface, Number>, R = Long
      // F = Function<T, not R> violates definition, therefore compilation error occurs
      // Compiler cannot infer type of method reference and 4L at the same time,
      // so it keeps the type of 4L as Long and attempts to infer a match for MyInterface::getNumber,
      // only to find that the types don't match up
      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      You can "fix" this problem with the following options:



      // stick to Long
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // stick to Number
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
      // explicitly convert the result of getNumber:
      new Builder<MyInterface>().with(myInstance -> (Long) myInstance.getNumber(), 4L);
      // explicitly convert the result of getLong:
      new Builder<MyInterface>().with(myInterface -> (Number) myInterface.getLong(), (Number) 4L);


      Beyond this point, it's mostly a design decision for which option reduces code complexity for your particular application, so choose whatever fits you best.



      The reason that you cannot do this without casting lies in the following, from the Java Language Specification:




      Boxing conversion treats expressions of a primitive type as expressions of a corresponding reference type. Specifically, the following nine conversions are called the boxing conversions:



      • From type boolean to type Boolean

      • From type byte to type Byte

      • From type short to type Short

      • From type char to type Character

      • From type int to type Integer

      • From type long to type Long

      • From type float to type Float

      • From type double to type Double

      • From the null type to the null type



      As you can clearly see, there is no implicit boxing conversion from long to Number, and the widening conversion from Long to Number can only occur when the compiler is sure that it requires a Number and not a Long. As there is a conflict between the method reference that requires a Number and the 4L that provides a Long, the compiler (for some reason???) unable to make the logical leap that Long is-a Number and deduce that F is a Function<MyInterface, Number>.



      Instead, I managed to resolve the problem by slightly editing the function signature:



      public <R> Builder<T> with(Function<T, ? super R> getter, R returnValue) 
      return null;//TODO



      After this change, the following occurs:



      // doesn't work, as it should not work
      new Builder<MyInterface>().with(MyInterface::getLong, (Number), 4L);
      // works, as it always did
      new Builder<MyInterface>().with(MyInterface::getLong, 4L);
      // works, as it should work
      new Builder<MyInterface>().with(MyInterface::getNumber, (Number)4L);
      // works, as you wanted
      new Builder<MyInterface>().with(MyInterface::getNumber, 4L);


      Edit:

      After spending some more time on it, it's annoyingly difficult to enforce getter-based type safety. Here's a working example that uses setter methods to enforce a builder's type-safety:



      public class Builder<T> 

      static public interface MyInterface
      //setters
      void number(Number number);
      void Long(Long Long);
      void string(String string);

      //getters
      Number number();
      Long Long();
      String string();

      // whatever object we're building, let's say it's just a MyInterface for now...
      private T buildee = (T) new MyInterface()
      private String string;
      private Long Long;
      private Number number;
      public void number(Number number)

      this.number = number;

      public void Long(Long Long)

      this.Long = Long;

      public void string(String string)

      this.string = string;

      public Number number()

      return this.number;

      public Long Long()

      return this.Long;

      public String string()

      return this.string;

      ;

      public <R> Builder<T> with(BiConsumer<T, R> setter, R val)

      setter.accept(this.buildee, val); // take the buildee, and set the appropriate value
      return this;


      public static void main(String[] args)
      // works:
      new Builder<MyInterface>().with(MyInterface::Long, 4L);
      // works:
      new Builder<MyInterface>().with(MyInterface::number, (Number) 4L);
      // compile time error, as it shouldn't work
      new Builder<MyInterface>().with(MyInterface::Long, (Number) 4L);
      // works, as it always did
      new Builder<MyInterface>().with(MyInterface::Long, 4L);
      // works, as it should
      new Builder<MyInterface>().with(MyInterface::number, (Number)4L);
      // works, as you wanted
      new Builder<MyInterface>().with(MyInterface::number, 4L);
      // compile time error, as you wanted
      new Builder<MyInterface>().with(MyInterface::number, "blah");




      Provided the type-safe ability to construct an object, hopefully at some point in the future we'll be able to return an immutable data object from the builder (maybe by adding a toRecord() method to the interface, and specifying the builder as a Builder<IntermediaryInterfaceType, RecordType>), so you don't even have to worry about the resulting object being modified. Honestly, it's an absolute shame that it requires so much effort to get a type-safe field-flexible builder, but it's probably impossible without some new features, code generation, or an annoying amount of reflection.







      share|improve this answer















      share|improve this answer




      share|improve this answer








      edited Oct 14 at 16:31

























      answered Oct 14 at 14:15









      AviAvi

      2,1441 gold badge6 silver badges19 bronze badges




      2,1441 gold badge6 silver badges19 bronze badges















      • Thanks for all your work but i do not see any improvement towards avoiding the manual typecast. My naive understanding is that a compiler should be able to infer (i.e. typecast) everything that a human can.

        – jukzi
        Oct 14 at 14:24











      • @jukzi My naive understanding is the same, but for whatever reason it doesn't work that way. I've come up with a workaround that pretty much achieves the desired effect, though

        – Avi
        Oct 14 at 14:39











      • Thanks again. But your new proposal is too wide (see stackoverflow.com/questions/58337639) since it allows compilation of ".with(MyInterface::getNumber, "I AM NOT A NUMBER")";

        – jukzi
        Oct 14 at 14:42












      • your sentence "Compiler cannot infer type of method reference and 4L at the same time" is cool. But i just want it the other way arround. the compiler should try Number based on the first parameter and do a widening to Number of the second parameter.

        – jukzi
        Oct 14 at 14:45






      • 1





        WHAAAAAAAAAAAT? Why does BiConsumer work as intended while Function does not? I do not get the idea. I admit this is exactly the typesafety i wanted but unfortunatlly does not work with getters. WHY WHY WHY.

        – jukzi
        Oct 14 at 16:22

















      • Thanks for all your work but i do not see any improvement towards avoiding the manual typecast. My naive understanding is that a compiler should be able to infer (i.e. typecast) everything that a human can.

        – jukzi
        Oct 14 at 14:24











      • @jukzi My naive understanding is the same, but for whatever reason it doesn't work that way. I've come up with a workaround that pretty much achieves the desired effect, though

        – Avi
        Oct 14 at 14:39











      • Thanks again. But your new proposal is too wide (see stackoverflow.com/questions/58337639) since it allows compilation of ".with(MyInterface::getNumber, "I AM NOT A NUMBER")";

        – jukzi
        Oct 14 at 14:42












      • your sentence "Compiler cannot infer type of method reference and 4L at the same time" is cool. But i just want it the other way arround. the compiler should try Number based on the first parameter and do a widening to Number of the second parameter.

        – jukzi
        Oct 14 at 14:45






      • 1





        WHAAAAAAAAAAAT? Why does BiConsumer work as intended while Function does not? I do not get the idea. I admit this is exactly the typesafety i wanted but unfortunatlly does not work with getters. WHY WHY WHY.

        – jukzi
        Oct 14 at 16:22
















      Thanks for all your work but i do not see any improvement towards avoiding the manual typecast. My naive understanding is that a compiler should be able to infer (i.e. typecast) everything that a human can.

      – jukzi
      Oct 14 at 14:24





      Thanks for all your work but i do not see any improvement towards avoiding the manual typecast. My naive understanding is that a compiler should be able to infer (i.e. typecast) everything that a human can.

      – jukzi
      Oct 14 at 14:24













      @jukzi My naive understanding is the same, but for whatever reason it doesn't work that way. I've come up with a workaround that pretty much achieves the desired effect, though

      – Avi
      Oct 14 at 14:39





      @jukzi My naive understanding is the same, but for whatever reason it doesn't work that way. I've come up with a workaround that pretty much achieves the desired effect, though

      – Avi
      Oct 14 at 14:39













      Thanks again. But your new proposal is too wide (see stackoverflow.com/questions/58337639) since it allows compilation of ".with(MyInterface::getNumber, "I AM NOT A NUMBER")";

      – jukzi
      Oct 14 at 14:42






      Thanks again. But your new proposal is too wide (see stackoverflow.com/questions/58337639) since it allows compilation of ".with(MyInterface::getNumber, "I AM NOT A NUMBER")";

      – jukzi
      Oct 14 at 14:42














      your sentence "Compiler cannot infer type of method reference and 4L at the same time" is cool. But i just want it the other way arround. the compiler should try Number based on the first parameter and do a widening to Number of the second parameter.

      – jukzi
      Oct 14 at 14:45





      your sentence "Compiler cannot infer type of method reference and 4L at the same time" is cool. But i just want it the other way arround. the compiler should try Number based on the first parameter and do a widening to Number of the second parameter.

      – jukzi
      Oct 14 at 14:45




      1




      1





      WHAAAAAAAAAAAT? Why does BiConsumer work as intended while Function does not? I do not get the idea. I admit this is exactly the typesafety i wanted but unfortunatlly does not work with getters. WHY WHY WHY.

      – jukzi
      Oct 14 at 16:22





      WHAAAAAAAAAAAT? Why does BiConsumer work as intended while Function does not? I do not get the idea. I admit this is exactly the typesafety i wanted but unfortunatlly does not work with getters. WHY WHY WHY.

      – jukzi
      Oct 14 at 16:22











      1


















      It seems the compiler has used the value 4L to decide that R is Long, and getNumber() returns a Number, which is not necessarily a Long.



      But I'm not sure why the value takes precedence over the method...






      share|improve this answer






























        1


















        It seems the compiler has used the value 4L to decide that R is Long, and getNumber() returns a Number, which is not necessarily a Long.



        But I'm not sure why the value takes precedence over the method...






        share|improve this answer




























          1














          1










          1









          It seems the compiler has used the value 4L to decide that R is Long, and getNumber() returns a Number, which is not necessarily a Long.



          But I'm not sure why the value takes precedence over the method...






          share|improve this answer














          It seems the compiler has used the value 4L to decide that R is Long, and getNumber() returns a Number, which is not necessarily a Long.



          But I'm not sure why the value takes precedence over the method...







          share|improve this answer













          share|improve this answer




          share|improve this answer










          answered Oct 14 at 13:53









          RickRick

          26611 bronze badges




          26611 bronze badges
























              0


















              The Java compiler is in general not good at inferring multiple/nested generic types or wildcards. Often I cannot get something to compile without using a helper function to capture or infer some of the types.



              But, do you really need to capture the exact type of Function as F? If not, maybe the following works, and as you can see, also seems to work with subtypes of Function.



              import java.util.function.Function;
              import java.util.function.UnaryOperator;

              public class Builder<T>
              public interface MyInterface
              Number getNumber();
              Long getLong();


              public <R> Builder<T> with(Function<T, R> getter, R returnValue)
              return null;


              // example subclass of Function
              private static UnaryOperator<String> stringFunc = (s) -> (s + ".");

              public static void main(String[] args)
              // works
              new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
              // works
              new Builder<String>().with(stringFunc, "s");








              share|improve this answer


























              • "with(MyInterface::getNumber, "NOT A NUMBER")" should not compile

                – jukzi
                Oct 15 at 8:20















              0


















              The Java compiler is in general not good at inferring multiple/nested generic types or wildcards. Often I cannot get something to compile without using a helper function to capture or infer some of the types.



              But, do you really need to capture the exact type of Function as F? If not, maybe the following works, and as you can see, also seems to work with subtypes of Function.



              import java.util.function.Function;
              import java.util.function.UnaryOperator;

              public class Builder<T>
              public interface MyInterface
              Number getNumber();
              Long getLong();


              public <R> Builder<T> with(Function<T, R> getter, R returnValue)
              return null;


              // example subclass of Function
              private static UnaryOperator<String> stringFunc = (s) -> (s + ".");

              public static void main(String[] args)
              // works
              new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
              // works
              new Builder<String>().with(stringFunc, "s");








              share|improve this answer


























              • "with(MyInterface::getNumber, "NOT A NUMBER")" should not compile

                – jukzi
                Oct 15 at 8:20













              0














              0










              0









              The Java compiler is in general not good at inferring multiple/nested generic types or wildcards. Often I cannot get something to compile without using a helper function to capture or infer some of the types.



              But, do you really need to capture the exact type of Function as F? If not, maybe the following works, and as you can see, also seems to work with subtypes of Function.



              import java.util.function.Function;
              import java.util.function.UnaryOperator;

              public class Builder<T>
              public interface MyInterface
              Number getNumber();
              Long getLong();


              public <R> Builder<T> with(Function<T, R> getter, R returnValue)
              return null;


              // example subclass of Function
              private static UnaryOperator<String> stringFunc = (s) -> (s + ".");

              public static void main(String[] args)
              // works
              new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
              // works
              new Builder<String>().with(stringFunc, "s");








              share|improve this answer














              The Java compiler is in general not good at inferring multiple/nested generic types or wildcards. Often I cannot get something to compile without using a helper function to capture or infer some of the types.



              But, do you really need to capture the exact type of Function as F? If not, maybe the following works, and as you can see, also seems to work with subtypes of Function.



              import java.util.function.Function;
              import java.util.function.UnaryOperator;

              public class Builder<T>
              public interface MyInterface
              Number getNumber();
              Long getLong();


              public <R> Builder<T> with(Function<T, R> getter, R returnValue)
              return null;


              // example subclass of Function
              private static UnaryOperator<String> stringFunc = (s) -> (s + ".");

              public static void main(String[] args)
              // works
              new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
              // works
              new Builder<String>().with(stringFunc, "s");









              share|improve this answer













              share|improve this answer




              share|improve this answer










              answered Oct 15 at 0:58









              machfourmachfour

              611 bronze badge




              611 bronze badge















              • "with(MyInterface::getNumber, "NOT A NUMBER")" should not compile

                – jukzi
                Oct 15 at 8:20

















              • "with(MyInterface::getNumber, "NOT A NUMBER")" should not compile

                – jukzi
                Oct 15 at 8:20
















              "with(MyInterface::getNumber, "NOT A NUMBER")" should not compile

              – jukzi
              Oct 15 at 8:20





              "with(MyInterface::getNumber, "NOT A NUMBER")" should not compile

              – jukzi
              Oct 15 at 8:20











              0


















              The most interesting part lies in the difference between those 2 lines, I think:



              // works:
              new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
              // compilation error: Cannot infer ...
              new Builder<MyInterface>().with(MyInterface::getNumber, 4L);



              In the first case, the T is explicitly Number, so 4L is also a Number, no problem. In the second case, 4L is a Long, so T is a Long, so your function is not compatible, and Java cannot know if you meant Number or Long.






              share|improve this answer






























                0


















                The most interesting part lies in the difference between those 2 lines, I think:



                // works:
                new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
                // compilation error: Cannot infer ...
                new Builder<MyInterface>().with(MyInterface::getNumber, 4L);



                In the first case, the T is explicitly Number, so 4L is also a Number, no problem. In the second case, 4L is a Long, so T is a Long, so your function is not compatible, and Java cannot know if you meant Number or Long.






                share|improve this answer




























                  0














                  0










                  0









                  The most interesting part lies in the difference between those 2 lines, I think:



                  // works:
                  new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
                  // compilation error: Cannot infer ...
                  new Builder<MyInterface>().with(MyInterface::getNumber, 4L);



                  In the first case, the T is explicitly Number, so 4L is also a Number, no problem. In the second case, 4L is a Long, so T is a Long, so your function is not compatible, and Java cannot know if you meant Number or Long.






                  share|improve this answer














                  The most interesting part lies in the difference between those 2 lines, I think:



                  // works:
                  new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
                  // compilation error: Cannot infer ...
                  new Builder<MyInterface>().with(MyInterface::getNumber, 4L);



                  In the first case, the T is explicitly Number, so 4L is also a Number, no problem. In the second case, 4L is a Long, so T is a Long, so your function is not compatible, and Java cannot know if you meant Number or Long.







                  share|improve this answer













                  share|improve this answer




                  share|improve this answer










                  answered Oct 15 at 1:39









                  njzk2njzk2

                  34.1k5 gold badges54 silver badges97 bronze badges




                  34.1k5 gold badges54 silver badges97 bronze badges
























                      0


















                      With the following signature:



                      public <R> Test<T> with(Function<T, ? super R> getter, R returnValue)


                      all your examples compile, except the third, which explicitly requires the method to have two type variables.



                      The reason that your version doesn't work, is because Java's method references do not have one specific type. Instead, they have the type which is required in the given context. In your case, R is inferred to be Long because of the 4L, but the getter cannot have the type Function<MyInterface,Long> because in Java, generic types are invariant in their arguments.






                      share|improve this answer


























                      • Your code would compile with( getNumber,"NO NUMBER") which is not desired. Also it is not true that generics are always invariant (see stackoverflow.com/a/58378661/9549750 for a prove that generics of setters behave other then those of getters)

                        – jukzi
                        Oct 15 at 13:33











                      • @jukzi Ah, my solution was already proposed by Avi. Too bad... :-). By the way, it is true that we can assign a Thing<Cat> to a Thing<? extends Animal> variable, but for real covariance I would expect that a Thing<Cat> can be assigned to a Thing<Animal>. Other languages, such as Kotlin, do allow to define co- and contravariant type variables.

                        – Hoopje
                        Oct 15 at 14:36















                      0


















                      With the following signature:



                      public <R> Test<T> with(Function<T, ? super R> getter, R returnValue)


                      all your examples compile, except the third, which explicitly requires the method to have two type variables.



                      The reason that your version doesn't work, is because Java's method references do not have one specific type. Instead, they have the type which is required in the given context. In your case, R is inferred to be Long because of the 4L, but the getter cannot have the type Function<MyInterface,Long> because in Java, generic types are invariant in their arguments.






                      share|improve this answer


























                      • Your code would compile with( getNumber,"NO NUMBER") which is not desired. Also it is not true that generics are always invariant (see stackoverflow.com/a/58378661/9549750 for a prove that generics of setters behave other then those of getters)

                        – jukzi
                        Oct 15 at 13:33











                      • @jukzi Ah, my solution was already proposed by Avi. Too bad... :-). By the way, it is true that we can assign a Thing<Cat> to a Thing<? extends Animal> variable, but for real covariance I would expect that a Thing<Cat> can be assigned to a Thing<Animal>. Other languages, such as Kotlin, do allow to define co- and contravariant type variables.

                        – Hoopje
                        Oct 15 at 14:36













                      0














                      0










                      0









                      With the following signature:



                      public <R> Test<T> with(Function<T, ? super R> getter, R returnValue)


                      all your examples compile, except the third, which explicitly requires the method to have two type variables.



                      The reason that your version doesn't work, is because Java's method references do not have one specific type. Instead, they have the type which is required in the given context. In your case, R is inferred to be Long because of the 4L, but the getter cannot have the type Function<MyInterface,Long> because in Java, generic types are invariant in their arguments.






                      share|improve this answer














                      With the following signature:



                      public <R> Test<T> with(Function<T, ? super R> getter, R returnValue)


                      all your examples compile, except the third, which explicitly requires the method to have two type variables.



                      The reason that your version doesn't work, is because Java's method references do not have one specific type. Instead, they have the type which is required in the given context. In your case, R is inferred to be Long because of the 4L, but the getter cannot have the type Function<MyInterface,Long> because in Java, generic types are invariant in their arguments.







                      share|improve this answer













                      share|improve this answer




                      share|improve this answer










                      answered Oct 15 at 12:48









                      HoopjeHoopje

                      10.6k6 gold badges28 silver badges44 bronze badges




                      10.6k6 gold badges28 silver badges44 bronze badges















                      • Your code would compile with( getNumber,"NO NUMBER") which is not desired. Also it is not true that generics are always invariant (see stackoverflow.com/a/58378661/9549750 for a prove that generics of setters behave other then those of getters)

                        – jukzi
                        Oct 15 at 13:33











                      • @jukzi Ah, my solution was already proposed by Avi. Too bad... :-). By the way, it is true that we can assign a Thing<Cat> to a Thing<? extends Animal> variable, but for real covariance I would expect that a Thing<Cat> can be assigned to a Thing<Animal>. Other languages, such as Kotlin, do allow to define co- and contravariant type variables.

                        – Hoopje
                        Oct 15 at 14:36

















                      • Your code would compile with( getNumber,"NO NUMBER") which is not desired. Also it is not true that generics are always invariant (see stackoverflow.com/a/58378661/9549750 for a prove that generics of setters behave other then those of getters)

                        – jukzi
                        Oct 15 at 13:33











                      • @jukzi Ah, my solution was already proposed by Avi. Too bad... :-). By the way, it is true that we can assign a Thing<Cat> to a Thing<? extends Animal> variable, but for real covariance I would expect that a Thing<Cat> can be assigned to a Thing<Animal>. Other languages, such as Kotlin, do allow to define co- and contravariant type variables.

                        – Hoopje
                        Oct 15 at 14:36
















                      Your code would compile with( getNumber,"NO NUMBER") which is not desired. Also it is not true that generics are always invariant (see stackoverflow.com/a/58378661/9549750 for a prove that generics of setters behave other then those of getters)

                      – jukzi
                      Oct 15 at 13:33





                      Your code would compile with( getNumber,"NO NUMBER") which is not desired. Also it is not true that generics are always invariant (see stackoverflow.com/a/58378661/9549750 for a prove that generics of setters behave other then those of getters)

                      – jukzi
                      Oct 15 at 13:33













                      @jukzi Ah, my solution was already proposed by Avi. Too bad... :-). By the way, it is true that we can assign a Thing<Cat> to a Thing<? extends Animal> variable, but for real covariance I would expect that a Thing<Cat> can be assigned to a Thing<Animal>. Other languages, such as Kotlin, do allow to define co- and contravariant type variables.

                      – Hoopje
                      Oct 15 at 14:36





                      @jukzi Ah, my solution was already proposed by Avi. Too bad... :-). By the way, it is true that we can assign a Thing<Cat> to a Thing<? extends Animal> variable, but for real covariance I would expect that a Thing<Cat> can be assigned to a Thing<Animal>. Other languages, such as Kotlin, do allow to define co- and contravariant type variables.

                      – Hoopje
                      Oct 15 at 14:36


















                      draft saved

                      draft discarded















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58378037%2fwhy-can-java-not-infer-a-supertype%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown









                      Popular posts from this blog

                      Canceling a color specificationRandomly assigning color to Graphics3D objects?Default color for Filling in Mathematica 9Coloring specific elements of sets with a prime modified order in an array plotHow to pick a color differing significantly from the colors already in a given color list?Detection of the text colorColor numbers based on their valueCan color schemes for use with ColorData include opacity specification?My dynamic color schemes

                      Invision Community Contents History See also References External links Navigation menuProprietaryinvisioncommunity.comIPS Community ForumsIPS Community Forumsthis blog entry"License Changes, IP.Board 3.4, and the Future""Interview -- Matt Mecham of Ibforums""CEO Invision Power Board, Matt Mecham Is a Liar, Thief!"IPB License Explanation 1.3, 1.3.1, 2.0, and 2.1ArchivedSecurity Fixes, Updates And Enhancements For IPB 1.3.1Archived"New Demo Accounts - Invision Power Services"the original"New Default Skin"the original"Invision Power Board 3.0.0 and Applications Released"the original"Archived copy"the original"Perpetual licenses being done away with""Release Notes - Invision Power Services""Introducing: IPS Community Suite 4!"Invision Community Release Notes

                      199年 目錄 大件事 到箇年出世嗰人 到箇年死嗰人 節慶、風俗習慣 導覽選單