skip to content

In Ruby, which values are falsy, and does a condition treat 0, an empty string or an empty array as true?

level: juniorimportance: must knowfreq 82%

answer

  1. a very short falsy list
  2. numbers and empties are plain objects
  3. empty?, zero?, nil? ask explicitly
  4. nil == false is false
  5. gets returns nil only at end of input

basics

~10 s

Only nil and false are falsy in Ruby. Every other object, including 0, 0.0, "", [], {} and the string "false", is truthy, so test emptiness or zero explicitly with empty?, zero? or nil?.

solid answer

~40 s

Ruby conditions (`if`, `unless`, `while`, the ternary, `&&` and `||`) treat exactly two values as false: `nil` and `false`. Everything else is truthy, because `0`, `""` and `[]` are ordinary objects rather than special empty markers. So `if count` passes when `count` is `0`, and `if middle_name` passes when a form sent `""`. When you mean zero or empty, say so: `count.zero?`, `middle_name.empty?`, `list.empty?`, or `value.nil?` when only a missing value matters. `nil` and `false` are also distinct objects: `nil == false` returns `false`, although both fail a condition. Python and JavaScript treat `0` and the empty string as falsy, which is where this rule trips people moving to Ruby.

code

ruby · 12 lines
ruby
[nil, false, 0, 0.0, "", [], {}, "false"].each do |value|
  verdict = value ? "truthy" : "falsy"
  puts "#{value.inspect.ljust(7)} #{verdict}"
end
# nil     falsy
# false   falsy
# 0       truthy
# 0.0     truthy
# ""      truthy
# []      truthy
# {}      truthy
# "false" truthy

go deeper

for a junior

Recall the two-item falsy list, nil and false, and name 0, "" and [] as truthy. Show empty?, zero? and nil? as the explicit checks.

for a middle

Explain that the rule is uniform across if, while, the ternary and the logical operators, and that nil and false remain different objects with different to_s and nil? answers.

for a senior

Point out where truthiness hides bugs in real code: blank form fields arriving as "", counts of 0 passing guards, and nil versus false carrying different meanings in stored records.

for a principal

Frame the trade-off: a tiny falsy set makes presence checks cheap and predictable, but pushes teams to write explicit emptiness predicates, which reviewers should expect rather than bare truthiness tests.

## The rule: two falsy values Every Ruby condition asks one question of the value it is given: is it `nil` or `false`? If so, the condition fails; for **any other object**, it passes. Ruby's own syntax reference says it directly: for the tests in control expressions, `nil` and `false` are false-values, and `true` and any other object are true-values. The words **truthy** and **falsy** describe this. A value is *truthy* when a condition treats it as true, *falsy* when a condition treats it as false. In Ruby the falsy set has exactly two members: - **`nil`**, the single instance of `NilClass`, meaning "no value". - **`false`**, the single instance of `FalseClass`. The same rule applies everywhere a truth value is tested: `if`, `unless`, `elsif`, `while`, `until`, the ternary `a ? b : c`, and the operators `&&`, `||` and `!`. ## Values that surprise newcomers In Ruby, numbers, strings and collections are ordinary objects. None of them carries a special "empty means false" meaning, so all of the following are truthy: | Value | Truthy in Ruby? | Explicit question to ask instead | |---|---|---| | `0` | yes | `count.zero?` | | `0.0` | yes | `amount.zero?` | | `""` | yes | `text.empty?` | | `[]` | yes | `list.empty?` | | `{}` | yes | `options.empty?` | | `"false"` | yes | `flag == "false"` | | `nil` | **no** | `value.nil?` | | `false` | **no** | `value == false` | The comparison with other languages is where interviews go. In Python and JavaScript, `0` and the empty string are falsy, and in Python so are empty lists and dictionaries. Code ported from those languages often writes `if items` meaning "if there are any items"; in Ruby that condition is true for `[]`. ## Asking the question you mean Because most values are truthy, a bare `if value` really means "if value is neither nil nor false". When that is not the question, name the one you mean: 1. **Missing?** Use `value.nil?`. `Kernel#nil?` returns `false` for every object, and `NilClass#nil?` returns `true`. 2. **Empty?** Use `empty?` on `String`, `Array`, `Hash` and `Set`. It returns `true` for `""`, `[]` and `{}`. 3. **Zero?** Use `zero?` on a number. 4. **Missing or empty?** Combine them, for example `value.nil? || value.empty?`, or convert first: `value.to_s.empty?` treats `nil` and `""` alike, because `nil.to_s` returns `""`. A common loop idiom leans on the rule on purpose. `while (line = gets)` keeps reading because an empty line still arrives as `"\n"`, a truthy string; `gets` returns `nil` only at the end of input, and that `nil` ends the loop. ## nil and false are not interchangeable Both fail a condition, but they are two different objects of two different classes: - `nil == false` returns `false`. Neither class redefines `==`, so the comparison is identity, and they are different objects. - `nil.nil?` is `true`; `false.nil?` is `false`. - `nil.to_s` is `""`; `false.to_s` is `"false"`. - A method that answers a yes-or-no question should return `false`; `nil` conventionally means "nothing was found" or "no value". Keep the two apart in data. A patient-intake record where `consented` is `nil` means the question was never answered; `false` means the patient said no. ## Using the rule on purpose The short falsy list is also why so many core methods report "nothing found" by returning `nil`: the caller can test the result directly, without comparing it against a sentinel. - `if (m = line.match(/\d+/))` enters the branch only when the pattern matched, because `String#match` returns a `MatchData` or `nil`. - `if (record = records.find { |r| r.id == id })` works the same way, because `find` returns the element or `nil`. - A method can return `nil` for "no answer" and any object for "here it is", and callers treat the result as a yes-or-no value. The pattern is safe precisely because only `nil` and `false` fail: a match object, a record with an id of `0` or an empty string all count as found. ## Worked example: an optional middle name A patient-intake form posts every field it has, so an untouched middle-name box usually arrives as `""`, not `nil`. A check written as `if middle_name` then treats the blank field as present: - `""` is truthy, so the branch that prints the middle name runs and prints nothing. - The fix is to ask the real question: `middle_name.nil? || middle_name.empty?` for "not provided". - When the value might be `nil` or `""`, `middle_name.to_s.empty?` covers both cases in one call. The habit worth building is simple: in Ruby, use a bare truthiness test only when you mean "not nil and not false", and write the explicit predicate otherwise.

  • In Ruby, why does nil == false return false when both fail an if?
    Truthiness and equality are separate rules. Conditions test whether a value is `nil` or `false`, while `==` compares objects. Neither `NilClass` nor `FalseClass` redefines `==`, so the comparison falls back to identity, and `nil` and `false` are two different objects of two different classes.
  • Why does while (line = gets) stop at end of input but not at a blank line?
    `gets` returns each line with its line separator, so a blank line arrives as `"\n"`, a truthy string. At end of input `gets` returns `nil`, the assignment evaluates to `nil`, and the loop condition fails. The idiom works only because `nil` is falsy and every string, even an empty one, is truthy.

A Ruby condition is a bouncer holding a list with only two names on it, nil and false. Anyone else gets in, however empty-handed: 0, an empty string and an empty array all pass because they are not on the list.

saying these in an interview costs you the question

  • 0 is falsy in Ruby, the same as in C or Python
  • An empty string or empty array fails an if check
  • nil and false are the same value, so nil == false is true
  • The string "false" is treated as false in a condition
  • if list.length checks whether the list is empty