Monday, 25 May 2015

Some CFML code that doesn't work

G'day:
I was sitting at Lord's yesterday watching England v NZ (and, um, we'll have no comments about that, thank-you very much), and a sudden thought popped into my head "Adam Presley might've been onto something there... if I leverage that....I wonder if I could get that code down to one statement?"

And that of course will mean nothing to anyone.

Lucee seems to mess up boolean expressions (kinda)

G'day:
Another bloody stumbling block writing this code (see CFML / Lucee: beware of "optional" semi-colons for the first one). This time Lucee's not getting the result of a OR expression right. Seriously. Well: I guess not as right as I'd like it to.

I was trying to write a compound sort callback, along these lines:

results = [
    {factor1=3,factor2=6},
    {factor1=3,factor2=5},
    {factor1=3,factor2=4},
    {factor1=2,factor2=3},
    {factor1=2,factor2=2},
    {factor1=1,factor2=1}
];

sortedResults = results.sort(function(e1,e2){
    return sgn(e1.factor1 - e2.factor1) || sgn(e1.factor2 - e2.factor2);
});

writeDump(sortedResults);

So the logic is here that factor1 is tested, and only if it's equal is factor2 checked. A fairly common requirement. On Lucee, this results in:


ie: no sorting taking place.

I had ColdFusion running too, so checked it on that:


That's more like it. So what the hell is going on with Lucee?

I put some debugging in, and groaned. Here's come code doing a truth table for the || operator:

operands = [-1,0,1];

operands.each(function(a){
    operands.each(function(b){
        writeOutput("#a# || #b# = #a || b#<br>");
    });
});

And the results:

-1 || -1 = true
-1 || 0 = true
-1 || 1 = true
0 || -1 = true
0 || 0 = false
0 || 1 = true
1 || -1 = true
1 || 0 = true
1 || 1 = true


Now. from a strictly boolean sense, where -1 and 1 are truthy, and 0 is falsy... this is correct.

However Lucee seems to be evaluating the expression as a whole, rather than short-circuiting. I expect -1 || -1 to be -1. It encounters the first truthy expression, and returns it. And -1 is truthy. There's no need to go any further.

But the issue is not that it's not short-circuiting per se (ie: it is short-circuiting, which is good), because if I drop factor2 from the last result, the sorting still works; so clearly the second half of the || expression is not being evaluated if it doesn't need to be. So it's like Lucee is just being a bit overly dogmatic for a loosely typed language: || expressions return booleans, so it's converting -1 into a true. Which... is not what it should be doing. Let's look at that truth table in ColdFusion:

-1 || -1 = -1
-1 || 0 = -1
-1 || 1 = -1
0 || -1 = -1
0 || 0 = 0
0 || 1 = 1
1 || -1 = 1
1 || 0 = 1
1 || 1 = 1


That's better. What about other loosely-typed languages though? Maybe my expectations are off. Here's a JS example:

operands = [-1,0,1];

operands.forEach(function(a){
    operands.forEach(function(b){
        console.log(a + " || " + b + " = " + (a || b));
    });
});

This outputs the same as CF does. And Python?

operands = [-1,0,1]

for a in operands:
    for b in operands:
        print("%d or %d = %d" % (a, b, a or b))

Again, the output was the same.

I tried Ruby, but it's a bit odd when it comes to boolean expressions. All numbers are true (even zero), so I cannot do a like-for-like example.

On the other hand, here's the Groovy equivalent:

operands = [-1,0,1];

operands.each {a->
    operands.each{b->
        println("${a} || ${b} = ${a || b}");
    };
};

And it agrees with Lucee:

-1 || -1 = true
-1 || 0 = true
-1 || 1 = true
0 || -1 = true
0 || 0 = false
0 || 1 = true
1 || -1 = true
1 || 0 = true
1 || 1 = true


Hmmm.

OK, so there's obviously not a cut and dried precedent here. That being the case, I'm going with my expectations of how CFML should do it being correct, and weight is also added to this given ColdFusion sets the standards for this sort of thing, and it behaves the way I'd expect.

I'm raising a bug with Lucee: LDEV-366.

--
Adam

CFML / Lucee: beware of "optional" semi-colons

G'day:
Not what I had in mind writing up today, but as often is the way... the easiest way to find bugs in CFML is it try to use it.

Wednesday, 20 May 2015

Random PHP (7) bits: improvements to generators

G'day:
I was gonna have a look at output buffering in PHP today, but my attention has been hijacked by PHP 7. So instead I'm gonna have a look at some enhancements they've made to generators in 7. I'm actually not at work today, so there's a chance I'll be able to write both articles anyhow. We'll see.

Tuesday, 19 May 2015

Random PHP bits: __debugInfo()

G'day:
This is not a very insightful article, but I just happened to stumble across this functionality, and found it moderately interesting. This is another one of these "PHP n00b" articles, so if you're a seasoned PHP person, you'll not be reading anything here you don't already know.

Monday, 18 May 2015

Lucee CFML: import and application-set mappings (kinda redux)

G'day:
This is a like a sequel to "Railo bug? Or ColdFusion bug...". That article details how ColdFusion will kind of allow import to use mappings set in Application.cfc, provided an include uses said mapping first. On RailoLucee they stick closer to the docs (that's the ColdFusion docs, not the Lucee docs):

Attribute: taglib
Optionality: required
Description: Tag library URI. The path must be relative to the web root (and start with /), the current page location, or a directory specified in the Administrator ColdFusion mappings page.
My emphasis.

The Lucee docs make no claim about this one way or the other, but that's how Lucee behaves. In short, on Lucee one cannot use Application.cfc mappings with an import statement like that.

Sunday, 17 May 2015

Getting PHP 5.x & 7-dev running on Windows/Apache

G'day:
Yesterday evening I discovered there are runnable versions of PHP 7-dev for Windows. I'd looked around for them before, but didn't spot them. Maybe they're new. I'm really struggling to get myself as far into the PHP loop as I am in the CFML one. Admittedly mostly due to lack of really trying.

Anyhow, I downloaded it and installed it (read: unzipped it), and indeed it seemed to a) work; b) do stuff PHP 5 can't do and PHP 7 is supposed to be able to do. So I figured "yeah, OK, so I do have PHP7 running". I'll write that lot up later on, once I have a decent play with it.

All my experiments last night - which were brief as I was at the bar @ LHR awaiting a flight - were running stuff via the CLI. This is fine with PHP but not how I'm used to doing stuff. Given I'm from a CFML background I'm used to running my test code in a browser, not a prompt, so I decided to get PHP7 running on Apache today. I've just managed to get it co-habitating with PHP 5. Win.

Here's what I had to do...