Local variable and local variable in block behave differently

Dear Rubyists,

I am sligthly surprised by this behaviour:

if false
b = ""
else
1.times { b = “b” }
end

puts defined? b # => local-variable
puts b # => b

1.times do
if false
a = ""
else
1.times { a = “a” }
end
puts defined? a # => local-variable(in-block)
puts a # => nil
end

Any reason?

Thanks

Seb.

Hi –

Dear Rubyists,

I am sligthly surprised by this behaviour:

if false
b = “”
else
1.times { b = “b” }
end

puts defined? b # => local-variable
puts b # => b

1.times do
if false
a = “”
else
1.times { a = “a” }
end
puts defined? a # => local-variable(in-block)
puts a # => nil
end

Any reason?

I’m not sure what aspect of it is surprising you, but maybe it has to
do with the fact that the assignment causes the variable to be defined
(even if, at runtime, the assignment isn’t executed):

$ ruby -e ‘if false; b = 1; end; p defined?(b)’
“local-variable”

Does that help explain it?

David

···

On Fri, 30 May 2003, Seb Clediere wrote:


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

I am sligthly surprised by this behaviour:

if false
b = “”

From this point, variable “b” is defined (even though the assignment is
never executed, the interpreter has parsed an assignment)

else
1.times { b = “b” }
end

This assigns to variable ‘b’. Because it already exists outside of the
block, it assigns to this pre-existing variable, instead of bringing a
temporary variable into existence just for the the lifetime of the block.

1.times do
if false
a = “”
else
1.times { a = “a” }
end
puts defined? a # => local-variable(in-block)
puts a # => nil
end

OK, that’s weird… I would have thought that the assignment to ‘a’ in the
inner block would have bound to the ‘a’ brought into existence in the outer
block, but it hasn’t.

Cheers,

Brian.

···

On Fri, May 30, 2003 at 09:49:40PM +0900, Seb Clediere wrote:

Hi,

dblack@superlink.net wrote:

I’m not sure what aspect of it is surprising you, but maybe it has to
do with the fact that the assignment causes the variable to be defined
(even if, at runtime, the assignment isn’t executed):

$ ruby -e ‘if false; b = 1; end; p defined?(b)’
“local-variable”

Does that help explain it?

David

Sorry, I should have been more explicit. What surprises me is that in
one case, the variable a has still its value “a” wherease in the other
case, b is nil. I would have expected both cases to be the same, the
assigned value.

Seb.

my best guess is that:

1.times do

···

On Fri, 30 May 2003, Brian Candler wrote:

On Fri, May 30, 2003 at 09:49:40PM +0900, Seb Clediere wrote:

I am sligthly surprised by this behaviour:

if false
b = “”

From this point, variable “b” is defined (even though the assignment is
never executed, the interpreter has parsed an assignment)

else
1.times { b = “b” }
end

This assigns to variable ‘b’. Because it already exists outside of the
block, it assigns to this pre-existing variable, instead of bringing a
temporary variable into existence just for the the lifetime of the block.

1.times do
if false
a = “”
else
1.times { a = “a” }
end
puts defined? a # => local-variable(in-block)
puts a # => nil
end

OK, that’s weird… I would have thought that the assignment to ‘a’ in the
inner block would have bound to the ‘a’ brought into existence in the outer
block, but it hasn’t.

####
#### here we are in a block
####
if false
  ####
  #### assignment is parsed but not executed, 'a' (block-local) is now nil
  ####
  a = ""
else
  ####
  #### at this point, there is no 'a' in *scope*, only a block-local 'a'
  #### thus the following block creates a new block-local 'a'
  ####
  1.times { a = "a" }
end
####
#### these statements operate on the only symbol known as 'a' at this
#### point, which happen to be the *first* block-local a.  this is not the
#### same thing as scope, since blocks do not introduce a new scope.
####
puts defined? a # => local-variable(in-block)
puts a          # => nil

end

this seems to confirm this:

a = 42
1.times do
if false
a = “”
else
1.times { a = “a” }
end
puts defined? a # => local-variable
puts a # => a
end

since here the print statement can operate on an ‘a’ which is in scope. the
first example is sort of bizarre because there never is an ‘a’ in scope, only
block-locals.

template = Amrita::TemplateText.new <<-html

html

-a

====================================

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ara.t.howard@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
~ > ruby -e ‘p % ^) .intern’
====================================

Hi,

···

In message “Re: local variable and local variable in block behave differently” on 03/05/30, Brian Candler B.Candler@pobox.com writes:

1.times do
if false
a = “”
else
1.times { a = “a” }
end
puts defined? a # => local-variable(in-block)
puts a # => nil
end

OK, that’s weird… I would have thought that the assignment to ‘a’ in the
inner block would have bound to the ‘a’ brought into existence in the outer
block, but it hasn’t.

Maybe a bug. Let me check.

						matz.

Well, it's more

my best guess is that:

  1.times do
    ####
    #### here we are in a block
    ####
    if false
      ####
      #### assignment is parsed but not executed, 'a' (block-local) is now nil
      ####
      a = ""

at compile time, ruby see a block local variable 'a', this variable will
be created (at runtime) at the first assignement

    else
      ####
      #### at this point, there is no 'a' in *scope*, only a block-local 'a'
      #### thus the following block creates a new block-local 'a'
      ####
      1.times { a = "a" }

at runtime this is the first assignement, and the variable is created
inside the second block

    end
    ####
    #### these statements operate on the only symbol known as 'a' at this
    #### point, which happen to be the *first* block-local a. this is not the
    #### same thing as scope, since blocks do not introduce a new scope.
    ####
    puts defined? a # => local-variable(in-block)

ruby say that it has seen a local variable at compile time

    puts a # => nil

and in this block, the local variable was not assigned

Guy Decoux

i was trying to say that… :wink:

one thing i’m fuzy on though - ruby parses/runs in one pass, so what exactly
is the distinction between the ‘complile’ and ‘run’ phases? this is easy to
imagine for a two pass interpreter, but harder for a one pass one…

-a

···

On Sat, 31 May 2003, ts wrote:

Well, it’s more

====================================
Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ara.t.howard@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
~ > ruby -e ‘p % ^) .intern’
====================================

I don’t think so - it parses and builds an AST in a single pass, then it
walks the AST after that. Certain types of syntax error break at the parsing
stage, so nothing gets run.

But note that the parsing of a class or method definition does not
actually create the class or method; it is only when it is run that the
class is created. At an extreme:

print "Do you want debugging? "
if gets =~ /\A[Yy]/
class Foo
… debug version
end
else
class Foo
… non-debug version
end
end

The class definitely isn’t defined until run-time.

Regards,

Brian.

···

On Sat, May 31, 2003 at 12:32:28AM +0900, ahoward wrote:

On Sat, 31 May 2003, ts wrote:

Well, it’s more

i was trying to say that… :wink:

one thing i’m fuzy on though - ruby parses/runs in one pass