Reputation: 4513
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
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
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
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