« Closures in Java: Too Much Typeing! | Main | JavaOne and JavaFX: I Think I've Been Here Before »

Groovy and (Dynamic Dispatch|Multiple Dispatch|MultiMethods): A Simpler Example

So my last entry on static vs. dynamic dispatch and how it interacts with method overloading got caught up in some weird rules relating to the automatic promotion of primitive types. Now I have concocted an example that runs, unmodfied, in both Java and Groovy. Caution: This is a code heavy post.

public class BabyColors {
    
    String color(Boy b) { return "Blue"; }
    String color(Girl g) { return "Pink"; }
    String color(Baby a) { return "Green"; }
    
    String whatColor(Baby a) { return color(a); }
    
    public static void testDirect() {
        BabyColors bc = new BabyColors();
        Baby a = new Baby();
        Baby bb = new Boy();
        Baby bg = new Girl();
        Boy b = new Boy();
        Girl g = new Girl();
        bc.color(a);
        bc.color(bb);
        bc.color(bg);
        bc.color(b);
        bc.color(g);
    }
    
    public static void testIndirect(int iterations) {
        BabyColors bc = new BabyColors();
        Baby a = new Baby();
        Baby bb = new Boy();
        Baby bg = new Girl();
        Boy b = new Boy();
        Girl g = new Girl();
        bc.whatColor(a);
        bc.whatColor(bb);
        bc.whatColor(bg);
        bc.whatColor(b);
        bc.whatColor(g);
    }
    
    public static void main(String[] s) {
        BabyColors bc = new BabyColors();
        Baby a = new Baby();
        Baby bb = new Boy();
        Baby bg = new Girl();
        Boy b = new Boy();
        Girl g = new Girl();
        System.out.println("Indirect -------");
        System.out.println("unknown   - " + bc.whatColor(a));
        System.out.println("baby boy  - " + bc.whatColor(bb));
        System.out.println("baby girl - " + bc.whatColor(bg));
        System.out.println("     boy  - " + bc.whatColor(b));
        System.out.println("     girl - " + bc.whatColor(g));
        System.out.println("Direct ---------");
        System.out.println("unknown   - " + bc.color(a));
        System.out.println("baby boy  - " + bc.color(bb));
        System.out.println("baby girl - " + bc.color(bg));
        System.out.println("     boy  - " + bc.color(b));
        System.out.println("     girl - " + bc.color(g));
    }
}

class Baby {}
class Boy extends Baby {}
class Girl extends Baby {}

Seems simple enough, rather than using virtual methods to store the information as to what color a baby blanket you would buy for a co-workers new baby. If it's a buy, you get blue. If it's a girl, you get pink. Not sure? Green. The Baby color class keeps this information because, after all, babies don't know what color blanket they should have. You throw an old beach towel on some of them when they sleep and they will be happy (not that I've done this...).

Ok, back to the post. What will Java output? Think about this before you scroll down too far. Java looks a the types it can prove at compile time and fixes the method it will call based on the type the variable is claiming to be, not the type it actually is at run time. So when we filter all of the calls to color through an intermediary that only accepts Baby objects it will treat them as thought that's all they can ever be, Babys. Even if the compiler knows at the time that the call is being processed that the type must be a boy or a girl, it forgets all of that information when it goes into the whichColor method. Now when the color method is called directly, in the two instances where the type of the object is declared to be a Boy or a Girl the gender specific variant is called.

Now there is the dynamically typed method dispatch (or multiple dispatch, or multimethods) which on current generation JVMs is about a thousand times slower. Java itself doesn't support this invocation style, but Groovy supports this style as the only style of method invocation. At runtime when you invoke a method on an object, the actual instances of the types of the object are inspected and compared against all of the available overloaded method signatures. Hence regardless of the declared type of the object, the overloaded method that is selected will be closest to the particular class type and interfaces types of the passed in object.

So how do the languages process the above code? Well Java does the type safe thing and always buys green, unless it know it must be a boy or a girl.

Indirect -------
unknown   - Green
baby boy  - Green
baby girl - Green
     boy  - Green
     girl - Green
Direct ---------
unknown   - Green
baby boy  - Green
baby girl - Green
     boy  - Blue
     girl - Pink

Groovy on the other hand, peeks into the babies diaper and buys the appropriate color, unless it can't do that.

Indirect -------
unknown   - Green
baby boy  - Blue
baby girl - Pink
     boy  - Blue
     girl - Pink
Direct ---------
unknown   - Green
baby boy  - Blue
baby girl - Pink
     boy  - Blue
     girl - Pink

Comments (2)

John "Z-Bo" Zabroski:

How is the Java example different from compile-time type erasure on parameterized types? See: http://angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html

At least, I think what you are talking about is compile-time type erasure.

Danno Ferrin [TypeKey Profile Page]:

Quite a bit different actually. Type erasure is more of a case of static typing where the types are known at compile time and then erased to a more generic type (if I understand erasure properly). Meta-Methods do all of the type matching at the actual time the method is called, that's what is causing the 1000x performance hit on a method call. Erasure abstracts most of it away at compile time.

While in this case it is trivial to insure what the actual type of the parameter to the color() method will be, in general the multiple dispatch technique examines the type at runtime. If you consider that after this file, via various tricks with Groovy we could introduce a class Grrl extends Girl and and method color(Grrl grr) {return "Red";}, do this all at runtime, and the Meta-Object-Protocol will make it work.

Post a comment


About

This page contains a single entry from the blog posted on May 2, 2007 1:11 PM.

The previous post in this blog was Closures in Java: Too Much Typeing!.

The next post in this blog is JavaOne and JavaFX: I Think I've Been Here Before.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33