I'm running ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux].
#!/usr/bin/env ruby
def ouch()
raise ArgumentError, "woof"
fred = 3
return( nil )
ensure
if ( defined?( fred ) ) then
printf( "fred is defined (%s)\n", fred.inspect() )
else
printf( "fred is not defined\n" )
end
end # ouch()
ouch()
When run, the output from the above ruby script is quite unexpected.
$ ./ouch.rb
fred is defined (nil)
./ouch.rb:4:in `ouch': woof (ArgumentError)
from ./ouch.rb:22:in `<main>'
So the raise/exception is occurring, fred isn't getting set to 3, but it is getting defined and set to nil, thereby defeating the test for defined?(). This is very confusing. Is this a bug? Obviously the test for defined needs to be followed by testing for not nil.
If this isn't a bug, can someone explain why not?
Local variables in Ruby are defined between the line they're first used at and the end of the current lexical scope. They're also initialized to nil
implicitly.
Consider also this example:
if false
var = 123
end
p var # => nil
This behavior is intended. Ruby is designed the way it could differentiate between method calls and local variable access at the parse step, not execution one. So, after the point at which a variable has been defined, all further references to that name will access the variable, whether it was explicitly set to some value or not.
(If someone will point me to the CALL_VCALL method call type in Ruby, I'll answer that as far as I know, it is only used in eval
: when you are eval
-ing, you cannot know from the beginning if some variable was defined on the previous line of irb, hence such accesses should be catched and dispatched accordingly.)
Here is a simpler example:
if false
alocal = 123
end
p defined? alocal
=> "local-variable"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With