Thursday 18 February 2016

ColdFusion 2016: the slipshoddiness from Adobe continues with ordered structs

G'day:
Hopefully "slipshoddiness" with keep Ron Stewart amused.

However no-one should be amused by any of this ColdFusion 2016 bullsh!t, which continues to be beta-quality the more of it I look at.

OK, so I wrote about the sorted/ordered structs coming to ColdFusion 2016 back when Adobe released that info to the public, a few months back: "ColdFusion 2016: ordered/sorted structs". Some of that info is out of date now, because [stuff that went on in the pre-release programme and I can't discuss], but the reasons were reasonably legit (-ish), and we all agreed to the scope reduction.

One of the changes was that it became clear that there really isn't a difference between the notion of "ordered" and "sorted": they are basically synonyms. Originally the idea was that an ordered struct had its keys in the order they were originally added into the struct; but a sorted struct was one in which one could supply a callback to define a bespoke ordering. It was pointed out that "insertion order" and "alphabetic order" and "bespoke order" are all variation of the same concept, so it was decided to drop the disparate concepts, and just run with ordered structs to cover all bases. Well until they had trouble with the callback-ordered version, and dropped that from ColdFusion 2016. This is correct: the callback option did not ship. It'll come "later". Which might be ColdFusion 2018, I should think. Or never.

So what's left: there's a new type of struct called an ordered struct. or as Adobe put it using their CFML-yoda-English "structOrdered" (FFS).

There's two ways of creating a new ordered struct:

orderedViaFunction = structNew("ordered");
writeDump(var=orderedViaFunction, label=orderedViaFunction.getClass().getName());

orderedViaLiteral = [=]; // or : for the assignment if you must
writeDump(var=orderedViaLiteral, label=orderedViaFunction.getClass().getName());

And these dump just like structs:

D:\src\CF12\structs\ordered>cf creation.cfm
coldfusion.runtime.StructOrdered - struct [empty]


coldfusion.runtime.StructOrdered - struct [empty]


D:\src\CF12\structs\ordered>

I think perhaps it's a slight glitch there that dump doesn't identify them as ordered structs. I'll raise a ticket for that (4119477).

Anyhow, and empty ordered struct is a bit of a cop-out. Here's one with something in it, demonstrating the different from a normal struct ("structNormal"?):

normal = {
    first = 1,
    second = 2,
    third = 3,
    fourth = 4,
    fifth = 5
};
writeDump(normal);

ordered = [
    first = 1,
    second = 2,
    third = 3,
    fourth = 4,
    fifth = 5
];
writeDump(ordered);

Result:

D:\src\CF12\structs\ordered>cf literal.cfm
struct

FIFTH: 5
FIRST: 1
FOURTH: 4
SECOND: 2
THIRD: 3

struct

FIRST: 1
SECOND: 2
THIRD: 3
FOURTH: 4
FIFTH: 5

D:\src\CF12\structs\ordered>

So you see that the latter dump has indeed preserved its key ordering. Lovely.

Oh... literal syntax there uses square brackets rather than curly braces.

I tested a bunch of other things: each(), map(), filter(), toJson(), for-looping, keyArray() etc, and they all worked. But it's all boring, so I'll spare you.

As with everything (it seems) in ColdFusion 2016, it's riddled with bugs though.

First - I did not find this one, Aaron Neff did - the literal syntax is a bit fragile (heaven forbid literal syntax in ColdFusion is brittle... struct- and array-literal syntax in ColdFusion was almost unusable when it was added in ColdFusion 8; almost production ready for ColdFusion 9, and I think by ColdFusion 10 it'll be stable. So with this stuff... maybe by ColdFusion 2020. Or it'll probably be COLDFVSION MMXX or something daft by then. But anyway...



One cannot quote the keys like one can with structs:

// compiles fine
normal = {
    "first" = 1,
    "second" = 2,
    "third" = 3,
    "fourth" = 4,
    "fifth" = 5
};

// does not compile
ordered = [
    "first" = 1,
    "second" = 2,
    "third" = 3,
    "fourth" = 4,
    "fifth" = 5
];


Invalid CFML construct found on line 12 at column 17.

ColdFusion was looking at the following text:=
The CFML compiler was processing:

  • A script statement beginning with ordered on line 11, column 1.
  • A cfscript tag beginning on line 1, column 2.
The error occurred inD:/apps/Adobe/ColdFusion/2016/full/cfusion/wwwroot/CF12/structs/ordered/literalBug.cfm: line 12
10 : 
11 : ordered = [
12 :  "first" = 1,
13 :  "second" = 2,
14 :  "third" = 3,

So that sux. I can't believe that did not come up in testing.

A variation on this is one cannot use dynamic keys either:

one = "first";
two = "second";

// compiles fine
normal = {
    #one# = 1,
    #two# = 2
};
writeDump(normal);


// does not
ordered = [
    #one# = 1,
    #two# = 2
];


Aaron found another glitch with WDDX in that it doesn't work:

normal = {
    first = 1,
    second = 2,
    third = 3,
    fourth = 4,
    fifth = 5
};

cfwddx(action="cfml2wddx", input=normal, output="wddx");
cfwddx(action="wddx2cfml", input=wddx, output="struct");
writeDump([wddx,struct]);


ordered = [
    first = 1,
    second = 2,
    third = 3,
    fourth = 4,
    fifth = 5
];
cfwddx(action="cfml2wddx", input=ordered, output="wddx");
cfwddx(action="wddx2cfml", input=wddx, output="struct");
writeDump([wddx,struct]);

Result:

D:\src\CF12\structs\ordered>cf wddx.cfm
array

1) [wddx]
[struct]
FIFTH: 5
FIRST: 1
FOURTH: 4
SECOND: 2
THIRD: 3


2) [struct]
        FIFTH: 5
        FIRST: 1
        FOURTH: 4
        SECOND: 2
        THIRD: 3

array

1) [wddx]
[struct]
THIRD: 3
SECOND: 2
FIFTH: 5
FIRST: 1
FOURTH: 4


2) [struct]
        THIRD: 3
        SECOND: 2
        FIFTH: 5
        FIRST: 1
        FOURTH: 4

D:\src\CF12\structs\ordered>

Note how it messes with the ordering of the keys, but doesn't get it right.

By the way, let's stop and marvel for a while how crap having to do this is:

cfwddx(action="cfml2wddx", input=normal, output="wddx");

Only in CFML would the variable being assigned by a function need to be passed into it as a string argument.

The other - somewhat more significant than any of those - issue is that Adobe forgot to implement structOrdered as a type, for type checking. None of this lot works:

ordered = [=];

try {
    param StructOrdered ordered;
}
catch (any e){
    writeDump([
        type=e.type,
        message=e.message
    ]);
}

StructOrdered function f(StructOrdered st){
    return st;
}

try {
    result = f(ordered);
}
catch (any e){
    writeDump([
        type=e.type,
        message=e.message
    ]);
}

Result:

D:\src\CF12\structs\ordered>cf typing.cfm
struct

TYPE: Expression
MESSAGE: The type attribute has an invalid value.

struct

TYPE: Application
MESSAGE: The ST argument passed to the f function is not of type StructOrdered.

D:\src\CF12\structs\ordered>

I mean... typechecking is kinda unnecessary for most of CFML, and I avoid it where I can. But I do think if one is writing a library which has an API and it's intended for public usage, then one should type-check the API so it "fails fast". And one needs to be able to specify that a function requires an ordered struct (or returns one). Filed as bug 4119475.

What I see here is that Adobe simply didn't plan this, they just sat down and started typing. And the fact they are not CFML developers or used to CFML at all stands out cos they clearly didn't do the usual things people do with CFML. I mean... none of this is pushing the boat out.

You can also possibly imagine that people who might do pre-release testing might ask for stuff like specs, plans, tests and stuff when they're doing their own testing. And say had they ever received them, then they'd probably be able to spot this sort of thing within a coupla hours (which is what it took me to find them this evening). Now I won't suggest how things on the pre-release actually were, but you do know I was on it, and you also know that perhaps I'd've been reasonably thorough in testing things had I been given the chance. Draw your own conclusions from there. Only a really amateur and basically negligent team would withhold this sort of information from their own volunteer testers, eh?

Hmmm.

All in all... nice idea... badly implemented.

Oh and don't go looking in the CFML docs for this stuff... I don't think you'll find it (4119454).

Disappointing. And another example of the Adobe ColdFusion Team really letting us down.

Righto.

--
Adam