JGutierrezC
JGutierrezC

Reputation: 4513

akward ternary evaluation in ruby

I'm very confused about some ternary expression in ruby.

I have this expression:

puts respond_to? "greeting".to_sym ? "hello" : "bye"

of course, that isn't what i'm doing in my app, is just for you to see.

the thing is that the above expression returns

false

when it should be returning hello if the method exists and bye if it don't right?

if i change the expression to

puts respond_to?("greeting".to_sym) ? "hello" : "bye"

it returns the right thing, either "hello" if it exists and "bye" otherwise.

Why is this happening? Is there something about ternary expression in ruby that i don't know?

Just for you to know the right code in my app is:

respond_to?(path.to_sym) ? self.send(path) : "#"

Which returns the right path for the db stored header menus and if it don't exists, it will simply put an "#" to avoid errors.

Upvotes: 2

Views: 163

Answers (3)

Ajedi32
Ajedi32

Reputation: 48318

Without the parentheses, it seems your code is being interpreted like this:

puts respond_to?("greeting".to_sym ? "hello" : "bye")

The stuff in the parenthesis is then evaluating to "hello", and self apparently doesn't respond to that, so respond_to? returns false.

This is why it's always a good idea to use parentheses whenever there's any doubt about the order of operations of your code; it makes your code more readable and eliminates mistakes such as this one.

Upvotes: 5

Michael Kohl
Michael Kohl

Reputation: 66837

I ran ruby --dump parsetree on your example (always a good way to see what's really happening). In the version without argument parenthesis, the ternary gets evaluated and respond_to? checks for "hello" or "bye". In the second case the code does what you intend.

Without parenthesis:

# @ NODE_SCOPE (line: 1)
# +- nd_tbl: (empty)
# +- nd_args:
# |   (null node)
# +- nd_body:
#     @ NODE_FCALL (line: 1)
#     +- nd_mid: :puts
#     +- nd_args:
#         @ NODE_ARRAY (line: 1)
#         +- nd_alen: 1
#         +- nd_head:
#         |   @ NODE_FCALL (line: 1)
#         |   +- nd_mid: :respond_to?
#         |   +- nd_args:
#         |       @ NODE_ARRAY (line: 1)
#         |       +- nd_alen: 1
#         |       +- nd_head:
#         |       |   @ NODE_IF (line: 1)
#         |       |   +- nd_cond:
#         |       |   |   @ NODE_CALL (line: 1)
#         |       |   |   +- nd_mid: :to_sym
#         |       |   |   +- nd_recv:
#         |       |   |   |   @ NODE_STR (line: 1)
#         |       |   |   |   +- nd_lit: "greeting"
#         |       |   |   +- nd_args:
#         |       |   |       (null node)
#         |       |   +- nd_body:
#         |       |   |   @ NODE_STR (line: 1)
#         |       |   |   +- nd_lit: "hello"
#         |       |   +- nd_else:
#         |       |       @ NODE_STR (line: 1)
#         |       |       +- nd_lit: "bye"
#         |       +- nd_next:
#         |           (null node)
#         +- nd_next:
#             (null node)

With:

# @ NODE_SCOPE (line: 1)
# +- nd_tbl: (empty)
# +- nd_args:
# |   (null node)
# +- nd_body:
#     @ NODE_FCALL (line: 1)
#     +- nd_mid: :puts
#     +- nd_args:
#         @ NODE_ARRAY (line: 1)
#         +- nd_alen: 1
#         +- nd_head:
#         |   @ NODE_IF (line: 1)
#         |   +- nd_cond:
#         |   |   @ NODE_FCALL (line: 1)
#         |   |   +- nd_mid: :respond_to?
#         |   |   +- nd_args:
#         |   |       @ NODE_ARRAY (line: 1)
#         |   |       +- nd_alen: 1
#         |   |       +- nd_head:
#         |   |       |   @ NODE_CALL (line: 1)
#         |   |       |   +- nd_mid: :to_sym
#         |   |       |   +- nd_recv:
#         |   |       |   |   @ NODE_STR (line: 1)
#         |   |       |   |   +- nd_lit: "greeting"
#         |   |       |   +- nd_args:
#         |   |       |       (null node)
#         |   |       +- nd_next:
#         |   |           (null node)
#         |   +- nd_body:
#         |   |   @ NODE_STR (line: 1)
#         |   |   +- nd_lit: "hello"
#         |   +- nd_else:
#         |       @ NODE_STR (line: 1)
#         |       +- nd_lit: "bye"
#         +- nd_next:
#             (null node)

Upvotes: 2

usha
usha

Reputation: 29349

If you don't have the parenthesis for respond_to, the evaluation happens like this

"greeting".to_sym ? "hello" : "bye" #results in "hello"

puts respond_to? "hello" #results in false

ternary expression will get evaluated first without the parenthesis for respond_to

Upvotes: 3

Related Questions