What's the equivalent of C# IEnumerable in Java? The covariant-capable one, not the Iterable

c#, java

Solution

Java generics allow covariance only if explicitly declared via wildcards in order to provide stricter type safety. This works:

    Iterable<? extends A> a = new ArrayList<A>();
    Iterable<B> b = new ArrayList<B>();
    a = b;

However, note that you now cannot add anything via the reference `a` since it's declared to contain instances of some specific but unknown class, which might be A or any subclass thereof. The behaviour of wildcards is often counter-intuitive and can get very complex, so they should be used in moderation.

Problem

This covariance is possible in C#: ``` IEnumerable<A> a = new List<A>(); IEnumerable<B> b = new List<B>(); a = b; ... class A { } class B : A { } ``` This is not possible in Java: (Iterable: Seen in this question Java Arrays & Generics : Java Equivalent to C# IEnumerable<T>). ``` Iterable<A> a = new ArrayList<A>(); Iterable<B> b = new ArrayList<B>(); a = b; ... class A { } class B extends A { } ``` With Iterable, Java doesn't see those two collection are covariance Which iterable/enumerable interface in Java that can facilitate covariance? Another good example of covariance, given the same A class and B class above, this is allowed on both Java and C# : ``` A[] x; B[] y = new B[10]; x = y; ``` That capability is on both languages from their version 1. It's nice that they are making progress to make this a reality on generics. C# has lesser friction though in terms of syntax. Covariance is a must on all OOP languages, otherwise OOP inheritance will be a useless exercise, e.g. ``` A x; B y = new B(); x = y; ``` And that power should extend to generics as well. Thanks everyone for the answer and insights. Got now a reusable method with covariant-capable Java generics now. It's not the syntax that some of us wants, but it(`<? extends classHere>`) certainly fits the bill: ``` import java.util.*; public class Covariance2 { public static void testList(Iterable<? extends A> men) { for(A good : men) { System.out.println("Good : " + good.name); } } public static void main(String[] args) { System.out.println("The A"); { List<A> team = new ArrayList<A>(); { A player = new A(); player.name = "John"; team.add(player); } { A player = new A(); player.name = "Paul"; team.add(player); } testList(team); } System.out.println("The B"); { List<B> bee = new ArrayList<B>(); { B good = new B(); good.name = "George"; bee.add(good); } { B good = new B(); good.name = "Ringo"; bee.add(good); } testList(bee); } } } class A { String name; } class B extends A {} ``` Output: ``` The A Good : John Good : Paul The B Good : George Good : Ringo ``` In case anyone are interested how it look like in C# ``` using System.Collections.Generic; using System.Linq; public class Covariance2 { internal static void TestList(IEnumerable<A> men) { foreach(A good in men) { System.Console.WriteLine("Good : " + good.name); } } public static void Main(string[] args) { System.Console.WriteLine("The A"); { IList<A> team = new List<A>(); { A player = new A(); player.name = "John"; team.Add(player); } { A player = new A(); player.name = "Paul"; team.Add(player); } TestList(team); } System.Console.WriteLine("The A"); { IList<B> bee = new List<B>(); { B good = new B(); good.name = "George"; bee.Add(good); } { B good = new B(); good.name = "Ringo"; bee.Add(good); } TestList(bee); } } } class A { internal string name; } class B : A {} ```

Original source

Related problems