Adam Tuttle

Taffy 3.1.0-RC1

Yep, you read that right! It's time to start testing Taffy 3.1.0-RC1 in your environments. I've been using the bleeding-edge code in production for months now without issue. All that was holding up the release was a few minor tickets and some documentation that needed to be written, and over the weekend (and some early this morning) I knocked almost all of that out.


The only remaining ticket is to find a good place to document the X-HTTP-METHOD-OVERRIDE header. (Any ideas?)

As you can read for yourself in the Release Notes, this release includes 11 bug fixes and 13 enhancements. The most noticeable changes all center around the dashboard. In particular, one that's been bugging me for a long time: It was getting too cluttered with stuff that you probably didn't need for a majority of your API's / requests. Now all of those extra non-essential features are hidden and easily toggled from a set of links:


Please Download Taffy 3.1.0-RC1 and give it a shot with your API. If you have any issues, please file a ticket or we can talk about it in the #taffy channel on the CFML slack team.

An Example of What ColdFusion Needs in the Next Version

Let me say up front that I am not in a particularly forgiving mood. So I may be a bit more critical here than you might consider fair.

But I contrast your fairness with: It's 2015 and we're expecting ColdFusion 12 to be released in the next... well... sometime. You never can tell what the release schedule is like any more. But the point is: version twelve. Of a programming language. In 2015.

I found myself today writing this code:

cgi.path_info.right( cgi.path_info.len() - 1 );

Granted, I'm very happy that we have member functions. I would be hard pressed to give them up and go back to ColdFusion 10. And that code is not horrible. But, in the context of the above (2015, twelve, etc), it just feels... lazy. Why haven't we fixed this problem yet?

Here are some other ways to write that same code that do in fact run on Adobe ColdFusion and achieve the exact same result, along with why I will not use them.

Option 1: Drop down to Java and use SubString

As proposed by Adam Cameron in Slack:

cgi.path_info.substring( 1 );

In terms of sheer efficiency, this approach wins hands down. Here's why I won't use it:

  • While this is standard and well documented Java functionality, and chances are decent that it will remain this way in perpetuity, there has been no promise of such. Because it is an "undocumented feature of CFML" (as is every available Java method), Adobe have reserved the right to implement a shadow function with the same name and completely different logic, or even a different method signature.
  • There is a context shift at play. ColdFusion uses "1" as the first index in arrays/positional stuff.
    • listGetAt("foo", 1, "") returns "f".
    • "foo".substring(1); returns "oo". (Or it would, if ColdFusion treated literals with the respect they deserve...) Java uses zero-based indexes, meaning that Java's 1 is the same as CF's 2.
    • If you were to come behind me reading my code and not realize that substring is a Java method, you might reasonably expect that cgi.path_info.substring(1); returns the entire string, not some substring of it.
  • Combine both of those previous bullet points into the perfect storm: Adobe chooses to implement substring( index [, length ] ) but of course chooses to use 1 as the first position. Now my code is broken, but no errors are thrown.

No thanks.

Option 2: RemoveChars

This was the Slack chat room favorite, proposed by Matthew Clemente, because it has a relatively simple implementation and does what I'm after... getting all except the first character.

cgi.path_info.removeChars( 1, 1 );

Except... I don't recall ever hearing of this function before today. I've been coding CFML for more about 15 years, held multiple "advanced certifications" in it, and if I ran across this line in someone else's code, I'd have to go look the function up. While it's short and simple, it's too obscure. Kind of like how I always have to look up the syntax for JavaScript's slice() method... it disrupts my flow.

Option 3: ListRest listToArray, slice, and arrayToList

This is a spin-off of an idea suggested by Brad Wood. He suggested using listChangeDelims(), combined with the fact that my first character will definitely be a slash, combined with the fact that CF will strip out empty list items by default... Too much implied for my taste. I prefer explicitness; especially when being clever. But it made me think of listRest().

cgi.path_info.listRest( '' );

As it turns out, this doesn't work. (You might think it would. I did. But then we'd both be wrong.) But this would work, and is identical in intention. It was suggested by Seth Stone:


This one gets the honorable mention of what I would probably use if I were more forgiving of "cleverness."

Here, the string is converted into a list, broken between every character; then we drop the first list item and return the rest. I use this approach frequently when dealing with lists and without hesitation. It's not too obscure, I think. But it's longer than the original approach, and not really any more readable. I've gotten to the point in my career where I strongly believe that code is meant to be read, not to be written. On all code that I write, I spend a little bit of extra time making sure that reading it will be pleasant and hopefully without disruption.

Aside from whatever performance degradation we may suffer if this string happens to be long (lists, as string manipulation, are not particularly efficient), it's just not a list. We're using this drug off-label because it has the intended side-effect. I would worry about future readers wondering why I'm treating path_info as a list, when in truth I don't need it in list form.

The Correct Solution

This is the code that ColdFusion should support, but doesn't:

cgi.path_info.mid( 2 );

Because the argument for the number of characters to return is required: cgi.path_info.mid( 2, cgi.path_info.len() - 1 );. In a perfect world, the mid() function would assume that, if you don't specify the number of characters you want returned, you want all of them until the end of the string.

In fact, this is how JavaScript's String.prototype.substr() (their equivalent of mid()) works (doc). And PHP's substr(). And Java's substring, as discussed above. And perl's substr. And C++, and C# (doc).

Python's syntax might look a little bit weird, but it is identical in intention: string_var[1:] (the colon splits a range, as in 1:3, and omitting the 2nd range value indicates "to the end of the string").


So no. I'm sticking with cgi.path_info.right( cgi.path_info.len() - 1 ); because, while it feels like a lazy hole in the language, is also straight-forward and not overly verbose.

Of course, I could write a UDF that would abstract away this functionality (using any of the above functional options, or others) and give it a reasonable name. E.g.:

function strAfter( str, skipCount ){
    return str.mid( skipCount, str.len() - skipCount );

That would pass all of my personal tests:

  • It would be readable
  • The syntax would be agreeable
  • There would be almost no chance of Adobe releasing a new function that would conflict with my chosen name

... but then I've written a UDF for a single string manipulation function, which really wasn't that terrible to begin with (just lazy), and I find myself with the undesirable problem of now having to find an appropriate place for a string-utils library... with one method in it.

I hasten to add that there's no way to add my own member functions without creating a CFC for this purpose, which is (yet another) real shame.

The title of this post is "An Example" of what ColdFusion needs to be working on, so let's bring it back to that.

They don't need to work on REST-administration (let's be honest: get your basic REST functionality fixed first, guys... Current implementation leaves A LOT to be desired). Not more "mobile" features. Not more UI tags. They need to fix things that smell bad in the language. You're building a skyscraper on a wooden foundation that's starting to rot. You might want to fix that before you add more floors on top.


Here's a little UDF that I just finished writing that I think will be useful to those of you that use ColdFusion's ORM.

The root of the problem is that doing a <cfdump> on an ORM entity is not really "safe" because its relationships will all be loaded and dumped too (unless you use the "top" attribute, which is poorly implemented). For a while I got around this by using a simpler version of the UDF that I'm about to share. The simpler version was this:

function deORM( obj ){ return deserializeJson( serializeJson( obj ) ); }

To prevent repeating myself, let's call this the "bad" function.

Hopefully you can see that this will be terribly inefficient: We're converting that ORM entity to a JSON text representation of itself (which looks like a standard structure) and then converting that text back to a standard CF structure. It's that second half that's going to take the biggest hit.

This worked very well for us, until it didn't. We started getting really random Java Heap Space exceptions, and the stack trace was completely unhelpful: Just a bunch of recursing in the implementation of serializeJson, until the stack trace truncated in the logs... so it was a big pain in the butt to track down, too!

It's not so bad when you're just converting 1 entity; but if you're trying to write a general purpose solution that, for example, logs the entire request local scope and session scope in the event of an exception, you can imagine how it would be really easy to get dozens and dozens of entities into the mix -- then memory usage skyrockets, and kablooey.

So, instead of this crazy over-usage of the bad function, I decided to try to "do it right," as it were. The result is below. The end result is the exact same thing that you would expect from the bad function, but without ever converting to and back from text. And it properly handles object inheritance, too. Not that the bad function had an issues here — it didn't — but it would be easy to overlook this otherwise...

I haven't done any performance benchmarks on the conversion speed of this approach, but at least it prevents the heap space errors we were seeing! (And if I had to guess, I'd say this way is faster, too...)

So here you go; the best way I've come up with so far to make any object safe to dump, even if somewhere down in the object graph there might be an ORM entity or 10:

function deORM( obj ){
    var deWormed = {};
    if (isSimpleValue( obj )){
        deWormed = obj;
    else if (isObject( obj )){
        var md = getMetadata( obj );
        do {
            if (md.keyExists('properties')){
                for (var prop in{
                    if (structKeyExists(obj, 'get' &{
                        if ( !prop.keyExists('fieldtype') || prop.fieldtype == "id" ){
                            deWormed[ ] = invoke(obj, "");
            if (md.keyExists('extends')){
                md = md.extends;
        } while(md.keyExists('extends'));
    else if (isStruct( obj )){
        for (var key in obj){
            deWormed[ key ] = deORM( obj[key] );
    else if (isArray( obj )){
        var deWormed = [];
        for (var el in obj){
            deWormed.append( deORM( el ) );
        deWormed = getMetadata( obj );
    return deWormed;

You can see I've got a catch-all at the end there that would show the object's metadata in the event it's not a type we're setup to handle. I've yet to find anything that falls into that path, but I figured I'd leave it there to be safe.

Hope this helps some of you, too!

Book Review: Armada by Ernest Cline

I was a big fan of Ready Player One; so much so that mere weeks after finishing the book, when I learned that the audiobook version was read by Wil Wheaton, I bought and listened to that version as well (and yes, Wil's reading was so worth the extra purchase!) While I did not rank well at all in the RPO easter egg games, I did play them, and I was excited to see him giving away a Delorian.

Given this, it should come as no surprise that when I heard that Ernest Cline had another book in the works, I started watching with, admittedly, some froth. On release day he did a Reddit AMA (which could have gone better, but apparently suffered because of some otherwise unrelated drama from Reddit HR) and I dutifully read through the entire thread, hoping to find some easter egg leads for the new book. I didn't.

I'm writing this review while listening to a Spotify playlist named Raid The Arcade Mix - created from the image of a hand-written Maxell cassette tape cover included at the end of the book, which has special significance in the book and is frequently referenced. That's a pretty neat take-away from the new book. I'll be coming back to this one for a while to come.

It took me a day or two to start the book, not for lack of motivation. Life just got in the way. And unfortunately, I caught wind of some negative reviews in the meantime, and they cast shade over the majority of my own reading of the book. I spent the first 60% or so wondering when I would start to agree with these reviews. When will the pop culture references start to feel forced and overbearing? When I realized I was waiting for it to happen, I was able to let it go: I decided that it probably wasn't going to happen because I just disagreed with the reviewers. In doing so, I greatly increased my own enjoyment of the book. Lesson learned: Screw professional reviewers, I'll form my own opinions as I go.

Does the book take too much from others in the civilians-drafted-to-save-the-world genre? I don't think so. It's been compared heavily to Ender's Game and even movies like The Last Starfighter, but to me it read more like a mashup than a rip-off. Everything I've seen listed as source material for Armada's ripping off was actually referenced in the book. Does that make it a cited reference rather than plagiarism? I don't know. But again: it read like a genuine attempt at adding to the genre, rather than paraphrasing to make a buck.

There isn't a lot of room to deviate from what you're probably expecting based on the synopsis: Video game playing kid dreams of living inside a Star Wars movie; sees a UFO one day; gets drafted to save the world. (Don't worry, no spoilers here...) Either he will or he won't. There are a few other plot lines opened in Act 1, too, that can only go two, maybe three different ways after all is said and done. But, as much as Cline has painted himself into a corner plot-wise, he's done a good job of it. The entire book (less epilogue) takes place over only a day or two, and the action is so well paced that every time I had to put my kindle down (you know, to eat or sleep or acknowledge the existence of my family) I found myself thinking, "but it was just getting good!"

I've just finished the story this morning before starting work, and I was really pleased with the ending and the book as a whole. I definitely got my $11.43 worth of entertainment, and I would recommend it to anyone willing to read with an open mind and especially those of us that grew up in the 80's and 90's involved with sci-fi video game and movie culture. What 80's kid hasn't played Descent and wanted to fly those ships for real?

I highlighted 12 passages on my kindle: 1 typo (because that's how I roll), and 11 pop culture references that I didn't get. I'll be using those highlights to go look up what are probably going to be books and movies that I'll really enjoy. And only now after putting the book down, I've found a link to a playable ROM for one of the fictional games referenced in the books: Phaƫton.

There you have it. I give it two enthusiastic thumbs up!