isEmpty function

August 17, 2012 · By Gert Franz · 9 Comments

So what I for instance do is:
<cfif len(trim(sMyVar)) neq 0>
or
<cfif qry.recordCount neq 0>
or
<cfif arrayLen(structKeyArray(sct)) neq 0>
or
<cfif arrayLen(arr) neq 0>

So I came up with a function that I wrote the other day which does these checks for me and I can pass anything I like to it. The function is called isEmpty(any) and takes any kind of variable you pass to it. Then instead of the above I can write:
<cfif !isEmpty(sMyVar)>
or
<cfif !isEmpty(qry)>
or
<cfif !isEmpty(sct)>
or
<cfif !isEmpty(arr)>

Or of course the isEmpty() without the ! in front of it. here's the function and the corresponding test code:
<cfscript>
   boolean function isEmpty(required any oObj) {
      if (isSimpleValue(oObj)) {
         if (isDate(oObj)) {
            return true;
         } else if (isNumeric(oObj)) {
            return oObj eq 0;
         } else if (isBoolean(oObj)) {
            return !oObj;
         } else {
            return len(trim(oObj)) eq 0;
         }
      } else {
         if (isArray(oObj)) {
            return arrayLen(oObj) eq 0;
         } else if (isStruct(oObj)) {
            return arrayLen(structKeyArray(oObj)) eq 0;
         } else if (isQuery(oObj)) {
            return oObj.recordCount eq 0;
         }
      }
   }
   return false;
</cfscript>

testIsEmpty.cfm:
<cfinclude template="isEmpty.cfm">
<cfset aTest = [0,
      1,
      -1,
      "",
      "       ",
      "susi",
      true,
      false,
      [],
      [1],
      now(),
      {},
      {christine:""},
      query("susi":[1]),
      query("susi":[])
      ]>

      
<cfloop array="#aTest#" index="element">
   <cfdump eval=isEmpty(element) label="#serialize(element)#">
</cfloop>

If you want to have the function available for your complete Railo server, just copy it into:
{theDirectoryWhereTheRailoJARFileIsLocated}/railo-server/context/library/function
and if you like to have it in your local context only, it should go into:
WEB-INF/railo/context/library/function

Don’t forget to restart your railo server for it to work. I would appreciate feedback to it. And I suppose Railo 4.1 will have the function built in so that it runs way faster.

Tags: Extension · Features · HowTo · Railo 4.0

9 responses so far ↓

  • 1 Russ // Aug 18, 2012 at 9:22 AM

    While I agree that this is a useful function to have, I do not entirely agree on the implementation (given it's name).

    Numeric, Boolean, and Date types cannot be "empty" conceptually, so you shouldn't attempt to handle them. Throw an error instead.

    A string that has a space in it isn't really "empty" either. It has a length of 1.

    I think what you've done can certainly be good and useful, however you may wish to rethink your function name. The "empty" concept really only applies well to collections.

    Maybe you could break it up into isEmpty for collections, isBlank for strings, and isFalsy for numeric, boolean, and possibly date types?

    Remember that someone else will eventually have to work on your code, so try to be reasonably accurate and explicit with your names.
  • 2 Gert // Aug 18, 2012 at 10:44 PM

    Actually the way I use it, I prefer it more like that. Especially the isEmpty(string) statement. This is something I use very often: len(trim(string)) etc. And for numbers (IMHO) 0$ means there is nothing in my pocket. So 0 means empty to me :-)
    For the rest I am open...

    Gert
  • 3 Russ // Aug 18, 2012 at 11:50 PM

    Of course YOU know what your function does, but what about the next guy who uses it assuming it means something else, and writes code like this?

    gameNotStartedYet = isEmpty(golfScore);
    makePlans = !isEmpty(futureLandingDate);
    endOfText = isEmpty(nextCharacter);

    And what about other types of non-simple objects, such as xml objects, or other types that CF introduces in the future? I suggest throwing an error for types that you did not plan for. Do you really want to be responsible for this:

    launchAllTheNukes = !isEmpty(someTypeYouDidntConsider);

    ?

    Another problem with your code is that CF automagically converts lots of strings into booleans. So isBoolean() will return true for "TRUE", "FALSE", "YES", "NO", "1", "0", "100", "1.1"... So isEmpty("false") returns true, even though I intended to see if the string "false" was to be considered empty (having a trimmed length of 0).

    (Also, it looks as though your last "return false" is outside of the function? Probably a cut/past accident?)

    If you want to ensure that this function acts as you expect it to, I highly recommend writing some MXUnit unit tests for all the various cases (both positive and negative).
  • 4 Igal // Aug 20, 2012 at 1:38 AM

    I, too, often find myself trimming strings so I like the isEmpty( string ) the way that Gert suggested.

    as for Booleans and Strings -- CFML has always been casting types implicitly, and since the isBoolean() test comes before the String length I think it should be fine.

    one thing to remember about writing custom BIFs is that the filename and the function name must be consistent. I'm not sure if that is documented anywhere, so in this case the isEmpty function must be in a isEmpty.cfm file (not case sensitive, of course).
  • 5 James Moberg // Aug 20, 2012 at 5:14 PM

    I went to CFLib.org to see if this UDF had been posted there and found that there is already one by the same name that behaves a little differently and doesn't test all conditions.
    http://www.cflib.org/udf/isEmpty

    Also, have you considering using YesNoFormat() for "false"? (Ig guess it's "trueFalseFormat()" for Railo.) What if "false" is a string response to a fill-in-the-blank question or a radio dialog box option. Extra server-side logic would be needed to ensure that these responses are identified as "empty" versus "filled in and negative."
  • 6 Dawesi // Sep 10, 2012 at 1:40 PM

    I like it, and when test cases are hammered through, will be a welcome addition.
  • 7 Ronan // Nov 8, 2012 at 12:42 PM

    I liked this.

    This follow the same concept from python where everything is an object.

    You have to just:
    if myVar:
    doThis()

    python knows that "" for string is empty/false, 0 for number is empty/false, an array with no objects is empty/false.

    It's much more intuitive.
  • 8 Michael Offner // Dec 20, 2012 at 5:13 PM

    FYI: there is a build in function "empty" that covers this functionality
  • 9 Will B. // Mar 19, 2013 at 7:52 PM

    Railo patch 4.1.0.004.rc, at least. Watch out.... I think they added an isEmpty() function. Found that an older version of Coldbox has an isEmpty() function, a custom UDF that is.

    Had to roll back the batch.

    - WB

Leave a Comment

Leave this field empty: