Pol0nium
Pol0nium

Reputation: 1376

Why do I get an unexpected result with a ternary condition?

Can anyone explain to me this result please:

(trad = {foo: "Foo", bar:"Bar"}).has_key? :foo ? trad[:foo] : :foo
=> false

I expected it to return:

=> "Foo"

Upvotes: 2

Views: 91

Answers (2)

the Tin Man
the Tin Man

Reputation: 160551

For want of parenthesis the app was lost...

(trad = {foo: "Foo", bar:"Bar"}).has_key? :foo  ? trad[:foo] : :foo  # => false
(trad = {foo: "Foo", bar:"Bar"}).has_key?(:foo) ? trad[:foo] : :foo  # => "Foo"

I'd be careful writing code like this:

(trad = {foo: "Foo", bar:"Bar"})

It's not idiomatic, so use:

trad = {foo: "Foo", bar:"Bar"}
trad.has_key?...

The reason is, in times of panic, like at 2:45 AM when your coding partner gets a call about a system outage because he's on call, and dives into the code, that assignment could be hard to find.

In a code review I'd suggest something like this over the other:

trad = {foo: "Foo", bar:"Bar"} 
trad.has_key?(:foo) ? trad[:foo]
                    : :foo        # => "Foo"

Note: This only works on Ruby 1.9+.

That all said, I'd highly recommend using fetch as recommended by @falsetru.

Upvotes: 1

falsetru
falsetru

Reputation: 368894

(trad = {foo: "Foo", bar:"Bar"}).has_key? :foo ? trad[:foo] : :foo

is like:

(trad = {foo: "Foo", bar:"Bar"}).has_key? (:foo ? trad[:foo] : :foo)

:foo ? trad[:foo] : :foo is evaluated to "Foo" because :foo is treated as truth value.

(trad = {foo: "Foo", bar:"Bar"}).has_key? "Foo" yields false because there's no "Foo" key.


Use following (override precedence by surrounding parentheses) to get the expected result:

>> ((trad = {foo: "Foo", bar:"Bar"}).has_key? :foo) ? trad[:foo] : :foo
=> "Foo"

Hash#fetch(key, default) seems more appropriate:

>> {foo: "Foo", bar:"Bar"}.fetch(:foo, :foo)
=> "Foo"
>> {foo: "Foo", bar:"Bar"}.fetch(:baz, :baz)
=> :baz

Upvotes: 8

Related Questions