Can I use `else if` over `elsif`?
- Is it safe to use
else if
overelsif
? - Is it better to use
elsif
because it follows Ruby's typing convention? - Or is this a preference?
This is a piece of code taken from a book. I added extra end
keywords and swapped elsif
keywords with else if
s.
def describe(inhabitant)
if inhabitant == "sophie"
puts 'gender: female'
puts 'height: 145'
else if inhabitant == "paul"
puts 'gender: male'
puts 'height: 145'
else if inhabitant == "dawn"
puts 'gender: female'
puts 'height: 170'
else if inhabitant == "brian"
puts 'gender: male'
puts 'height: 180'
else if
puts 'species: Trachemys scripta elegans'
puts 'height: 6'
end
end
end
end
end
end
This made me realize how ugly else if
is.
You can use else if
and it's safe. However note that this means extra end
keywords are needed.
if n == 1
puts "foo"
elsif n == 2
puts "bar"
end
is logically the same as:
if n == 1
puts "foo"
else if n == 2
puts "bar"
end
end
or the equivalent:
if n == 1
puts "foo"
else
if n == 2
puts "bar"
end
end
TL;DR - Replacing elsif
with else if
is alright for a conditional with only 2 paths. Remember to close the second if
conditional created with else if
. It is best practice to have as few levels of conditionals as you can, making for a less-complex method. So err on the side of caution and use elsif
.
Depending on how you plan to write your method, else if
may work. It is not a good habit to get into, however.
Take the following example. There are only 2 conditions. The second condition looks similar to elsif
, but is interpreted as the second chunk of code:
# What you may want to write
if true
puts 'true'
else if false
puts 'false'
end
# How Ruby requires it
if true
puts 'true'
else
if false # You may also do: puts 'false' if false
puts 'false'
end
end
The first block will search for another end
to close the primary conditional. Take note, you can bypass the extra end with a single line if
statement. (I only suggest this if the executed code can be written on a single line.)
It is important to note that once you declare an else
, you may have no other conditionals in the same tier as that else
. Given the second example above, the second if
is nested under the else
. If you were to call else
or elsif
on the same tier as the initial else
, the conditional will fail.
Here is when you would not want to implement else if
:
def describe(inhabitant)
if inhabitant == "sophie"
puts 'gender: female'
puts 'height: 145'
elsif inhabitant == "paul"
puts 'gender: male'
puts 'height: 145'
elsif inhabitant == "dawn"
puts 'gender: female'
puts 'height: 170'
elsif inhabitant == "brian"
puts 'gender: male'
puts 'height: 180'
else
puts 'species: Trachemys scripta elegans'
puts 'height: 6'
end
end
Notice that neither of the elsif
statements can be "converted" to else if
in a clean way.
UPDATE: Thanks to Stefan, you can still use else if
, leading to a very nested method.
https://gist.github.com/sos4nt/a41b36d21f6eec5e0a42
I would prefer elsif
over else if
. But that is just my opinion and technically there is no difference.
But I would suggest to use a case
block instead of multiple elsif
your example:
def describe(inhabitant)
case inhabitant
when "sophie"
puts 'gender: female'
puts 'height: 145'
when "paul"
puts 'gender: male'
puts 'height: 145'
when "dawn"
puts 'gender: female'
puts 'height: 170'
when "brian"
puts 'gender: male'
puts 'height: 180'
else
puts 'species: Trachemys scripta elegans'
puts 'height: 6'
end
Or I would store that mapping in a hash:
PEOPLE = {
'sophie' => { :gender => :female, :height => 145 },
'paul' => { :gender => :male, :height => 145 },
# ...
}
def describe(inhabitant)
description = PEOPLE.fetch(
inhabitant, { :species => 'Trachemys scripta elegans', :height => 6 }
)
puts "gender: #{description[:gender]}" if description[:gender]
puts "species: #{description[:species]}" if description[:species]
puts "height: #{description[:height]}"
end