[Prev][Next][Index][Thread]

Re: Subject reduction fails in Java



   Delivery-Date: Fri, 19 Jun 1998 08:14:09 -0500
   Cc: hahosoya@cs.indiana.edu, David Turner <dnt@an-teallach.com>
   Date: Fri, 19 Jun 1998 09:13:52 -0400
   From: Philip Wadler <wadler@research.bell-labs.com>
   Errors-To: types-errors@cs.indiana.edu

   [------- The Types Forum ------ http://www.cs.indiana.edu/types -------]

   Haruo, Benli, Dave,

   This is the least of your problems.  Reduction, in the sense
   you define it, can easily change the meaning of a program,
   thanks to Java's notion of overloading.

   Original program prints "true".

     class Counterexample {
       static boolean overloaded (Object x) { return true; }
       static int overloaded (String s) { return 42; }
       static void m (Object x) { System.out.println(overloaded(x)); }
       public static void main (String[] args) {
	 m("hello");
       }
     }

   Reduced program prints "42".

     class Counterexample {
       static boolean overloaded (Object x) { return true; }
       static int overloaded (String s) { return 42; }
       static void m (Object x) { System.out.println(overloaded(x)); }
       public static void main (String[] args) {
	 System.out.println(overloaded("hello"));
       }
     }

A nice concise example illustrating a common pitfall for newbie
Java programmers. More details on Java's "pseudo compile-time
method resolution" at
http://www.javasoft.com/docs/books/jls/html/8.doc.html#227941:

  When a method is invoked, the number of actual arguments and
  the compile-time types of the argument are used, at
  compile-time, to determine the signature of the method that
  will be invoked.

Note that the "right" notion of reduction for Java would unfold
the program to:

     class Counterexample {
       static boolean overloaded (Object x) { return true; }
       static int overloaded (String s) { return 42; }
       static void m (Object x) { System.out.println(overloaded(x)); }
       public static void main (String[] args) {
         Object x = "hello";
	 System.out.println(overloaded(x));
       }
     }

Java won't brook any compile-time flow analysis that will let you
infer a type for arguments "tighter" than the declared type!

Why was Java designed so? Clearly, doing full run-time type
resolution (checking the exact type of the arguments at run-time,
and then choosing the "most refined" method body available) might
be too costly. So the decision taken was to record in the
bytecodes for the call (in the classfile) the actual signature
(well, signature modulo classloader) of the method that
compile-time resolution identifies as the target, and then to use
this signature to search at run-time on the subject for the
actual method.

But I wonder. Is there a "better" way of resolving this problem,
which would allow more accurate compile-time inference of
argument types to be used?

Best,

Vijay