Is this a bug in the defined? operator?

The behavior of the following code seems like a bug to me:

···

[1, 2, 3, 4].each { |x|
if defined? foo
puts "foo is defined"
else
puts "foo not defined"
foo = true
end
}

[1, 2, 3, 4].each { |x|
if (x % 2) == 0
if defined? bar
puts "bar is defined"
else
puts "bar not defined"
bar = true
end
else # <–
if defined? bar # <–
puts “bar is defined” # <–
else # <–
puts “bar not defined” # <–
bar = true # <–
end # <–
end
}

This produces:

foo not defined
foo not defined
foo not defined
foo not defined
bar is defined
bar not defined
bar is defined
bar not defined

In other words, in the second loop, inside the “highlighted” ‘else’ clause
– and only inside that clause – ‘defined? bar’ evaluates to
"local-variable(in-block)" for some reason. This is either a bug or
something so subtle it’s beyond me…

I didn’t find anything in ruby-talk archives about it, and the behavior is
consistent among the following versions:

ruby 1.6.5 (2001-09-19) [i686-linux]
ruby 1.6.7 (2002-06-04) [i686-linux]
ruby 1.7.2 (2002-06-04) [i686-linux]

Cheers,

  • jeff

Hi,

In other words, in the second loop, inside the “highlighted” ‘else’ clause
– and only inside that clause – ‘defined? bar’ evaluates to
“local-variable(in-block)” for some reason. This is either a bug or
something so subtle it’s beyond me…

`defined? local-variable’ is determined statically regardless
wheather it’s a dynamic variable or not, and wheather it’s
assigned actually or not.


[1, 2, 3, 4].each { |x|
if (x % 2) == 0
if defined? bar
puts “bar is defined”
else
puts “bar not defined”
bar = true

`bar’ is defined here, so it’s defined bellow.

end

else # ←
if defined? bar # ←
puts “bar is defined” # ←
else # ←
puts “bar not defined” # ←
bar = true # ←
end # ←
end
}

If you want to know it’s really assigned, you can use

eval “defined? bar”

···

At Wed, 5 Jun 2002 11:11:06 +0900, Gray, Jeff jeff.gray@intel.com wrote:


Nobu Nakada

Hi,

The behavior of the following code seems like a bug to me:

No, local variable scope is static, not dynamic, so that:

[1, 2, 3, 4].each { |x|
if defined? foo
puts “foo is defined” # no “foo” defined here
else # even in the second loop
puts “foo not defined”
foo = true # “foo” defined here
end
}

I think what you want is

foo = false
[1, 2, 3, 4].each { |x|
if foo
puts “foo is set”
else
puts “foo not set”
foo = true
end
}

						matz.
···

In message “Is this a bug in the defined? operator?” on 02/06/05, “Gray, Jeff” jeff.gray@intel.com writes: