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