Thursday, January 05, 2006

Creating ColdFusion’s missing ‘instanceof’ method

Yesterday I was going back over some ColdSpring code, implementing some new features, and I came across the answer (sort of) to a question I remember being discussed a while back on CVCDev or topica. How do you find out if an object is an instance of a particular cfc or one of it’s subclasses? Unfortunately, ColdFusion doesn’t have the keyword ‘instanceof’ like Java and C#, which I suppose is far more commonly used in a strongly typed language. Why would it be more necessary? Well, for one thing the O’Reilly C# book I have advocates the use of instanceof before casting, alleviating ClassCastExceptions, but that’s another story. Anyway, I have run into a few situations in ColdFusion where I really need this functionality. So how do we do this in CF? Well, when I looked at what I had written a few months ago, although it works ok, the comment below it, ‘shouldn’t I be looking in the ‘extends’ key only?’, basically pointed out that it was a shotty implementation at best (btw, I looked back over the history of the file, and the original comment was ‘this sucks, I need to do this better later!’), so I asked Sean what he thought about it. Here’s something along the line of the original code I sent him, the main problem here being that by using StructFind() I am searching every key in every nested struct:

<cffunction name="isInstanceOf" access="public" returntype="Boolean" output="false">
  <cfargument name="obj" type="any" required="true"/>
  <cfargument name="reqType" type="string" required="true" />
  <cfif ArrayLen(StructFindValue(getMetaData(obj), reqType, "ALL"))>
    <cfreturn true />
  <cfelse>
    <cfreturn false />
  </cfif>
</cffunction>


Sean immediately pointed out that that was ok, but slow. Maybe I should search recursively through the extends keys of the metadata. So here’s what I ended up with, which seems a heck of a lot tighter to me. I shied away from the recursive method call, because that seemed it would be putting a little extra overhead on the search, but this implementation seams nice to me, thank for the input Sean!

<cffunction name="isInstanceOf" access="public" returntype="Boolean" output="false">
  <cfargument name="obj" type="any" required="true"/>
  <cfargument name="reqType" type="string" required="true" />
  <cfset var searchMd = getMetaData(obj) />
  <cfif searchMd.name IS reqType >
    <cfreturn true />
  <cfelse>
    <cfloop condition="#StructKeyExists(searchMd, "extends")#">
       <cfset searchMd = searchMd.extends />
       <cfif searchMd.name IS reqType>
         <cfreturn true />
       </cfif>
    </cfloop>
  </cfif>
  <cfreturn false />
</cffunction>

6 Comments:

Anonymous Chris Rockett said...

Hal Helms uses a similar technique in his baseComponent.cfc although I think your way is cleaner.

He draws a distinction between instanceOf and kindOf using the former for an exact match and the later for any parent the object may extend.

I'm not sure how other languages do it but it seems his way is a little more flexible, what do you think?

6:44 AM  
Blogger Chris Scott said...

If you would like to have just an exact match function, you could simply return searchMd.Name IS reqType for that method, and then you could have both. Instanceof in Java includes all superclasses, so you kind of ask for what your looking for there.

2:44 PM  
Anonymous Jason Sheedy said...

Nice one Chris. I've been looking for something like this. Does is work on java objects? I don't suppose the getMetadata() function works for java object...haven't used it before, so I'm not sure. Only one way to find out. I guess I'll give it a try. :)

4:51 PM  
Anonymous Jason Sheedy said...

Chris, I've made a modification to your code. I hope you don't mind. I add functionality to the method to test Java obects as well. It seems to be pretty efficient, but there may be a better way to do it. You can see it here.

http://cdscott.blogspot.com/2006/01/creating-coldfusions-missing.html

7:46 PM  
Anonymous Jason Sheedy said...

Oops .. it's here.

http://www.jmpj.net/jason/index.cfm?mode=entry&entry=F0CA5269-CF1D-76B8-A5C87D160216A7C1

7:47 PM  
Blogger Chris Scott said...

Hey Jason, that looks pretty sweet. I think adding a check for java types is a nice addition. Hmm, maybe I should be coming up with a CF8 wish list, instanceof would definitely be on it!

8:11 PM  

Post a Comment

<< Home