Overriding Built-In ColdFusion Methods With Custom ColdFusion Component Methods

Posted November 29, 2006 at 1:54 PM

Tags: ColdFusion

ColdFusion has a TON of amazing functions built right into. The problem (in a weird way) with some of these functions is that they have great names. This is a good thing most of the time, but sometimes, a function name is so good that you want to use it for another purpose. Image a situation where you have a custom data type. You might want to slap a ToString() method on it, DataType::ToString(). Or what about a bean that has some sort of validation issues. You might want to slap an IsValid() method on it, Bean::IsValid().

If you try to define these methods within the ColdFusion component you are creating as such:

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • displayname="Bean"
  • output="false">
  •  
  • <cffunction
  • name="IsValid"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="Determines if bean data is valid.">
  •  
  • <!--- For testing just return true. --->
  • <cfreturn true />
  • </cffunction>
  •  
  • </cfcomponent>

... ColdFusion throws the compile-time error:

The names of user defined functions cannot be the same as built-in ColdFusion functions. The name IsValid used for a user defined function is the name of a built-in ColdFusion function.

This is a shame since IsValid() would be such a sweet member method of the ColdFusion component right? You have two options at this point: One, choose a different name or Two, declare the method indirectly using method pointers.

Option one is lame. Why change the name of the method you want just because ColdFusion doesn't like it. The reason you chose the name (and the reason ColdFusion has a method with the same name) is because that name rocks! If that name were a girl, you would take it out the movies and buy it dinner. Let's not run and hide.

Option two is the one I would suggest. It is slightly kludgy but it accomplishes exactly what you want it to do with minimal work. Remember, the errors we get her are compile time errors, not run time errors. Also remember that pretty much everything in ColdFusion is an object, including variables and user defined functions. We can use this to our advantage.

To get around the compile time issue, we simply cannot name the function exactly how we want it to be named. Sorry. But, we can name a variable with that name. Then, at run time, we can set that variable to point towards the method we want. This, for all intents and purposes, is the same thing as defining a method with the chosen name. Here is the above example with our method:

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • displayname="Bean"
  • output="false">
  •  
  • <!--- Set method access pointers. --->
  • <cfset THIS.IsValid = $IsValid />
  •  
  • <cffunction
  • name="$IsValid"
  • access="private"
  • returntype="boolean"
  • output="false"
  • hint="Determines if bean data is valid.">
  •  
  • <!--- For testing just return true. --->
  • <cfreturn true />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="IsNotValid"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="Determines if bean data is not valid.">
  •  
  • <cfreturn NOT THIS.IsValid() />
  • </cffunction>
  •  
  • </cfcomponent>

Notice that in the ColdFusion component's pseudo constructor (the code outside of method definitions), I am creating a public, THIS-scoped variable of the same name (as the member function I want to create). I am setting this variable to be a pointer to the first class object which is our private, VARIABLES-scoped member method. When I declare the method I prepend the name with the "$" to make sure the code compiles. Since the method gets validated at compile time, this ColdFusion component does not have any parsing errors. However, since the pseudo constructor runs a run time, we end up with a public, THIS-scoped method with our desired name.

 Launch code in new window » Download code as text file »

  • <!--- Create the bean. --->
  • <cfset objBean = CreateObject( "component", "Bean" ) />
  •  
  • <!--- Call test methods. --->
  • #objBean.IsValid()#
  • #objBean.IsNotValid()#

... gives us:

true
NO

Now, when calling this method from within the ColdFusion component (say from the IsNotValid() method), you MUST scope the method call. If you do not, ColdFusion first looks in its list of methods before checking the scopes of the ColdFusion component itself. Not scoping will result in the error:

Parameter validation error for function IsValid. The function allows 3 parameters, but found 0.

Personally, I think scoping all of your method calls is a good idea any way. To me, this ups readability of the code. The down side of this is that since we calling a scoped variable (IsValid) then we have to use the appropriate scope during the method invocation. This however, should not be a big deal, but something to note.

If anyone knows of a way to do this WITHOUT having the intermediary step, I am all ears.

Download Code Snippet ZIP File

Comments (2)  |  Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page




Adobe ColdFusion 8.0.1 Update - Helping Programmers To Be Signifanctly Less Girlie - Download ColdFusion 8 Update 8.0.1 Now.

Reader Comments

I'd say its better to pick a different name and to bite the bullet rather than using method pointers because doing so breaks inheritance.

If you extend your object and redefine the $IsValid method and do not explicitly redefine the this.IsValid variable then method calls with call the old method. Subclasses shouldn't need to maintain function pointers in super classes either.

How about BeanIsValid() instead?

Posted by Elliott Sprehn on Dec 8, 2006 at 2:41 AM


Elliot,

You make a good point. Due to my limited OOP experience, I do not always think about a solution's implications within an OOP environment (such as one that would use "extend"tion).

As far as just biting the bullet, I suppose you are correct. However, there are going to be times when I am certain a class will never be extended, and when they do, I can handle it then. I am not quite ready to bite the bullet as of yet... I just don't like the idea of redundancy in method and variable names. If I am in a bean, there really is no reason that any of the methods (99%) of the time should have "bean" or the class's name should be in any variable or method name... if you are in a bean all those methods and variables relate to that bean.

But again, I have limited to experience with such matters, so I might have to come down off my pedestal and do as you suggest. And, to be honest, that is mostly what I have been doing as thw whole pointer thing just occurred to me a few weeks ago and I have been using CFCs since MX6.

Posted by Ben Nadel on Dec 8, 2006 at 7:14 AM


Post Comment  |  Ask Ben


Home   |   Web Log   |   ColdFusion   |   Projects   |   Resume   |   Job Form   |   Search   |   Contact
Epicenter Consulting - Custom Software Solutions for Business Evolution HostMySite.com - The Leader In ColdFusion Hosting