I frequently see comments that 'unless' and 'until' are difficult to understand.
I've also heard that it's prohibited in tools like rubocop.
This is a fundamentally flawed way of thinking.
As a basic principle, abandon the idea of "if it becomes false".
The basic principle is to remember what happens when it becomes true, and you won't get confused.
unless
Think of unless as an expression that will not be executed if the condition is met.
result = 1 if a && b # If a && b is satisfied, execute the left side.
result = 2 unless a && b # If a && b is satisfied, do not execute the left side.
When combined with return (guard clause), it should be considered a condition for proceeding with the process.
return if a && b # Terminate processing if the (a && b) is satisfied.
return unless a && b # Proceed with processing if the (a && b) is satisfied.
When using them as guard clauses, remember the following: The two have distinctly different roles.
| Keywords | Role | Action |
|---|---|---|
return if expression |
blacklist | Terminate processing if the expression is satisfied |
return unless expression |
whitelist | Proceed with processing if the expression is satisfied |
To differentiate their use, any judgment formulas that involve both should be separated.
An example is shown below.
def gagazet_gate(yevonite) # case 1
return if yevonite == Kimahri
# Blocks only Kimahri. This allows unauthorized people to pass through.
end
def gagazet_gate(yevonite) # case 2
return unless yevonite == Summoner || yevonite == Guardian
# Summoners and guards are allowed through. This means Kimahri can also get through.
end
def gagazet_gate(yevonite) # Bad case
return if yevonite == Kimahri || yevonite != Summoner && yevonite != Guardian
# "No passing if you're Kimahri, and also if you're not a summoner, and also if..."
# Not Biran!
end
def gagazet_gate(yevonite) # Best case
return unless yevonite == Summoner || yevonite == Guardian
return if yevonite == Kimahri
# Summoner may pass. Guardians may pass. Kimahri not pass!
# These two gate clauses are meaningful precisely because they are used separately.
end
until
The until statement can be thought of as a condition that exits the loop when it becomes true.
i = 0
p i while (i += 1) < 10 # Loops while i is less than 10
p i until (i -= 1) <= 0 # Exit the loop when i becomes 0 or less
For example, the following example is easy to understand. The formula is also elegant.
a = (1..100).to_a
a.shift until a.empty? # Exit the loop when a becomes empty
Summary
While it's often suggested that unless be replaced with if not, that suggestion is based on a flawed premise.
unless and until are not constructs that reverse the evaluation of if and while conditional expressions. Rather, they are constructs that "reverse the behavior" of a conditional expression.
Furthermore, until is actually more suitable for loops than while because it clarifies the goal.
The true ace of loop statements is until. It is definitely not a variation of while.
Top comments (0)