开发者

in ruby, why doesn't defined? work as one would expect when used with ensure

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.)


  • Not a bug
  • Local variables are created by assignment, but it turns out that the assignment only needs to be parsed, not actually executed...

Here is a simpler example:

 if false
   alocal = 123
 end
 p defined? alocal
 => "local-variable"
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜