I was talking with Daria Norris this morning about an odd cfcache issue she was seeing when I discovered a simple mistake that could completely break cfcache in your application. This isn't a bug, but it could be considered a backwards compatibility issue you want to look out for. For fun, I'll post her code, and you see if you can find the issue. You don't need to save it to your file system, just know that the the result is a page that never seems to cache.
<cfoutput>
This page was generated at #now()#<br>
</cfoutput> <cfparam name="url.id" default="no URL parm passed">
<cfoutput>The value of url.id = #url.id#</cfoutput>
<cfcache timespan="#createTimeSpan(0,0,10,0)#" usequerystring="true" />
Figured it out yet? ColdFusion 9 added the ability to use cfcache as a wrapper tag. This allows you to cache part of a file. So for example:
Normal, fast code.
<cfcache timespan="#createTimeSpan(0,0,10,0)#">
Slow code
</cfcache>
Fast code again.
In the block above, ColdFusion would save the result of the generated output inside the tag and cache it. Very handy for cases where you only need to cache part of a page. And yes - you can do it more than once on a page. So given that? Do you see the error?
<cfcache timespan="#createTimeSpan(0,0,10,0)#" usequerystring="true" />
It's the trailing /. To ColdFusion, this is the same as:
<cfcache timespan="#createTimeSpan(0,0,10,0)#" usequerystring="true"></cfcache>
So technically, ColdFusion was caching - but it was caching an empty fragment. Now - I know some people are kinda anal about using xhmlt looking code. I'm not. But even I will use that syntax from time to time. If you have a ColdFusion 8 site you want to quickly scan it for this before updating to ColdFusion 9.
Archived Comments
Another great reason for CFML developers to stop putting trailing slashes everywhere for no reason, please! :)
Justin,
I disagree. We should just be putting the trailing slash in the correct places.
I agree, the correct places are the places where they serve a purpose. This example was not one of those places ;)
And what would you define as 'serving a purpose'?
I frequently use:
<cfset var myVar = "value" />
I think it makes it more readable.
I agree with Scott. It tells me that the tag has ended and I don't need to go looking around for an ending tag. cfset may not be the best example (although I self-close them all the time as well), but what about calling a custom tag? Personally I want to know if I'm expecting to find an ending tag somewhere in the code. By self-closing it, the developer has explained to me his purpose.
With that said, I consider this use of cfcache with a self-closing tag a bug in ColdFusion because it is not the way other tags in CF work. Maybe Ray disagrees, but I say "bug". Look at it this way, if Adobe were to fx this bug, would it break anyone's code? I mean, are people "really" caching a blank spot of nothing? I think not :)
How is it different Jeff? <a /> == <a></a> IS exactly how other tags work. Can you show me an example of where it is not? Also, how would you fix this? Would you say something like, "No insides, treat like top level cache tag" - ok, but what if I cache content and in my business logic, there are times when nothing is output?
This is not a bug.
<cfcache/> != <cfcache>
where <a/> == <a><a/>.
So, by your logic, doing <cfcache timespan="#createTimeSpan(0,0,10,0)#" usequerystring="true"> should only cache a block of nothing at the top of the page.
Do you see the confusion here?
I guess its a fine line (bug, not a bug?). But it sure is confusing. Personally I don't think they should have changed it. There is no purpose what-so-ever to want to cache a block of nothing. So why change it? I say leave it the way it was in CF8.
<cfcache/> != <cfcache>
That's not what I said Jeff, not even close. I said
<cfcache/> = <cfcache></cfcache>
That's different.
"So, by your logic, doing <cfcache timespan="#createTimeSpan(0,0,10,0)#" usequerystring="true"> should only cache a block of nothing at the top of the page.
Do you see the confusion here?"
No, it should act as it has for 10 years. Cache the entire page. It is no different than any other custom tag where thisTag.hasEndTag == false.
"So why change it?"
They didn't change it. Basically, they made the tag _aware_ of it's insides. It's a developer mistake then to include nothing on the inside, and as I described, there may be cases where you DO cache nothing. For example, imagine if the slow process, 10% of the time, returns nothing. In that case, you still want the cache benefit.
I know that using self closing tags are a matter of preference, but the truth is ColdFusion isn't XML compliant. Tags like CFRETURN and CFELSE simply break if you try to apply XML rules to them.
I've found that if you don't use the self-closing syntax at all you have to do less debugging later, as Daria and Ray are demonstrating above.
I understand that CF is nto XMl compliant, but that does not mean that we can't use it as such. I find tags that are self closed are easier to read... especially custom tags where you may not be sure if a tag is 'auto closed', like <cfset>.
Not sure what is supposed 'break' by adding trailing slash to <cfretrun>. This code works perfectly fine:
<cffunction name="getStuff">
<cfreturn "stuff" />
</cffunction>
<cfdump var="#getStuff()#">
<cfelse> is a unique beast as there is no normal closing tag for it anyway (well, except for </cfif>)
You know what Scott,
You're right. Cfreturn does work on both my production CF9 and CF8 servers. However, I just tested on an older version of Railo that I use at home and it throws an error.
<shrug> or <shrug /> I if you prefer :)
I prefer <shrug />, because if you have <shrug> with no </shrug>, I will never know when you are done shrugging.
I come in on the side of no trailing slashes. CFML is not XML nor is it XHTML.
Trailing tags serve a purpose where they add meaningful context or add some intended behaviour. The use of a trailing slash is really like saying "Instead of providing a tag body and a closing tag for this tag, I'm just going to use the shorthand form and close the tag now with no body".
So Ray is spot on with his example. This:
<cfcache timespan="#createTimeSpan(0,0,10,0)#" usequerystring="true" />
.. is effectively this (which means you are trying to cache the empty tag body, i.e. not a bug):
<cfcache timespan="#createTimeSpan(0,0,10,0)#" usequerystring="true"></cfcache>
The most common use of trailing slashes in CFML is with custom tags and probably a very limited number of built-in tags (as above).
Where trailing slashes serve no purpose is where closing tags don't exist, hence where it makes little sense to use them. So this:
<cfset blah = "blah" />
... is effectively this:
<cfset blah = "blah"></cfset>
A closing </cfset> tag doesn't really exist, and in CF9 it's not handled well at all, so if you tried to use it (not that anyone would expect it to work) you'll get an error like this:
"Context validation error for tag cfset. The end tag </cfset> encountered on line 1 at column 24 requires a matching start tag."
We are just lucky (or unlucky, hehe) that <cfset /> and other tags don't throw a similar error.
I also think it's a fallacy that a trailing slash makes code more readable, or even should be used in an attempt to made code more readable, since that's clearly not the purpose of it. It's also much more readable to use indentation to identify nested code than it is to scan the end of each line for a trailing slash or no trailing slash.
IMO it's just a misunderstanding about what a trailing slash actually does, which can then lead to cases such as this. I'd much prefer that developers know when and why to use it.
(Sorry, that probably turned out more like a blog post than a comment...)
Just because you do not agree with some thing does not make it a 'fallacy'. I stated that I find it to be more readable. By calling that a 'fallacy' you are effectively calling me a liar.
I am fully aware of what a trailing slash does, as I am sure Daria does. The fact that she used one in the wrong place should not lead you to presume otherwise. I know this may surprise you, but people do, from time to time, make mistakes.
I will say it again, so that you can truly understand it is not a fallacy: I use trailing slashes on CF tags that do not require them because I personally find them easier to read. I also think that using a trailing slash in places where you might not need one - such as <cfset blah="blah" /> - makes it easier for people who may be seeing ColdFusion code for the first time to understand exactly what is going on.
I don't use trailing slashes in tags that don't require them as part of the CFML syntax rules. I've never run across any bugs or pitfalls by following this practice. To each their own.
Why don't we let the coldfusion remain the way it was. Its not xml, its not OOP's, by try to make it that way why not to just use java or xml or any other language for that matter. When we talk about code readability (<cfset x=20 /> or <cfset x=20>) are both readable to a cfml developer. CFML has it this way some tag have end tags some have not. Someone reading a code line oughta be a cfml programmer. Anybody else trying to figure that out has no business doing so. And if those "anybody" start doing it s/he is snatching my bread. :)
@Kerr - I do use trailing slashes in tags that do not require them as part of CFML. I've never run into any bugs or pitfalls by following this practice.
@Dinesh - Yes, both <cfset blah = " blah > and <cfset blah = "blah" /> are readable to CF developers, but what about someone who is just learning CF? Or someone who uses another language and is asked to support a CF app. The people might not be a 'cfml developer' but will need to look at code. BTW - if you think only CFML developers should look at CF code, how will we get new CF developers?
Liar is a strong word, sorry if you took it that way Scott because it's not at all what I meant. I was trying to say that the act of using a trailing slash to improve readability is a fallacy because that it not the purpose of it. If you find it more readable then that's cool, I'm not saying you'd lie about that.
My other points about readability are secondary; the way you scan code with your eyes (left edge not right edge), proper indentation, syntax highlighting, etc are probably far bigger indicators of where something starts and finishes. The trailing slash is almost never required in built-in CFML tags (again, custom tags are the big users of it) and therefore we hardly ever need to look for it.
Maybe you need to look up the word fallacy. I am telling you I believe adding a trailing slash when it is not required is easier to read and easier for non-cf developers to understand. You are calling that a fallacy. Basically, you are telling me its a mistaken belief.
Other things people look for when reading tag based code is the closing tags. If you take someone who has never seen ColdFusion code before it may be easier for them to understand what is going on with:
<cfinput type="checkbox" name="moo" value="blarg" />
As opposed to:
<cfinput type="checkbox" name="moo" value="blarg" >
If you are not used to reading/using CF, but are used to other tag based languages, you may spend time looking for the </cfinput>, which, based on the way you imply you code, will not be there.
Adding trailing slashes when not required to do so does not cause issues and, in my opinion, is easier to read - even if you think its a 'fallacy'.
Maybe 3rd time lucky... I mean the act of adding a trailing slash to improve readability is a false notion because that is not the intended purpose of a trailing slash. I'm purely speaking about the purpose.
I didn't say it's impossible for you to find it more readable after the fact, and I didn't call you a liar - if you think I did then I apologize.
However, using trailing slashes where they are not required (or not intended to be used) clearly caused an issue here with cfcache (as they would with some custom tags). They also cause issues in HTML 4.01 where no trailing slash or explicit closing tags are required. In those cases it's not a matter of personal preference because things literally won't work.
I love it that the blog posts I assume will get no comments end up getting a crap load. ;)
(Mistaken belief about readability no, mistaken belief about the purpose of a trailing slash - perhaps!)
Yes Ray :) Damn my tongue in cheek comment.
If adding a trailing slash improves readability, even for one person, how is it 'false'? I add the slash mostly for readability, so, I would argue that in the case of <cfset blah = "blah" />, if it makes i easier to read and understand the code, then it has served its intended purpose.
I would also argue that if adding a trailing slash (or closing tag, even) on a custom tag caused issues, then the custom tag was poorly written.
Lastly, adding a trailing slash when it is not required will not cause any issues with HTML 4.01....at all. I use trailing slashes in CF tags all the time, and have done so for years, and have never had a time where it caused issues with CF processing the code, or any rendering issues with HTML 4.01.
Ever seen a self closing script tag work in IE? Ever had a HTML 4.01 document pass validation without warnings when littered with <img /> and <a /> tags?...
I'm not making this stuff up, it can actually have consequences... as already demonstrated.
The purpose of the trailing slash in my CF code is to show that the tag in question is now 'closed'. You and I both know its not necessary, but a new developer or one not familiar with CF might not know that <cfset> or <cfinput> don't need a trailing slash and look for the 'closing' tag. I had to explain this issue to someone quite a while ago, and that is part of the reason why I started adding trailing slashes.
Adding trailing slashes DOES NOT mess with the way CF processes the code (except poorly written custom tags), WILL NOT mess with the rendering of any HTML and WILL LIKELY help others read/understand the code, so I am not sure what the fuss is about.
Adding proper spacing serves nu purpose other than for readability, and I have seen cases where extra spaces from indenting code DID cause issues with HTML rendering, so one could argue that indenting code is also a bad practice.
Justin, Last time I checked <img> and <a> are NOT CF code. I was not referring to HTML tags, I was referring to CF tags. You do understand the difference, right?
"Lastly, adding a trailing slash when it is not required will not cause any issues with HTML 4.01....at all."
Sorry, I thought you meant HTML 4.01 tags, my bad.
It should be noted that this code:
http://pastebin.com/1sKGfqvu
Note the trailing slash does validate for HTML 4.01 Strict - though, admittedly, there are warnings against it.
Of course there are warnings, the spec says that it's an empty element - aka the closing tag must be omitted ;)
I have been wondering why I have not seen those warnings before when validating HTML - because I use <img src="blah" ... /> all the time. It hit me this AM. I typically use XHTML strict doctype. I cannot say I exclusively use it, but I cannot recall the last time I did not.