Learning ColdFusion 9: CFScript Updates For Tag Operators

Posted July 24, 2009 at 9:33 AM

Tags: ColdFusion

ColdFusion 9 has made a number of upgrades to CFScript. Yesterday, I explored the CFScript-based updates in ColdFusion Components; today, I wanted to take a quick look at the other CFScript operators that were added to mimic ColdFusion tag functionality. When it comes to these tag operators, we have two basic kinds: those that have content bodies, such as CFThread and CFLock, and those that do not, such as CFParam and CFExit. Service-based tags that have bodies, such as CFMail and CFHTTP, are handles as actual ColdFusion components, not as operators, and will be covered in a later post.

To be completely honest, I find the tag operators to be very inconsistent. Some of them use name-value attribute pairs; some use anonymous strings; some can use either attribute pairs or anonymous strings, but not both (ex. property); some can use comment-based, JavaDoc style attribute definitions; some even have function-based alternatives (ex. throw); and some tags don't even have operator or object-based script equivalents (ex. CFContent)! It seems to be all over the map as far as implementation goes. When it comes down to it, I think you simply have to memorize what goes where and how specific tags operators are implemented (if they're implemented at all) - deduction doesn't seem to be an option.

That said, let's take a look at the tag operators that do not have content bodies. I won't be covering the CFProperty tag operator as that was discussed in the previous post. As this is really just a lesson in syntax, I'll leave most of my explanation in the comments.

 Launch code in new window » Download code as text file »

  • <cfscript>
  •  
  • // Import a component name space for use with the NEW
  • // opeartor.
  • //
  • // NOTE: You cannot use the import operator to import
  • // tag libraries.
  • import "demo.com.*";
  •  
  •  
  • // Catch any error that was thrown. We will be catching
  • // two errors here to demonstrate both the throw and the
  • // rethrow tag operators.
  • try {
  •  
  • // Thow an error. This tag cannot use name-value
  • // attribute pairs. You can only use one anonymous
  • // string as demonstrate.
  • //
  • // NOTE: This has a function-based alternative,
  • // throw(), that has many more options including
  • // message, detail, and type arguments:
  • // throw( type='', message='', detail='' );
  • throw "You can't do that!";
  •  
  • } catch( any error ){
  •  
  • // Try to catch another error.
  • try {
  •  
  • // Rethrow the current top-level error. This tag
  • // operator does not take any attributes.
  • rethrow;
  •  
  • } catch( any subError ){
  •  
  • // Nothing to do here...
  •  
  • }
  •  
  • }
  •  
  •  
  • // Include another template. This can only use the anonymous
  • // string, not name-value attribute pairs.
  • include "include.cfm";
  •  
  •  
  • // Param the given values. This can handle all of the name-
  • // value attribute pairs that CFParam can handle.
  • param
  • name="name"
  • type="string"
  • default="Tricia"
  • ;
  •  
  •  
  • // Exit out of this page.
  • // NOTE: This cannot use name-value attribute pairs, only
  • // the anonymous string.
  • exit "exittemplate";
  •  
  • </cfscript>

As you can see, I left a number of comments in the code above as to the limitations or alternatives of the tag operators. Now, let's take a look at the tag operators that have content bodies. Once again, as this is really just a lesson in syntax, I'll leave most of the explanation in the comments.

 Launch code in new window » Download code as text file »

  • <cfscript>
  •  
  • // Lock the current temp on the named lock.
  • lock
  • scope="application"
  • type="exlusive"
  • timeout="10"
  • {
  •  
  • // Copy the application scope.
  • request.appData = duplicate( application );
  •  
  • }
  •  
  •  
  • // Start a transaction
  • // NOTE: We are not going to run any queries since that
  • // is not relevant at this point.
  • // NOTE: Trasnaction functionality has greatly increased
  • // in ColdFusion 9 as well, but can be covered later.
  • transaction
  • action="begin"
  • {
  •  
  • // Run a query.
  • include "insert_query.cfm";
  •  
  • // Save this rollback point.
  • // NOTE: This could have also been accomplished with the
  • // function-based alternateive:
  • // transactionSetSavepoint( "SP1" );
  • transaction
  • action="setSavePoint"
  • savepoint="SP1"
  • ;
  •  
  • // Run a query.
  • include "insert_query.cfm";
  •  
  • // Check to see if something went wrong.
  • if (false){
  •  
  • // Roll back the transaction.
  • // NOTE: This can also be accomplished with the
  • // function-based laternative:
  • // transactionRollback();
  • transaction action="rollback";
  •  
  • }
  •  
  • // Roll back to our save point above.
  • // NOTE: This could have also been accomplished with the
  • // function-based alternative:
  • // transactionRollback( "SP1" );
  • transaction
  • action="rollback"
  • savepoint="SP1"
  • ;
  •  
  • }
  •  
  •  
  • // Launch an asynchronous thread.
  • thread
  • action="run"
  • name="firstThread"
  • appname="scriptdemo"
  • {
  •  
  • // Store a return value.
  • thread.returnValue = "From Thread One";
  • }
  •  
  • // Launch a second thread.
  • thread
  • action="run"
  • name="secondThread"
  • appname="scriptdemo"
  • {
  •  
  • // Store a return value.
  • thread.returnValue = "From Thread Two";
  • }
  •  
  • // Sleep the current thread.
  • thread
  • action="sleep"
  • duration="10"
  • ;
  •  
  • // Check to see if our async thread has completed. If it has
  • // not completed, then terminate it.
  • if (cfthread.firstThread.status neq "completed"){
  •  
  • // Terminate the thread.
  • // NOTE: This could have been accomplished with the
  • // function-based alternative:
  • // threadTerminate( "firstThread" );
  • thread
  • action="terminate"
  • name="firstThread"
  • ;
  •  
  • }
  •  
  • // Join the second thread to the page.
  • // NOTE: This could have also been accomplished with the
  • // function-based alternateive:
  • // threadJoin( "secondThread" );
  • thread
  • action="join"
  • name="secondThread"
  • ;
  •  
  • </cfscript>

As you can see above, the tag operators with bodies, namely CFThread and CFTransaction, have many function-based alternatives. I guess these function-based alternatives will also apply to the tag-based versions of these operators; that said, I wonder how Adobe decided which tag actions to turn into functions and which to leave as just operators. All in all, something here feels very inconsistent. I don't foresee myself switching over to CFScript any time - I'm just a tag man at heart.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page


You Might Also Be Interested In:



Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Jul 24, 2009 at 9:52 AM // reply »
1 Comments

Hey,

For me, I am a fan of the work to advance cfscript. I do about 75% of my coding in script so most of this is a welcome addition to me. Having said that, I have to agree with you. The improvements made for CF9 do seem a little inconstant. It is going to be a challenge to remember what to use and where. I think that the beginner is going to find this all to confusing and shy away from it.

--Dave


Jul 24, 2009 at 9:57 AM // reply »
7,572 Comments

@Dave,

I guess I shouldn't view the function alternatives as a problem; after all, those can be use with both script and tag-based coding. But one thing that I don't get is why CFLocation is !only! in method format? This never even made it to an operator.

Of course, in my previous post, Adam Cameron pointed out that not everything with parenthesis is actually a method call (ie. if(), catch()). But, that doesn't make me feel any better. If that was the case, then how do we know when it's an operator and when its a method...and why some have one, some have the other, and some have both?


Jul 24, 2009 at 10:34 AM // reply »
44 Comments

So ... we've gone from this:

<cflock scope="session" timeout="5" type="exclusive"></cflock>

... to this:

lock scope="session" timeout="5" type="exclusive" { }

That is, we've taken off the angle brackets and replaced an explicit block terminator with an anonymous closing brace.

Welcome back to brace-counting Hell, boys. But it was worth it, right? Right?


Jul 24, 2009 at 10:48 AM // reply »
41 Comments

@rick,

i totally agree.


Jul 24, 2009 at 10:54 AM // reply »
7,572 Comments

@Rick,

Ha ha ha. I guess now I really need to switch to an editor that has matching brace highlighting!


Jul 24, 2009 at 11:24 AM // reply »
86 Comments

While CF remains very verbose, it will be gaining a slightly more lightweight syntax.

One of the issues that disturbs me with Adobe's implementation is the large number of language-level constructs they are introducing, rather than implementing these things as library-level constructs.

For example, in Rails, transactions look like:

ActiveRecord::Base.transaction do
david.withdrawal(100)
mary.deposit(100)
end

'ActiveRecord::Base' is a class, 'transaction' is a class method on class 'ActiveRecord::Base', and the 'do ... end' syntax creates a code block and passes it to the 'transaction' method. The 'transaction' method internally sets up a transaction, runs the code block passed to it, and either commits the transaction or rolls it back depending on whether the block threw an exception.

With NHibernate, transactions look like:

using(var txn = nh.BeginTransaction()) {
david.Withdrawal(100);
mary.deposit(100);
txn.Commit();
}

'using' is a syntax element that permits the object defined in the parentheses to run code after the block of code in the braces ends, whether that block of code in the braces ended successfully or threw an error.

Neither C# nor Ruby has any language-level concept of transactions. It worries me that CF is introducing a language-level concept of transactions into CFScript, making the CFScript language rather complex and irregular. What Adobe should instead be working on is implementing namespaced library functions to implement such things as threads and transactions. (Language-level function-looking things, such as most of the CF standard functions, are not namespaced library functions but rather are language-level syntax elements.)

For example, can I continue to do the following? Or is this CF change a breaking change?

var transaction = new lib.MyCustomTransactionClass(1, 2, "three");
transaction.doSomeTransactionyStuff();

@Ben, please note that methods are functions bound to classes or objects. Unattached functions are not methods - this includes all CF standard functions.


Jul 24, 2009 at 11:48 AM // reply »
7,572 Comments

@Justice,

I appreciate your note about methods, but I like to keep things informal around here. As such, I will swap terms like method and function, or class and object and component. I guess it's just my revolting against the fact that in my QBasic class the teacher kept trying to tell me that "subroutines" didn't return values, only "functions" did. Really?? Really?? Well guess what, I like the term FUNCTION better... ok, ok, breathe, that was so many years ago, it's ok, it's over now :)

I guess old habits are hard to break.


Jul 24, 2009 at 11:49 AM // reply »
7,572 Comments

@Justice,

What's funny now that I think about it is that it can be completely fluid in ColdFusion. For example, you can take an unattached Function and inject it into a component and bam, you have a Method. So, I guess it really depends on the context, not even so much on what it is.


Jul 24, 2009 at 2:43 PM // reply »
86 Comments

@Ben, you are correct in noting that, in ColdFusion, functions are methods only when they are invoked in a certain way. But functions cannot intrinsically be methods in and of themselves.

This is actually how JavaScript works as well: the object that the 'this' keyword in a JavaScript function refers to depends on how the function was invoked.


Aug 5, 2009 at 12:43 AM // reply »
7 Comments

Ben, you mentioned that cfhttp and cfmail are handled as components and you'd cover them later... I'm tying to find documentation on these, and not seeing them in the Adobe beta cfml or dev guide documentation any idea where I can find that?


Aug 5, 2009 at 8:14 AM // reply »
7,572 Comments

@Ted,

No problem, I'll try to cover that this week.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 21, 2010 at 6:32 AM
ColdFusion CFPOP - My First Look
Apologies... The field name in the db for C. is "BounceCode" It stores the code / message which is returned in the email. Sorry for the confusion. ... read »
Mar 21, 2010 at 6:29 AM
ColdFusion CFPOP - My First Look
@Jose Galdamez, Hi Ben and Jose 1st of all.. big thanks to Jose for his Skype chat a few weeks back. Your time was much appreciated. I have come up with a rather unelegant solution to my problem a ... read »
Mar 21, 2010 at 3:42 AM
A New Wrist Pain
Chiropractic treatment is one of the best methods for treating numerous health problems naturally. After years of experience being a chiropractor, I have found that it is a powerful way to solve many ... read »
Mar 20, 2010 at 12:07 PM
Drawing On The iPhone Canvas With jQuery And ColdFusion
Simply awesome. Saved my day. ... read »
Mar 20, 2010 at 9:00 AM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
I would like to say thx for an easy way to create a bottom bar. I do have a ?. Is it possible to center the bar if i want to resize it to ex 85%. Regards Offenbach ... read »
Mar 19, 2010 at 7:26 PM
MySQL 3/4 - com.mysql.jdbc.Driver And allowMultiQueries=true
Thank you very much for this post. Adding allowMultiQueries="true" in context.xml didn't help until I added it to url as allowMultiQueries=true Good idea is to use prepared statements and it will he ... read »
Jim
Mar 19, 2010 at 4:49 PM
Nobody Puts Baby In The Corner!
Wow. This is like suddenly finding a support group for your secret shame. I'm not alone! I always liked this movie, even though it is extremely cheesy. I just wish Jennifer Grey hadn't gotten the ... read »
Mar 19, 2010 at 4:47 PM
Application.cfc OnRequest() Method Affects OnError() Arguments
@Jason and @Ben, I've been doing some CF9 refactoring on our systems and noticed an odd occurrence with onError as well. Found a way to work around my problem, but what I saw was... Background: Our ... read »