Search code examples
rubysyntaxswitch-statementsemantics

What does a Ruby case expression mean without an expression to inspect?


Take this example Ruby expression:

case
  when 3 then "foo"
  when 4 then "bar"
end

I was surprised to learn that this is not a syntax error. Instead, it evaluates to "foo"!

Why? What are the syntax and evaluation rules being applied here?


Solution

  • In this form of the case expression, the then clause associated with the lexically first when clause that evaluates to a truthy value is evaluated.

    See clause b) 2) of §11.5.2.2.4 Semantics of the ISO Ruby Language Specification (bold emphasis mine):

    Semantics

    A case-expression is evaluated as follows:

    • a) […]
    • b. The meaning of the phrase “O is matching” in Step c) is defined as follows:
      1. […]
      2. If the case-expression is a case-expression-without-expression, O is matching if and only if O is a trueish object.
    • c) Take the following steps:
      1. Search the when-clauses in the order they appear in the program text for a matching when-clause as follows:
        • i) If the operator-expression-list of the when-argument is present:
        • I) For each of its operator-expressions, evaluate it and test if the resulting value is matching.
        • II) If a matching value is found, other operator-expressions, if any, are not evaluated.
        • ii) If no matching value is found, and the splatting-argument (see 11.3.2) is present:
        • I) Construct a list of values from it as described in 11.3.2. For each element of the resulting list, in the same order in the list, test if it is matching.
        • II) If a matching value is found, other values, if any, are not evaluated.
        • iii) A when-clause is considered to be matching if and only if a matching value is found in its when-argument. Later when-clauses, if any, are not tested in this case.
      2. If one of the when-clauses is matching, evaluate the compound-statement of the then-clause of this when-clause. The value of the case-expression is the resulting value.
      3. If none of the when-clauses is matching, and if there is an else-clause, then evaluate the compound-statement of the else-clause. The value of the case-expression is the resulting value.
      4. Otherwise, the value of the case-expression is nil.

    The RDoc documentation, while much less precise, also states that truthiness is the selection criteria, when the condition is omitted; and lexical ordering determines the order in which when clauses are checked (bold emphasis mine):

    case

    The case statement operator. Case statements consist of an optional condition, which is in the position of an argument to case, and zero or more when clauses. The first when clause to match the condition (or to evaluate to Boolean truth, if the condition is null) "wins", and its code stanza is executed. The value of the case statement is the value of the successful when clause, or nil if there is no such clause.