Why is an array not assignable to Iterable?

JavaLanguage Design

Java Problem Overview


with Java5 we can write:

Foo[] foos = ...
for (Foo foo : foos) 

or just using an Iterable in the for loop. This is very handy.

However you can't write a generic method for iterable like this:

public void bar(Iterable<Foo> foos) { .. }

and calling it with an array since it is not an Iterable:

Foo[] foos = { .. };
bar(foos);  // compile time error 

I'm wondering about the reasons behind this design decision.

Java Solutions


Solution 1 - Java

Arrays can implement interfaces (Cloneable and java.io.Serializable). So why not Iterable? I guess Iterable forces adding an iterator method, and arrays don't implement methods. char[] doesn't even override toString. Anyway, arrays of references should be considered less than ideal - use Lists. As dfa comments, Arrays.asList will do the conversion for you, explicitly.

(Having said that, you can call clone on arrays.)

Solution 2 - Java

The array is an Object, but its items might not be. The array might hold a primitive type like int, which Iterable can't cope with. At least that's what I reckon.

Solution 3 - Java

Arrays ought to support Iterable, they just don't, for the same reason that .NET arrays don't support an interface that allows readonly random access by position (there is no such interface defined as standard). Basically, frameworks often have annoying little gaps in them, which it's not worth anyone's time to fix. It wouldn't matter if we could fix them ourselves in some optimal way, but often we can't.

UPDATE: To be even-handed, I mentioned .NET arrays not supporting an interface that supports random access by position (see also my comment). But in .NET 4.5 that exact interface has been defined and is supported by arrays and the List<T> class:

IReadOnlyList<int> a = new[] {1, 2, 3, 4};
IReadOnlyList<int> b = new List<int> { 1, 2, 3, 4 };

All is still not quite perfect because the mutable list interface IList<T> doesn't inherit IReadOnlyList<T>:

IList<int> c = new List<int> { 1, 2, 3, 4 };
IReadOnlyList<int> d = c; // error

Maybe there is a possible backward compatibility gotcha with such a change.

If there's any progress on similar things in newer versions of Java, I'd be interested to know in the comments! :)

Solution 4 - Java

Unfortunately, arrays aren't 'class-enough'. They don't implement the Iterable interface.

While arrays are now objects that implement Clonable and Serializable, I believe an array isn't an object in the normal sense, and doesn't implement the interface.

The reason you can use them in for-each loops is because Sun added in some syntatic sugar for arrays (it's a special case).

Since arrays started out as 'almost objects' with Java 1, it would be far too drastic of a change to make them real objects in Java.

Solution 5 - Java

The compiler actually translates the for each on an array into a simple for loop with a counter variable.

Compiling the following

public void doArrayForEach() {
	int[] ints = new int[5];

	for(int i : ints) {
		System.out.println(i);
	}
}

and then decompiling the .class file yields

public void doArrayForEach() {
    int[] ints = new int[5];
    int[] var2 = ints;
    int var3 = ints.length;

    for(int var4 = 0; var4 < var3; ++var4) {
        int i = var2[var4];
        System.out.println(i);
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondfaView Question on Stackoverflow
Solution 1 - JavaTom Hawtin - tacklineView Answer on Stackoverflow
Solution 2 - JavaGareth AdamsonView Answer on Stackoverflow
Solution 3 - JavaDaniel EarwickerView Answer on Stackoverflow
Solution 4 - JavajjnguyView Answer on Stackoverflow
Solution 5 - Javadas KeksView Answer on Stackoverflow