Project

General

Profile

Actions

Bug #16631

closed

Local variable assignment occured in condition clause of postfix-if doesn't allow immediate access to this variable

Added by prijutme4ty (Ilya Vorontsov) almost 5 years ago. Updated almost 5 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:<unknown>]

Description

I've found that usual-if and postfix-if work differently when there is an assignment in condition.
In both cases, a value is assigned to a variable, but in postfix-if left part doesn't have access to a variable if it is a local variable which was first defined in a condition.

When a variable if defined everything goes as intended:

lv_predefined = nil
puts("lv_predefined inside postfix-if: `#{lv_predefined}`") if lv_predefined = 'some value'
# lv_predefined inside postfix-if: `some value`

puts("lv_predefined after postfix-if: `#{lv_predefined}`")
# lv_predefined after postfix-if: `some value`

When a local variable is not defined, it is assigned but is unavailable in postfix-if body:

puts("undef_lv_postfix inside postfix-if: `#{undef_lv_postfix}`") rescue 'error'  if undef_lv_postfix = 'some value'
# => error

puts("undef_lv_postfix after postfix-if: `#{undef_lv_postfix}`")
# undef_lv_postfix after postfix-if: `some value`

That's different from usual if, which defines a variable and make it available for its body:

if lv_if = 'some value'
    puts("lv_if inside usual-if: `#{lv_if}`")
end
# lv_if inside usual-if: `some value`

To make things even more confusing, instance variable are immediately available in postfix-if unlike local variables.

puts("@iv inside postfix-if: `#{@iv}`") if @iv = 'some value'
# @iv inside postfix-if: `some value`

puts("@iv after postfix-if: `#{@iv}`")
# @iv after postfix-if: `some value`

I think this behavior doesn't meet the principle of least surprise.
And here's a case where assignment in postfix-if is indeed useful. I wish to match some string against a pattern and extract some information from it, so I have the following code:

query = 'HGNC:1234'
# query = 'MGI:5678'
puts("human gene: #{match[1]}")  if match = query.match(/HGNC:(\d+)/)
puts("mouse gene: #{match[1]}")  if match = query.match(/MGI:(\d+)/)

These two lines look identical but they are not (because match is an undefined local variable if this code was invoked from scratch). For human genes this code raises an exception, for mouse genes it works as intended. Very subtle problem.

Actions

Also available in: Atom PDF

Like0
Like0Like0