Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable scope and order of parsing vs. operations: Assignment in an "if"

My understanding is that the if statements at the end of the line are evaluated before the code at the front of the line:

'never shown' if (false)

And assignment is possible in an if statement.

'shown' if (value = 'dave is king')
value #=> "dave is king"

And, when a variable that doesn't exist is assigned to, it is created. There is no need for it to exist beforehand. Is this true?

If all these assumptions are true, why does this fail?

error_array << error if (error = import_value(value))
#=> undefined local variable or method `error' for

It assigned to error before the array push right? I want to understand when things are evaluated.

This one does work:

if (error = import_value(value))
  error_array << error
end

Now I'm really confused.

like image 879
baash05 Avatar asked Dec 21 '22 09:12

baash05


1 Answers

It only happens when you try to assign a literal value, if you call a function it works.

def foo(a)
  a
end

p 'not shown' if(value = foo(false))
p 'shown' if(value = foo(true))

# This outputs a Warning in IRB
p 'shown' if(value = false)
(irb):2: warning: found = in conditional, should be ==

If you turn on debugging (-d) you will see a warning about an used variable value

warning: assigned but unused variable - value

This "works" because the statement does evaluate to true as far as if is concerned, allowing the code preceeding it to run.

What is happening here is that if() when used as a modifier has it's own binding scope, or context. So the assignment is never seen outside of the if, and therefore makes no sense to perform. This is different than if the control structure because the block that the if statement takes is also within the same scope as the assignment, whereas the line that preceeded the if modifier is not within the scope of the if.

In other words, these are not equivelant.

if a = some(value)
  puts a
end

puts a if(a = some(value))

The former having puts a within the scope of the if, the latter having puts a outside the scope, and therefore having different bindings(what ruby calls context).

Ruby Order of Operations

like image 100
Cluster Avatar answered May 06 '23 21:05

Cluster