Why How to Refer to a Variable Outside of an If/Unless/Case Statement That Never Ran

Why can I refer to a variable outside of an if/unless/case statement that never ran?

It's because of how the Ruby parser works. Variables are defined by the parser, which walks through the code line-by-line, regardless of whether it will actually be executed.

Once the parser sees x =, it defines the local variable x (with value nil) henceforth in the current scope. Since if/unless/case/for/while do not create a new scope, x is defined and available outside the code block. And since the inner block is never evaluated as the conditional is false, x is not assigned to (and is thus nil).

Here's a similar example:

defined?(x) and x = 0
x #=> nil

Note that this is a rather high-level overview of what happens, and isn't necessarily exactly how the parser works.

Why does Ruby seem to hoist variable declarations from inside a case statement even if that code path is not executed?

When the Ruby parser sees the sequence identifier, equal-sign, value,
as in this expression

x = 1

it allocates space for a local variable called x. The creation of the
variable—not the assignment of a value to it, but the internal
creation of a variable—always takes place as a result of this kind of
expression, even if the code isn’t executed! Consider this example:

if false
x = 1
end
p x # Output: nil
p y # Fatal Error: y is unknown

The assignment to x isn’t executed, because it’s wrapped in a failing
conditional test. But the Ruby parser sees the sequence x = 1, from
which it deduces that the program involves a local variable x. The
parser doesn’t care whether x is ever assigned a value. Its job is
just to scour the code for local variables for which space needs to
be allocated. The result is that x inhabits a strange kind of variable limbo.
It has been brought into being and initialized to nil.
In that respect, it differs from a variable that has no existence at
all; as you can see in the example, examining x gives you the value
nil, whereas trying to inspect the non-existent variable y results
in a fatal error. But although x exists, it has not played any role in
the program. It exists only as an artifact of the parsing process.

Well-Grounded Rubyist chapter 6.1.2

Ruby: Variables defined in If/else statement are accessible outside of if/else?

Variables are local to a function, class or module defintion, a proc, a block.

In ruby if is an expression and the branches don't have their own scope.

Also note that whenever the parser sees a variable assignment, it will create a variable in the scope, even if that code path isn't executed:

def test
if false
a = 1
end
puts a
end

test
# ok, it's nil.

It's bit similar to JavaScript, though it doesn't hoist the variable to the top of the scope:

def test
puts a
a = 1
end

test
# NameError: undefined local variable or method `a' for ...

So even if what you were saying were true, it still wouldn't be nil.

Ruby variable assignment for not evaluated lines

Before your Ruby code can be run, it must first be parsed, and it's at this stage that the behavior you're experiencing originates.

As the parser scans through the code, whenever it encounters a declaration (foo = 'something') it allocates space for that variable by setting its value to nil. Whether that variable declaration is actually executed in the context of your code is irrelevant. For example:

if false
foo = 42
end

p foo
#=> nil

In the above code's logic foo is never declared, however it's space in memory is recognized and allocated for by Ruby when the code is parsed out.

Hope this helps!

How to access the variables after if-condition when the variable is defined inside the if-condition in python

Your problem appears to be the fact that you are referencing a variable outside of its scope. Essentially what is happening is in your if statement you are creating a variable exclusively for use within the if scope. Effectively when you have said print vn.firstChild.nodeValue you can also imagine it as being any other variable such as print undefinedVar. What is occuring is your are referencing (calling) upon the variable before it has even been defined.

However, no worries here since this is very easy to fix. What we can do is simply create your vn and test variables outside of the if scope, hence inside your actual method by doing the following:

vn = None
test = None

for DO in range(count) :
atnnames = doc.getElementsByTagName("atnId")[DO]
atn = atnnames.childNodes[0].nodeValue
if atn == line[0]:
vn = doc.getElementsByTagName("vn")[DO]
vncontent = vn.childNodes[0].nodeValue
y = vncontent.encode('utf-8')
# print y
if '-' in y:
slt = (int(y.split('-')[0][-1]) + 1)
test = y.replace(y.split('-')[0][-1], str(slt))
# print test
else:
slt = (int(y.split('.')[-1]) + 1)
test = y.replace(y.split('.')[-1], str(slt))
# print test
else:
#print test
vn.firstChild.nodeValue = test
print vn.firstChild.nodeValue

This basically just creates an empty variable in the outermost scope. I've set the values to None since they get defined once your for loop runs. So what happens now is you have a variable which has been declared outside, and is None at the start, but as you run your for loop you are not creating a temporary variable just inside the if statement, but you are actually changing the value of

Strange local variable behavior in Ruby

Ruby determines the lifetime of local variables while it parses the code, so even if params = 1 assignment wouldn't be reached, params will be interpreted as local variable (and set to nil by default) in this scope.

Here's the link to documentation:

http://docs.ruby-lang.org/en/2.1.0/syntax/assignment_rdoc.html#label-Local+Variables+and+Methods

Ruby lexical scope inside iterator block

I will answer quoting a book by A.Black: Well Grounded Rubyist, Chapter 6, p. 158. (second edition 2014):

When the Ruby parser sees the sequence identifier, equal-sign, and value, as in this expression,

a = 123

it allocates space for a local variable a. The creation of the variable - not the assignment of a value to it, but the internal creation of a variable - always takes place as a result of this kind of expression, event if the code isn't executed.

I don't understand ruby local scope

There a couple of things going on here. First, variables declared inside the if block have the same local scope as variables declared at the top level of the method, which is why bar is available outside the if. Second, you're getting that error because bob is being referenced straight out of the blue. The Ruby interpreter has never seen it and never seen it initialized before. It has, however, seen bar initialized before, inside the if statement. So when is gets to bar it knows it exists. Combine those two and that's your answer.



Related Topics



Leave a reply



Submit