John from Cincinnati (no, not really) asks:
Actually I think you have it backwards. Think of UDFs first as a the code that you single unit (single function, black box, whatever) that you can use from multiple places. A CFC though is a collection of UDFs. We typically call them methods when inside a CFC.I have a question, as I am learning cfcs, and I am wondering is there a difference between cfcs and a UDF? From my understanding a cfc is a function that does something you want,and is something that you can call, and therefore use in other projects. Such as, have a date function that you can from other CF pages. Is this what a UDF is too? I don't seem to understand how the two are different, but I think that they must be.
You would normally use UDFs for operations that don't really relate to anything else. So for example, a UDF to do both a date and time format in one call is fairly simple, doesn't need anything else, and would be just fine by itself.
Now imagine a few other UDFs. One adds a record to the Users table. One reads a record. One delete. Etc. All these UDFs are related to each other. They all probably share a common variable for the datasource. You can probably share some code for the Add User and Edit User routines. These common functions would work nicely together in a common CFC.
Let me be clear. You wouldn't have to actually use a CFC. But the benefits of having these methods together, being able to share the same code and variables, make it more sensible to do so.
Let me also use this as an opportunity to bring up the ColdFusion Unconference again. If you are going to MAX this year, my first session is on code encapsulation options in ColdFusion. I talk about all the ways you can blackbox code and compare where and when you would use each.
Archived Comments
CFCs have the awesome power of inheritance, which makes an OOP approach possible in coldfusion. some people define CFCs as a class and the functions inside as objects of that class, not sure if pure OOP is possible but does make life a lot easier now with CFCs....
Hi Ray,
Cincinnati, well never been there:)
Thanks so much for clearing some of my confusion up!
I actually did not know that a cfc was a collection of udfs.
I see (at least a little) how you would use this now. That is, using a udf would be used for things that don’t relate to other things.
My thinking was to create a convert time function that would be used to change the time of the server time to my localtime. I did write a cfc for this. I was thinking that there should be a way to to create a function that would use my localtime as default.
I see on volume 2 of the CF WACK book(part V,chapter 24) covers this. I am still reading Volume I, and have not purchased this later volume, but I think that when I get to that one, this will become very clear.
Thanks so much for taking the time to write a blog post on this, and explaining this to me:)
I have to try and get some money to get to Max, I checked out some of the talks, sounds great.
Thanks Ray!
John
@shakti: Very good comment there. I was being overly simplistic in my response I think. OO things like inheritance, interface, or just design patterns in general, can make CFCs even more powerful. Certainly more than just a collection of methods, your CFCs really become a model for your application.
John,
In my humble opinion cfcs are the greatest thing since sliced bread and bottled beer. They definitely get you in the mindset of ultimate code re-use. One thing that I'll caution you on is to avoid an early trap that I fell into which was making mega cfcs. You're not charged by the file here so make lots of little cfcs whose functions belong together and try to avoid making one cfc to control the world. Here's an example of how I might separate logic in an app...
cfc name / purpose
appcommon.cfc / commonly used stuff like security validators and handlers, etc.
filemgmt.cfc / functions that I might use to generate ajax file tree data, data to get ajax grids related to cfdirectory queries, handling multiple file uploads, file renames, cfsearch and index stuff, etc.
customer.cfc / insert, update, delete statements for handling customer table records and maybe even functions with statements to handle subsidiary data related to customers, etc.
item.cfc / insert, update, delete statements for handling item table records and along with functions having statements to handle subsidiary data related to items, etc.
inventory.cfc / advanced logic to handle gathering records for item journal batches, posting to an item ledger, gathering qty. on hand, basically this cfc would have methods for things related to inventory
Now obviously this is a very simple example and for a big app I truly might end up with dozens of cfcs but I'll tell you that some of the first big apps that I wrote that were heavily powered by cfcs back on CF7 had a pretty serious flaw - they had 2 or 3 cfcs powering the entire app and some of these cfcs had well over 40 or 50 methods. It is not smart to build code like that because it becomes hard to maintain and hard to find things and when you start growing your operation and hiring more developers your cfcs can cause them to make mistakes or flat out lose their bearings because you've made them too all encompassing.
I'll stop rambling but trust me - lots of little cfcs with some thought up front in regards to cfc and method naming/system nomenclature that makes sense to you and your organization.
There are also some performance issues to consider when comparing CFC, UDF, and (though not mentioned here) custom tags.
"It takes relatively more processing time to instantiate a CFC than to process a custom tag. In turn, it takes substantially more time to process a custom tag than to execute a user-defined function (UDF). However, after a CFC is instantiated, calling a CFC method has about the same processing overhead as an equivalent UDF. As a result, you should not use CFCs in place of independent, single-purpose custom tags or UDFs. Instead, you should use CFCs to create bodies of related methods, particularly methods that share properties." (from "When to use CFCs" in the CF Docs)
Hi Andy,
Thanks so much for your advice.
I am starting to think that cfc are the coolest thing ever! I am just starting out, and so I have not figured out how to do too many things with them.
I am looking for re-usable code with cfc as well. I did not know(or even think about)the time to process a cfc, and I would most likly not(as a am a newbie) write really big cfcs, but I can see that people would want all the funtionally in a few files over many files. I am glad to hear about this "best practice" in the begining then learning the hard way later.
The more I play with cfcs the more I am learning about them,and I am liking them a lot! I am trying to write an application at school that will use a cfcs apprach.
Thanks again, as well as everbody else here, espeically Ray for all your advice.
John
@John,
Just to build a bit on what JC is outlining in his post, performance-wise. The reason a UDF is faster than a CFC is because it can be inline in a CFM: a CFFUNCTION tag at the top of the file (or in a common include, etc) is a true UDF, while a CFC is generally a collection of CFFUNCTION tags all wrapped up in the CFC's own CFCOMPONENT wrapper.
Hope that helps
I just wanted to add that UDFs could run into naming collisions with existing CF functions or new ones as the language develops, and this is the only encapsulation method that has this problem. CFX tags, custom tags and CFCs don't have this issue. One of the reasons some simply take their UDFs and wrap them up with CFCs.
@Jason Fisher
While inlining is in theory possible the compiler certainly doesn't do it. Since CF supports function pointers and metadata for UDFs inlining is incredibly difficult. It gets worse when you realize you can cfinclude another templates and thus would need to have the compiled function, not the inlined version available anyway. And even worse than that is that you can shadow a function with a variable assignment.
CF just doesn't do enough static analysis to be able to do this, and honestly I doubt you'd see very much gain. UDFs are fast, Wicked fast, and putting in the incredible time burning effort to add this kind of tiny performance improvement would likely not solve anyone's bottleneck.
(Currently UDFs are compiled to static inner classes on the pages. So calling them is little more than this.MYFUNC.runFunction(...), so you don't gain too much with an inlining)
@Elliot,
Thanks for the clarification on how the Java code is compiled. I certainly do NOT recommend inlining UDFs, but was simply trying to explain how could a UDF be faster than a custom tag? which had been stated above :)
-jfish