Thursday, February 25, 2010

Concerning deep*$#!%

How do Arrays.deepToString, deepHashCode, deepEquals handle self-containing arrays? Inconsistently, apparently...
import java.util.Arrays;

public class LetsGetToTheBottomOfThis {
   
   public static Object[] selfContainingArray() {
      Object[] arr = new Object[1];
      arr[0] = arr;
      return arr;
   }
   
   public static void main(String[] args) {
      try {
         System.out.println(
            Arrays.deepToString(
               selfContainingArray()
            )
         );
      } catch (StackOverflowError e) {
         System.out.println(e);
      } // prints "[[...]]"

      try {
         System.out.println(
            Arrays.deepHashCode(
               selfContainingArray()
            )
         );
      } catch (StackOverflowError e) {
         System.out.println(e);
      } // stack overflows

      try {
         System.out.println(
            Arrays.deepEquals(
               selfContainingArray(),
               selfContainingArray()
            )
         );
      } catch (StackOverflowError e) {
         System.out.println(e);
      } // stack overflows
   }
   
}
This behavior is documented clearly, so I suppose it's not exactly a bug (which is why it's not in the database, or else I would've submitted it). It is curious, though, why deepToString is made cycle-aware and the rest aren't. I admit that deepEquals will be made quite complicated, but deepHashCode is essentially the same as deepToString.
Also, this suggests to me the need for some sort of visitor pattern as well.
Update 03/01: OK, it's a bit worse than I thought: this inconsistency is also there with List (where presumably you favor safety to efficiency).
Note: While it is permissible for lists to contain themselves as elements, extreme caution is advised: the equals and hashCode methods are no longer well defined on such a list.

No comments:

Post a Comment