Can I use `else if` over `elsif`?

Ruby

Ruby Problem Overview


  1. Is it safe to use else if over elsif?
  2. Is it better to use elsif because it follows Ruby's typing convention?
  3. 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 ifs.

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.

Ruby Solutions


Solution 1 - Ruby

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

Solution 2 - Ruby

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

Solution 3 - Ruby

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 

Solution 4 - Ruby

You should pick the option that results in better readable code. I give below an example of code where I tend to feel that use of else if is more readable.

result = "Unknown"
error_code = 911

#  Version 1 - uses else if
if result == "Success"
	puts "Good job!"
else
	if error_code == "100"
		puts "No worries, we can still recover"
	else
		puts "Hopeless case!"
	end
end


#  Version 2 - uses elsif
if result == "Success"
	puts "Good job!"
elsif result != "Success" and error_code == "100"
	puts "No worries, we can still recover"
else
	puts "Hopeless case!"
end

My guess is this has to do something with Level of Abstraction. If all the conditions in the if-elsif-else-end are at same level, then it will be more readable. If they are at different levels, it may be beneficial to use fewelse if in the code.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPrimRockView Question on Stackoverflow
Solution 1 - RubyYu HaoView Answer on Stackoverflow
Solution 2 - RubyonebreeView Answer on Stackoverflow
Solution 3 - RubyspickermannView Answer on Stackoverflow
Solution 4 - RubyWand MakerView Answer on Stackoverflow