Skip to main content
Ben Nadel at dev.Objective() 2015 (Bloomington, MN) with: Kev McCabe
Ben Nadel at dev.Objective() 2015 (Bloomington, MN) with: Kev McCabe ( @bigmadkev )

What If ColdFusion Recognized More Truthy / Falsey Values

By on
Tags:

I think all programming languages have the concept of a Boolean - that is, a value that can be either True or False. Most programming languages then additionally have Truthy / Falsey values - that is, values that can be implicitly converted into Boolean values. In ColdFusion, the number zero is considered a Falsey. In Javascript, a good number of values can be considered Falsey. I know that some people posit that Truthy / Falsey values make code harder to read; but, I love them. Sometimes, I wonder what ColdFusion would look like if more values could be implicitly converted to True and False.

To consider the appropriate Truthy / Falsey values, one must simply consider the conditional checks that he or she uses most often within a ColdFusion application. When it comes to control flow, here's what I check most often:

  • Whether or not a query has any rows.
  • Whether of not an array has a length.
  • Whether or not a string is empty.

Taking these conditions, we can now encapsulate them within a ColdFusion user defined function (UDF), truthy():

<cffunction
	name="truthy"
	access="public"
	returntype="boolean"
	output="false"
	hint="I determine if the given argument can be converted / shoe-horned into a boolean value. By default, we will be trying to create a FALSE; everything else will be TRUE.">

	<!--- Define arguments. --->
	<cfargument
		name="value"
		type="any"
		required="false"
		hint="I am the truthy / falsey value being converted into a Boolean value."
		/>

	<!---
		Check to see if the given argument can be converted to a
		False value. The following will be considered falseys:

		-- NULL / undefined value
		-- False (boolean)
		-- Empty queries
		-- Empty arrays
		-- Empty structs
		-- Zero (numeric) [same as Boolean already]
		-- Empty strings
	--->
	<cfif (
				!structKeyExists( arguments, "value" )
			||
				(
					isBoolean( arguments.value ) &&
					!arguments.value
				)
			||
				(
					isQuery( arguments.value ) &&
					!arguments.value.recordCount
				)
			||
				(
					isArray( arguments.value ) &&
					!arrayLen( arguments.value )
				)
			||
				(
					isStruct( arguments.value ) &&
					!structCount( arguments.value )
				)
			||
				(
					isStruct( arguments.value ) &&
					structKeyExists( arguments.value, "toBoolean" ) &&
					!arguments.value.toBoolean()
				)
			||
				(
					isSimpleValue( arguments.value ) &&
					!len( arguments.value )
				)
		)>

		<!--- This can be considered a false. --->
		<cfreturn false />

	</cfif>

	<!---
		If we made it this far, then the given value could not be
		converted to a False; as such, it must be True (that which
		is not false must be true - there is no room for anything
		in between).
	--->
	<cfreturn true />
</cffunction>


<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->


<!--- Build up an empty query. --->
<cfset myQuery = queryNew( "id, name" ) />

<!--- Build up an empty array. --->
<cfset myArray = [] />

<!--- Build up an empty struct. --->
<cfset myStruct = {} />

<!--- Build up an empty string. --->
<cfset myString = "" />


<!--- Now, let's test each of these "empty" data types. --->
<cfoutput>

	<!--- Null value. --->
	<cfif truthy( javaCast( "null", "" ) )>
		Null Value: True
	<cfelse>
		Null Value: False
	</cfif>

	<br />

	<!--- Empty query. --->
	<cfif truthy( myQuery )>
		Empty Query: True
	<cfelse>
		Empty Query: False
	</cfif>

	<br />

	<!--- Empty array. --->
	<cfif truthy( myArray )>
		Empty Array: True
	<cfelse>
		Empty Array: False
	</cfif>

	<br />

	<!--- Empty struct. --->
	<cfif truthy( myStruct )>
		Empty Struct: True
	<cfelse>
		Empty Struct: False
	</cfif>

	<br />

	<!--- Empty string. --->
	<cfif truthy( myString )>
		Empty String: True
	<cfelse>
		Empty String: False
	</cfif>

</cfoutput>


<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->


<!---
	To make sure we aren't getting false Falses, let's run the
	same tests with non-empty values.
--->


<!--- Build up a non-empty query. --->
<cfset queryAddRow( myQuery, 1 ) />

<!--- Build up a non-empty array. --->
<cfset myArray = [ "Joanna" ] />

<!--- Build up a non-empty struct. --->
<cfset myStruct = { tricia = "my BFF" } />

<!--- Build up a non-empty string. --->
<cfset myString = "Outstanding" />


<!--- Now, let's test each of these "full" data types. --->
<cfoutput>

	<br />
	<br />

	<!--- Non-empty query. --->
	<cfif truthy( myQuery )>
		Non-Empty Query: True
	<cfelse>
		Non-Empty Query: False
	</cfif>

	<br />

	<!--- Non-empty array. --->
	<cfif truthy( myArray )>
		Non-Empty Array: True
	<cfelse>
		Non-Empty Array: False
	</cfif>

	<br />

	<!--- Non-empty struct. --->
	<cfif truthy( myStruct )>
		Non-Empty Struct: True
	<cfelse>
		Non-Empty Struct: False
	</cfif>

	<br />

	<!--- Non-empty string. --->
	<cfif truthy( myString )>
		Non-Empty String: True
	<cfelse>
		Non-Empty String: False
	</cfif>

</cfoutput>

For the most part, you can see that this ColdFusion user defined function (UDF) simply brings the conditional logic into the function, allowing the core values to be seen as true or false depending on their runtime state. I've also added a check for structCount() to the list of possible truthy / falsey concerns; and, I've provided for a struct-like object to present a toBoolean() method.

NOTE: I think that Railo has these "magic functions" for component-based type casting; but, I could not find a reference to them.

After the UDF, I'm simply running a few tests to make sure that our Falseys are False and our Truthys are True:

Null Value: False
Empty Query: False
Empty Array: False
Empty Struct: False
Empty String: False

Non-Empty Query: True
Non-Empty Array: True
Non-Empty Struct: True
Non-Empty String: True

Truthy / Falsey values are pretty awesome. But obviously, having to use an intermediary user defined function in order to leverage these truthy / falsey values takes some of the allure out of it. Perhaps one day, ColdFusion will allow us to provide functions that define a more robust runtime datatype casting?

Want to use code from this post? Check out the license.

Reader Comments

23 Comments

I usually just use query_name.RecordCount and arrayLen(array_name) and len(string) when checking, because although they're not directly binary, it still has the zero/positive number duality.

I wonder what the difference in system resources is for each method.

15,643 Comments

@Kate,

Yeah, that's what I typically use currently. But, sometimes, I really wish I could just do:

<cfif query> ... or
<cfif array>

Or maybe I'm just crazy :)

15,643 Comments

@Lola,

You'd still have to know what kind of data types you are working with. This is just meant to be a short-hand for common use cases. For example, I could always use find() as such:

<cfif (find( .. ) neq 0)>

... but rather than using the explicit comparison, I would much rather (and do) use this:

<cfif find( ... )>

Here, the numeric index is being implicitly converted to a Boolean. Of course, I still need to know that the value coming back IS a number that that non-zero values are TRUE.

So, it works IF you know what you're dealing with - you can't get out of that :)

4 Comments

Ben, you're definitely NOT crazy for wishing this. :) I have wished that Coldfusion would cast more values to boolean for a long time. I mean, it's already such a loosely-typed language, it would make a lot of sense to extend the loosely-typed nature to cast everything you mention above to boolean when a boolean is needed.

I switch back and forth between programming in Javascript and Coldfusion so much, and I use truthiness/falsiness in Javascript so much that I very often forget about CF's selectivity in this area. I can't count the number of times I've seen:

The value '' cannot be converted to a boolean

on my pages. :)

15,643 Comments

@Darren,

Yeah, I love that Javascript will treat "" as a falsey! The whole concept of a truthy value is the closest thing to "Just do what I mean!" in programming :)

30 Comments

A minor quibble Ben, in this section:

# (
# isSimpleValue( arguments.value ) &&
# !len( arguments.value )
# )

only works if the simple value is truly empty. What about when there is a space or similar value? For most practical purposes a value with an space is also empty. Accordingly I'd make a slight change to this section:

# (
# isSimpleValue( arguments.value ) &&
# !len( trim( arguments.value ) )
# )

regards,
larry

9 Comments

Nice idea (and one that I also wish that CF would do more of) -- it gets tiring going through the whole test exist - test populated - test valid -- thing.

BUT, since I'm such a negative guy working for such a negative organization, we always assume falsey until proven otherwise. This way, we don't take any sort of good action to let you continue until your present a valid value, and so we'd never assume to return truth.

290 Comments

@Ben,

I think JavaScript's ability to use "if (obj.prop)" as an existence test is transforming you and your expectations for CF. It makes "if (prop in obj)" seem like StructKeyExists, doesn't it?

3 Comments

Ben, I completely agree with that these values are hard to read. There's a programmer here that always does:

<cfif len(string)>
...
</cfif>

Instead of <cfif string neq "">.

It works, but if you're reading the code fast, you will have to process that in your mind if you're not used to. Like:

1-) Well, here he is retrieving the length of a string
2-) The length can be any number
3-) The boolean for 0 is false, so if it is empty, then the result will be 0, which is false.
4-) if it is 1, then it will be true
5-) If it is more than 1.. then.. well, I think Coldfusion will interpret that as true too.

For me it would be much easier to read <cfif string neq "">, it wouldn't make me think too much.

15,643 Comments

@Larry,

I wouldn't be opposed to adding a trim to the simple value.

@Brian,

Ha ha ha :)

@WebManWalking,

Yeah, the "in" is very much like structKeyExists(). And then Javascript also has the hasOwnProperty() object method as well.

I'm just trying to pull in ideas from the various languages we use.

@Henrique,

I think it all is a matter of what you are accustomed to seeing. It's like the first time I ever looked at Ruby code and thought it looked like someone just scribbled all over the screen; the syntax was so different and confusing. But, people clearly love it.

So for me personally, I almost never have to test the length of a string unless I'm validating against a max length. Typically, the kind of validation that I do is for non-zero lengths.

30 Comments

@henrique

There is reason for using the len(trim()) or len() type of evaluation. Evaluating a boolean or a number is much more efficient and faster than doing an string evaluation like <cfif string neq "">.

8 Comments

Very neat idea.

@Ben/Lola,
Being able to do "<cfif query>" would be handy if query wasn't always a query object. An example being if you declared a variable at the start of a function as 0, but the setting the variable to the value of a query was the result of some if logic (so you may not always want to make the database call, so a query object is only created when you are making a database call). That would save on writing:

<cfif isQuery(query) and query.recordCount>

Granted, if query were ever 1, that would bork things up. But that goes back to knowing what you're working with.

@Larry,
I like that idea for trimming strings, but I would probably make it an optional argument for the rare cases that you want to include whitespace as a valid character (similar to listToArray).

For some reason whenever I read "truthy" or "falsey" in this post, I think of some cartoon characters in a sunny field teaching children about boolean logic.

383 Comments

Love truthy-falsies.

I've worked in very negative environments as described before also. In some languages, doesn't -1 evaluate to true? I found that confusing sometimes, because I generally often think... > 0 is true, 0 or below is false. And I think there is a language that evaluates it this way, but I am certain I recently got into a conversation with someone where we discussed the fact that -1 is true. I could see where this might would be a bit confusing to someone, especially someone who was used to negative, or "non-positive" numbers being false.

8 Comments

@Anna,

I think most languages that allow -1 to be true is because for that language, any non-zero numeric value is true.

This made me realize that I tend to force the "false <= 0" logic whenever I have a numeric variable that could be negative. I don't think I've ever intentionally let -1 be true (unless I was testing for that specific value). I'm not necessarily opposed to it, I just don't seem to use it. There must be a case for that though, right?

9 Comments

That -1 as a language primitive sounds very familiar -- I'll have to dredge around the headspace to see if I can find it.

My alternative point, @Ben, and you may have missed it through all the negativity is that in a secure computing environment, it is a Good Thing(TM) to assume falsey or denial until truthy is proven. Land Shark is a classic case of where you would want to deny anyone until they prove who they are (and no, "candygram" isn't enough)

Same thing with data -- Don't trust that a value has value until is proven otherwise -- sounds a little paranoid (and recursive), but has great value in keeping secure systems secure.

If I pass a structure, and it somehow passes the deliberative checks for being not being falsey, does that mean it's REALLY truthy? What if you haven't tested all possibilities for falsey? We're human (except for Camden, he's a Jedi), and I'd rather default return falsey but prove the truthy test internal -- unless I can guarantee that I've covered every falsey test AND nothing in future will ever come up that might trip it up.

Make sense? [I wrote this drivel, and it makes sense to me, but i work in a negative environent...]

68 Comments

PHP has an empty(value) function that does something similar. Where we might write structKeyExists(URL,'param') a whole lot of PHP code is written !empty($_GET['param']) instead of the true equivalent of array_key_exists('param',$_GET).

I have an aversion to the empty()-style checks because it just looks like you're using a value before you're sure it actually exists, which is something I spend quite a bit of time reinforcing that my students shouldn't do. But if that's how the majority of PHP code is written, then that's how I'll teach it ...

15,643 Comments

@Anna,

Yeah, as @Mike said, anything that is non-zero is true (in languages in which numbers can be implicitly converted to booleans).

@Brian,

I think, though, that there is a difference between data be considered valid from a business standpoint vs. true/false. For example, if you are presented with a Boolean value, there's no sense in assuming its False until proven that its True - the nature of a Boolean is to be either True or False. It's an entirely different thing to say is this *particular* boolean allowed to be True in this *particular* case, which is where you are going.

At the end of the day, whether or not a empty query is a truthy/falsey is completely different from whether or not YOUR application can allow for an empty query.

@Rick,

Speaking of checking values before they exist, isNull() is a fun example of that :) But, it is one that I have gotten used to. Of course, I am still a HUGE fan of CFParam - I like me some juicy defaults.

290 Comments

@Ben:

I'm not on GIT either. When you finally do it, would you please write an article here about how to set up an account and how it works?

Pretty please? :-)

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel