Overload vs Override, Java vs Groovy

Groovy is one of my favorite languages. It is simple yet powerful. More importantly, it can be integrated into Java stack easily, bringing us thousands of libraries that are ready to use.

One interesting thing about Java and Groovy is the difference in treating overload. A lot of scripting languages do not have function overloading. For example, in Python you need to use named parameters if you want to have some kinds of workaround for that. In JavaScript you need to check if a parameter is defined manually in the function, which brings complexity and lacks intuition. Same things happen to Matlab, where you have to check the number of arguments like the old C code:

int main(int argc, char** args);

Java has overloading, and it is reasonable that Groovy also has overloading. However, they treat overloading differently.

Java dispatch overloading during compile time. In other words, it is fixed and cannot be changed during run-time. However, as a dynamic language, Groovy dispatch overloading at run-time, which causes a different result in the following program.

//Java Code
public class TestJava
{
   public void print(Object a)
   {
      System.out.println("Object");
   }


   public void print(String a)
   {
      System.out.println("String");
   }

   public static void main(String[] args)
   {
      TestJava test = new TestJava();
      String s = "Hello World";
      Object o = s;
      test.print(s);
      test.print(o);
   }
}
//Groovy Code
class TestGroovy {
    public void print(Object a)
    {
        System.out.println("Object");
    }


    public void print(String a)
    {
        System.out.println("String");
    }

    public static void main(String[] args)
    {
        TestGroovy test = new TestGroovy();
        String s = "Hello World";
        Object o = s;
        test.print(s);
        test.print(o);
    }
}

These two pieces of code are identical to each other, except for the class name. However, the results are quite different. In Java, the output is String and Object, while in Groovy, the output is String and String.

What if we call the Java code in Groovy, and call the Groovy code in Java?

//Java Code
public class TestJava
{
   public void print(Object a)
   {
      System.out.println("Object");
   }

   public void print(String a)
   {
      System.out.println("String");
   }

   public static void main(String[] args)
   {
      String s = "Hello World";
      Object o = s;
      TestGroovy groovy = new TestGroovy();
      groovy.print(s);
      groovy.print(o);
   }
}
//Groovy Code
class TestGroovy {
    public void print(Object a)
    {
        System.out.println("Object");
    }


    public void print(String a)
    {
        System.out.println("String");
    }

    public static void main(String[] args)
    {
        String s = "Hello World";
        Object o = s;
        TestJava java = new TestJava();
        java.print(s);
        java.print(o);
    }
}

For the Java code, the output is String and Object, and for Groovy, String and String.

This experiment tells us the only deciding factor of which kind of dispatch method is being used is your code type that you are actually writing. If you are writing Java, not matter you are referring a code from Java or Groovy,  overloading functions are dispatched at compile time. If you are writing Groovy, overloading functions are dispatched at run time. This brings us a very essential problem: we need to be really careful with overloaded functions that come from Java library when we are writing Groovy code: it is the devil in the detail.

The good news is that, for function override, both Java and Groovy treat it in run-time and share the same behaviour.

Leave a Reply

Your email address will not be published. Required fields are marked *