Why is 'if name is empty' not true when the String is unset?

← Common String Operations · Ref: Q1480

An UNSET String is not empty - and it is not 'not empty' either. 'name is empty' on an unset String gives an UNSET Boolean, and an if whose condition is unset does not take its branch. So the branch below is skipped exactly when there is no name at all, which is usually the very case it was written for:

  trapCheck()
    -> name as String
    <- rtn as String: "has text, or the check was skipped"
    if name is empty
      rtn := "empty"

trapCheck(String()) returns "has text, or the check was skipped". Writing 'is not empty' instead does not help: it is unset too, so that branch is skipped as well.

WHY

A value is absent, present but unset, or set. An operator on an unset value gives an unset result instead of guessing, and if, while and the ternary act only on a SET true. An empty String "" IS set - its value is known, it has no characters - so 'is empty' is true for it. Missing and blank are different answers, and EK9 keeps them apart.

SAY WHICH ONE YOU MEAN

Missing OR blank - test set-ness first:

  blankOrMissing()
    -> name as String
    <- rtn as Boolean: not name? or name is empty

Missing and blank handled differently - '?' first, then 'is empty':

  describe()
    -> name as String
    <- rtn as String?
    if not name?
      rtn := "missing"
    else if name is empty
      rtn := "empty"
    else
      rtn := `text '${name}'`

Only real text - 'name? and name is not empty':

  displayName()
    -> name as String
    <- rtn as String: "(anonymous)"
    if name? and name is not empty
      rtn := name

The program below runs each one on an unset String, on "" and on "Alice". A collection is never unset once it exists (see Q1019), but a String - a parameter, a field, a value read from input - can be.

Example

defines module qa.stringops.unsetisnotempty

  defines function

    trapCheck()
      -> name as String
      <- rtn as String: "has text, or the check was skipped"
      if name is empty
        rtn := "empty"

    blankOrMissing()
      -> name as String
      <- rtn as Boolean: not name? or name is empty

    describe()
      -> name as String
      <- rtn as String?
      if not name?
        rtn := "missing"
      else if name is empty
        rtn := "empty"
      else
        rtn := `text '${name}'`

    displayName()
      -> name as String
      <- rtn as String: "(anonymous)"
      if name? and name is not empty
        rtn := name

  defines program

    UnsetIsNotEmptyDemo()
      stdout <- Stdout()
      missing <- String()
      blank <- ""
      alice <- "Alice"

      stdout.println(`trap on unset: ${trapCheck(missing)}`)
      stdout.println(`trap on blank: ${trapCheck(blank)}`)
      stdout.println(`is empty on unset is set?: ${(missing is empty)?}`)
      stdout.println(`is not empty on unset is set?: ${(missing is not empty)?}`)

      stdout.println(`blankOrMissing unset: ${blankOrMissing(missing)}`)
      stdout.println(`blankOrMissing blank: ${blankOrMissing(blank)}`)
      stdout.println(`blankOrMissing text: ${blankOrMissing(alice)}`)

      stdout.println(`describe unset: ${describe(missing)}`)
      stdout.println(`describe blank: ${describe(blank)}`)
      stdout.println(`describe text: ${describe(alice)}`)

      stdout.println(`displayName unset: ${displayName(missing)}`)
      stdout.println(`displayName blank: ${displayName(blank)}`)
      stdout.println(`displayName text: ${displayName(alice)}`)
Other ways to ask this
  • My 'if name is empty' branch is skipped when no name was given - why?
  • Is an unset String empty in EK9?
  • How do I check that a String is missing or blank?
  • Why does 'is not empty' also skip its branch for an unset String?

Coming from another language?

Java: name.isEmpty() on null throws NullPointerException, so code writes name == null || name.isEmpty() (or StringUtils.isEmpty). Kotlin: name.isNullOrEmpty(). Python: 'if not name' treats None and "" alike. C#: string.IsNullOrEmpty(name). EK9: an unset String gives an unset answer to 'is empty', and an if skips an unset condition - so write 'not name? or name is empty' when missing and blank mean the same thing.

Keywords: unset, is not empty, blank, tri-state, null or empty, String, set check, empty, is empty, ?, isNullOrEmpty, missing