G'day:
This all stems from a Jira ticket for Lucee: "Redefining truthy and falsey values (LDEV-449)". The way the ticket is worded means it's not convenient to copy and paste a chunk of its detail to explain the gist of it, so I'll reiterate.

At the moment CFML relies on type coercion rules determine which values are valid to be used where boolean values are expected. Obviously at the base of things boolean values are true or false. But because CFML is loosely and dynamically typed, one doesn't need to simply use actual booleans in boolean expressions. The following value for other types will also coerce to boolean when called for:

Type

Value

Coerces to

String

"true" (as opposed to true, which is a keyword, and fundamentally boolean already)

true

String

"false"

false

String

"Yes"

true

String

"No"

false

Numeric

!=0

true

Numeric

0

false

There are other coercions that will feed into these, for example strings with numeric values - eg: "42" (as opposed to just 42) - will happily coerce into a numeric, then from there to a boolean.

What this ticket is about is extending this to have a notion of "truthy" and "falsy" for other values and other data types. This notion stems from Groovy (and perhaps other languages) which is pretty liberal with what it will consider truthy or falsy. These terms "truthy" and "falsy" denote the values are not actually boolean, but will pass / fail a boolean check.

So all the common data types, and indeed custom data types have a sense of truthiness (and, by inversion: falsiness).

This is the gist of the ticket. Basically... checking for emptiness in an object (irrespective of what the definition of "empty" is), is a very very common requirement, and this truthiness concept just gives the ability to abbreviate that via some synatactic sugar and an agreed-on method of identifying what it is to be empty, and fielding that as a boolean: empty is "falsy", and not-empty is "truthy".

I think it's a good idea.

There's been some kick-back on it by people who don't seem to understand the concept of "syntactic sugar" and simply "don't get" the ticket. I'll leave it to you to read their comments and form your own opinion.

Now, as for implementation, I think there is a critical step here, as suggested by that Groovy code. LAS need to implement this as an interface, for both Java and LuceeLang. See how the demo class I have there implements an asBoolean() method:

boolean asBoolean(){
return (value == "truthy")
}

Any class that implements that method can then have its objects used in boolean expressions. Basically they need to implement something like a BooleanBehaviour interface. Obviously my class there doesn't implement any interfaces, but I have not got far enough into Groovy to know whether interface implementation is just fulfilled by behaviour, rather than by contract (like it is in CFML).

I think it's essential for Lucee's implemention of this to follow an approach like this. Not just to bung some behaviour in to allow its current types to magically behave like booleans, but implement it in a formal fashion. And also expose the same interface to both Lucee users' .lucee code, but Java code too.

The current ticket seems to be asking for this for Lucee's CFML implementation, but I think this is a mistake because some of the CFML's implementation's automatic coercion to boolean conflicts with the "truthy" approach. Most notably a string "0" in CFML is false, because it will be converted to a numeric, and 0 is false. But using sensible "truthy" behaviour for strings... "" is false, and any other string is true. It makes little sense (and violates POLA, IMO) to have "" and "0" as false, and [any other string] be true. It would just make CFML look like it "didn't quite get it" when it implemented this feature.

Also note that Brad's narrative mentions toBoolean(), whereas Groovy's handling is asBoolean(). This might seem like a semantic difference, but I think it requires closer examination. Groovy has both toBoolean() and asBoolean(); and it looks like C# does too. Best LAS get this one right. At least understand the differences (which I don't, I have to say), before deciding how to approach.

Sorry this article isn't so interesting. I started to percolate away at it during the week and reckon I got enough content for an article, but never really achieved any real nuance to it. Still: for something that started as a Jira comment I guess it's all right.

Friday, 29 January 2016

G'day:
I am fundamentally opposed to any software which - as its missions statement, basically - censors a website's choice of content. This is what this new Brendan Eich project seems to be setting out to do as its raison d'être. Even if it's just the ads they choose to display:

It is not the place of a browser vendor to second-guess the materiel a website chooses to display. Especially when it means they replace that content with their own content.

I know user-agent sniffing is frowned upon as a solution to this sort of thing, but generally this is because one should be detecting browser features, not the browsers themselves. In this case I actually want to specifically identify the browser, so it seems a reasonable - if not very thorough - approach.

Obviously it's easy to circumvent, so do that if you like.

Also if anyone gets redirected to here and they're not using Brave, lemme know.

And you're entitled to disagree (or agree!) with my position on this, and you're more than welcome to put forward your case in the comments below.

If someone makes a compelling case why I should stop doing this, I will.

As it stands though: don't support this shittiness. If you're seeing this page because you are a "Brave" user... consider changing your browser decision.

G'day:
If you know something about Hibernate and/or using ColdFusion's wrapper around same, perhaps you could cast your analytical eye over this, and help determine whether Mingo has - as it seems - found a bug in it, or whether Himavanth has some basis to what he's saying, and it's not just a case of him (willfully choosing to ~ ?) not understanding what Mingo is saying, and there's actually no problem. Can you guess which side I come down on?

Problem Description:

When you have a base component (base.cfc) with MappedSuperClass set to true, a
persisted component (animal.cfc) inheriting from that and another (dog.cfc)
inheriting from that one ColdFusion throws an exception (a Hibernate one).
To make this bug more fun, CF doesn't always throw this exception.

The reason why this happens becomes clear when you setthis.ormsettings.savemapping=true and take a look at the hbmxml files.

Notice the extra name property, that's not supposed to be there, because that should be inherited from the animal class.

My knowledge of ColdFusion's ORM is pretty theoretical as I've never used it beyond testing it, and my knowledge of Hibernate is scant (I've scanned a Hibernate book whilst testing the initial ColdFusion 9 implementation).

The most telling thing is that Lucee does what Mingo expects, and it works. That kinda suggests ColdFusion has got it wrong. It would seem too coincidental that Mingo's expectations are off, and it just so happens Lucee's implemented things in such a way that match Mingo's expectations. Occam's Razor 'n' all.

So perhaps you lot can eyeball this and the rest of the detail in Mingo's ticket, and offer your input?

Wednesday, 27 January 2016

G'day:
We've finally nailed down an Adobe ColdFusion Team member on the #documentation sub-channel of the CFML slack channel. So if you have issues with the documentation, post there, and direct it to +Jacob Royal (ooh: Google added that link for me automatically. Cool!).

Coincidentally this morning I read of a CFML newbie trying to write code, assisted by said documentation (ColdFusion parsing JSON). It's a reasonable question, and the root of the problem is they tried to use the online ColdFusion docs to learn how to do something. Worse: they tried to glean how the deserializeJson() function works from reading the code example. One cannot really fault a newbie for RTFMing, but this is often not a helpful thing to do when trying to learn CFML. Because the code examples on the Adobe ColdFusion documentation site are, generally, sh!t.

Here's the code example. How quickly can you spot the actual usage of deserializeJson():

<!--- First, find the positions of the columns in the data array. --->

<cfsetcolList=ArrayToList(cfData.COLUMNS)>

<cfsetcityIdx=ListFind(colList, "City")>

<cfsettempIdx=ListFind(colList, "Temp")>

<cfsetfcstIdx=ListFind(colList, "Forecasts")>

<!--- Now iterate through the DATA array and display the data. --->

<cfoutput>

<cfloopindex="i"from="1"to="#ArrayLen(cfData.DATA)#">

<h3>#cfData.DATA[i][cityIdx]#</h3>

Current Temperature: #cfData.DATA[i][tempIdx]#

<b>Forecasts</b>

<cfloopindex="j"from="1"to="#ArrayLen(cfData.DATA[i][fcstIdx])#">

<b>Day#j#</b>

Outlook: #cfData.DATA[i][fcstIdx][j].WEATHER#

High: #cfData.DATA[i][fcstIdx][j].HIGH#

Low: #cfData.DATA[i][fcstIdx][j].LOW#

</cfloop>

</cfloop>

</cfoutput>

</cfif>

Note: I have not lost any formatting there... that's how it's presented in the docs.

What a f***ing mess. There's 43 lines of code there, and it's not until line 17 that deserializeJson() is actually used. Every single other line in there is a complete waste of time. What the hell has HTTP calls, treating the result like JSONP and mark-up got to do with deserialising JSON? Nothing.

Also note at no point do they actually show what the result of that bullsh!t might be.

There should then be additional simple - and separate - examples showing the other options such as how to deserialise a previously serialised query, so that the deserialised object becomes a query again, not a struct of arrays of structs (or however the hell ColdFusion handles it).

And another example of using a custom deserialiser. Although even that is probably out of scope for this page, instead linking through to a broader section on custom serialisers.

None of this is rocket science. Even making the comparison to rocket science is like comparing... oh, I dunno... scribbling on a sheet of paper with a crayon to rocket science.

It's nice and succinct which is good, but I think it unnecessarily muddies the water by using " as the string delimiter, as JSON itself requires that character as a delimiter, so the source string is - as a result - a bit confusing. For no good reason, given Pete could have instead simply used a single quote as a delimiter:

It's not much different, but I think it is a lot clearer. Always try to keep code examples on point. If somethign is unnecessary to the example: get rid.

One great thing about cfdocs.org is that it's community maintainable. So I expect by the time you come to read this, Dan Fredericks will have gone in and fixed this (that's me getting revenge on Dan for him volunteering me to write docs, yesterday ;-).

And one crap thing about the Adobe docs - ell: "another crap thing ~" - is that whilst they used ot be community maintainable, they removed that functionality recently. Cos they're daft.

Anyway, I'll jump on Jacob to get this sorted out, and hopefully encourage him to start weeding out the rest of the crap in there, and get the code examples more focused. I hasten to add that I doubt Jacob wrote those docs... they will predate his involvement in this. I don't blame him one bit for the lack of common sense employed on that site.

Search This Blog

About

I've been a web developer since 2001. I have spent 13yrs as a CFML developer, and until Sept 2014, that was the main subject matter here. I've now been re-tasked as a PHP developer, so learning PHP will become the focus of this blog. But I also mess around with other languages too.

I tend to be a bit "forthright" in my opinions, I am indelicate, and I tend to swear too much. This will come out occasionally here: I make no apology for it.

Everything said here is my own opinion. Feel free to disagree with me :-)