340

How is the conditional operator (? :) used in Ruby?

For example, is this correct?

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>
3
  • 1
    yes, I think, but I also think you could accomplish that by: question=question[0,20] If it was smaller than 20, it won't change it any. Commented Nov 23, 2010 at 5:06
  • i also need to add a '...' if length is greater than 20 Commented Nov 23, 2010 at 5:32
  • 1
    Be careful blindly chopping off a line at a given column. You can end up cutting a word midway then appending the elipsis ('...'), which looks bad. Instead, look for a nearby punctuation or whitespace character, and truncate there. Only if there is no better breaking point nearby should you truncate mid-word. Commented Nov 23, 2010 at 6:11

7 Answers 7

535

It is the ternary operator, and it works like in C (the parenthesis are not required). It's an expression that works like:

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

However, in Ruby, if is also an expression so: if a then b else c end === a ? b : c, except for precedence issues. Both are expressions.

Examples:

puts (if 1 then 2 else 3 end) # => 2

puts 1 ? 2 : 3                # => 2

x = if 1 then 2 else 3 end
puts x                        # => 2

Note that in the first case parenthesis are required (otherwise Ruby is confused because it thinks it is puts if 1 with some extra junk after it), but they are not required in the last case as said issue does not arise.

You can use the "long-if" form for readability on multiple lines:

question = if question.size > 20 then
  question.slice(0, 20) + "..."
else 
  question
end
Sign up to request clarification or add additional context in comments.

3 Comments

Puts 0 ? 2 : 3 also gives 2 as a result. Why is that?
@X_Trust In Ruby, the only falsy values are nil and false. Not very usual, indeed.
This is a good explanation, but like almost every explanation I've seen, the behavior is essentially described as condition ? value if true : value if false. I think a much better way to describe the behavior is this: condition ? value if TRUTHY : value if FALSEY. The difference is subtle but very important to understand.
41
puts true ? "true" : "false"
=> "true"


puts false ? "true" : "false"
=> "false"

2 Comments

Terse but explains what it does.
Small edit puts (true ? "true" : "false") with parenthesis. Otherwise the order of operations is not clear. When I first read this I was confused as I read it as (puts true) ? "true" : "false" then expected puts to return the boolean which then became the string value.
26

Your use of ERB suggests that you are in Rails. If so, then consider truncate, a built-in helper which will do the job for you:

<% question = truncate(question, :length=>30) %>

3 Comments

This is great! what I exactly want to do!!
This is years late, but I was very impressed with this answer as it jumped past all the syntactical aspects and went right to what the questioner was trying to accomplish.
+1, but erb does not necessarily imply rails (Sinatra, standalone ERB, etc).
19

@pst gave a great answer, but I'd like to mention that in Ruby the ternary operator is written on one line to be syntactically correct, unlike Perl and C where we can write it on multiple lines:

(true) ? 1 : 0

Normally Ruby will raise an error if you attempt to split it across multiple lines, but you can use the \ line-continuation symbol at the end of a line and Ruby will be happy:

(true)   \
  ? 1    \
  : 0

This is a simple example, but it can be very useful when dealing with longer lines as it keeps the code nicely laid out.

It's also possible to use the ternary without the line-continuation characters by putting the operators last on the line, but I don't like or recommend it:

(true) ?
  1 :
  0

I think that leads to really hard to read code as the conditional test and/or results get longer.

I've read comments saying not to use the ternary operator because it's confusing, but that is a bad reason to not use something. By the same logic we shouldn't use regular expressions, range operators ('..' and the seemingly unknown "flip-flop" variation). They're powerful when used correctly, so we should learn to use them correctly.


Why have you put brackets around true?

Consider the OP's example:

<% question = question.size > 20 ? question.question.slice(0, 20)+"..." : question.question %>

Wrapping the conditional test helps make it more readable because it visually separates the test:

<% question = (question.size > 20) ? question.question.slice(0, 20)+"..." : question.question %>

Of course, the whole example could be made a lot more readable by using some judicious additions of whitespace. This is untested but you'll get the idea:

<% question = (question.size > 20) ? question.question.slice(0, 20) + "..." \
                                   : question.question 
%>

Or, more written more idiomatically:

<% question = if (question.size > 20)
                question.question.slice(0, 20) + "..."
              else 
                question.question 
              end
%>

It'd be easy to argument that readability suffers badly from question.question too.

5 Comments

If multi-line, why not just use if...else...end?
Because of too many years working in Perl and C? I use either, depending on the situation and whether one is visually clearer than the other. Sometimes if/else is too verbose, sometimes ?: is ugly.
@WayneConrad The if has at least one problem explained in this answer: stackoverflow.com/a/4252945/2597260 Compare a few ways of using multiline if/ternary operator: gist.github.com/nedzadarek/0f9f99755d42bad10c30
Why have you put brackets around true?
Because true is actually sitting in for what would be an expression that evaluates to true or false. It's better to visually delimit those since ternary statements can quickly devolve into visual noise, reducing readability which affects maintainability.
3

A simple example where the operator checks if player's id is 1 and sets enemy id depending on the result

player_id=1
....
player_id==1? enemy_id=2 : enemy_id=1
# => enemy=2

And I found a post about to the topic which seems pretty helpful.

2 Comments

Why not enemy_id = player_id == 1 ? 2 : 1?
@AaronBlenkush Thanks for the elegant input. I am still in noob level, probably it is why :)
0

Easiest way:

param_a = 1
param_b = 2

result = param_a === param_b ? 'Same!' : 'Not same!'

since param_a is not equal to param_b then the result's value will be Not same!

Comments

-1

The code condition ? statement_A : statement_B is equivalent to

if condition == true
  statement_A
else
  statement_B
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.