Search code examples
groovyoperator-overloading

Why doesn't the plus operator overload work for strings in Groovy?


I was able to achieve an operator overlay for my class, but I can't achieve it for String in any way. Why?

static void main(String[] args) {
    String.metaClass.plus = {
        r -> return "-";
    }

    print "left" + "right"
}



//I tried and so:
static void main(String[] args) {
    String.metaClass.plus = {
        r -> return "-".toString();
    }

    print "left".toString() + "right".toString()
}

Example from Groovy online compiler

Update.

I managed to achieve the desired result. I just added the String type to the anonymous function parameter.

//Old - non-working version.
String.metaClass.plus = {
    r -> "-";
}

//New - working version.
String.metaClass.plus = {
    String r -> "-";
}

The question remains the same, why didn't the old version work and the new one works? In the lesson that I'm watching, everything works well, ChatGPT also said that everything should work.


Solution

  • Groovy already has plus overloaded (the behaviour you are seeing).

    Your version String.metaClass.plus = { "-" } implies this version: String.metaClass.plus = { Object it -> "-" } (by default groovy closures have a default single argument it, which is of type Object (or def in groovy-speak).

    So now there are two plus on String and the JVM picks the best match, when calling it (polymorphism at work)... which is not yours, because Object is more generic than CharSequence for your example arguments.

    So you can force your version like this:

    static void main(String[] args) {
        String.metaClass.plus = { "-" }
        print "left" + 42 // ⇒ -
    } 
    

    Forcing the type of the argument to String -- like you did in your working example -- makes your function now the chosen one, when called with a String argument (and maybe any argument, because Groovy might coerce).

    Note beside:

    Writing closures like

    {
        String r -> "-"
    }
    

    is extremely misleading to the reader. Arguments are usually kept in the line with the opening brace.

    { String r -> 
        "-"
    }