Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird behavior of defined?(super) check

Lately I came across some weird behavior with the defined? operator used to check if super keyword can be used in current context. Usually it works fine, but when I tried to combine the defined? super check with a tiny bit of metaprogramming, it gave me unexpected results.

It's easier to show then to describe, so here is a distilled example to illustrate the problem:

class A; 
  def self.def_f!; 
    singleton_class.send(:define_method, :f) { defined? super }
  end
end
class AA < A; end

(A and AA classes both have .def_f! class method)

A.def_f!

A.f  # => nil
AA.f # => nil

(A.f has no super and AA.f dispatches to A.f, so everything's OK so far, but...)

AA.def_f! # define its own .f method in the AA class

AA.f # => "super"
A.f  # => "super" # WHY???

Could anyone explain me the last line? A.f has no super method, then why it returns "super" instead of nil? Is it a bug?

(I tried it in 1.9.2 and 1.9.3—same results)

UPD: I opened a ticket on the Ruby bugtracker: http://bugs.ruby-lang.org/issues/6644

like image 717
Alexis Avatar asked Jun 24 '12 20:06

Alexis


2 Answers

Ok, so @Niklas was right, I reported this issue to the Ruby bugtracker and they confirmed and fixed the bug: https://bugs.ruby-lang.org/issues/6644.

As far as I've understood, the fix will be included in ruby 2.0.0.

like image 192
Alexis Avatar answered Jan 04 '23 06:01

Alexis


Yeah there are a few quirks with define_method, this is not a problem with defined?(super) really, but more with define_method. Having said that, whenever I encounter an edge case like this with define_method, I usually just end up eval'ing a string of Ruby code and it always ends up working as expected.

module M;
  def def_f!
    singleton_class.class_eval <<-RUBY
      def f
        defined?(super)
      end
    RUBY
  end
end

class A; extend M; end
class AA < A; end

A.def_f!

p A.f  # => nil
p AA.f # => nil

AA.def_f! # define its own .f method in the AA class

p AA.f # => "super"
p A.f # => nil

As to why it works this way, I'm not experienced enough with Ruby's source to know, maybe somebody who knows more than I do can chime in. But for practical purposes, evaluating a string has always worked for me.

like image 39
luke-gru Avatar answered Jan 04 '23 05:01

luke-gru