Question

I wrote an if-then-else program, but when changing the code to use the ternary operator I am getting a syntax error and cannot figure out why it will not work:

def are_you_over_21
  puts"How old are you?"
  age = gets.chomp.to_i
  age>=21 ? puts"You're over 21!" : puts"You're too young."
end

are_you_over_21
Was it helpful?

Solution

You'll have to think about the Ruby parser.

This will work fine:

age >= 21 ? puts("You're over 21!") : puts("You're too young.")

The reason is that if you use the puts method without brackets, the parser doesn't understand the : token that comes afterwards; it doesn't realise that it is associated with the ternary operator earlier. You can also do this:

puts age >= 21 ? "You're over 21!" : "You're too young."

This is fine -- the parser doesn't run into any ambiguities here.

You can also do this:

puts "You're #{ age >= 21 ? 'over 21!' : 'too young.' }"

Here's why the ambiguity happens. Let's say you have two functions, x and a, like this:

2.0.0-p195 :033 > def x(y)
2.0.0-p195 :034?>   y + 1
2.0.0-p195 :035?>   end
 => nil 
2.0.0-p195 :036 > def a(b)
2.0.0-p195 :037?>   b + 2
2.0.0-p195 :038?>   end
 => nil 

The brackets don't make a difference here:

2.0.0-p195 :039 > x a 1
 => 4 
2.0.0-p195 :040 > x a(1)
 => 4 
2.0.0-p195 :041 > x(a(1))
 => 4 
2.0.0-p195 :042 > x(a 1)
 => 4 

But if x could take more than one parameter? Now you have to help the parser out:

2.0.0-p195 :043 > def x(y, z)
2.0.0-p195 :044?>   y + z + 1
2.0.0-p195 :045?>   end

Let's make a call without brackets like before:

2.0.0-p195 :047 > x a 1, 2 

Are you passing a(1), 2 to x, or are you trying to call a(1, 2) and pass the result to x? By convention Ruby assumes you are trying to call a(1, 2), but a only takes one argument, so you get an error:

ArgumentError: wrong number of arguments (2 for 1)
  from (irb):36:in `a'

So you need brackets:

2.0.0-p195 :052 > x a(1), 2
 => 6 

OTHER TIPS

Try this:

age>=21 ? puts("You're over 21!") : puts("You're too young.")

The ternary operator gets confused when the given options have function calls without the parenthesis.

You can also do this:

puts age>=21 ? "You're over 21!" : "You're too young."

Better than doing the unconditional puts in the ternary, which is a conditional statement, why not puts the result of the ternary?

def are_you_over_21                                
  puts"How old are you?"                           
  age = gets.to_i                                  
  age >= 21 ? "You're over 21!" : "You're too young."
end                                                

puts are_you_over_21 

Also, it isn't an error, but the nature of a number (Integer in your case) means that it will never need a chomp, as numbers do not have new lines. You never need to use chomp.to_i or chomp.to_f.

Notice that the method now returns an instance of String, rather than nil. It can now be used as you would like, in this case, using puts to display to the terminal.

Spaces around the comparison operator makes it easier to read.

The method itself may as well not be a method if you are going to prompt, get data, and report. You would be doing just as well to remove the method definition and just have this as running code.

I have refactored this to be that way:

def are_you_over_21(age)
  age >= 21 ? "You're over 21!" : "You're too young."
end

[18, 20, 21, 22, 100].each do |age|
  puts are_you_over_21(age)
end

# >> You're too young.
# >> You're too young.
# >> You're over 21!
# >> You're over 21!
# >> You're over 21!

Hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top