0

I am practicing the following problem in Ruby. https://leetcode.com/problems/defanging-an-ip-address/

I find that I need to have a parentheses in my ternary operator to get the same result as the equivalent line of code with the if/else condition. Why is that ?

# @param {String} address
# @return {String}
def defang_i_paddr(address)
  return address if address.isEmpty?

  result_from_ternary = ''
  result_from_if = ''

  address.each_char do |letter|
    # Why do I need parentheses here ?
    result_from_ternary << (letter == '.' ? '[.]' : letter)

    # Why dont I need parentheses here ?
    result_from_if << if letter == '.'
                        '[.]'
                      else
                        letter
                      end
  end
  result_from_ternary = ''
end
zulu-700
  • 47
  • 5
  • @knut has explained why the parentheses are needed, but it's not just those you need be concerned about. Suppose `letter = '.'`, `res = ''` and you execute: `res << (letter == '.' ? (String.new 'cat') : (String.new 'dog')) #=> "cat"`. No problem, but if you execute `res << (letter == '.' ? String.new 'cat' : (String.new 'dog'))` you will get `...syntax error, unexpected ':', expecting ')'...`. Similarly, `res << (letter == '.' ? (String.new 'cat') : String.new 'dog')` raises a syntax exception. [This article](https://www.rubyguides.com/2019/10/ruby-ternary-operator/) may be of interest. – Cary Swoveland Mar 07 '20 at 23:06
  • While parenthesis are optional in Ruby, they are important, just as in every other language, when trying to direct the interpreter or compiler to understand the order of operations for your code. When doing code reviews I'd always harp on this because relying on the interpreter or compiler to get it right is risky, especially at 3AM when you're slightly hungover and working on code someone else wrote. "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. Code for readability." — John Woods – the Tin Man Mar 08 '20 at 05:18

2 Answers2

1

Just let's see this example:

a1 = []
a1 << 1 == 2 ? 'a' : 'b'
p a1  #[1]

a2 = []
a2 << ( 1 == 2 ? 'a' : 'b')
p a2 #["b"]

Without the parentheses, the code a1 << 1 == 2 ? 'a' : 'b' is evaluated as a1 << 1 and the result ([1]) is compared with 2. Depending on the reslt (false) the ternary operation returns 'b'.

If you change the test to != the result is a.

Example:

p    a1 << 1 == 2 ? 'a' : 'b'
p    a1 << 1 != 2 ? 'a' : 'b'

When you set the paretheses, then the command 1 == 2 ? 'a' : 'b' is evaluated first. Then the result (b) is added to the array.

knut
  • 27,320
  • 6
  • 84
  • 112
1

The reason is operator precedence. When there are no parentheses to guide Ruby then Ruby evaluates the operator with higher precedence first.

Looking a the table of Ruby operator precedence you can see that << has higher precedence than == and the ? : operator.

That means, Ruby would interpret

result_from_ternary << letter == '.' ? '[.]' : letter

in this order

((result_from_ternary << letter) == '.') ? '[.]' : letter

This is obviously not what you want therefore you need to "override" the default precedence order by adding parentheses:

result_from_ternary << (letter == '.' ? '[.]' : letter)
spickermann
  • 100,941
  • 9
  • 101
  • 131