Why are Optional's or and flatMap methods' supplier type parameters wildcards?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
29
down vote

favorite
5












The Optional.or method was added in Java 9. This is the method signature



public Optional<T> or​(Supplier<? extends Optional<? extends T>> supplier)


Why is the type parameter of the Supplier taking ? extends Optional rather than just Optional, since Optional is a final class?



The same is true for the Optional.flatMap method. This is a change from Java 8.



In Java 8, it was Function<? super T, Optional<U>> mapper whereas it was changed to Function<? super T,​? extends Optional<? extends U>> in Java 9.










share|improve this question























  • Kinda seems like they're positioning it to not be a final class in future version?
    – nbrooks
    Dec 10 at 1:42










  • @nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
    – user7
    Dec 10 at 1:45






  • 3




    My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
    – Daniel Pryden
    Dec 10 at 17:52















up vote
29
down vote

favorite
5












The Optional.or method was added in Java 9. This is the method signature



public Optional<T> or​(Supplier<? extends Optional<? extends T>> supplier)


Why is the type parameter of the Supplier taking ? extends Optional rather than just Optional, since Optional is a final class?



The same is true for the Optional.flatMap method. This is a change from Java 8.



In Java 8, it was Function<? super T, Optional<U>> mapper whereas it was changed to Function<? super T,​? extends Optional<? extends U>> in Java 9.










share|improve this question























  • Kinda seems like they're positioning it to not be a final class in future version?
    – nbrooks
    Dec 10 at 1:42










  • @nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
    – user7
    Dec 10 at 1:45






  • 3




    My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
    – Daniel Pryden
    Dec 10 at 17:52













up vote
29
down vote

favorite
5









up vote
29
down vote

favorite
5






5





The Optional.or method was added in Java 9. This is the method signature



public Optional<T> or​(Supplier<? extends Optional<? extends T>> supplier)


Why is the type parameter of the Supplier taking ? extends Optional rather than just Optional, since Optional is a final class?



The same is true for the Optional.flatMap method. This is a change from Java 8.



In Java 8, it was Function<? super T, Optional<U>> mapper whereas it was changed to Function<? super T,​? extends Optional<? extends U>> in Java 9.










share|improve this question















The Optional.or method was added in Java 9. This is the method signature



public Optional<T> or​(Supplier<? extends Optional<? extends T>> supplier)


Why is the type parameter of the Supplier taking ? extends Optional rather than just Optional, since Optional is a final class?



The same is true for the Optional.flatMap method. This is a change from Java 8.



In Java 8, it was Function<? super T, Optional<U>> mapper whereas it was changed to Function<? super T,​? extends Optional<? extends U>> in Java 9.







java optional java-9 supplier






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 10 at 13:47









Boann

36.7k1287121




36.7k1287121










asked Dec 10 at 1:25









user7

9,22432242




9,22432242











  • Kinda seems like they're positioning it to not be a final class in future version?
    – nbrooks
    Dec 10 at 1:42










  • @nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
    – user7
    Dec 10 at 1:45






  • 3




    My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
    – Daniel Pryden
    Dec 10 at 17:52

















  • Kinda seems like they're positioning it to not be a final class in future version?
    – nbrooks
    Dec 10 at 1:42










  • @nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
    – user7
    Dec 10 at 1:45






  • 3




    My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
    – Daniel Pryden
    Dec 10 at 17:52
















Kinda seems like they're positioning it to not be a final class in future version?
– nbrooks
Dec 10 at 1:42




Kinda seems like they're positioning it to not be a final class in future version?
– nbrooks
Dec 10 at 1:42












@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 at 1:45




@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 at 1:45




3




3




My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
– Daniel Pryden
Dec 10 at 17:52





My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
– Daniel Pryden
Dec 10 at 17:52













3 Answers
3






active

oldest

votes

















up vote
35
down vote













I found the reasoning behind this from Stuart Marks himself



http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html



This has to do with nested generics (Optional is nested within Function).
From the mail thread




 Function<..., Optional<StringBuilder>>


is not a subtype of



 Function<..., Optional<? extends CharSequence>>


To get around this, we have to add the outer wildcard as well, so that



 Function<..., Optional<StringBuilder>>


is a subtype of



 Function<..., ? extends Optional<? extends CharSequence>>






share|improve this answer


















  • 8




    +1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach" <V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper) would not work in all circumstances.
    – Stefan Zobel
    Dec 10 at 8:48


















up vote
10
down vote













FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are



static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)


These signatures do not allow for some combinations of seeds and UnaryOperators that are sound from a type perspective, e.g. the following doesn't compile:



UnaryOperator<String> op = s -> s; 
Stream<CharSequence> scs = iterate("", op); // error


The proposed solution is to change the method signatures to



static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)


So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.






share|improve this answer



























    up vote
    9
    down vote













    Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple> is an actual subtype of List<? extends Fruit> (considering that Apple extends Fruit); this is also called covariance.



    Or in the examples that you have shown, it means that Optional<StringBuilder> is a subtype of Optional<? extends Optional<? extends CharSequence>>, so you could for example do:



    List<Optional<String>> left = new ArrayList<>();
    List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();

    right = left; // will compile


    or assign a Function to the other






    share|improve this answer






















      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/3.0/"u003ecc by-sa 3.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%2f53698401%2fwhy-are-optionals-or-and-flatmap-methods-supplier-type-parameters-wildcards%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      35
      down vote













      I found the reasoning behind this from Stuart Marks himself



      http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html



      This has to do with nested generics (Optional is nested within Function).
      From the mail thread




       Function<..., Optional<StringBuilder>>


      is not a subtype of



       Function<..., Optional<? extends CharSequence>>


      To get around this, we have to add the outer wildcard as well, so that



       Function<..., Optional<StringBuilder>>


      is a subtype of



       Function<..., ? extends Optional<? extends CharSequence>>






      share|improve this answer


















      • 8




        +1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach" <V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper) would not work in all circumstances.
        – Stefan Zobel
        Dec 10 at 8:48















      up vote
      35
      down vote













      I found the reasoning behind this from Stuart Marks himself



      http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html



      This has to do with nested generics (Optional is nested within Function).
      From the mail thread




       Function<..., Optional<StringBuilder>>


      is not a subtype of



       Function<..., Optional<? extends CharSequence>>


      To get around this, we have to add the outer wildcard as well, so that



       Function<..., Optional<StringBuilder>>


      is a subtype of



       Function<..., ? extends Optional<? extends CharSequence>>






      share|improve this answer


















      • 8




        +1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach" <V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper) would not work in all circumstances.
        – Stefan Zobel
        Dec 10 at 8:48













      up vote
      35
      down vote










      up vote
      35
      down vote









      I found the reasoning behind this from Stuart Marks himself



      http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html



      This has to do with nested generics (Optional is nested within Function).
      From the mail thread




       Function<..., Optional<StringBuilder>>


      is not a subtype of



       Function<..., Optional<? extends CharSequence>>


      To get around this, we have to add the outer wildcard as well, so that



       Function<..., Optional<StringBuilder>>


      is a subtype of



       Function<..., ? extends Optional<? extends CharSequence>>






      share|improve this answer














      I found the reasoning behind this from Stuart Marks himself



      http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html



      This has to do with nested generics (Optional is nested within Function).
      From the mail thread




       Function<..., Optional<StringBuilder>>


      is not a subtype of



       Function<..., Optional<? extends CharSequence>>


      To get around this, we have to add the outer wildcard as well, so that



       Function<..., Optional<StringBuilder>>


      is a subtype of



       Function<..., ? extends Optional<? extends CharSequence>>







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 10 at 8:07









      JAD

      1,0441923




      1,0441923










      answered Dec 10 at 1:45









      user7

      9,22432242




      9,22432242







      • 8




        +1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach" <V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper) would not work in all circumstances.
        – Stefan Zobel
        Dec 10 at 8:48













      • 8




        +1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach" <V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper) would not work in all circumstances.
        – Stefan Zobel
        Dec 10 at 8:48








      8




      8




      +1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach" <V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper) would not work in all circumstances.
      – Stefan Zobel
      Dec 10 at 8:48





      +1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach" <V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper) would not work in all circumstances.
      – Stefan Zobel
      Dec 10 at 8:48













      up vote
      10
      down vote













      FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are



      static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
      static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)


      These signatures do not allow for some combinations of seeds and UnaryOperators that are sound from a type perspective, e.g. the following doesn't compile:



      UnaryOperator<String> op = s -> s; 
      Stream<CharSequence> scs = iterate("", op); // error


      The proposed solution is to change the method signatures to



      static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
      static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)


      So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.






      share|improve this answer
























        up vote
        10
        down vote













        FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are



        static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
        static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)


        These signatures do not allow for some combinations of seeds and UnaryOperators that are sound from a type perspective, e.g. the following doesn't compile:



        UnaryOperator<String> op = s -> s; 
        Stream<CharSequence> scs = iterate("", op); // error


        The proposed solution is to change the method signatures to



        static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
        static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)


        So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.






        share|improve this answer






















          up vote
          10
          down vote










          up vote
          10
          down vote









          FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are



          static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
          static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)


          These signatures do not allow for some combinations of seeds and UnaryOperators that are sound from a type perspective, e.g. the following doesn't compile:



          UnaryOperator<String> op = s -> s; 
          Stream<CharSequence> scs = iterate("", op); // error


          The proposed solution is to change the method signatures to



          static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
          static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)


          So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.






          share|improve this answer












          FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are



          static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
          static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)


          These signatures do not allow for some combinations of seeds and UnaryOperators that are sound from a type perspective, e.g. the following doesn't compile:



          UnaryOperator<String> op = s -> s; 
          Stream<CharSequence> scs = iterate("", op); // error


          The proposed solution is to change the method signatures to



          static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
          static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)


          So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Dec 10 at 12:10









          Stefan Zobel

          2,44031828




          2,44031828




















              up vote
              9
              down vote













              Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple> is an actual subtype of List<? extends Fruit> (considering that Apple extends Fruit); this is also called covariance.



              Or in the examples that you have shown, it means that Optional<StringBuilder> is a subtype of Optional<? extends Optional<? extends CharSequence>>, so you could for example do:



              List<Optional<String>> left = new ArrayList<>();
              List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();

              right = left; // will compile


              or assign a Function to the other






              share|improve this answer


























                up vote
                9
                down vote













                Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple> is an actual subtype of List<? extends Fruit> (considering that Apple extends Fruit); this is also called covariance.



                Or in the examples that you have shown, it means that Optional<StringBuilder> is a subtype of Optional<? extends Optional<? extends CharSequence>>, so you could for example do:



                List<Optional<String>> left = new ArrayList<>();
                List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();

                right = left; // will compile


                or assign a Function to the other






                share|improve this answer
























                  up vote
                  9
                  down vote










                  up vote
                  9
                  down vote









                  Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple> is an actual subtype of List<? extends Fruit> (considering that Apple extends Fruit); this is also called covariance.



                  Or in the examples that you have shown, it means that Optional<StringBuilder> is a subtype of Optional<? extends Optional<? extends CharSequence>>, so you could for example do:



                  List<Optional<String>> left = new ArrayList<>();
                  List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();

                  right = left; // will compile


                  or assign a Function to the other






                  share|improve this answer














                  Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple> is an actual subtype of List<? extends Fruit> (considering that Apple extends Fruit); this is also called covariance.



                  Or in the examples that you have shown, it means that Optional<StringBuilder> is a subtype of Optional<? extends Optional<? extends CharSequence>>, so you could for example do:



                  List<Optional<String>> left = new ArrayList<>();
                  List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();

                  right = left; // will compile


                  or assign a Function to the other







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Dec 10 at 12:48

























                  answered Dec 10 at 12:31









                  Eugene

                  68k997160




                  68k997160



























                      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.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • 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%2f53698401%2fwhy-are-optionals-or-and-flatmap-methods-supplier-type-parameters-wildcards%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

                      How to check contact read email or not when send email to Individual?

                      Displaying single band from multi-band raster using QGIS

                      How many registers does an x86_64 CPU actually have?