Is List f() a useful signature? Is there any problem with it / using it?












33














Is <T> List<? extends T> f() a useful signature? Is there any problem with it / using it?



This was an interview question. I know this:




  1. It compiles fine

  2. Use it like List<? extends Number> lst = obj.<Number>f(), and then I can call on lst only those List methods that do not contain T in their signatures (say, isEmpty(), size(), but not add(T), remove(T)


Does that fully answer the question?










share|improve this question


















  • 3




    Returning a wildcard is not really useful
    – NEGR KITAEC
    Jan 2 at 10:41






  • 1




    You can still call add(null) etc.
    – Andy Turner
    Jan 2 at 10:46








  • 1




    Using type inference you can just do List<? extends Number> lst = s.f();. Also, you can do Number number = lst.get(0); System.out.println(number);.
    – DodgyCodeException
    Jan 2 at 10:48






  • 3




    I think that what the interviewer was getting at was the fact that the return type of the method contains a wildcard. From Effective Java, 2nd Ed. "You should not return a wildcard type because it forces the users of an API to deal with wildcards." (paraphrased) Perhaps the best answer is that the return type is appropriate for use in package-private or private methods within a system, but it should not be used as part of an exported API.
    – scottb
    Jan 2 at 16:04






  • 1




    @ArtB no, the advice of the 2nd ed still very much stands: wildcards are to increase the flexibility of parameters; they should not be used in return types.
    – Andy Turner
    Jan 2 at 20:10
















33














Is <T> List<? extends T> f() a useful signature? Is there any problem with it / using it?



This was an interview question. I know this:




  1. It compiles fine

  2. Use it like List<? extends Number> lst = obj.<Number>f(), and then I can call on lst only those List methods that do not contain T in their signatures (say, isEmpty(), size(), but not add(T), remove(T)


Does that fully answer the question?










share|improve this question


















  • 3




    Returning a wildcard is not really useful
    – NEGR KITAEC
    Jan 2 at 10:41






  • 1




    You can still call add(null) etc.
    – Andy Turner
    Jan 2 at 10:46








  • 1




    Using type inference you can just do List<? extends Number> lst = s.f();. Also, you can do Number number = lst.get(0); System.out.println(number);.
    – DodgyCodeException
    Jan 2 at 10:48






  • 3




    I think that what the interviewer was getting at was the fact that the return type of the method contains a wildcard. From Effective Java, 2nd Ed. "You should not return a wildcard type because it forces the users of an API to deal with wildcards." (paraphrased) Perhaps the best answer is that the return type is appropriate for use in package-private or private methods within a system, but it should not be used as part of an exported API.
    – scottb
    Jan 2 at 16:04






  • 1




    @ArtB no, the advice of the 2nd ed still very much stands: wildcards are to increase the flexibility of parameters; they should not be used in return types.
    – Andy Turner
    Jan 2 at 20:10














33












33








33


6





Is <T> List<? extends T> f() a useful signature? Is there any problem with it / using it?



This was an interview question. I know this:




  1. It compiles fine

  2. Use it like List<? extends Number> lst = obj.<Number>f(), and then I can call on lst only those List methods that do not contain T in their signatures (say, isEmpty(), size(), but not add(T), remove(T)


Does that fully answer the question?










share|improve this question













Is <T> List<? extends T> f() a useful signature? Is there any problem with it / using it?



This was an interview question. I know this:




  1. It compiles fine

  2. Use it like List<? extends Number> lst = obj.<Number>f(), and then I can call on lst only those List methods that do not contain T in their signatures (say, isEmpty(), size(), but not add(T), remove(T)


Does that fully answer the question?







java






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 2 at 10:38









user10777718user10777718

31018




31018








  • 3




    Returning a wildcard is not really useful
    – NEGR KITAEC
    Jan 2 at 10:41






  • 1




    You can still call add(null) etc.
    – Andy Turner
    Jan 2 at 10:46








  • 1




    Using type inference you can just do List<? extends Number> lst = s.f();. Also, you can do Number number = lst.get(0); System.out.println(number);.
    – DodgyCodeException
    Jan 2 at 10:48






  • 3




    I think that what the interviewer was getting at was the fact that the return type of the method contains a wildcard. From Effective Java, 2nd Ed. "You should not return a wildcard type because it forces the users of an API to deal with wildcards." (paraphrased) Perhaps the best answer is that the return type is appropriate for use in package-private or private methods within a system, but it should not be used as part of an exported API.
    – scottb
    Jan 2 at 16:04






  • 1




    @ArtB no, the advice of the 2nd ed still very much stands: wildcards are to increase the flexibility of parameters; they should not be used in return types.
    – Andy Turner
    Jan 2 at 20:10














  • 3




    Returning a wildcard is not really useful
    – NEGR KITAEC
    Jan 2 at 10:41






  • 1




    You can still call add(null) etc.
    – Andy Turner
    Jan 2 at 10:46








  • 1




    Using type inference you can just do List<? extends Number> lst = s.f();. Also, you can do Number number = lst.get(0); System.out.println(number);.
    – DodgyCodeException
    Jan 2 at 10:48






  • 3




    I think that what the interviewer was getting at was the fact that the return type of the method contains a wildcard. From Effective Java, 2nd Ed. "You should not return a wildcard type because it forces the users of an API to deal with wildcards." (paraphrased) Perhaps the best answer is that the return type is appropriate for use in package-private or private methods within a system, but it should not be used as part of an exported API.
    – scottb
    Jan 2 at 16:04






  • 1




    @ArtB no, the advice of the 2nd ed still very much stands: wildcards are to increase the flexibility of parameters; they should not be used in return types.
    – Andy Turner
    Jan 2 at 20:10








3




3




Returning a wildcard is not really useful
– NEGR KITAEC
Jan 2 at 10:41




Returning a wildcard is not really useful
– NEGR KITAEC
Jan 2 at 10:41




1




1




You can still call add(null) etc.
– Andy Turner
Jan 2 at 10:46






You can still call add(null) etc.
– Andy Turner
Jan 2 at 10:46






1




1




Using type inference you can just do List<? extends Number> lst = s.f();. Also, you can do Number number = lst.get(0); System.out.println(number);.
– DodgyCodeException
Jan 2 at 10:48




Using type inference you can just do List<? extends Number> lst = s.f();. Also, you can do Number number = lst.get(0); System.out.println(number);.
– DodgyCodeException
Jan 2 at 10:48




3




3




I think that what the interviewer was getting at was the fact that the return type of the method contains a wildcard. From Effective Java, 2nd Ed. "You should not return a wildcard type because it forces the users of an API to deal with wildcards." (paraphrased) Perhaps the best answer is that the return type is appropriate for use in package-private or private methods within a system, but it should not be used as part of an exported API.
– scottb
Jan 2 at 16:04




I think that what the interviewer was getting at was the fact that the return type of the method contains a wildcard. From Effective Java, 2nd Ed. "You should not return a wildcard type because it forces the users of an API to deal with wildcards." (paraphrased) Perhaps the best answer is that the return type is appropriate for use in package-private or private methods within a system, but it should not be used as part of an exported API.
– scottb
Jan 2 at 16:04




1




1




@ArtB no, the advice of the 2nd ed still very much stands: wildcards are to increase the flexibility of parameters; they should not be used in return types.
– Andy Turner
Jan 2 at 20:10




@ArtB no, the advice of the 2nd ed still very much stands: wildcards are to increase the flexibility of parameters; they should not be used in return types.
– Andy Turner
Jan 2 at 20:10












4 Answers
4






active

oldest

votes


















19














This method signature is "useful", in the sense that you can implement non-trivial, non-degenerate methods with it (that is, returning null and throwing errors are not your only options). As the following example shows, such a method can be useful for implementing some algebraic structures like e.g. monoids.



First, observe that List<? extends T> is a type with the following properties:




  • You know that all elements of this list conform to the type T, so whenever you extract an element from this list, you can use it in position where a T is expected. You can read from this list.

  • The exact type is unknown, so you can never be certain that an instance of a particular subtype of T can be added to this list. That is, you effectively cannot add new elements to such a list (unless you use nulls / type casts / exploit unsoundness of Java's type system, that is).


In combination, it means that List<? extends T> is kind-of like an append-protected list, with type-level append-protection.



You can actually do meaningful computations with such "append-protected" lists. Here are a few examples:





  • You can create append-protected lists with a single element:



    public static <T> List<? extends T> pure(T t) {
    List<T> result = new LinkedList<T>();
    result.add(t);
    return result;
    }



  • You can create append-protected lists from ordinary lists:



    public static <T> List<? extends T> toAppendProtected(List<T> original) {
    List<T> result = new LinkedList<T>();
    result.addAll(original);
    return result;
    }



  • You can combine append-protected lists:



    public static <T> List<? extends T> combineAppendProtected(
    List<? extends T> a,
    List<? extends T> b
    ) {
    List<T> result = new LinkedList<T>();
    result.addAll(a);
    result.addAll(b);
    return result;
    }



  • And, most importantly for this question, you can implement a method that returns an empty append-protected list of given type:



    public static <T> List<? extends T> emptyAppendProtected() {
    return new LinkedList<T>();
    }



Together, combine and empty form an actual algebraic structure (a monoid), and methods like pure ensure that it's non-degenerate (i.e. it has more elements that just an empty list). Indeed, if you had an interface similar to the usual Monoid typeclass:



  public static interface Monoid<X> {
X empty();
X combine(X a, X b);
}


then you could use the above methods to implement it as follows:



  public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
return new Monoid<List<? extends T>>() {
public List<? extends T> empty() {
return ReadOnlyLists.<T>emptyAppendProtected();
}

public List<? extends T> combine(
List<? extends T> a,
List<? extends T> b
) {
return combineAppendProtected(a, b);
}
};
}


This shows that methods with the signature given in your question can be used to implement some common design patterns / algebraic structures (monoids). Admittedly, the example is somewhat contrived, you probably wouldn't want to use it in practice, because you don't want to astonish the users of your API too much.





Full compilable example:



import java.util.*;

class AppendProtectedLists {

public static <T> List<? extends T> emptyAppendProtected() {
return new LinkedList<T>();
}

public static <T> List<? extends T> combineAppendProtected(
List<? extends T> a,
List<? extends T> b
) {
List<T> result = new LinkedList<T>();
result.addAll(a);
result.addAll(b);
return result;
}

public static <T> List<? extends T> toAppendProtected(List<T> original) {
List<T> result = new LinkedList<T>();
result.addAll(original);
return result;
}

public static <T> List<? extends T> pure(T t) {
List<T> result = new LinkedList<T>();
result.add(t);
return result;
}

public static interface Monoid<X> {
X empty();
X combine(X a, X b);
}

public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
return new Monoid<List<? extends T>>() {
public List<? extends T> empty() {
return AppendProtectedLists.<T>emptyAppendProtected();
}

public List<? extends T> combine(
List<? extends T> a,
List<? extends T> b
) {
return combineAppendProtected(a, b);
}
};
}

public static void main(String args) {
Monoid<List<? extends String>> monoid = appendProtectedListsMonoid();
List<? extends String> e = monoid.empty();
// e.add("hi"); // refuses to compile, which is good: write protection!
List<? extends String> a = pure("a");
List<? extends String> b = pure("b");
List<? extends String> c = monoid.combine(e, monoid.combine(a, b));
System.out.println(c); // output: [a, b]
}

}





share|improve this answer































    16














    I interpret "is it a useful signature" to mean "can you think of a use-case for it".



    T is determined at the call site, not inside the method, so there are only two things that you can return from the method: null or an empty list.



    Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it.





    Actually, another value that can be safely returned is a list where all of the elements are null. But this isn't useful either, since you can only invoke methods which add or remove literal null from the return value, because of the ? extends in the type bound. So all you've got is thing which counts the number of nulls it contains. Which isn't useful either.






    share|improve this answer























    • Well, looking very desperately for a contrived way of making it useful, you could have called a setReturnType(Class<?> cls) method on the same object beforehand, and then f() would use that information to return a list of the required type.
      – DodgyCodeException
      Jan 2 at 10:53






    • 1




      @DodgyCodeException I suppose - but this would be the protocol anti-pattern.
      – Boris the Spider
      Jan 2 at 11:38










    • "Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it." Really? Invoking .<String>empty() seems way more pleasant than invoking ((List<? extends String>) new List<String>()). How would you construct an expression of type List<? extends String> without such a method?
      – Andrey Tyukin
      Jan 2 at 14:45






    • 1




      @AndreyTyukin List<? extends String> list = new ArrayList<>();. Or even just new List<String> - that's a List<? extends String>.
      – Andy Turner
      Jan 2 at 14:45












    • @AndyTurner That's a statement, not an expression. One would have to pollute the local scope with extra variables (like list). The simple idea of instantiating an empty append-protected list would be spread over two different lines in code. And this statement is still way longer than a simple .<String>empty(). The new List<String>() is a List<? extends String> only if it's in a context where the type inference expects a List<? extends String>. It's not so useful if you want to create an expression that guides type inference instead of relying on it.
      – Andrey Tyukin
      Jan 2 at 14:48





















    1














    The official Generics tutorial suggests not to use wildcard return types.




    These guidelines do not apply to a method's return type. Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards."




    The reasoning given isn't exactly convincing, though.






    share|improve this answer































      0














      It's not particularly useful, for the reasons given in other answers. However, consider it's "usefulness" in a class like the following (although it's probably a bit of an antipattern):



      public class Repository {
      private List<Object> lst = new ArrayList<>();

      public <T> void add(T item) {
      lst.add(item);
      }

      @SuppressWarnings("unchecked")
      public <T> List<? extends T> f() {
      return (List<? extends T>) lst;
      }

      public static void main(String args) {
      Repository rep = new Repository();
      rep.add(BigInteger.ONE);
      rep.add(Double.valueOf(2.0));
      List<? extends Number> list = rep.f();
      System.out.println(list.get(0).doubleValue() + list.get(1).doubleValue());
      }
      }


      Note the following features:




      1. The declared return type of f() means that the caller can set whatever T they like and the method will return the required type. If f() weren't declared like that, then the caller would need to cast every call to get(N) to the required type.

      2. As it uses a wildcard, the declared return type makes the returned list read-only. This can often be a useful feature. When caller a getter, you don't want it to return a list you can write to. Often, getters use Collections.unmodifiableList() which forces a list to be read-only at run-time, but using the wildcard generic parameter forces the list to be read-only at compile-time!

      3. The drawback is that it's not particularly type-safe. It is up to the caller to ensure that f() returns a type where T is a common superclass of all the previously added items.

      4. It would typically be much better to make the class Repository generic instead of the method f().






      share|improve this answer



















      • 3




        Wildcard lists aren't read-only. You can remove elements, you can add null to the list, and you can use a wildcard capturing helper method to add and reorder its own elements.
        – Radiodef
        Jan 2 at 14:37











      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%2f54004821%2fis-t-list-extends-t-f-a-useful-signature-is-there-any-problem-with-it%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      19














      This method signature is "useful", in the sense that you can implement non-trivial, non-degenerate methods with it (that is, returning null and throwing errors are not your only options). As the following example shows, such a method can be useful for implementing some algebraic structures like e.g. monoids.



      First, observe that List<? extends T> is a type with the following properties:




      • You know that all elements of this list conform to the type T, so whenever you extract an element from this list, you can use it in position where a T is expected. You can read from this list.

      • The exact type is unknown, so you can never be certain that an instance of a particular subtype of T can be added to this list. That is, you effectively cannot add new elements to such a list (unless you use nulls / type casts / exploit unsoundness of Java's type system, that is).


      In combination, it means that List<? extends T> is kind-of like an append-protected list, with type-level append-protection.



      You can actually do meaningful computations with such "append-protected" lists. Here are a few examples:





      • You can create append-protected lists with a single element:



        public static <T> List<? extends T> pure(T t) {
        List<T> result = new LinkedList<T>();
        result.add(t);
        return result;
        }



      • You can create append-protected lists from ordinary lists:



        public static <T> List<? extends T> toAppendProtected(List<T> original) {
        List<T> result = new LinkedList<T>();
        result.addAll(original);
        return result;
        }



      • You can combine append-protected lists:



        public static <T> List<? extends T> combineAppendProtected(
        List<? extends T> a,
        List<? extends T> b
        ) {
        List<T> result = new LinkedList<T>();
        result.addAll(a);
        result.addAll(b);
        return result;
        }



      • And, most importantly for this question, you can implement a method that returns an empty append-protected list of given type:



        public static <T> List<? extends T> emptyAppendProtected() {
        return new LinkedList<T>();
        }



      Together, combine and empty form an actual algebraic structure (a monoid), and methods like pure ensure that it's non-degenerate (i.e. it has more elements that just an empty list). Indeed, if you had an interface similar to the usual Monoid typeclass:



        public static interface Monoid<X> {
      X empty();
      X combine(X a, X b);
      }


      then you could use the above methods to implement it as follows:



        public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
      return new Monoid<List<? extends T>>() {
      public List<? extends T> empty() {
      return ReadOnlyLists.<T>emptyAppendProtected();
      }

      public List<? extends T> combine(
      List<? extends T> a,
      List<? extends T> b
      ) {
      return combineAppendProtected(a, b);
      }
      };
      }


      This shows that methods with the signature given in your question can be used to implement some common design patterns / algebraic structures (monoids). Admittedly, the example is somewhat contrived, you probably wouldn't want to use it in practice, because you don't want to astonish the users of your API too much.





      Full compilable example:



      import java.util.*;

      class AppendProtectedLists {

      public static <T> List<? extends T> emptyAppendProtected() {
      return new LinkedList<T>();
      }

      public static <T> List<? extends T> combineAppendProtected(
      List<? extends T> a,
      List<? extends T> b
      ) {
      List<T> result = new LinkedList<T>();
      result.addAll(a);
      result.addAll(b);
      return result;
      }

      public static <T> List<? extends T> toAppendProtected(List<T> original) {
      List<T> result = new LinkedList<T>();
      result.addAll(original);
      return result;
      }

      public static <T> List<? extends T> pure(T t) {
      List<T> result = new LinkedList<T>();
      result.add(t);
      return result;
      }

      public static interface Monoid<X> {
      X empty();
      X combine(X a, X b);
      }

      public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
      return new Monoid<List<? extends T>>() {
      public List<? extends T> empty() {
      return AppendProtectedLists.<T>emptyAppendProtected();
      }

      public List<? extends T> combine(
      List<? extends T> a,
      List<? extends T> b
      ) {
      return combineAppendProtected(a, b);
      }
      };
      }

      public static void main(String args) {
      Monoid<List<? extends String>> monoid = appendProtectedListsMonoid();
      List<? extends String> e = monoid.empty();
      // e.add("hi"); // refuses to compile, which is good: write protection!
      List<? extends String> a = pure("a");
      List<? extends String> b = pure("b");
      List<? extends String> c = monoid.combine(e, monoid.combine(a, b));
      System.out.println(c); // output: [a, b]
      }

      }





      share|improve this answer




























        19














        This method signature is "useful", in the sense that you can implement non-trivial, non-degenerate methods with it (that is, returning null and throwing errors are not your only options). As the following example shows, such a method can be useful for implementing some algebraic structures like e.g. monoids.



        First, observe that List<? extends T> is a type with the following properties:




        • You know that all elements of this list conform to the type T, so whenever you extract an element from this list, you can use it in position where a T is expected. You can read from this list.

        • The exact type is unknown, so you can never be certain that an instance of a particular subtype of T can be added to this list. That is, you effectively cannot add new elements to such a list (unless you use nulls / type casts / exploit unsoundness of Java's type system, that is).


        In combination, it means that List<? extends T> is kind-of like an append-protected list, with type-level append-protection.



        You can actually do meaningful computations with such "append-protected" lists. Here are a few examples:





        • You can create append-protected lists with a single element:



          public static <T> List<? extends T> pure(T t) {
          List<T> result = new LinkedList<T>();
          result.add(t);
          return result;
          }



        • You can create append-protected lists from ordinary lists:



          public static <T> List<? extends T> toAppendProtected(List<T> original) {
          List<T> result = new LinkedList<T>();
          result.addAll(original);
          return result;
          }



        • You can combine append-protected lists:



          public static <T> List<? extends T> combineAppendProtected(
          List<? extends T> a,
          List<? extends T> b
          ) {
          List<T> result = new LinkedList<T>();
          result.addAll(a);
          result.addAll(b);
          return result;
          }



        • And, most importantly for this question, you can implement a method that returns an empty append-protected list of given type:



          public static <T> List<? extends T> emptyAppendProtected() {
          return new LinkedList<T>();
          }



        Together, combine and empty form an actual algebraic structure (a monoid), and methods like pure ensure that it's non-degenerate (i.e. it has more elements that just an empty list). Indeed, if you had an interface similar to the usual Monoid typeclass:



          public static interface Monoid<X> {
        X empty();
        X combine(X a, X b);
        }


        then you could use the above methods to implement it as follows:



          public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
        return new Monoid<List<? extends T>>() {
        public List<? extends T> empty() {
        return ReadOnlyLists.<T>emptyAppendProtected();
        }

        public List<? extends T> combine(
        List<? extends T> a,
        List<? extends T> b
        ) {
        return combineAppendProtected(a, b);
        }
        };
        }


        This shows that methods with the signature given in your question can be used to implement some common design patterns / algebraic structures (monoids). Admittedly, the example is somewhat contrived, you probably wouldn't want to use it in practice, because you don't want to astonish the users of your API too much.





        Full compilable example:



        import java.util.*;

        class AppendProtectedLists {

        public static <T> List<? extends T> emptyAppendProtected() {
        return new LinkedList<T>();
        }

        public static <T> List<? extends T> combineAppendProtected(
        List<? extends T> a,
        List<? extends T> b
        ) {
        List<T> result = new LinkedList<T>();
        result.addAll(a);
        result.addAll(b);
        return result;
        }

        public static <T> List<? extends T> toAppendProtected(List<T> original) {
        List<T> result = new LinkedList<T>();
        result.addAll(original);
        return result;
        }

        public static <T> List<? extends T> pure(T t) {
        List<T> result = new LinkedList<T>();
        result.add(t);
        return result;
        }

        public static interface Monoid<X> {
        X empty();
        X combine(X a, X b);
        }

        public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
        return new Monoid<List<? extends T>>() {
        public List<? extends T> empty() {
        return AppendProtectedLists.<T>emptyAppendProtected();
        }

        public List<? extends T> combine(
        List<? extends T> a,
        List<? extends T> b
        ) {
        return combineAppendProtected(a, b);
        }
        };
        }

        public static void main(String args) {
        Monoid<List<? extends String>> monoid = appendProtectedListsMonoid();
        List<? extends String> e = monoid.empty();
        // e.add("hi"); // refuses to compile, which is good: write protection!
        List<? extends String> a = pure("a");
        List<? extends String> b = pure("b");
        List<? extends String> c = monoid.combine(e, monoid.combine(a, b));
        System.out.println(c); // output: [a, b]
        }

        }





        share|improve this answer


























          19












          19








          19






          This method signature is "useful", in the sense that you can implement non-trivial, non-degenerate methods with it (that is, returning null and throwing errors are not your only options). As the following example shows, such a method can be useful for implementing some algebraic structures like e.g. monoids.



          First, observe that List<? extends T> is a type with the following properties:




          • You know that all elements of this list conform to the type T, so whenever you extract an element from this list, you can use it in position where a T is expected. You can read from this list.

          • The exact type is unknown, so you can never be certain that an instance of a particular subtype of T can be added to this list. That is, you effectively cannot add new elements to such a list (unless you use nulls / type casts / exploit unsoundness of Java's type system, that is).


          In combination, it means that List<? extends T> is kind-of like an append-protected list, with type-level append-protection.



          You can actually do meaningful computations with such "append-protected" lists. Here are a few examples:





          • You can create append-protected lists with a single element:



            public static <T> List<? extends T> pure(T t) {
            List<T> result = new LinkedList<T>();
            result.add(t);
            return result;
            }



          • You can create append-protected lists from ordinary lists:



            public static <T> List<? extends T> toAppendProtected(List<T> original) {
            List<T> result = new LinkedList<T>();
            result.addAll(original);
            return result;
            }



          • You can combine append-protected lists:



            public static <T> List<? extends T> combineAppendProtected(
            List<? extends T> a,
            List<? extends T> b
            ) {
            List<T> result = new LinkedList<T>();
            result.addAll(a);
            result.addAll(b);
            return result;
            }



          • And, most importantly for this question, you can implement a method that returns an empty append-protected list of given type:



            public static <T> List<? extends T> emptyAppendProtected() {
            return new LinkedList<T>();
            }



          Together, combine and empty form an actual algebraic structure (a monoid), and methods like pure ensure that it's non-degenerate (i.e. it has more elements that just an empty list). Indeed, if you had an interface similar to the usual Monoid typeclass:



            public static interface Monoid<X> {
          X empty();
          X combine(X a, X b);
          }


          then you could use the above methods to implement it as follows:



            public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
          return new Monoid<List<? extends T>>() {
          public List<? extends T> empty() {
          return ReadOnlyLists.<T>emptyAppendProtected();
          }

          public List<? extends T> combine(
          List<? extends T> a,
          List<? extends T> b
          ) {
          return combineAppendProtected(a, b);
          }
          };
          }


          This shows that methods with the signature given in your question can be used to implement some common design patterns / algebraic structures (monoids). Admittedly, the example is somewhat contrived, you probably wouldn't want to use it in practice, because you don't want to astonish the users of your API too much.





          Full compilable example:



          import java.util.*;

          class AppendProtectedLists {

          public static <T> List<? extends T> emptyAppendProtected() {
          return new LinkedList<T>();
          }

          public static <T> List<? extends T> combineAppendProtected(
          List<? extends T> a,
          List<? extends T> b
          ) {
          List<T> result = new LinkedList<T>();
          result.addAll(a);
          result.addAll(b);
          return result;
          }

          public static <T> List<? extends T> toAppendProtected(List<T> original) {
          List<T> result = new LinkedList<T>();
          result.addAll(original);
          return result;
          }

          public static <T> List<? extends T> pure(T t) {
          List<T> result = new LinkedList<T>();
          result.add(t);
          return result;
          }

          public static interface Monoid<X> {
          X empty();
          X combine(X a, X b);
          }

          public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
          return new Monoid<List<? extends T>>() {
          public List<? extends T> empty() {
          return AppendProtectedLists.<T>emptyAppendProtected();
          }

          public List<? extends T> combine(
          List<? extends T> a,
          List<? extends T> b
          ) {
          return combineAppendProtected(a, b);
          }
          };
          }

          public static void main(String args) {
          Monoid<List<? extends String>> monoid = appendProtectedListsMonoid();
          List<? extends String> e = monoid.empty();
          // e.add("hi"); // refuses to compile, which is good: write protection!
          List<? extends String> a = pure("a");
          List<? extends String> b = pure("b");
          List<? extends String> c = monoid.combine(e, monoid.combine(a, b));
          System.out.println(c); // output: [a, b]
          }

          }





          share|improve this answer














          This method signature is "useful", in the sense that you can implement non-trivial, non-degenerate methods with it (that is, returning null and throwing errors are not your only options). As the following example shows, such a method can be useful for implementing some algebraic structures like e.g. monoids.



          First, observe that List<? extends T> is a type with the following properties:




          • You know that all elements of this list conform to the type T, so whenever you extract an element from this list, you can use it in position where a T is expected. You can read from this list.

          • The exact type is unknown, so you can never be certain that an instance of a particular subtype of T can be added to this list. That is, you effectively cannot add new elements to such a list (unless you use nulls / type casts / exploit unsoundness of Java's type system, that is).


          In combination, it means that List<? extends T> is kind-of like an append-protected list, with type-level append-protection.



          You can actually do meaningful computations with such "append-protected" lists. Here are a few examples:





          • You can create append-protected lists with a single element:



            public static <T> List<? extends T> pure(T t) {
            List<T> result = new LinkedList<T>();
            result.add(t);
            return result;
            }



          • You can create append-protected lists from ordinary lists:



            public static <T> List<? extends T> toAppendProtected(List<T> original) {
            List<T> result = new LinkedList<T>();
            result.addAll(original);
            return result;
            }



          • You can combine append-protected lists:



            public static <T> List<? extends T> combineAppendProtected(
            List<? extends T> a,
            List<? extends T> b
            ) {
            List<T> result = new LinkedList<T>();
            result.addAll(a);
            result.addAll(b);
            return result;
            }



          • And, most importantly for this question, you can implement a method that returns an empty append-protected list of given type:



            public static <T> List<? extends T> emptyAppendProtected() {
            return new LinkedList<T>();
            }



          Together, combine and empty form an actual algebraic structure (a monoid), and methods like pure ensure that it's non-degenerate (i.e. it has more elements that just an empty list). Indeed, if you had an interface similar to the usual Monoid typeclass:



            public static interface Monoid<X> {
          X empty();
          X combine(X a, X b);
          }


          then you could use the above methods to implement it as follows:



            public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
          return new Monoid<List<? extends T>>() {
          public List<? extends T> empty() {
          return ReadOnlyLists.<T>emptyAppendProtected();
          }

          public List<? extends T> combine(
          List<? extends T> a,
          List<? extends T> b
          ) {
          return combineAppendProtected(a, b);
          }
          };
          }


          This shows that methods with the signature given in your question can be used to implement some common design patterns / algebraic structures (monoids). Admittedly, the example is somewhat contrived, you probably wouldn't want to use it in practice, because you don't want to astonish the users of your API too much.





          Full compilable example:



          import java.util.*;

          class AppendProtectedLists {

          public static <T> List<? extends T> emptyAppendProtected() {
          return new LinkedList<T>();
          }

          public static <T> List<? extends T> combineAppendProtected(
          List<? extends T> a,
          List<? extends T> b
          ) {
          List<T> result = new LinkedList<T>();
          result.addAll(a);
          result.addAll(b);
          return result;
          }

          public static <T> List<? extends T> toAppendProtected(List<T> original) {
          List<T> result = new LinkedList<T>();
          result.addAll(original);
          return result;
          }

          public static <T> List<? extends T> pure(T t) {
          List<T> result = new LinkedList<T>();
          result.add(t);
          return result;
          }

          public static interface Monoid<X> {
          X empty();
          X combine(X a, X b);
          }

          public static <T> Monoid<List<? extends T>> appendProtectedListsMonoid() {
          return new Monoid<List<? extends T>>() {
          public List<? extends T> empty() {
          return AppendProtectedLists.<T>emptyAppendProtected();
          }

          public List<? extends T> combine(
          List<? extends T> a,
          List<? extends T> b
          ) {
          return combineAppendProtected(a, b);
          }
          };
          }

          public static void main(String args) {
          Monoid<List<? extends String>> monoid = appendProtectedListsMonoid();
          List<? extends String> e = monoid.empty();
          // e.add("hi"); // refuses to compile, which is good: write protection!
          List<? extends String> a = pure("a");
          List<? extends String> b = pure("b");
          List<? extends String> c = monoid.combine(e, monoid.combine(a, b));
          System.out.println(c); // output: [a, b]
          }

          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited yesterday

























          answered Jan 2 at 14:37









          Andrey TyukinAndrey Tyukin

          27k42349




          27k42349

























              16














              I interpret "is it a useful signature" to mean "can you think of a use-case for it".



              T is determined at the call site, not inside the method, so there are only two things that you can return from the method: null or an empty list.



              Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it.





              Actually, another value that can be safely returned is a list where all of the elements are null. But this isn't useful either, since you can only invoke methods which add or remove literal null from the return value, because of the ? extends in the type bound. So all you've got is thing which counts the number of nulls it contains. Which isn't useful either.






              share|improve this answer























              • Well, looking very desperately for a contrived way of making it useful, you could have called a setReturnType(Class<?> cls) method on the same object beforehand, and then f() would use that information to return a list of the required type.
                – DodgyCodeException
                Jan 2 at 10:53






              • 1




                @DodgyCodeException I suppose - but this would be the protocol anti-pattern.
                – Boris the Spider
                Jan 2 at 11:38










              • "Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it." Really? Invoking .<String>empty() seems way more pleasant than invoking ((List<? extends String>) new List<String>()). How would you construct an expression of type List<? extends String> without such a method?
                – Andrey Tyukin
                Jan 2 at 14:45






              • 1




                @AndreyTyukin List<? extends String> list = new ArrayList<>();. Or even just new List<String> - that's a List<? extends String>.
                – Andy Turner
                Jan 2 at 14:45












              • @AndyTurner That's a statement, not an expression. One would have to pollute the local scope with extra variables (like list). The simple idea of instantiating an empty append-protected list would be spread over two different lines in code. And this statement is still way longer than a simple .<String>empty(). The new List<String>() is a List<? extends String> only if it's in a context where the type inference expects a List<? extends String>. It's not so useful if you want to create an expression that guides type inference instead of relying on it.
                – Andrey Tyukin
                Jan 2 at 14:48


















              16














              I interpret "is it a useful signature" to mean "can you think of a use-case for it".



              T is determined at the call site, not inside the method, so there are only two things that you can return from the method: null or an empty list.



              Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it.





              Actually, another value that can be safely returned is a list where all of the elements are null. But this isn't useful either, since you can only invoke methods which add or remove literal null from the return value, because of the ? extends in the type bound. So all you've got is thing which counts the number of nulls it contains. Which isn't useful either.






              share|improve this answer























              • Well, looking very desperately for a contrived way of making it useful, you could have called a setReturnType(Class<?> cls) method on the same object beforehand, and then f() would use that information to return a list of the required type.
                – DodgyCodeException
                Jan 2 at 10:53






              • 1




                @DodgyCodeException I suppose - but this would be the protocol anti-pattern.
                – Boris the Spider
                Jan 2 at 11:38










              • "Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it." Really? Invoking .<String>empty() seems way more pleasant than invoking ((List<? extends String>) new List<String>()). How would you construct an expression of type List<? extends String> without such a method?
                – Andrey Tyukin
                Jan 2 at 14:45






              • 1




                @AndreyTyukin List<? extends String> list = new ArrayList<>();. Or even just new List<String> - that's a List<? extends String>.
                – Andy Turner
                Jan 2 at 14:45












              • @AndyTurner That's a statement, not an expression. One would have to pollute the local scope with extra variables (like list). The simple idea of instantiating an empty append-protected list would be spread over two different lines in code. And this statement is still way longer than a simple .<String>empty(). The new List<String>() is a List<? extends String> only if it's in a context where the type inference expects a List<? extends String>. It's not so useful if you want to create an expression that guides type inference instead of relying on it.
                – Andrey Tyukin
                Jan 2 at 14:48
















              16












              16








              16






              I interpret "is it a useful signature" to mean "can you think of a use-case for it".



              T is determined at the call site, not inside the method, so there are only two things that you can return from the method: null or an empty list.



              Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it.





              Actually, another value that can be safely returned is a list where all of the elements are null. But this isn't useful either, since you can only invoke methods which add or remove literal null from the return value, because of the ? extends in the type bound. So all you've got is thing which counts the number of nulls it contains. Which isn't useful either.






              share|improve this answer














              I interpret "is it a useful signature" to mean "can you think of a use-case for it".



              T is determined at the call site, not inside the method, so there are only two things that you can return from the method: null or an empty list.



              Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it.





              Actually, another value that can be safely returned is a list where all of the elements are null. But this isn't useful either, since you can only invoke methods which add or remove literal null from the return value, because of the ? extends in the type bound. So all you've got is thing which counts the number of nulls it contains. Which isn't useful either.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Jan 2 at 10:55

























              answered Jan 2 at 10:50









              Andy TurnerAndy Turner

              81.1k881136




              81.1k881136












              • Well, looking very desperately for a contrived way of making it useful, you could have called a setReturnType(Class<?> cls) method on the same object beforehand, and then f() would use that information to return a list of the required type.
                – DodgyCodeException
                Jan 2 at 10:53






              • 1




                @DodgyCodeException I suppose - but this would be the protocol anti-pattern.
                – Boris the Spider
                Jan 2 at 11:38










              • "Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it." Really? Invoking .<String>empty() seems way more pleasant than invoking ((List<? extends String>) new List<String>()). How would you construct an expression of type List<? extends String> without such a method?
                – Andrey Tyukin
                Jan 2 at 14:45






              • 1




                @AndreyTyukin List<? extends String> list = new ArrayList<>();. Or even just new List<String> - that's a List<? extends String>.
                – Andy Turner
                Jan 2 at 14:45












              • @AndyTurner That's a statement, not an expression. One would have to pollute the local scope with extra variables (like list). The simple idea of instantiating an empty append-protected list would be spread over two different lines in code. And this statement is still way longer than a simple .<String>empty(). The new List<String>() is a List<? extends String> only if it's in a context where the type inference expects a List<? extends String>. It's not so useful if you want to create an expression that guides type inference instead of relying on it.
                – Andrey Tyukin
                Jan 2 at 14:48




















              • Well, looking very desperately for a contrived way of making it useful, you could have called a setReturnType(Class<?> cls) method on the same object beforehand, and then f() would use that information to return a list of the required type.
                – DodgyCodeException
                Jan 2 at 10:53






              • 1




                @DodgyCodeException I suppose - but this would be the protocol anti-pattern.
                – Boris the Spider
                Jan 2 at 11:38










              • "Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it." Really? Invoking .<String>empty() seems way more pleasant than invoking ((List<? extends String>) new List<String>()). How would you construct an expression of type List<? extends String> without such a method?
                – Andrey Tyukin
                Jan 2 at 14:45






              • 1




                @AndreyTyukin List<? extends String> list = new ArrayList<>();. Or even just new List<String> - that's a List<? extends String>.
                – Andy Turner
                Jan 2 at 14:45












              • @AndyTurner That's a statement, not an expression. One would have to pollute the local scope with extra variables (like list). The simple idea of instantiating an empty append-protected list would be spread over two different lines in code. And this statement is still way longer than a simple .<String>empty(). The new List<String>() is a List<? extends String> only if it's in a context where the type inference expects a List<? extends String>. It's not so useful if you want to create an expression that guides type inference instead of relying on it.
                – Andrey Tyukin
                Jan 2 at 14:48


















              Well, looking very desperately for a contrived way of making it useful, you could have called a setReturnType(Class<?> cls) method on the same object beforehand, and then f() would use that information to return a list of the required type.
              – DodgyCodeException
              Jan 2 at 10:53




              Well, looking very desperately for a contrived way of making it useful, you could have called a setReturnType(Class<?> cls) method on the same object beforehand, and then f() would use that information to return a list of the required type.
              – DodgyCodeException
              Jan 2 at 10:53




              1




              1




              @DodgyCodeException I suppose - but this would be the protocol anti-pattern.
              – Boris the Spider
              Jan 2 at 11:38




              @DodgyCodeException I suppose - but this would be the protocol anti-pattern.
              – Boris the Spider
              Jan 2 at 11:38












              "Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it." Really? Invoking .<String>empty() seems way more pleasant than invoking ((List<? extends String>) new List<String>()). How would you construct an expression of type List<? extends String> without such a method?
              – Andrey Tyukin
              Jan 2 at 14:45




              "Given that you can create both of these values in roughly as much code as invoking this method, there isn't really a good reason to use it." Really? Invoking .<String>empty() seems way more pleasant than invoking ((List<? extends String>) new List<String>()). How would you construct an expression of type List<? extends String> without such a method?
              – Andrey Tyukin
              Jan 2 at 14:45




              1




              1




              @AndreyTyukin List<? extends String> list = new ArrayList<>();. Or even just new List<String> - that's a List<? extends String>.
              – Andy Turner
              Jan 2 at 14:45






              @AndreyTyukin List<? extends String> list = new ArrayList<>();. Or even just new List<String> - that's a List<? extends String>.
              – Andy Turner
              Jan 2 at 14:45














              @AndyTurner That's a statement, not an expression. One would have to pollute the local scope with extra variables (like list). The simple idea of instantiating an empty append-protected list would be spread over two different lines in code. And this statement is still way longer than a simple .<String>empty(). The new List<String>() is a List<? extends String> only if it's in a context where the type inference expects a List<? extends String>. It's not so useful if you want to create an expression that guides type inference instead of relying on it.
              – Andrey Tyukin
              Jan 2 at 14:48






              @AndyTurner That's a statement, not an expression. One would have to pollute the local scope with extra variables (like list). The simple idea of instantiating an empty append-protected list would be spread over two different lines in code. And this statement is still way longer than a simple .<String>empty(). The new List<String>() is a List<? extends String> only if it's in a context where the type inference expects a List<? extends String>. It's not so useful if you want to create an expression that guides type inference instead of relying on it.
              – Andrey Tyukin
              Jan 2 at 14:48













              1














              The official Generics tutorial suggests not to use wildcard return types.




              These guidelines do not apply to a method's return type. Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards."




              The reasoning given isn't exactly convincing, though.






              share|improve this answer




























                1














                The official Generics tutorial suggests not to use wildcard return types.




                These guidelines do not apply to a method's return type. Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards."




                The reasoning given isn't exactly convincing, though.






                share|improve this answer


























                  1












                  1








                  1






                  The official Generics tutorial suggests not to use wildcard return types.




                  These guidelines do not apply to a method's return type. Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards."




                  The reasoning given isn't exactly convincing, though.






                  share|improve this answer














                  The official Generics tutorial suggests not to use wildcard return types.




                  These guidelines do not apply to a method's return type. Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards."




                  The reasoning given isn't exactly convincing, though.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jan 2 at 11:53









                  Andy Turner

                  81.1k881136




                  81.1k881136










                  answered Jan 2 at 11:22









                  togorkstogorks

                  385




                  385























                      0














                      It's not particularly useful, for the reasons given in other answers. However, consider it's "usefulness" in a class like the following (although it's probably a bit of an antipattern):



                      public class Repository {
                      private List<Object> lst = new ArrayList<>();

                      public <T> void add(T item) {
                      lst.add(item);
                      }

                      @SuppressWarnings("unchecked")
                      public <T> List<? extends T> f() {
                      return (List<? extends T>) lst;
                      }

                      public static void main(String args) {
                      Repository rep = new Repository();
                      rep.add(BigInteger.ONE);
                      rep.add(Double.valueOf(2.0));
                      List<? extends Number> list = rep.f();
                      System.out.println(list.get(0).doubleValue() + list.get(1).doubleValue());
                      }
                      }


                      Note the following features:




                      1. The declared return type of f() means that the caller can set whatever T they like and the method will return the required type. If f() weren't declared like that, then the caller would need to cast every call to get(N) to the required type.

                      2. As it uses a wildcard, the declared return type makes the returned list read-only. This can often be a useful feature. When caller a getter, you don't want it to return a list you can write to. Often, getters use Collections.unmodifiableList() which forces a list to be read-only at run-time, but using the wildcard generic parameter forces the list to be read-only at compile-time!

                      3. The drawback is that it's not particularly type-safe. It is up to the caller to ensure that f() returns a type where T is a common superclass of all the previously added items.

                      4. It would typically be much better to make the class Repository generic instead of the method f().






                      share|improve this answer



















                      • 3




                        Wildcard lists aren't read-only. You can remove elements, you can add null to the list, and you can use a wildcard capturing helper method to add and reorder its own elements.
                        – Radiodef
                        Jan 2 at 14:37
















                      0














                      It's not particularly useful, for the reasons given in other answers. However, consider it's "usefulness" in a class like the following (although it's probably a bit of an antipattern):



                      public class Repository {
                      private List<Object> lst = new ArrayList<>();

                      public <T> void add(T item) {
                      lst.add(item);
                      }

                      @SuppressWarnings("unchecked")
                      public <T> List<? extends T> f() {
                      return (List<? extends T>) lst;
                      }

                      public static void main(String args) {
                      Repository rep = new Repository();
                      rep.add(BigInteger.ONE);
                      rep.add(Double.valueOf(2.0));
                      List<? extends Number> list = rep.f();
                      System.out.println(list.get(0).doubleValue() + list.get(1).doubleValue());
                      }
                      }


                      Note the following features:




                      1. The declared return type of f() means that the caller can set whatever T they like and the method will return the required type. If f() weren't declared like that, then the caller would need to cast every call to get(N) to the required type.

                      2. As it uses a wildcard, the declared return type makes the returned list read-only. This can often be a useful feature. When caller a getter, you don't want it to return a list you can write to. Often, getters use Collections.unmodifiableList() which forces a list to be read-only at run-time, but using the wildcard generic parameter forces the list to be read-only at compile-time!

                      3. The drawback is that it's not particularly type-safe. It is up to the caller to ensure that f() returns a type where T is a common superclass of all the previously added items.

                      4. It would typically be much better to make the class Repository generic instead of the method f().






                      share|improve this answer



















                      • 3




                        Wildcard lists aren't read-only. You can remove elements, you can add null to the list, and you can use a wildcard capturing helper method to add and reorder its own elements.
                        – Radiodef
                        Jan 2 at 14:37














                      0












                      0








                      0






                      It's not particularly useful, for the reasons given in other answers. However, consider it's "usefulness" in a class like the following (although it's probably a bit of an antipattern):



                      public class Repository {
                      private List<Object> lst = new ArrayList<>();

                      public <T> void add(T item) {
                      lst.add(item);
                      }

                      @SuppressWarnings("unchecked")
                      public <T> List<? extends T> f() {
                      return (List<? extends T>) lst;
                      }

                      public static void main(String args) {
                      Repository rep = new Repository();
                      rep.add(BigInteger.ONE);
                      rep.add(Double.valueOf(2.0));
                      List<? extends Number> list = rep.f();
                      System.out.println(list.get(0).doubleValue() + list.get(1).doubleValue());
                      }
                      }


                      Note the following features:




                      1. The declared return type of f() means that the caller can set whatever T they like and the method will return the required type. If f() weren't declared like that, then the caller would need to cast every call to get(N) to the required type.

                      2. As it uses a wildcard, the declared return type makes the returned list read-only. This can often be a useful feature. When caller a getter, you don't want it to return a list you can write to. Often, getters use Collections.unmodifiableList() which forces a list to be read-only at run-time, but using the wildcard generic parameter forces the list to be read-only at compile-time!

                      3. The drawback is that it's not particularly type-safe. It is up to the caller to ensure that f() returns a type where T is a common superclass of all the previously added items.

                      4. It would typically be much better to make the class Repository generic instead of the method f().






                      share|improve this answer














                      It's not particularly useful, for the reasons given in other answers. However, consider it's "usefulness" in a class like the following (although it's probably a bit of an antipattern):



                      public class Repository {
                      private List<Object> lst = new ArrayList<>();

                      public <T> void add(T item) {
                      lst.add(item);
                      }

                      @SuppressWarnings("unchecked")
                      public <T> List<? extends T> f() {
                      return (List<? extends T>) lst;
                      }

                      public static void main(String args) {
                      Repository rep = new Repository();
                      rep.add(BigInteger.ONE);
                      rep.add(Double.valueOf(2.0));
                      List<? extends Number> list = rep.f();
                      System.out.println(list.get(0).doubleValue() + list.get(1).doubleValue());
                      }
                      }


                      Note the following features:




                      1. The declared return type of f() means that the caller can set whatever T they like and the method will return the required type. If f() weren't declared like that, then the caller would need to cast every call to get(N) to the required type.

                      2. As it uses a wildcard, the declared return type makes the returned list read-only. This can often be a useful feature. When caller a getter, you don't want it to return a list you can write to. Often, getters use Collections.unmodifiableList() which forces a list to be read-only at run-time, but using the wildcard generic parameter forces the list to be read-only at compile-time!

                      3. The drawback is that it's not particularly type-safe. It is up to the caller to ensure that f() returns a type where T is a common superclass of all the previously added items.

                      4. It would typically be much better to make the class Repository generic instead of the method f().







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Jan 2 at 13:55

























                      answered Jan 2 at 13:42









                      DodgyCodeExceptionDodgyCodeException

                      3,3191424




                      3,3191424








                      • 3




                        Wildcard lists aren't read-only. You can remove elements, you can add null to the list, and you can use a wildcard capturing helper method to add and reorder its own elements.
                        – Radiodef
                        Jan 2 at 14:37














                      • 3




                        Wildcard lists aren't read-only. You can remove elements, you can add null to the list, and you can use a wildcard capturing helper method to add and reorder its own elements.
                        – Radiodef
                        Jan 2 at 14:37








                      3




                      3




                      Wildcard lists aren't read-only. You can remove elements, you can add null to the list, and you can use a wildcard capturing helper method to add and reorder its own elements.
                      – Radiodef
                      Jan 2 at 14:37




                      Wildcard lists aren't read-only. You can remove elements, you can add null to the list, and you can use a wildcard capturing helper method to add and reorder its own elements.
                      – Radiodef
                      Jan 2 at 14:37


















                      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%2f54004821%2fis-t-list-extends-t-f-a-useful-signature-is-there-any-problem-with-it%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

                      Human spaceflight

                      Can not write log (Is /dev/pts mounted?) - openpty in Ubuntu-on-Windows?

                      File:DeusFollowingSea.jpg