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