Project

General

Profile

Bug #16631

Updated by prijutme4ty (Ilya Vorontsov) almost 5 years ago

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: 
 ``` ruby 
 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: 

 ``` ruby 
 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: 
 ``` ruby 
 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. 
 ``` ruby 
 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). variable). For human genes this code raises an exception, for mouse genes it works as intended. Very subtle problem.

Back