A few simple (and harmless) ColdFusion mistakes

This post is more than 2 years old.

This has been sitting in my "To Do" pile for a while and this morning Scott Stroz added a suggestion to help me complete this post. What are a few mistakes that ColdFusion programmers tend to make that are - for the most part - harmless? Here's a quick list, along with fixes, and as always, if my readers have some other suggestions, leave a comment.

1) Overusing Pound Signs
One of the more common mistakes folks new to ColdFusion make is knowing when they need to use pound signs. So for example:

<cfset person = {}> <cfset name = "Ray"> <cfset person.name = #name#>

The last line assigns the name variable to a structure key. The pound signs there is certainly valid CFML, but is also unnecessary. There are only two cases where you need pounds:

a) Within CFOUTPUT to tell ColdFusion to evaluate it as a variable
b) Within a string variable to tell ColdFusion to evaluate it as a variable

That second one may be a bit confusing - here is what I mean:

<cfset greeting = "Hello, #name#">


2) Using "throw away" variables

There are a few functions in ColdFusion that return a value that you don't really need. One of the best examples is arrayAppend. So you'll commonly see ColdFusion developers write the following:

<cfset p = []> <cfset temp = arrayAppend(p, "foo")> <cfset temp = arrayAppend(p, "goo")>

In the code block above, the temp variable is created and not used. The developer mistakenly thought they had to have "something" to catch the result. However, you don't. This works just as well:

<cfset p = []> <cfset arrayAppend(p, "foo")> <cfset arrayAppend(p, "goo")>


3) Using a name for a cfquery when you don't have a result set

Ok, so the first two tips were definitely harmless, but I think most folks agree they were also mistakes. This one I might get some push back on. When working with queries that do not return a result set, like an insert, update, or delete query, you do not need to use a name for the query tag. So for example:

<cfquery> delete from foo where id = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.id#"> </cfquery>

In the above query I left off the name since I'm not going to be working with any set of records returned from the query. (I also left off the datasource. Don't forget you can do that in ColdFusion 9!) Some may argue there's no harm in using the name. I agree. But if you are moving your queries into CFCs, then this is just one more thing you have to var scope. Less var scoping means less work!


4) Use of Evaluate when Struct functions are fine

This is one of my favorite ones and is the one Stroz reminded me of. One thing you often see ColdFusion developers doing is using evaluate to get a dynamic form field. So for example:

<cfset key = "firstname"> <cfset value = evaluate("form.#key#")>

This works perfectly fine, and isn't even that slow (a common warning used about the evaluate function), but it also isn't necessary. All of ColdFusion's built in scopes can be treated like a structure, and a structure provides an incredible simple way to get a key - bracket notation:

<cfset key = "firstname"> <cfset value = form[key]>

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Phillip Senn posted on 6/13/2011 at 10:00 PM

I think the phrase that's gaining popularity is "antipatterns". Could be wrong though.

Comment 2 by Ryan Vikander posted on 6/13/2011 at 10:02 PM

You could always do for #1:

<cfset greeting = "Hello, " & name>

Comment 3 by Craig S posted on 6/13/2011 at 10:05 PM

Just to prove you right, I'm going to strongly disagree with you on #3... the name might not have any real purpose in the code when you're doing a delete, update, or insert query, but the name does appear with the query in the debug output. I've found this can be helpful when debugging on a page that has a lot of queries running.

Comment 4 by Raymond Camden posted on 6/13/2011 at 10:08 PM

@PS: I always thought of 'anti patterns' as being a bit bigger.

@RV: Yep, exactly, but, I would say the form I have above is a bit easier to read. Especially if you had more punctuation around it.

@CS: Good point there. :)

Comment 5 by Rob Barthle posted on 6/13/2011 at 10:14 PM

Only pushback I'd give regarding query names in CFC's is if you scope variables in the local scope, there's no extra work involved to begin with in terms of var-scoping.

Comment 6 by Raymond Camden posted on 6/13/2011 at 10:15 PM

I'm one of those folks who -hate- using local.x for var scope declaration. I've used it - but rarely. To be clear, I'm very happy Adobe added a "formal" scope for it. I just don't like typing it.

Comment 7 by Peter Boughton posted on 6/13/2011 at 10:38 PM

I'd be tempted to say #3 doesn't belong in this list, as it's a different "class" of mistake to the others.

I guess if it was code like <cfquery name="temp"> then that'd be as depressing as the rest, but if it's descriptive it can be useful (even excluding the debugging benefit) - you could see it like the hint attribute of cfargument; a quick description of what the query does.

If you don't like typing "local.x" you can just setup a snippet/template so you can type cfqn{ctrl-j} and get <cfquery name="local.{cursor}"></cfquery> output ready for you to fill in.

Comment 8 by Robert Zehnder posted on 6/13/2011 at 10:39 PM

I admit I still cringe when I see unneeded pound signs in code.

Comment 9 by Rob Barthle posted on 6/13/2011 at 10:41 PM

@Ray that is interesting because I have the same visceral reaction to having to type &lt;cfset var variablename = "" /&gt; in a function. When Ben Nadel introduced me to var scoping a local scope in CF8 and putting all variables in there, only having to do it one time was like a dream. Now not having to do it at all is even more so.

To each their own, it seems. :-)

Comment 10 by Peter Boughton posted on 6/13/2011 at 10:43 PM

Oooh, and there's a #5 for you - this is something I hate seeing!

<cfargument name="firstname" type="string" required="true" default="" hint="first name" />

If I ever catch anyone red-handed putting a hint in that is (essentially) identical to the name, I think I may do something very painful to them! ;)

Same goes for stuff like this:
<cffunction name="setFirstname" hint="sets the first name">

argh!

Comment 11 by Raymond Camden posted on 6/13/2011 at 11:00 PM

@PB: There's a great section on comments in "Clean Code" that discusses that topic. I agree completely.

Comment 12 by David Hammond posted on 6/13/2011 at 11:01 PM

@Peter, I'm not sure if you intended it or not, but I think your example contains #6 too. AFAIK, there's never a reason to supply a default value if the argument is required.

Comment 13 by Daniel Heighton posted on 6/13/2011 at 11:12 PM

Just wanted to add another place you need the pounds can be in your rags. like cfloop list="" or cfdump var="" if you don't use them it treats it as a string text and loops through, or display the string respectively.

Comment 14 by Rich Hefter posted on 6/13/2011 at 11:32 PM

I also think a query name in #3 could be used for a querynbame.recordcount if you need to see how many records were updated or deleted?

Comment 15 by Raymond Camden posted on 6/13/2011 at 11:36 PM

@Rick: THat is returned, but in the result value, not the query name value. So you would do: <cfquery result="apples"> and it's in the apples struct. (Going by memory here - be gentle.)

Comment 16 by Alejandro Suarez posted on 6/14/2011 at 12:19 AM

4) it will work in some cases no?
eg: evaluate("#i#_type") i can use [i]_type? is that correct? thanks ray

Comment 17 by Raymond Camden posted on 6/14/2011 at 12:22 AM

If you were looking in the form scope, it would be:

value=form["#id#_type"]

Or

value=form[id & "_type"]

If you meant as a general variable, use variables[] instead of form[].

Comment 18 by AXL posted on 6/14/2011 at 12:40 AM

Could I also add this to the pound signs usage?

c) For creating a dynamic variable name

<cfset id = 1>
<cfset "user#id#" = "Ray">

Comment 19 by Raymond Camden posted on 6/14/2011 at 12:43 AM

I'd probably write that as

<cfset variables["user#id#"] = "Ray">

As for pound sign usage - see my comment to Ryan V. I think that's more readable in context. But you could also do

<cfset variables["user" & id] = "ray">

Comment 20 by Alejandro Suarez posted on 6/14/2011 at 12:56 AM

hey thanks that will be really helpful for me,

BTW: i think this other tip could be useful in your post

<cfif x is "a" or x is "b" or x is "c">
use:
<cfif listFindNoCase("a,b,c", x) is not 0>

Comment 21 by Raymond Camden posted on 6/14/2011 at 12:59 AM

I'll disagree with that one too. If you had more than 3 items, sure. But as 3 items I find it easier and more direct. Yes it's more typing, but it's also "logically" clearer.

And we are WAY now into the "personal opinion" ranch now. ;)

Comment 22 by AXL posted on 6/14/2011 at 1:14 AM

I was just trying to say that "#" can be used in a dynamic variable name. That's all.

Comment 23 by Raymond Camden posted on 6/14/2011 at 1:17 AM

Sure -but I'd still use variables[] - just as personal preference.

Comment 24 by AXL posted on 6/14/2011 at 1:21 AM

Me too. It was just an example.

Comment 25 by Jaana Gilbert posted on 6/14/2011 at 1:22 AM

I'm going to chime in on the #3 on insert.

If you plan on using
SET NOCOUNT ON /
Select @@identity as NewID
SET NOCOUNT OFF

You will need the name attribute in your cfquery.

<cfquery datasource="xxx">
SET NOCOUNT ON

INSERT INTO mytable
(
email
)
VALUES
(
<cfqueryparam xxx>
)

Select @@identity as NewID
SET NOCOUNT OFF
</cfquery>
<cfoutput>#NewID#</cfoutput>
That will throw an error:
"Variable NEWID is undefined. "

As soon as you put the name attribute in place, this works :)

Jaana

Comment 26 by Raymond Camden posted on 6/14/2011 at 1:25 AM

@Jaana: That syntax isn't required since CF8. Use result="foo" and it's returned in the structure.

Comment 27 by Jaana Gilbert posted on 6/14/2011 at 1:27 AM

Cool, thanks for correcting me :) I'll be reducing my code now :)

Comment 28 by Sharon posted on 6/14/2011 at 1:44 AM

<cfif listFindNoCase("a,b,c", x) is not 0>

Not getting into other debate, but you can do a short-circuit boolean with

<cfif listFindNoCase("a,b,c", x)>

No need to include the "IS NOT 0" or "NEQ 0".

Comment 29 by Chris Tierney posted on 6/14/2011 at 1:58 AM

Thanks for the query name tip, I never knew that. Though I'd probably still always use it to give me a hint of what the code is doing in both the code and debugging.

Comment 30 by Chris Giminez posted on 6/14/2011 at 2:09 AM

I have been wondering about the need to use cfqueryparam in a cfc where the data has already been "typed" by the cfargument tag. Isn't the cfqueryparam overkill at that point?

Comment 31 by Raymond Camden posted on 6/14/2011 at 2:12 AM

Having overkill for security is a bit like having too much money. It's a problem you want to have. That being said, the cfargument "protection" will validate data types, but nor prevent sql injection. Nor will it help the db perform better. You want the queryparam. :)

Comment 32 by Peter Boughton posted on 6/14/2011 at 2:26 AM

David wrote:
> I'm not sure if you intended it or not, but I think your
> example contains #6 too. AFAIK, there's never a reason
> to supply a default value if the argument is required.

Well, yes and no.

I did mean to refer to that and forgot (thanks for picking up on it), but your reading of it is slightly off.

If an argument is required, there *cannot* (logically) be a default, because a default can only come into play when a value is not supplied, and you're not allowed to not supply a required argument. (It's not quite a case of not being a *reason* to do it; the actual concept doesn't make sense.)

However, in CFML what happens is that the "default" attribute is looked at *before* the "required" attribute.
This means, if default exists, the required attribute is ignored altogether (which equates to being false).

Even in the above code where the attribute claims it is required, it is NOT actually required.

i.e. all three of these lines have the same functionality (remember, attribute order doesn't matter):

<cfargument name="firstname" default="" required="true" />
<cfargument name="firstname" default="" required="false" />
<cfargument name="firstname" default="" />

Hopefully that explanation makes sense?

The other point I was planning to make is about when people put bad defaults in - generally, either empty string or zero - instead of correctly setting required, and (if required false), using StructKeyExists to determine if a value has been provided or not.

Defaults should be used when they are helpful (basically, when an argument is most of the time a particular value, that should probably be the default, to simplify the calling code), but "data arguments" (things like firstname) should usually not have defaults (they are either required or optional).

Comment 33 by tof posted on 6/14/2011 at 5:06 AM

@Jaana: In any case, you should't use @@identity but SCOPE_IDENTITY() instead :-).

Comment 34 by PaulH posted on 6/14/2011 at 6:59 AM

didn't cf builder used to whine about cfquery tags without a name?

Comment 35 by Raymond Camden posted on 6/14/2011 at 8:29 AM

Don't know about CFB1, but CFB2 doesn't mind.

Comment 36 by Mihai Baboi posted on 6/14/2011 at 1:01 PM

Guilty on the first one. I'm always afraid that without the pound signs it won't evaluate as a variable.

And a bit off topic... I see you're very active on Twitter, yet you don't have a Twitter share button. It would be really nice if I could share easier. Thanks :)

Comment 37 by Raymond Camden posted on 6/14/2011 at 3:13 PM

I go back and forth about what "bling" to put on blog posts. BlogCFC has a "Share" toolbar that allows for hitting all the big services. My blog is blogcfc of course, but a different front end.

Comment 38 by Jim Partin posted on 6/14/2011 at 5:28 PM

Regarding the lack of name in a cfquery, does that affect how the execution plan is cached? I'm presuming that things like inserts and deletes with queryparams, forming a 'fingerprint' associated with the query name. Does not using a name break this 'fingerprint' and cause the loss of execution plan caching/reuse?

Comment 39 by Raymond Camden posted on 6/14/2011 at 5:30 PM

The name of the query is entirely a ColdFusion thing. The DB server doesn't know what you named it. So it has no impact on that.

Comment 40 by Martin posted on 6/14/2011 at 6:30 PM

I really want to add how much I hate capitalised
<CFTAGS/>

Sorry everyone. I feel better now.
ps Pardon my non US spelling :-)

Comment 41 by Jim Partin posted on 6/14/2011 at 7:27 PM

The DB doesn't know, but what about coldfusion in using, what is essentially, a prepared statement. If the name is not present, does it create a new prepared statement, or is the fingerprint of the sql query itself enough to inform it to use an existing one?

Comment 42 by Raymond Camden posted on 6/14/2011 at 7:32 PM

I don't think I quite understand you. As far as I know, the name of the query has _nothing_ to do with the prepared statement. All CF does is send the SQL and bound params. The name isn't meaningful in this context in anyway.

Comment 43 by larry c lyons posted on 6/14/2011 at 9:25 PM

# 1 drives me crazy all the time. All too often these days I see this sort of error. I suspect its a hold over from very early CF practices.

As for throw away variables. I may be wrong about this but didn't the earlier versions of CFWACK use this approach for a lot of its examples? Given the popularity of the book Ican see why this keeps appearing in code.

I didn't know about #3, I thought you always needed to use the name attribute. Like the datasource, is this CF9 only or does it work with earlier versions?

As for #4, yes. An idea for you Ray, given that you're the acknowledged leader of the "Evaluate?!?! We don't need no stinkin' Evaluate!!" movement, perhaps you could devote some blog space discussing when Evaluate is appropriate.

regards,
larry

Comment 44 by Jim Partin posted on 6/14/2011 at 9:31 PM

You're thinking of Coldfusion strictly as it's own language. Coldfusion is built on java and thus jdbc. Our coldfusion code gets compiled down into java byte code using those libraries, as evident by the fact that a coldfusion query resultset is extended from jdbc's RowSet classes. We also know that if one doesn't use cfqueryparams for variables or use cfifs to dynamically generate the query syntax, our queries are treated as ad-hoc queries.

So, when we DO use queryparams, that will get grinded down into the use of jdbc PreparedStatements classes, which allows the DB server to have a cached execution plan that is expected to run repeatedly with changing variables of the same data types, this also allows query caching to a degree on the DB server's side (as opposed to coldfusion caching with cachedwithin).

When coldfusion encounters your query with query params, it's going to created the PreparedStatement object and likely store it in some sort of java collection that acts as a cache. I would presume that in addition to the query name, page name, the query syntax itself, and possibly cffunction name are incorporated in some fashion to make a hash to use as a key to the PreparedStatement in the java collection for object reuse to reduce object instantiation overhead.

My Concern is that by not using a name, does that force the query's execution as adhoc in the udnerlying java? Does it still generate a fingerprint or hash to use a PreparedStatement? If it does, does it generate some sort of UUID each time that query is run, or does it intuitively know you want to use the same PreparedStement and use that uuid in place of the missing name, in which case everything could be fine.

Always keep in mind the underlying architecture.

Something to think about.

Comment 45 by Raymond Camden posted on 6/14/2011 at 10:19 PM

@Larry: I used to complain about evaluate a lot. But it's been "sped up" quite a bit in recent versions. Mainly now I only recommend against it when it isn't necessary. I use it nowadays in script-only CFCs when I need to execute a dynamic method. You can do it w/o evaluate in tags using cfinvoke, but not in script.

@Jim: I disagree completely about CF sending the query name, etc, to the DB. There is absolutely no reason the DB needs to know the query name or where it comes from. All the DB cares about is the SQL and the parameters. Period. Who cares if foo.cfc calls it and then goo.cfc calls it? If the same SQL is used then the same query plan should be reused. Shoot, even foo.aspx calls the DB I'd expect the same query plan to be used as well.

Comment 46 by Jim Partin posted on 6/14/2011 at 11:57 PM

I absolutely agree, the query name never gets sent to the DB. What I am addressing is the coldfusion side, how prepared statement handles are cached in the underlying jdbc architecture.

Unfortunately, not all databases agree with you in that if the query sql string is the same, the execution plan should be reused. DBs recognize 2 types of queries, adhoc and prepared. Prepareds are given a much higher priority by DBs for query execution plan caching as it's considered an optimized query for repetitive use. Non prepared queires, or adhoc, are give low exec plan caching (if any) in that they are presumed to be one-off queries from a tool or command line interface. There are significant performance differences between the two types of queries.

Back on the coldfusion side, you have the object instantiation of either a Statement object (adhoc), or a PreparedStatement object (non-adhoc). You don't keep around a Statement object in java memory, it's fire and forget since it's usually going to be treated as adhoc by the DB, especially if you have variables/flow logic in it, then it is indeed going to be a different query, and thus a new instantiation each time the query string changes.

When you use cfqueryparam, you are telling cf that you would really like to have a PreparedStatement. It looks to see if you have any flow logic or non-paramed variables. If the query is clean, you get a PreparedStatement object.

PreparedStatements are facts. The query never changes, it has placeholders for variables, but the query string itself does not change. This is beneficial in that the instantiated PreparedStatement (PS) object can be cached by coldfusion and repeatedly called instead of being reinstantiated over and over like a regular adhoc Statement object. Coldfusion, not the DB, would be the interested in knowing the name of the cfquery tag, as it should use that as part of the Key it would use to look up that PS object in it's Mixed Collection of PS objects acting as a cache. Since it needs to check if the query string has changed in order to ensure it's selecting the correct PS object, a oneway hash of both the name and the query string together, and potentially other things such as page, function name, etc, would generate a unique fingerprint key for the Mixed Collection PS cache. It finds a match, it uses that PS object instead of instantiating a new one, the DB is happy because it still has the handle reference from the last time the PS was used on that connection and thus remembers the exec plan and can run it quicker / potentially pull unchanged data from memory cache, and you have a very optimized system, both on the DB side and the CF side.

Everything is fine if during first pageload (compile time), it assigns a UUID behind the scenes as a name for that parameterized query, as then the rest of the system works as normal. But like not using full variable scopes to address your variables, does saving the 1-3 seconds to type name="qBlah", is it worth the performance loss of not being specific in your cfquery tag. It takes a few cycles longer to generate a UUID than to concatenate a string together for a hash. Perhaps on a small systems with little to medium usage, but on high activity systems, you'll want to squeeze out every piece of performance you can. A little bit of developer pain upfront saves cycles down the road and sets good practices for use elsewhere.

Given that you are a respected CF dev that many go to for advice and tips, you may want to re-emphasize the performance caveats of devs using the "harmless" mistakes in addition to your fixes. A ineperienced/time crunched dev seeing "harmless" will continue on his way without changing his bad habbit if pitfalls aren't explained. Perhaps "Mostly Harmless" is better in the title ;)

Comment 47 by Raymond Camden posted on 6/15/2011 at 12:01 AM

While I am not an expert in JDBC - I feel very strongly that you are incorrect here. But - I have no proof. Therefore - I'm going to the source. ;)

Comment 48 by Pete Freitag posted on 6/15/2011 at 1:30 AM

@Jim PreparedStatement caching can be handled by the JDBC driver itself, and isn't necessarily the onus of the Application (ColdFusion in this case). ColdFusion uses DataDirect JDBC drivers which support prepared statement caching via the Max Prepared Statement setting. You seam to be speculating that the query name is part cache key, I would imagine the SQL with parameter placeholders would be the cache key as that would be much more efficient. Have you proven this to be not the case?

Comment 49 by Peter Boughton posted on 6/15/2011 at 1:59 AM

> You can do it w/o evaluate in tags using cfinvoke, but not in script.

You can do that with without evaluate everywhere ...in Railo. ;)

It's been bugging me for ages that ACF doesn't support this syntax:

<cfset Variable = Object[FuncName](Args) />

I finally went and it added a feature request the other day, but I guess it needs more than just me to do so before Adobe might take notice...

Comment 50 by GrumpyCFer posted on 6/15/2011 at 3:09 PM

@Craig#3 Fully agree.

@Ray#6 @Rob#9 The use of "local." is CFCs is banned at my company. While the intention is good, the execution is dangerous and can introduce some nasty bugs. e.g. the scope of a variable can change (e.g. mid function) depending on where you declare the "local." version of that variable. So you either need to make sure you declare all "local." first, always use "local." everywhere, or never use a "local." variable that is the same name as other scoped variables. While it's possible to accomplish those things, it's a lot safer to require the declaration of a var scoped struct at the top of the function and use that, a la CF8.

@Alejandro#20 I prefer that as well. (but with NEQ)

@Sharon#28 We only allow short-circuiting on functions that actually return a boolean, so ListFindNoCase wouldn't be allowed. This is because we've had too many occurrences of developers thinking typeless like CF and then create bugs because their evaluation needed to be typed. The more we make them think typed the fewer of those bugs we experience.

@Ray#31 Double thumbs up and a cheesy smile.

@Larry#43 re: throw away... Yes, it was required a long time ago. Not now, tho.

Comment 51 by Raymond Camden posted on 6/15/2011 at 6:39 PM

From Rupesh Kumar of Adobe:

"Name of the query is used only as the name of the query variable. It is not used for caching of the statement or query result. Prepared statement is used irrespective of query name specified and its caching is taken care of by the driver."

Comment 52 by Sarah Kelly posted on 6/15/2011 at 11:24 PM

What are your thoughts on (in pseudo-code):
if (isDefined(someVar) AND someVar EQ 20)
vs
if (isDefined(someVar))
if (someVar EQ 20)

I have encountered some situations where I *think* the second is necessary (complex else situations), but as a general practice, it drives me crazy.

Comment 53 by Raymond Camden posted on 6/15/2011 at 11:30 PM

@Sarah: Meh, it depends. I think for 2 clauses then the first one is a lot more readable and sensible. At the end of the day - the real answer is - which is most easy to understand by you and your coworkers?

Comment 54 by Paul posted on 6/16/2011 at 9:29 PM

Another one that bothers me: Not self-closing tags that should be self-closed.

<cfset hello = "goodbye">

v.

<cfset hello = "goodbye" />

It works fine without it, but just seems wrong to me.

Comment 55 by Raymond Camden posted on 6/16/2011 at 9:30 PM

Oh I _definitely_ disagree with you there Paul. :) CFML isn't XML.

Comment 56 by Mihai Baboi posted on 6/16/2011 at 9:34 PM

I know it's strictly a personal preference but I like to close single tags too. Not only does it look better, but I find the code easier to read (especially for noobs like me the don't know for sure witch tags are single and witch are not).

Comment 57 by Paul posted on 6/16/2011 at 9:36 PM

It's certainly not xml, but it is tagged-based.

I suppose it's all opinion...

Comment 58 by Peter Boughton posted on 6/16/2011 at 9:45 PM

Except for being tag-based, CFML isn't anywhere near XML - and closing cfset (and other tags) doesn't make it XML.
(It does, however, give a nice visual aid when scanning large blocks of code, and is almost zero extra time typing.)

But this is *definitely* getting away from simple/harmless mistakes and into personal preferences, which tends to generate a lot of posts whilst not being constructive - because very few people even consider changing their style (assuming they even have one in the first place).

Comment 59 by larry c lyons posted on 6/16/2011 at 9:58 PM

You'd think that these annoyances would create some performance related issues. But it looks like they may not. When I set up a string concatenation in side a loop of over 50000 iterations.
For <cfset foo = foo + "Hello World" /> 15, 325 ms.
For <cfset foo = #foo# + "Hello World" /> 15,478 ms.

Comment 60 by Raymond Camden posted on 6/16/2011 at 9:59 PM

Well, that's why I titled this "harmless" mistakes. I don't think any of the issues I raised would have any performance issues.

As an aside - if you really do need to a lot of string concats, you should switch to Java instead. (I don't mean the entire page, but StringBuffers via createObject. And not StringBuffer, but whatever the 'newer' version of that is in the latest Java. Folks know what I mean.)

Comment 61 by larry c lyons posted on 6/16/2011 at 10:04 PM

Actually Ray, Java string concatenation is almost as slow. The fastest was using an ArrayAppend (127ms) then CFSaveContent (45ms) followed by java.lang.StringBuffer, 142 ms. Java string object concatenation (string.concat("Hello World") was as slow as CF concatenation at 16,580 ms.

Comment 62 by Raymond Camden posted on 6/16/2011 at 10:08 PM

I didn't say Java concat was fast - I specifically meant StrinfBugger (again though - there's something newer, isn't there?). I forgot about the array/cfsavecontent versions though. I remember someone (was it you maybe) talking about that a year or so ago.

Comment 63 by Peter Boughton posted on 6/16/2011 at 10:08 PM

StringBuilder is newer than StringBuffer, but it's not a direct replacement.
StringBuilder is slightly faster, but at the expense of not being thread-safe, whilst the older StringBuffer is thread safe.

(The difference between StringBuilder and StringBuffer is minuscule compared to the difference with immutable strings.)

Comment 64 by Raymond Camden posted on 6/16/2011 at 10:08 PM

StringBuilder is the "newer" class I was thinking of but couldn't remember.

Comment 65 by Raymond Camden posted on 6/16/2011 at 10:09 PM

Thanks Peter - your comment came in while I was typing mine and didn't see it. Sounds like StringBuffer then is still the one folks should use. (Or try an array as Larry suggests.)

Comment 66 by larry c lyons posted on 6/16/2011 at 10:11 PM

I was one of them commenting on this.

In this case I wanted to include the concat for comparison. I'm still surprised how fast the array methods are. Not something I would have expected given the array to list conversion I used as the last step within the timer.

Comment 67 by Raymond Camden posted on 6/16/2011 at 10:14 PM

Normally this is where I point out that these types of comparisons are fun - but not terribly useful in practical situations. But I ran into this in a big way in an Ajax app where I was generated a large response. Switching to Java helped tremendously.

Comment 68 by larry c lyons posted on 6/16/2011 at 10:22 PM

I included string builder in the mix, the time was within a few milliseconds of string buffer. Over 50,000 iterations, the differences are not significant

Comment 69 by Josh Curtiss posted on 6/17/2011 at 12:42 AM

Mistake #1 is a huge pet peeve of mine and immediately knocks my opinion of a developer down to "noob" status if I see them doing it. Which is fine if they are in fact new to CF...

Mistake #3: Been doing CF for 12 years and I never knew that.

Comment 70 by Josh Curtiss posted on 6/17/2011 at 12:45 AM

On the self-closing tags... I agree with Paul on this one.. When I look at my old code that didn't close CFSET and other tags like that, I cringe.. I totally know it's not necessary and CFML is not XML, but now that I do it, it feels wrong when it's not there. :-D

Comment 71 by Paul Connell posted on 6/20/2011 at 12:44 PM

As to #2, arrayAppend DOES have a return value, 'true' if the append works - so having temp there to catch that you could evaluate it to check the append was successful - but is there ever a situation where it is 'false' but doesn't throw a catchable error? (Just reading the CF8 docs here).

Comment 72 by Raymond Camden posted on 6/20/2011 at 3:12 PM

Not that I know of Paul.

Comment 73 by GDavis posted on 3/16/2012 at 9:46 PM

I know this is an old post, but I just need to get my opinion out there...

How is adding the pound symbol any more of a mistake then self closing a tag? They both personal preference and unnecessary.

Comment 74 by Raymond Camden posted on 3/16/2012 at 10:09 PM

I'd argue overuse of pound signs is more cosmetically disturbing then closing tags you don't have to. But this entire post is really just about _harmless_ things. :)

Comment 75 by Scott posted on 5/20/2013 at 11:01 PM

[Edited by Ray]

keep on getting the error: edit does not exist?

how do i fix ? :(

Comment 76 by Raymond Camden posted on 5/20/2013 at 11:17 PM

Scott, I've edited your comment. First, please do not post large blocks of code. As the form above says, use Pastebin or Gists instead. Second, if your comment does not relate to an issue described here, please consider using my contact form, or the cf-talk listserv, or my forums (link above) to ask your general CF question.

Comment 77 by dawesi posted on 12/16/2016 at 4:19 PM

Landed back here years later looking for something else... google now sucks and it's results suck more than bing in 2016... #irony google is back to it's humble beginnings with inaccurate searches... #anyway

I know this post is four years old, but these aren't mistakes, they are guidelines. Mistakes end up with an error, or a serious issue. None of these do, so they are no mistakes, just personal preferences.

"2) Using “throw away” variables"

counters are a great use of throw away variables ;-) #oneofmany request cleans them up fine.

"3) Using a name for a cfquery when you don’t have a result set"

Agree (sort of)... no CRUD query should have no result sets... no error reporting back what happened, not even for audit logs? #badpractice - did your delete effect 1 row or 100,000... #ouch - can't think of a reason why I wouldn't have a name or feedback about what happened... of course I always diff my db changes to the db or disk so they can be rewound and replayed without the offending transactions... I find this easier than to rewind and replay database transaction logs.

"4) Use of Evaluate when Struct functions are fine"

Basic use sure, but what about `<cfset bob="evaluate('#var#')"> where var = "one.two.three".... #lol evaluate is a great tool, but not for basic structs...

Comment 78 (In reply to #77) by Raymond Camden posted on 12/16/2016 at 4:32 PM

Replies inline:

"mistakes vs guidelines" Ok, fine, seems a bit picky, but I won't disagree.

"throw away variables" - I think I was pretty clear about the particular use case here that it applied to. I didn't say to not use counters.

"name for result sets" - tracking the result is a good example of when you would want it - sure.

"evaluate" - given that "one.two.three" is a valid CF variable (is it?) than the scope would work fine:

myval = variables[key]