Overriding Built-In ColdFusion Methods With Custom ColdFusion Component Methods

Posted November 29, 2006 at 1:54 PM by Ben Nadel

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:

  • <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:

  • <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.

  • <!--- 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.




Reader Comments

Dec 8, 2006 at 2:41 AM // reply »
1 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?


Dec 8, 2006 at 7:14 AM // reply »
11,246 Comments

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.


Mar 31, 2009 at 8:36 PM // reply »
1 Comments

Thanks Ben.
Just what I needed to override the toString() method in my component.


Sep 30, 2009 at 5:48 PM // reply »
7 Comments

This is really neat, way to think out of the box Ben!

I don't imagine there is any way to do this with ColdFusion tags? I would like to override the cfinclude tag to display the name of the file its including (would be great for tracking down display code within a framework).


Oct 1, 2009 at 7:58 AM // reply »
11,246 Comments

@Ryan,

You can always create a custom tag to do things like this. And, with CF8 and the usage of AttributeCollection, it becomes much easier:

<cf_location url="" addtoken="" />

... and then your tag internals (which I think work for the CFLocation tag):

<cflocation attributecollection="#attributes#" />

Then, of course, you do what ever you want before the CFLocation tag is actually executed.


Oct 1, 2009 at 9:15 AM // reply »
7 Comments

True, but that would require me to go through and change all my code. And the framework's core code.

But if you could override it, you could have each included file displayed with a border around it, with the file name displayed in it as well. Would be awesome for tracking down which display files you need to edit when you want to change something you are looking at.


Oct 31, 2009 at 10:24 PM // reply »
11,246 Comments

@Ryan,

Yeah, it would be kind of cool. I think Railo might let you do that stuff.


Jan 25, 2010 at 11:21 AM // reply »
1 Comments

I have found to my surprise that CF9 seems to allow for overriding system functions without this trick. I haven't found this documented anywhere yet but it doesn't complain about my trace() dump() toString() or any other such function.


Jan 25, 2010 at 9:02 PM // reply »
11,246 Comments

@David,

Really! That is very interesting. I'll have to take a look at the on my local machine. That could lead to some confusing / interesting approaches.


Sep 24, 2011 at 5:22 AM // reply »
2 Comments

@Ben,
David is totally right. In CF9 we can create function with same name that available in coldfusion, only issue with this is we need to scope with this to call same function within CFC.

I am looking for override now() function with additional argument timezone where it will automatically convert current server time to my timezone. I thought same way it may work in Application.cfc as well and it is but not able to call from my cfm/cfc due to no scope available to call Application.cfc function.

Any Idea?


Sep 24, 2012 at 11:11 AM // reply »
3 Comments

@Pritesh
The downside I've found to this is that if within public function a() you call private function b(), where b() is a function name ALSO used by ColdFusion, you can't do this.b() -- Coldfusion reports that it can't find the function b().

At this point, you are compelled to rename b() to something that doesn't collide with the ColdFusion built-in function.


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 25, 2013 at 10:08 AM
Using "//" And ".//" Expressions In XPath XML Search Directives In ColdFusion
@Ben, my question is that i want the current node with its tag and its parent node. i just want only that data. So, give me the solution for that. and remember solution is working on " xpath 1.0 ... read »
May 25, 2013 at 10:01 AM
Using "//" And ".//" Expressions In XPath XML Search Directives In ColdFusion
hey ben, i want get my current node tag and also want the root node tag withing. So, how can i fix it.. ! ... read »
May 24, 2013 at 5:39 PM
Ask Ben: Manually Enforcing Basic HTTP Authorization In ColdFusion
@Adam Oops! My mistake! I hadn't gotten that far in my testing - I'm still baby stepping my way through the process. ... read »
May 24, 2013 at 5:13 PM
Ask Ben: Manually Enforcing Basic HTTP Authorization In ColdFusion
Hi Jason, Thanks for checking up on that, but I still stand firm on my position. :) There are actually two listLast()'s in use, and you're right that the one using a space as a delimiter is fine. ... read »
May 24, 2013 at 4:45 PM
Ask Ben: Manually Enforcing Basic HTTP Authorization In ColdFusion
@Ben I have been lurking your site for quite some time, and haven't stepped up to comment until today. Thanks for all the great info - keep it up! @Adam I believe you are mistaken... as the commen ... read »
May 24, 2013 at 11:21 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, Ha ha, let's us never speak of justifying "##" notation again :P ... read »
May 24, 2013 at 11:18 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Ah, so it was indeed how I vaguely remembered it to be: A direct assignment value = users.id[ i ] causes value to retain the sticky datatype of the query column. Although unnecessary in ... read »
May 24, 2013 at 9:11 AM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Brandon, Hi, No, I haven't been able to do that. I have just kept it as it is. ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools