58
  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.

sawa
  • 165,429
  • 45
  • 277
  • 381
PrimRock
  • 1,076
  • 2
  • 15
  • 27

4 Answers4

86

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
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 4
    Well, normally, the `else` stands alone and the `else` block is on the next line indented two spaces. If you follow that normal convention (and why shouldn't you, after all `else if` isn't special, because *there is no `else if`*), then it *really* sticks out like a sore thumb. – Jörg W Mittag Aug 06 '15 at 15:20
  • 1
    I'm now noticing the extra `end` statements. If I was aware of this sooner I would of swapped over to `elsif` in a heartbeat. Thanks for the reply! – PrimRock Aug 06 '15 at 15:28
  • Why it is `elsif` but not `elseif` LAMO. – Zhou Haibo Sep 28 '22 at 08:17
20

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

Community
  • 1
  • 1
onebree
  • 1,853
  • 1
  • 17
  • 44
  • 3
    Converting your last example to `else if` would result in https://gist.github.com/sos4nt/a41b36d21f6eec5e0a42 - that's still clean, just more nested. – Stefan Aug 06 '15 at 15:44
3

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 
spickermann
  • 100,941
  • 9
  • 101
  • 131
  • 1
    I literally just recommended this to OP in a comment! :-) I refrained from including that in my answer, as I felt it would be a little extraneous to the question. – onebree Aug 06 '15 at 15:36
0

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.

Wand Maker
  • 18,476
  • 8
  • 53
  • 87