Groovy Operator Overloading Does Not Work In The ColdFusion Context

Posted September 18, 2009 at 10:15 AM by Ben Nadel

Tags: ColdFusion

Disclaimer: I just started looking into Groovy so a lot of this might be dead wrong.

When I watched Barney Boisvert talk about Groovy, one of the first things that I wanted to try was operator overloading. It's been a really long time since I've played around with a programming langauge that even allowed it, so the prospect of implicitly handling the (+) operator with underlying logic was extremely titilating. To experiment with this concept, I took my Class instantiation demo from yesterday, paired it down, and added the method, Person::enterRelationship() (NOTE: I have moved my Groovy Factory code into a CFInclude as it had no immediate value in these demos):

  • <!--- Import the CFGroovy tag library. --->
  • <cfimport prefix="g" taglib="../cfgroovy/" />
  •  
  • <g:script>
  •  
  • <!---
  • Include the groovy factory. This will put an instance
  • of the "GroovyFactory" into the variables scope:
  •  
  • varibles.groovyFactory = new GroovyFactory();
  • --->
  • <cfinclude template="./groovyfactory.groovy.cfm" />
  •  
  •  
  • <!--- ------------------------------------------------- --->
  • <!--- Groovy Class Definitions ------------------------ --->
  • <!--- ------------------------------------------------- --->
  •  
  •  
  • class Person {
  •  
  • private def name = "";
  •  
  • public Person( String name ){
  • this.name = name;
  • }
  •  
  • public String getName(){
  • return( this.name );
  • }
  •  
  • <!---
  • This method allows a relationship to be created as a
  • behavior made available from a given person instance.
  • --->
  • public Object enterRelationship( person ){
  • return(
  • new Relationship( this, person )
  • );
  • }
  •  
  • };
  •  
  •  
  • <!--- ------------------------------------------------- --->
  • <!--- ------------------------------------------------- --->
  •  
  •  
  • class Relationship {
  •  
  • def private Person person1;
  • def private Person person2;
  •  
  • public Relationship(
  • Person person1,
  • Person person2
  • ){
  • this.person1 = person1;
  • this.person2 = person2;
  • }
  •  
  • public String toString(){
  • return(
  • (
  • person1.getName() +
  • " is dating " +
  • person2.getName() +
  • " ... awesome!"
  • ).toString()
  • );
  • }
  •  
  • };
  •  
  • </g:script>
  •  
  •  
  • <!--- Create a girl. --->
  • <cfset sarah = groovyFactory.get( "Person" ).init( "Sarah" ) />
  •  
  • <!--- Create a boy (using a slightly different syntax). --->
  • <cfset ben = groovyFactory.get( "Person" ).init( "Ben" ) />
  •  
  • <!--- Create a relationship. --->
  • <cfset relationship = ben.enterRelationship( sarah ) />
  •  
  • <!--- Output the relationship string. --->
  • <cfoutput>
  • #relationship.toString()#<br />
  • </cfoutput>

As you can see in the Groovy classes above, the call to Person::enterRelationship() is a proxy call to [new Relationship()], using the target person and the given person instances as the two people being used to form the new Relationship instance. We haven't done any operator overloading yet, but we've set up the context for it. And, when we run the code, we get the appropriate Relationship output:

Ben is dating Sarah ... awesome!

Now that we have our Person::enterRelationship() method, let's overload the plus (+) operator. Since I view (+) as more of a "gesture" and short-hand for forming a relationship between two peopl, what I'm gonna hve it do is have it (the plus operator) turn around and call the enterRelationship() method. This way, we centralize the logic for forming relationships. You'll notice that I am overloading the plus (+) operator by providing the Person class with a plus() method:

  • <!--- Import the CFGroovy tag library. --->
  • <cfimport prefix="g" taglib="../cfgroovy/" />
  •  
  • <g:script>
  •  
  • <!---
  • Include the groovy factory. This will put an instance
  • of the "GroovyFactory" into the variables scope:
  •  
  • varibles.groovyFactory = new GroovyFactory();
  • --->
  • <cfinclude template="./groovyfactory.groovy.cfm" />
  •  
  •  
  • <!--- ------------------------------------------------- --->
  • <!--- Groovy Class Definitions ------------------------ --->
  • <!--- ------------------------------------------------- --->
  •  
  •  
  • class Person {
  •  
  • private def name = "";
  •  
  • public Person( String name ){
  • this.name = name;
  • }
  •  
  • public String getName(){
  • return( this.name );
  • }
  •  
  • <!---
  • This method allows a relationship to be created as a
  • behavior made available from a given person instance.
  • --->
  • public Object enterRelationship( person ){
  • return(
  • new Relationship( this, person )
  • );
  • }
  •  
  • <!---
  • This plus() method is an operator overload method
  • that will handle allow us to implicitly handles calls
  • like (person + person).
  • --->
  • public Object plus( Person person ){
  • return(
  • this.enterRelationship( person )
  • );
  • }
  •  
  • };
  •  
  •  
  • <!--- ------------------------------------------------- --->
  • <!--- ------------------------------------------------- --->
  •  
  •  
  • class Relationship {
  •  
  • def private Person person1;
  • def private Person person2;
  •  
  • public Relationship(
  • Person person1,
  • Person person2
  • ){
  • this.person1 = person1;
  • this.person2 = person2;
  • }
  •  
  • public String toString(){
  • return(
  • (
  • person1.getName() +
  • " is dating " +
  • person2.getName() +
  • " ... awesome!"
  • ).toString()
  • );
  • }
  •  
  • };
  •  
  • </g:script>
  •  
  •  
  • <!--- Create a girl. --->
  • <cfset sarah = groovyFactory.get( "Person" ).init( "Sarah" ) />
  •  
  • <!--- Create a boy (using a slightly different syntax). --->
  • <cfset ben = groovyFactory.get( "Person" ).init( "Ben" ) />
  •  
  • <!--- Create a relationship using PLUS operator overloading. --->
  • <cfset relationship = (ben + sarah) />
  •  
  • <!--- Output the relationship string. --->
  • <cfoutput>
  • #relationship.toString()#<br />
  • </cfoutput>

As I was writing this code, I could barely contain my excitement; which, is why I was completely heart broken when running the above code threw the following ColdFusion error:

The value Person cannot be converted to a number.
coldfusion.runtime.Cast$NumberConversionException: The value Person cannot be converted to a number. at coldfusion.runtime.Cast._double()

To make sure I wasn't doing something wrong, I re-ran the code, this time putting the "meat" of it back into the Groovy context (I have removed the redudandant code for clarity):

  • <!--- Import the CFGroovy tag library. --->
  • <cfimport prefix="g" taglib="../cfgroovy/" />
  •  
  • <g:script>
  •  
  • <!--- ... PREVIOUS CODE ... --->
  •  
  • <!--- Create two people. --->
  • def ben = new Person( "Ben" );
  • def sarah = new Person( "Sarah" );
  •  
  • <!---
  • Create a relationship between these two people using
  • the Groovy operator overloading (plus operator).
  • --->
  • def relationship = (ben + sarah);
  •  
  • <!--- Output the relationship as a string. --->
  • println( relationship );
  •  
  • </g:script>

Notice that this time, since we are in the Groovy context, I don't have to explicitly call toString() on the resultant Relationship object. That is because Groovy will access the existing toString() method when it needs to implicitly convert a given object to a string (such as is required by the println() function). This time, when we run the above code, the plus operator (+) overloading successfully calls the Person::enterRelationship() method and we get the following output:

Ben is dating Sarah ... awesome!

Operator overloading is definitely an awesome concept; but, unfortunately, it looks like the operator overloading functionality provided by the Groovy language does not extend beyond the Groovy context. Once we move out of Groovy and back into the ColdFusion context, ColdFusion tries to perform math with the plus (+) operator, which is why it threw an exception above, trying to convert the Person instance into a numeric value.




Reader Comments

Sep 18, 2009 at 1:28 PM // reply »
25 Comments

I don't actually know this for fact, but my suspicion is that the method overloading in Groovy is implemented as compiler trickery, much the same way varargs are implemented in both Groovy and Java. Since your CFML doesn't run through the Groovy compiler, it doesn't get that syntactic sugar. However, you can still use the 'plus' method (which is what the Groovy compiler is converting the '+' into):

[cfset relationship = ben.plus(sarah) /]

You lose some of the elegance of an operator, but you still retain the 'addition' semantic.


Sep 18, 2009 at 1:31 PM // reply »
11,238 Comments

@Barney,

Ah, ok that makes sense. It would have been cool though :)


Sep 18, 2009 at 1:45 PM // reply »
25 Comments

Yeah, it'd be awesome if it worked, but oh well. Groovy does stuff at both compile time and runtime, and it's not always obvious where a given feature is implemented until it fails in the CFML context (and therefore is a compile-time feature).


Sep 18, 2009 at 1:47 PM // reply »
11,238 Comments

The question is - what to play with next :)


Sep 18, 2009 at 1:57 PM // reply »
45 Comments

Slightly off-topic, but the operator overloading stories are some of my favorites at thedailywtf.com :) Definitely worth reading if you have some free time.


Sep 18, 2009 at 3:57 PM // reply »
11,238 Comments

@Roland,

Ha ha, I guess anything can get out of hand.


Nov 21, 2009 at 11:03 AM // reply »
2 Comments

Hi Ben, Thanks for this informative post. Now I am reading ur old posts too


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
May 20, 2013 at 4:24 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I thought when you used array notation to reference queries you always had to have the row or it would throw a similar error as well? ... read »
May 20, 2013 at 11:45 AM
Using jQuery's Animate() Step Callback Function To Create Custom Animations
This is really useful. I found out that you don't actually have to use a dummy css property (surprisingly). To animate a property in a linear-gradient for instance I did this this.css('someLinearGra ... read »
May 20, 2013 at 10:51 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Josh, Oh snap! You're totally right! I'm not sure I've ever tried that. I did know that you can call a number of other array-methods on ColdFusion query columns: http://www.bennadel.com/blog/167 ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools