Why does it work? (variable scope)

Two similar cases (same behavior):

1)

···

---------------------
my_var = 123 if false

puts my_var
=> nil
---------------------

2)
---------------------
if false
  my_var = 123
end

puts my_var
=> nil
---------------------

Somebody could expect that "puts my_var" should raise "NameError:
undefined local variable or method `my_var'" in both cases.

So I can understand that in case 1) the Ruby interpreter knows about
my_var variable since it reads it before checking the "if". But in
case 2) It seems that my_var variable is known when the script/file is
loaded since the interpreter will never run into the "if false"
statement.

Am I right? Thanks a lot.

BTW:

--------------------
puts "1: defined? my_var: #{(defined? my_var).inspect}"

if false
  my_var = 123
end

puts "2: defined? my_var: #{(defined? my_var).inspect}"

=>
1: defined? my_var: nil
2: defined? my_var: "local-variable"
--------------------

--
Iñaki Baz Castillo
<ibc@aliax.net>

Two similar cases (same behavior):

1)
---------------------
my_var = 123 if false

puts my_var
=> nil
---------------------

2)
---------------------
if false
  my_var = 123
end

puts my_var
=> nil
---------------------

Somebody could expect that "puts my_var" should raise "NameError:
undefined local variable or method `my_var'" in both cases.

The issue with expectations is that sometimes they aren't met. :slight_smile:

So I can understand that in case 1) the Ruby interpreter knows about
my_var variable since it reads it before checking the "if". But in
case 2) It seems that my_var variable is known when the script/file is
loaded since the interpreter will never run into the "if false"
statement.

Am I right? Thanks a lot.

Mostly. The variable is known from the lexical position in the code
where it is defined - even if that code is not executed - as you found
out:

--------------------
puts "1: defined? my_var: #{(defined? my_var).inspect}"

if false
  my_var = 123
end

puts "2: defined? my_var: #{(defined? my_var).inspect}"

=>
1: defined? my_var: nil
2: defined? my_var: "local-variable"
--------------------

That's also the reason why these behave differently although they seem
to do the same:

$ ruby -e 'if x.nil?; x=123; end; p x'
-e:1:in `<main>': undefined local variable or method `x' for
main:Object (NameError)
$ ruby -e 'x=123 if x.nil?; p x'
123

Kind regards

robert

···

On Mon, Sep 10, 2012 at 4:57 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Hi,

Local variables are determined purely by the existence of an assignment
expression in the current scope. It doesn't matter if the assignment is
ever executed.

Also note that there's *no* difference between "if ... end" and "... if
..." with regard to the order of evaluation. In both cases the condition
is evaluated first, and if it evaluates to true, the body is executed.

···

--
Posted via http://www.ruby-forum.com/.

Jan E. писал 10.09.2012 19:14:

Hi,

Local variables are determined purely by the existence of an assignment
expression in the current scope. It doesn't matter if the assignment is
ever executed.

Also note that there's *no* difference between "if ... end" and "... if
..." with regard to the order of evaluation. In both cases the condition
is evaluated first, and if it evaluates to true, the body is executed.

Exactly.

If existence of a local variable would be determined by the matter of it
being executed, that would create an awful ambiguity. For example:

def a(q)
   if q
     b = 1
   end
   b
end

would sometimes return 1, and sometimes call a method b.

Things would get much worse if loops and scopes are involved.

···

--
   WBR, Peter Zotov.

Clear. Thanks a lot to all.

···

2012/9/10 Robert Klemme <shortcutter@googlemail.com>:

On Mon, Sep 10, 2012 at 4:57 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:

Two similar cases (same behavior):

1)
---------------------
my_var = 123 if false

puts my_var
=> nil
---------------------

2)
---------------------
if false
  my_var = 123
end

puts my_var
=> nil
---------------------

Somebody could expect that "puts my_var" should raise "NameError:
undefined local variable or method `my_var'" in both cases.

The issue with expectations is that sometimes they aren't met. :slight_smile:

So I can understand that in case 1) the Ruby interpreter knows about
my_var variable since it reads it before checking the "if". But in
case 2) It seems that my_var variable is known when the script/file is
loaded since the interpreter will never run into the "if false"
statement.

Am I right? Thanks a lot.

Mostly. The variable is known from the lexical position in the code
where it is defined - even if that code is not executed - as you found
out:

--------------------
puts "1: defined? my_var: #{(defined? my_var).inspect}"

if false
  my_var = 123
end

puts "2: defined? my_var: #{(defined? my_var).inspect}"

=>
1: defined? my_var: nil
2: defined? my_var: "local-variable"
--------------------

That's also the reason why these behave differently although they seem
to do the same:

$ ruby -e 'if x.nil?; x=123; end; p x'
-e:1:in `<main>': undefined local variable or method `x' for
main:Object (NameError)
$ ruby -e 'x=123 if x.nil?; p x'
123

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

--
Iñaki Baz Castillo
<ibc@aliax.net>