Unexpected behaviour of defined? under 1.8.x

Discussion in 'Ruby' started by Jarmo Pertman, Sep 22, 2010.

  1. Hello!

    I've just landed upon a very interesting landmine by using defined?

    Consider the following code:

    # a.rb
    module A
    autoload :B, "b.rb"
    end

    defined?(A::B::C)
    p A::B
    p A::B.new.one
    p A::B.new.two


    # b.rb
    module A
    class B
    puts "loading"
    def one; 1; end

    raise "no-no-no!"

    def two; 2; end
    end
    end

    So, when running a.rb what would you expect?

    I would expect defined? line to raise an RuntimeError, but instead i
    will see this:
    loading
    A::B
    1
    a.rb:8: undefined method `two' for #<A::B:0x49590c0> (NoMethodError)

    This happens with 1.8.6 and 1.8.7, but is working as expected with
    1.9.1.

    In real life the code was something like this:
    return unless defined?(A::B.some_method)

    During the autoload, there was a ton of require statements of which
    one failed with LoadError, but this didn't get raised to the console
    and half of the unit-tests were failing. Yes, you guessed it right - i
    did spend some amount of time with the debugger :)

    Anyway, i've fixed that line to use respond_to? instead, but it is
    still odd behaviour...


    Jarmo Pertman
    -----
    IT does really matter - http://www.itreallymatters.net
    Jarmo Pertman, Sep 22, 2010
    #1
    1. Advertising

  2. On Wed, Sep 22, 2010 at 5:35 PM, Jarmo Pertman <> wrote:
    > Hello!
    >
    > I've just landed upon a very interesting landmine by using defined?
    >
    > Consider the following code:
    >
    > # a.rb
    > module A
    > =A0autoload :B, "b.rb"
    > end
    >
    > defined?(A::B::C)
    > p A::B
    > p A::B.new.one
    > p A::B.new.two
    >
    >
    > # b.rb
    > module A
    > =A0 =A0class B
    > =A0 =A0 =A0 =A0puts "loading"
    > =A0 =A0 =A0 =A0def one; 1; end
    >
    > =A0 =A0 =A0 =A0raise "no-no-no!"
    >
    > =A0 =A0 =A0 =A0def two; 2; end
    > =A0 =A0end
    > end
    >
    > So, when running a.rb what would you expect?
    >
    > I would expect defined? line to raise an RuntimeError,...


    Why?

    defined? is there to check WITHOUT raising an runtime error

    ruby-1.8.7-p302 > defined? Blatz
    =3D> nil
    ruby-1.8.7-p302 > defined? A::B::C
    =3D> nil
    ruby-1.8.7-p302 > defined? Object
    =3D> "constant"

    And it's the same for 1.9.2

    ruby-1.9.2-p0 > defined? Blatz
    =3D> nil
    ruby-1.9.2-p0 > defined? A::B::C
    =3D> nil
    ruby-1.9.2-p0 > defined? Object
    =3D> "constant"



    --=20
    Rick DeNatale

    Blog: http://talklikeaduck.denhaven2.com/
    Github: http://github.com/rubyredrick
    Twitter: @RickDeNatale
    WWR: http://www.workingwithrails.com/person/9021-rick-denatale
    LinkedIn: http://www.linkedin.com/in/rickdenatale
    Rick DeNatale, Sep 23, 2010
    #2
    1. Advertising

  3. Rick Denatale wrote:
    >> I would expect defined? line to raise an RuntimeError,...

    >
    > Why?
    >
    > defined? is there to check WITHOUT raising an runtime error


    I think the point is the autoload stuff.

    If you have autoload set up for A::B, and you are checking "defined?
    A::B::C", then of course A::B has to be autoloaded before you check
    A::B::C. But when an exception is raised in the source file which is
    being autoloaded, it just finishes at that point silently, so you end up
    with half a file loaded.

    Here is another example:

    ---- a.rb ----
    module A
    autoload :B, "b.rb"
    end

    p defined?(A::B::C) # nil
    p defined?(A::B::C) # "constant"

    ---- b.rb ----
    module A
    class B
    puts "Starting"
    C = 123
    raise "Oops"
    puts "Never get here"
    end
    end
    --
    Posted via http://www.ruby-forum.com/.
    Brian Candler, Sep 23, 2010
    #3
  4. I'm fully aware that it was related with autoload and why the file got
    partially loaded, but it was just strange behaviour.

    I didn't expect that defined? rescues silently any Exceptions (or is
    there anything which isn't rescued?). Considering from the name
    "defined?" i thought that it will rescue only NameError (which could
    happen only if trying to see if any const/class/module/variable is not
    defined), but rescueing everything didn't make sense.

    As i pointed out then in 1.9.1 the result is more of an expected:
    loading
    b.rb:6:in `<class:B>': no-no-no! (RuntimeError)
    from b.rb:2:in `<module:A>'
    from b.rb:1:in `<top (required)>'
    from a.rb:6:in `<main>'

    Just checked that 1.9.2 works the same.

    Rick, why do you expect it to rescue every Exception? What's your
    logic behind that assumption or is it just because you knew that this
    is the correct behavior?

    Jarmo

    On Sep 23, 11:17 am, Brian Candler <> wrote:
    > Rick Denatale wrote:
    > >> I would expect defined? line to raise an RuntimeError,...

    >
    > > Why?

    >
    > > defined? is there to check WITHOUT raising an runtime error

    >
    > I think the point is the autoload stuff.
    >
    > If you have autoload set up for A::B, and you are checking "defined?
    > A::B::C", then of course A::B has to be autoloaded before you check
    > A::B::C. But when an exception is raised in the source file which is
    > being autoloaded, it just finishes at that point silently, so you end up
    > with half a file loaded.
    >
    > Here is another example:
    >
    > ---- a.rb ----
    > module A
    >   autoload :B, "b.rb"
    > end
    >
    > p defined?(A::B::C)   # nil
    > p defined?(A::B::C)   # "constant"
    >
    > ---- b.rb ----
    > module A
    >   class B
    >     puts "Starting"
    >     C = 123
    >     raise "Oops"
    >     puts "Never get here"
    >   end
    > end
    > --
    > Posted viahttp://www.ruby-forum.com/.
    Jarmo Pertman, Sep 23, 2010
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mark
    Replies:
    4
    Views:
    2,947
    scoude
    Jan 12, 2011
  2. Steven Van den Berghe

    unexpected map behaviour

    Steven Van den Berghe, Aug 28, 2003, in forum: C++
    Replies:
    2
    Views:
    417
    Christian Janßen
    Aug 28, 2003
  3. Oodini
    Replies:
    1
    Views:
    1,767
    Keith Thompson
    Sep 27, 2005
  4. Rob Clewley
    Replies:
    3
    Views:
    229
    Rob Clewley
    Jan 13, 2009
  5. Joe Ardent
    Replies:
    1
    Views:
    343
Loading...

Share This Page