Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Pablo Fredrikson
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Pablo Fredrikson ( @pablokbs )

Reflecting On Natural Language Operators In ColdFusion

By on
Tags:

The other day, on the Lucee Dev Forum, I suggested that ColdFusion might benefit from having starts with and ends with operators. These would fall under the "natural language" operators, in that they read like normal human language, not computer jargon. But, my suggestion is somewhat fraudulent considering the fact that I never use the natural language operators in ColdFusion. This conversation, however, gave me pause to reflect on this choice more deeply.

In ColdFusion, there's nothing "unique" about the natural language operators. Everything that can be done with human speak can also be done with more traditional operators and function calls. For example, here's two sets of expressions that all evaluate to Truthy outcomes. The first half uses the natural language operators and the second half uses the standard equivalents:

<cfscript>

	// All of these tests have a "Truthy" outcome.

	// Natural language operators.
	echo( "foo" is "foo" );
	echo( "foo" equal "foo" );
	echo( "foo" contains "oo" );
	echo( "foo" does not contain "bar" );
	echo( "foo" not equal "fooo" );
	echo( 2 greater than 1 );
	echo( 1 less than or equal to 2 );

	// Computer science operators.
	echo( "foo" == "foo" );
	echo( "foo".findNoCase( "oo" ) );
	echo( ! "foo".findNoCase( "bar" ) );
	echo( "foo" != "fooo" );
	echo( 2 > 1 );
	echo( 1 <= 2 );

</cfscript>

Note: String-based operators are all case-insensitive in ColdFusion. Which is why I am using the .findNoCase() function and not the .find() function.

As you can see, the natural language operators are a bit more friendly. And, can more easily be understood by those less familiar with the language. But, they are much wordier. And, they don't offer anything unique. That is, there's nothing that they can do that can't be done using other language semantics.

For example, my suggestion to add starts with and ends with operators can be accomplished either with existing constructs or with custom functions (UDF). The following code breaks because these operators don't actually exist in CFML. But, this shows my intent; and, demonstrates that such made up operators can already by implemented using either Regular Expression anchors or string slicing:

<cfscript>

	// CAUTION: These DO NOT EXIST in the CFML language.
	// CAUTION: These DO NOT EXIST in the CFML language.
	// --
	echo( "ben@bennadel.com" starts with "ben" );
	echo( "ben@bennadel.com" does not start with "sarah" );
	echo( "ben@bennadel.com" ends with "@bennadel.com" );
	echo( "ben@bennadel.com" does not end with "@example.com" );
	// --
	// CAUTION: These DO NOT EXIST in the CFML language.
	// CAUTION: These DO NOT EXIST in the CFML language.


	// Using existing RegEx constructs (with boundary anchors).
	echo( "ben@bennadel.com".reFindNoCase( "^ben" ) );
	echo( ! "ben@bennadel.com".reFindNoCase( "^sarah" ) );
	echo( "ben@bennadel.com".reFindNoCase( "@bennadel\.com$" ) );
	echo( ! "ben@bennadel.com".reFindNoCase( "sarah$" ) );

	// Using user defined functions (UDF).
	echo( startsWith( "ben@bennadel.com", "ben" ) );
	echo( ! startsWith( "ben@bennadel.com", "sarah" ) );
	echo( endsWith( "ben@bennadel.com", "@bennadel.com" ) );
	echo( ! endsWith( "ben@bennadel.com", "@example.com" ) );

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	public boolean function startsWith(
		required string source,
		required string substring
		) {

		return( left( source, len( substring ) ) == substring );

	}

	public boolean function endsWith(
		required string source,
		required string substring
		) {

		return( right( source, len( substring ) ) == substring );

	}

</cfscript>

There is something very alluring about the natural language operators. So, why don't I ever use any of them?

My first reaction is extremely superficial: some part of me believes that "real programmers" don't use these types of operators. What is this based on? ABSOLUTELY NOTHING! This is just some weird-ass bias that my brain has developed.

I wonder if it is rooted in the old tag-based constraints in the early days of ColdFusion. It used to be that in tag-based markup, you couldn't use all of the available operators. For example, if you tried to use "greater than" in a <cfif> tag:

<cfif ( query.recordCount > 3 )>

... ColdFusion would blow up because it thought the greater than (>) operator was actually the end of the <cfif tag. As such, when dealing with tags, you had to replace the bracket-based operators with things like gt, gte, lt, and lte (I think you even had to replace == with eq if memory serves):

<cfif ( query.recordCount gt 3 )>

I think this original constraint created an accidental hierarchy in my head: there were the operators that I wanted to use; and then, there were the operators that I had to use due to limitations of the CFML parser. And, while this really only applied to some of the operators, this divergence automatically grew to include all of the natural language operators. Meaning, the natural language operators were the operators that were forced on me due to the compiler.

This made me view the natural language operators in a diminishing light. They became the "runner up" operators. The "ugg, I can't believe this compiler is still broken, why won't they fix it" operators.

This isn't fair to the natural language operators. And, of course, the logic and reasoning parts of my brain do not diminish the operators or the developers who use them. But, I'm only human; and, I will admit that I do get a small twinge when I see them in code.

But, again, that's my own baggage.

Another reason that I push back against them is that some of them are just a lot more to read. The most egregious one is, less than or equal to. Compare that with, <=. Not only is <= easier to read, it's a single token. Which makes it much easier for the brain to recognize and process in its pattern matching.

And, here's some more of my mental baggage: I crave consistency. Which means, some part of me avoids the natural language operators simply because it would break my pattern of usage. This is so silly, I know! But, I have trouble accepting the idea that some of my expressions can use the terse operators and some of my expressions can use natural language operators. Some part of me feels that mixing-and-matching is "sloppy". Like when someone pastes a Script-based Function into a Tag-based Component without rewriting it—sloppy!

But, again, this is just my own emotional baggage!

Another reason that I have trouble with natural language operators has nothing to do with ColdFusion at all: the unless operator. I believe this is a Ruby operator that allows you to write code like this:

return "yes" unless psyched_you_out

I suppose this isn't really an "operator", it's more of a control-flow construct (like if and else). But—to me—this way of writing code is just bat-shit crazy! It feels like an attempt to use "natural language" to improve things; but, all it does it make the code more confusing by putting the condition after the action being taken.

I don't quite know why seeing unless scarred me so deeply. I don't even use Ruby; and yet, this construct haunts me. And, I am sure, it has unfairly tainted a larger "natural language" approach.

In the end, I don't think I have any compelling reason to entirely rule-out natural language operators. The biggest thing holding me back is my own emotional baggage. And, I'm sure that the only way I can overcome such a personal hurdle is with usage. So, maybe I'll force myself to use more of the natural language operators and see how it feels.

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

Reader Comments

15 Comments

Great, now ChatGPT is going to parse your blog and it won't be long before GitHub CoPilot is suggesting your fake operators to everyone! 😁

I had the same mental association with GTE, LT, etc as the "second-class" operators I had to use in tags back in the day due to parsing issues. I don't tend to use the GREATER THAN EQUAL TO sort of ones just because I think >= is also quite readable and much more concise. I do use contains quite often however as I do like the readability and it saves me one more "nesting" of parenthesis around my value.

I do use someString.startsWith() fairly often, but one must be VERY CAREFUL as that is a member function on the java.lang.String class and is case sensitive! There's a fighting chance I might use something like

if( foo STARTS WITH "f" ) {
}

in my code, but I do also half expect the rest of the programming world to laugh at that as "not a real language".

15,688 Comments

@Brad,

I can relate. The contains feels like the only one of the existing ones that I would really consider using. But, I have such a mental block to it. And, I'm always so torn about wanting them to add more member-methods to the data types. Does it just start to bloat the language? Would adding "string".startsWith() to the CFML spec itself be a problem? Or should that really be in a utility library?

Obviously, as you point out, Java answered that question by adding directly to the java.lang.String class. But, it can be a slipper slope. I never know what the right answer is.

15,688 Comments

I wish I had a litmus test where I could easily answer the question: should it be a member method, as in:

String.includes( value )

... or, should it be in a standard utility library like:

StringUtils.includes( source, value )

I wish I had some decision tree that made it easy to answer that type of a question.

15 Comments

Would adding "string".startsWith() to the CFML spec itself be a problem?

Sadly yes, because a lot of code and even frameworks today rely on that calling the Java method which is case sensitive, so adding a CFML version would be a breaking change. This is one of the issues with having a sort of mashup between CF member functions and actual Java member functions. The former employ a fair bit of magic and used to not work if the simple value was actually a boolean or float under the covers. The latter defo requires you to have an actual java string, but at least that is understandable.

Java answered that question by adding directly to the java.lang.String class

It's interesting to note Java also has a handful of helper methods for things like files or arrays in their Files and Arrays class In some cases, Java will put helper methods directly on interfaces such as Map.of(). I don't know what Java's litmus test is-- most of these cases involve factory methods for creating new instances, but Java's Arrays class has an boatload of methods for things like filling an array with values, or sorting an array.
https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html
Though, considering how arrays are a primitive in Java and have no methods, perhaps that's the real reason why these methods live here.

15,688 Comments

@Brad,

Yeah, that's a great point re: case-sensitive Java call vs. what would presumably be a case-insensitive ColdFusion call. Would absolutely break some stuff that is already out in the wild. 😨 There's definitely no easy answer for that.

Unless they made it into an Application.cfc setting — just kidding 🤣

21 Comments

Letters tend to be easier for me to type without much thought as opposed to symbols. Yes, they're just one row further away, but I am much more accustomed to typing letters than brackets and equal signs, so it requires less "work" to just type gte compared to >=.

I still generally prefer symbols, but when I have the pleasure of working with ColdFusion for a change, it's nice to be able to just go for the more comfortable to type operators.

15,688 Comments

@Kevin,

I actually find the eq, gt, gte, lt, and lte operators kind of nice. Since our code-base is so old, we still have a good number of these mixed in with the view-templates; and, my brain seems to process them just as easily as anything else. They are nice and short.

Post A Comment — I'd Love To Hear From You!

Post a Comment

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