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.
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 ->
"-"
}