tags:

views:

185

answers:

2

The newer versions of ColdFusion (I believe CF 8 and 9) allow you to create structs with object literal notation similar to JSON.

My question is, are there specific benefits (execution efficiency maybe) to using object literal notation over individual assignments for data that is essentially static?

For example:

With individual assignments you would do something like this:

var user = {};
user.Fname = "MyFirstnam";
user.Lname = "MyLastName";
user.titles = [];
ArrayAppend(user.titles,'Mr');
ArrayAppend(user.titles,'Dr.');

Whereas with object literals you would do something like.

var user = {Fname = "MyFirstnam",
            Lname = "MyLastName",
            titles = ['Mr','Dr']};

Now this limited example is admittedly simple, but if titles was an array of structures (Say an array of addresses), the literal notation becomes awkward to work with.

+2  A: 

Literal notation is declarative programming, not procedural programming.

With literal notation, you tell the computer what it is you want clearly and in a single step. Without literal notation, you build what you want slowly, piece by piece, and without clarity.

Note that literal notation in CF8 is awkward and flawed, at best. It should rarely be used, and then only in simple cases. The literal notation in CF9 is fine.

For CF8, you can define helpers:

function $A() {
    var r = [ ];
    var i = 0;
    var m = ArrayLen(Arguments);
    for(i = 1; i <= m; i += 1)
        ArrayAppend(r, Arguments[i]);
    return r;
}
function $S() {
    return StructCopy(Arguments);
}

And use them as such:

var user = $S(
    Fname = "MyFirstnam",
    Lname = "MyLastName",
    titles = $A('Mr', 'Dr')
);

These helpers work all the time, preserve struct key case (struct keys are not simply uppercased but are cased as you typed them), and nest recursively without bound.

Justice
Thanks. I understand the difference, I'm most interested in if there is a particular advantage to the object literal notation to offset the syntax pitfalls (nested brackets/commas) for static data that could easily be done either way.
Tom Hubbard
As I mentioned at the beginning, literal notation is declarative programming, where the programmer expresses his intentions succinctly and clearly. In procedural programming, the programmer is reduced to specifying how to build up data structures ploddingly and step by step, and is unable to express his intentions succinctly and clearly. The rest of the post was a clarification on literal notation and its use in CF8 vs CF9. Although one may be unfamiliar with it or unused to it without practice, the syntax is not a pitfall - the syntax frees the programmer instead.
Justice
+5  A: 

Before I tried anything, I thought straight away that literals would be faster, as you create everything you need in runtime, and don't need to waste time creating variables, then calling functions to append and all that.

I then wrote a little test that produces a chart with the results. You got me curious there :-)

The results prove I was right, as the graph shows a staggering difference as you can see: alt text

But remember that although one would jump and go with literal notation, I think it's important to remember that literal notation can be awkward, and will most of the times confuse more.

Obviously, if you are developing a page that really needs the speed boost, literal notation is what you're looking for, but be aware that sometimes on CF8, it will produce some strange behaviour.

Just to show you the sort of tests I run:

<cfset aLiterals = arrayNew(1) />
<cfset aDirect = arrayNew(1) />

<cfsilent>
    <cfloop from="1" to="10000" index="mm">

        <!--- LITERAL --->
        <!--- start timer --->
        <cfset start = getTickcount() />
        <cfloop from="1" to="1000" index="ii">  
            <cfset user = {Fname = "MyFirstnam", Lname = "MyLastName", titles = ['Mr','Dr']} />
        </cfloop>
        <!--- end timer --->
        <cfset end = getTickCount()>

        <!--- Display total time --->
        <cfset total = end-start>
        <cfset arrayAppend(aLiterals,total) />

        <!--- DIRECT --->
        <!--- start timer --->
        <cfset start1 = getTickcount() />
        <cfloop from="1" to="1000" index="jj">
            <cfset user = {} />
            <cfset user.Fname = "MyFirstnam" />
            <cfset user.Lname = "MyLastName" />
            <cfset user.titles = [] />
            <cfset ArrayAppend(user.titles,'Mr') />
            <cfset ArrayAppend(user.titles,'Dr.') />
        </cfloop>

        <!--- end timer --->
        <cfset end1 = getTickCount()>

        <!--- Display total time --->
        <cfset total1 = end1-start1>
        <cfset arrayAppend(aDirect,total1) />   
    </cfloop>
</cfsilent>

<!--- The cfchart --->
<cfchart format="png" xaxistitle="function" yaxistitle="Loading Time (in secs.)">
    <cfchartseries type="bar" serieslabel="literal">
        <cfchartdata item="literal" value="#arrayAvg(aLiterals)#">
    </cfchartseries>
    <cfchartseries type="bar" serieslabel="direct">
        <cfchartdata item="direct" value="#arrayAvg(aDirect)#">
    </cfchartseries>
</cfchart>

Hope this helps you.

Marcos Placona
Great! Exactly what I was looking for. Thanks.
Tom Hubbard
Note for interested: for Railo 3.1.2 difference is a bit smaller, but still significant.
Sergii
You are not comparing apples to apples. Perhaps in the second loop, try using associative-array notation, and then run the performance test again. Eg: `<cfset user["titles"] = [ ] />`
Justice
@Justice I've tried, it makes no difference at all.
Sergii
This is somewhat shocking to me. Is the reason because parsing the literal notation is really that expensive? I can't think of another reason that direct is 2.5x slower than literal.
Bialecki