Saturday, 30 January 2016

Appendix to previous article: Python examples of truthy/falsy

G'day:
All code and no narrative, this one. Here's the Python 3 equivalent of the Groovy code from the previous article (CFML (or probably LuceeLang) and what constitutes "The Truth").

print("none")
if None:
    print("truthy")
else:
    print("falsy")
print("=====================")


print("empty string")
if "":
    print("truthy")
else:
    print("falsy")
print("=====================")

print("non-empty string")
if "0":
    print("truthy")
else:
    print("falsy")
print("=====================")

print("zero")
if 0:
    print("truthy")
else:
    print("falsy")
print("=====================")

print("non-zero")
if -1:
    print("truthy")
else:
    print("falsy")
print("=====================")

print("empty list")
if []:
    print("truthy")
else:
    print("falsy")
print("=====================")


print("non-empty list")
if [None]:
    print("truthy")
else:
    print("falsy")
print("=====================")


print("empty dictionary")
if {}:
    print("truthy")
else:
    print("falsy")
print("=====================")

print("non-empty dictionary")
if {"key":None}:
    print("truthy")
else:
    print("falsy")
print("=====================")

class Test:
    def __init__(self, value):
        self.value = value

    def __bool__(self):
        return self.value == "truthy"

print("truthy object")
test = Test("truthy")
if test:
    print("truthy")
else:
    print("falsy")
print("=====================")

print("non-truthy object")
if Test("anything else"):
    print("truthy")
else:
    print("falsy")
print("=====================")

Output:

>python truthy.py
none
falsy
=====================
empty string
falsy
=====================
non-empty string
truthy
=====================
zero
falsy
=====================
non-zero
truthy
=====================
empty list
falsy
=====================
non-empty list
truthy
=====================
empty dictionary
falsy
=====================
non-empty dictionary
truthy
=====================
truthy object
truthy
=====================
non-truthy object
falsy
=====================

>

The most interesting thing in this is __init__ and __bool__? FFS. I've found a language even worse than PHP for its shit function names and underscore usage, it seems.

More Guinness, pls...

--
Adam

CFML (or probably LuceeLang) and what constitutes "The Truth"

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:

TypeValueCoerces 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!=0true
Numeric0false

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.

Here's a quick demo, which is fairly self-explanatory:

print "populated string: "
println " " ? "truthy" : "falsy" 

print "empty string: "
println "" ? "truthy" : "falsy" 
println "============="

print "non-zero: "
println (-1 ? "truthy" : "falsy") 

print "zero: "
println 0 ? "truthy" : "falsy" 
println "============="

print "populated collection: "
println([null] ? "truthy" : "falsy") 

print "empty collection: "
println([] ? "truthy" : "falsy") 
println "============="

print "populated map: "
println([key:""] ? "truthy" : "falsy") 

print "empty map: "
println([:] ? "truthy" : "falsy")
println "============="

class Test{
    String value
    
    Test(value){
        this.value = value
    }
    
    boolean asBoolean(){
        return (value == "truthy")
    }
}

print "truthy object: "
println new Test("truthy") ? "truthy" : "falsy" 

print "falsy object: "
println new Test("anything else") ? "truthy" : "falsy" 
println "============="


And the output:

>groovy truthy.groovy
populated string: truthy
empty string: falsy
=============
non-zero: truthy
zero: falsy
=============
populated collection: truthy
empty collection: falsy
=============
populated map: truthy
empty map: falsy
=============
truthy object: truthy
falsy object: falsy
=============

>

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.

Back to me Guinness...

--
Adam

Friday, 29 January 2016

Brave users will not be able to access this blog

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.

As such I am shortly putting some JS in my main template, thus:

if ((window.navigator.userAgent.indexOf("brave") > 0)  && (document.location.pathname != "/2016/01/brave-users-will-not-be-able-to-access.html")){
    document.location = "/2016/01/brave-users-will-not-be-able-to-access.html"
}

This is based on my user agent string being:

Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) brave/0.7.10 Chrome/47.0.2526.110 Brave/0.36.5 Safari/537.36

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.

Righto.

--
Adam

Thursday, 28 January 2016

TeraTech's State of the CF Union Survey 2016

G'day:
We're trying to drum up more submissions to TeraTech's State of the CF Union Survey 2016. That's a link to their blog article about it, and the survey itself is here.

As well as making sure you fill it in yourself, please do the rounds of your colleagues and contacts who don't usually participate in the community, and... well... get them to pitch in.

Cheers.

--
Adam

ColdFusion: help with clarifying if an issue exists with CF's ORM implementation

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?

Here's the detail:

4024472: ORM entities are incorrectly created when using single table inheritance with mappedSuperClass

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 set
this.ormsettings.savemapping=true and take a look at the hbmxml files.

The XML in dog.hbmxml contains the fields from base.cfc:
<property name="name" type="string"><column name="name"/></property>


Steps to Reproduce:

Use the files included with this bug [I'll include 'em inline here].


// base.cfc
component mappedSuperClass="true"
{
  property fieldType="id" name="id" generator="increment";
  property fieldType="column" name="name";
}

// animal.cfc
component extends="base" persistent="true" table="animal" discriminatorColumn="type"
{
  property fieldType="column" name="isAlive" type="boolean" default=true;
}

// dog.cfc
component extends="animal" persistent="true" table="animal" discriminatorValue="dog"
{
  property fieldType="column" name="furColor" default="brown";
}

Actual Result:

An exception: Repeated column in mapping for entity: {entity-name} column: {column-name} (should be mapped with insert="false" update="false")

Expected Result:

Correctly generated hibernate entities.

Any Workarounds:

You can write your own .hbmxml files to work around the problem.

Further information


For clarity: the dog entity gets the following HBM XML generated:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-cascade="none" default-access="property" default-lazy="true" auto-import="true">
 <subclass discriminator-value="dog" entity-name="dog" extends="cfc:18502eb2916b8041cf1e.animal" lazy="true" name="cfc:18502eb2916b8041cf1e.dog" dynamic-update="false" dynamic-insert="false" select-before-update="false">
  <property name="name" type="string" unique="false" optimistic-lock="true" lazy="false" generated="never">
   <column name="name" />
  </property>
  <property name="furColor" type="string" unique="false" optimistic-lock="true" lazy="false" generated="never">
   <column name="furColor" />
  </property>
 </subclass>
</hibernate-mapping>


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?

Cheers.

--
Adam

Wednesday, 27 January 2016

ColdFusion: how not to document a function

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():

<!--- Get the JSON Feed --->
<!--- JSON data is sometimes distributed as a JavaScript function.
The following REReplace functions strip the function wrapper. --->
<cfset theData=REReplace(cfhttp.FileContent,
"^\s*[[:word:]]*\s*\(\s*","")>
<cfset theData=REReplace(theData, "\s*\)\s*$", "")>
<!--- Test to make sure you have JSON data. --->
<cfif !IsJSON(theData)>
<h3>The URL you requested does not provide valid JSON</h3>
<cfdump var="#theData#">
<!--- If the data is in JSON format, deserialize it. --->
<cfelse>
<cfset cfData=DeserializeJSON(theData)>
<!--- Parse the resulting array or structure and display the data.
In this case, the data represents a ColdFusion query that has been
serialized by the SerializeJSON function into a JSON structure with
two arrays: an array column names, and an array of arrays,
where the outer array rows correspond to the query rows, and the
inner array entries correspond to the column fields in the row. --->
<!--- First, find the positions of the columns in the data array. --->
<cfset colList=ArrayToList(cfData.COLUMNS)>
<cfset cityIdx=ListFind(colList, "City")>
<cfset tempIdx=ListFind(colList, "Temp")>
<cfset fcstIdx=ListFind(colList, "Forecasts")>
<!--- Now iterate through the DATA array and display the data. --->
<cfoutput>
<cfloop index="i" from="1" to="#ArrayLen(cfData.DATA)#">
<h3>#cfData.DATA[i][cityIdx]#</h3>
Current Temperature: #cfData.DATA[i][tempIdx]#
<b>Forecasts</b>
<cfloop index="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.

The example should be this:

someJson = '{"stringValue":"a string", "arrayValue": ["a","b","c"], "booleanValue":true, "numericValue": 42}';
myStruct = deserializeJson(someJson);

writeDump(myStruct);

And simple show the output:


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.

Almost all the docs for ColdFusion are like this. Crap.

cfdocs.org is better in this regard, but I think the example here does still let them down a bit:

person = deserializeJSON("{""company"":""Foundeo"",""name"":""Pete Freitag""}");
writeOutput( person.company );

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:

person = deserializeJSON('{"company":"Foundeo","name":"Pete Freitag"}');
writeOutput( person.company );

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.

Righto.

--
Adam