Tuesday, March 6, 2012

Java has smarter foreach

Given this..

class Animal { 
}

class Dog extends Animal { 
}

class Cat extends Animal { 
}




..Java's compilation of for each is smarter than C#

So this would not compile in Java:

private static void testAnimal() {     
                                               
 Animal[] a = { new Dog(), new Cat() };                                            
                                                                                   
 for(Dog d : a) { // Type mismatch: cannot convert from element type Animal to Dog 
  System.out.println("Hey!");                                                    
 }                                                                                 
}                                                                                     

Whereas C# would happily compile the same construct:

static void testAnimal ()
{
 Animal[] a = { new Dog(), new Cat() };
 
 foreach(Dog d in a)
 {
  Console.WriteLine ("Hey!");
 }
}

But that relaxed foreach would bite you where it hurts the most, i.e. during runtime. The above construct will produce this output and error during runtime:


Hey!

Unhandled Exception: System.InvalidCastException: Cannot cast from source type to destination type.
  at ListInitializer.MainClass.testAnimal () [0x00017] in /Users/Michael/Projects/ListInitializer/ListInitializer/Main.cs:47 
  at ListInitializer.MainClass.Main (System.String[] args) [0x00000] in /Users/Michael/Projects/ListInitializer/ListInitializer/Main.cs:40 
[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidCastException: Cannot cast from source type to destination type.
  at ListInitializer.MainClass.testAnimal () [0x00017] in /Users/Michael/Projects/ListInitializer/ListInitializer/Main.cs:47 
  at ListInitializer.MainClass.Main (System.String[] args) [0x00000] in /Users/Michael/Projects/ListInitializer/ListInitializer/Main.cs:40 


Cat is not compatible with Dog.


Though if the intention is to really iterate all Dogs only, you can do so by using OfType extension method:


static void testAnimal ()
{
 Animal[] a = { new Dog(), new Cat() };
 
 foreach(Dog d in a.OfType<Dog>())
 {
  Console.WriteLine ("Hey!");
 }
}

As of the time of this writing, Java still doesn't support extension method, this is where C# clearly trumps Java


To approximate the same in Java, you have to use good collections library (e.g. Guava):

private static void testAnimal() {     
                                               
 Animal[] a = { new Dog(), new Cat() };                                            
                                                                                   
 for(Dog d : Iterables.filter(Arrays.asList(a), Dog.class)) { 
  System.out.println("Hey!");                                                    
 }  
}                     

No comments:

Post a Comment