Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

ruby

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?

like image 314
eclectic923 Avatar asked Aug 07 '11 17:08

eclectic923


2 Answers

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

like image 73
whitequark Avatar answered Nov 17 '22 21:11

whitequark


  • 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"
like image 31
DigitalRoss Avatar answered Nov 17 '22 21:11

DigitalRoss