Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between inline if conditional and block if conditional in Ruby

Today I come across this weird behaviour of Ruby's inline if and block if

2.0.0-p247 :001 > inline_if = 'value will not set but no error' if inline_if
 => nil 
2.0.0-p247 :002 > if block_if
2.0.0-p247 :003?>   block_if = 'forget about setting value, I will raise an error'
2.0.0-p247 :004?>   end
NameError: undefined local variable or method `block_if' for main:Object
    from (irb):2
    from /Users/myuser/.rvm/rubies/ruby-2.0.0-p247/bin/irb:13:in `<main>'

What is the difference between inline if conditional and block if conditional?

like image 783
Hardik Avatar asked Nov 15 '14 06:11

Hardik


3 Answers

I suspect it has something to with ruby parser. Because when writing inline if

inline_if = 'value will not set but no error' if inline_if

Ruby parser actually parse from left to right. So in above line it first encounters setter method of variable inline_if. so it actually defines this variable with value nil and then it checks for the condition if inline_if which will be evaluated as if nil.

Now with the block if condition

if block_if
  block_if = 'forget about setting value, I will raise an error'
end

it first tries to access the block_if variable which is not yet defined. hence it will trow an error.

It's amazing thing that from programmer view both of above block should be evaluated equally. but they behave different

like image 80
Hardik Avatar answered Nov 15 '22 12:11

Hardik


See Local Variables and Methods:

The local variable is created when the parser encounters the assignment, not when the assignment occurs:

a = 0 if false    # does not assign to a
p local_variables # prints [:a]
p a               # prints nil

In the first example, inline_if encountered first in assignment, so it is created(and has a value of nil). While in the second example, block_if is seen in the condition before it's seen in the assignment, which causes the error.

like image 22
Yu Hao Avatar answered Nov 15 '22 10:11

Yu Hao


The "Ruby interpreter initializes a local variable with nil when it sees an assignment to it." See this answer to a related simpler question that highlights the crucial part of the behaviour you're seeing.

> a = a
# => nil (and assigns nil to a)
> b = c
# => NameError...

Also, watch this hilarious video about JavaScript and Ruby oddities!

like image 41
Amit Kumar Gupta Avatar answered Nov 15 '22 12:11

Amit Kumar Gupta