Conditional Expressions

Conditional keywords

  • Never use then for multi-line if/unless.
    [link]

    1. # bad
    2. if some_condition then
    3. ...
    4. end
    5. # good
    6. if some_condition
    7. ...
    8. end
  • Never use do for multi-line while or
    until.[link]

    1. # bad
    2. while x > 5 do
    3. ...
    4. end
    5. until x > 5 do
    6. ...
    7. end
    8. # good
    9. while x > 5
    10. ...
    11. end
    12. until x > 5
    13. ...
    14. end
  • The and, or, and not keywords are banned. It’s
    just not worth it. Always use &&, ||, and ! instead.
    [link]

  • Modifier if/unless usage is okay when
    the body is simple, the condition is simple, and the whole thing fits on
    one line. Otherwise, avoid modifier if/unless.
    [link]

    1. # bad - this doesn't fit on one line
    2. add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page]) if request_opts[:trebuchet_experiments_on_page] && !request_opts[:trebuchet_experiments_on_page].empty?
    3. # okay
    4. if request_opts[:trebuchet_experiments_on_page] &&
    5. !request_opts[:trebuchet_experiments_on_page].empty?
    6. add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page])
    7. end
    8. # bad - this is complex and deserves multiple lines and a comment
    9. parts[i] = part.to_i(INTEGER_BASE) if !part.nil? && [0, 2, 3].include?(i)
    10. # okay
    11. return if reconciled?
  • Never use unless with else. Rewrite
    these with the positive case first.[link]

    1. # bad
    2. unless success?
    3. puts 'failure'
    4. else
    5. puts 'success'
    6. end
    7. # good
    8. if success?
    9. puts 'success'
    10. else
    11. puts 'failure'
    12. end
  • Avoid unless with multiple
    conditions.[link]

    1. # bad
    2. unless foo? && bar?
    3. ...
    4. end
    5. # okay
    6. if !(foo? && bar?)
    7. ...
    8. end
  • Avoid unless with comparison operators if you can use if with an opposing comparison operator.[link]

    1. # bad
    2. unless x == 10
    3. ...
    4. end
    5. # good
    6. if x != 10
    7. ...
    8. end
    9. # bad
    10. unless x < 10
    11. ...
    12. end
    13. # good
    14. if x >= 10
    15. ...
    16. end
    17. # ok
    18. unless x === 10
    19. ...
    20. end
  • Don’t use parentheses around the
    condition of an if/unless/while.
    [link]

    1. # bad
    2. if (x > 10)
    3. ...
    4. end
    5. # good
    6. if x > 10
    7. ...
    8. end

Ternary operator

  • Avoid the ternary operator (?:) except
    in cases where all expressions are extremely trivial. However, do use the
    ternary operator(?:) over if/then/else/end constructs for single line
    conditionals.[link]

    1. # bad
    2. result = if some_condition then something else something_else end
    3. # good
    4. result = some_condition ? something : something_else
  • Use one expression per branch in a ternary
    operator. This also means that ternary operators must not be nested. Prefer
    if/else constructs in these cases.[link]

    1. # bad
    2. some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else
    3. # good
    4. if some_condition
    5. nested_condition ? nested_something : nested_something_else
    6. else
    7. something_else
    8. end
  • Avoid multiple conditions in ternaries.
    Ternaries are best used with single conditions.
    [link]

  • Avoid multi-line ?: (the ternary
    operator), use if/then/else/end instead.
    [link]

    1. # bad
    2. some_really_long_condition_that_might_make_you_want_to_split_lines ?
    3. something : something_else
    4. # good
    5. if some_really_long_condition_that_might_make_you_want_to_split_lines
    6. something
    7. else
    8. something_else
    9. end

Nested conditionals


  • Avoid the use of nested conditionals for flow of control.
    ([More on this][avoid-else-return-early].) [link]

    Prefer a guard clause when you can assert invalid data. A guard clause
    is a conditional statement at the top of a function that returns as soon
    as it can.

    The general principles boil down to:

    • Return immediately once you know your function cannot do anything more.
    • Reduce nesting and indentation in the code by returning early. This makes
      the code easier to read and requires less mental bookkeeping on the part
      of the reader to keep track of else branches.
    • The core or most important flows should be the least indented.
    1. # bad
    2. def compute
    3. server = find_server
    4. if server
    5. client = server.client
    6. if client
    7. request = client.make_request
    8. if request
    9. process_request(request)
    10. end
    11. end
    12. end
    13. end
    14. # good
    15. def compute
    16. server = find_server
    17. return unless server
    18. client = server.client
    19. return unless client
    20. request = client.make_request
    21. return unless request
    22. process_request(request)
    23. end

    Prefer next in loops instead of conditional blocks.

    1. # bad
    2. [0, 1, 2, 3].each do |item|
    3. if item > 1
    4. puts item
    5. end
    6. end
    7. # good
    8. [0, 1, 2, 3].each do |item|
    9. next unless item > 1
    10. puts item
    11. end

    See also the section “Guard Clause”, p68-70 in Beck, Kent.
    Implementation Patterns. Upper Saddle River: Addison-Wesley, 2008, which
    has inspired some of the content above.