Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

c#

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 {}
like image 973
Hao Avatar asked May 19 '12 11:05

Hao


2 Answers

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.

like image 128
Michael Borgwardt Avatar answered Sep 27 '22 21:09

Michael Borgwardt


Generics are not covariant in Java. You'll have to do it the old way, like it was when C# didn't support covariance in generics.

However, in Java, you can pretend a generic iterable is an iterable of anything, denoted by a question mark. A list of anything contains only objects.

Iterable<A> a = new ArrayList<A>();
Iterable<?> b = a;
like image 40
Daniel A.A. Pelsmaeker Avatar answered Sep 27 '22 22:09

Daniel A.A. Pelsmaeker