Adam Tuttle

301 Moved Permanently

I've been itching to move my blog for a while now, and it's finally done!

For the time being, my email address will stay the same, for those of you that might have it and be wondering what to do about that. I've been using it for 8+ years, which means I've accumulated a crap-ton of associated website accounts. I couldn't stop using it any time soon, even if I wanted to.

I do want to make an attempt to port all –or most– of my old articles over, at some point. And once that's done, I may make an attempt to import old comments into Disqus — after enabling it for new comments at the new site, of course.

I know that Disqus is not universally loved. I hear it's disabled by some corporate firewalls, which is a shame. But static sites really are pretty awesome, so it's (kind of) a small price to pay.

You can find the new blog here:

Go check out the new site. There's not a lot there, but I'm very happy with it so far, and I have lots of plans to continue improving it.

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!