Подтвердить что ты не робот

Странное поведение определенной (супер) проверки

В последнее время я столкнулся с каким-то странным поведением с оператором defined?, используемым для проверки того, можно ли использовать ключевое слово super в текущем контексте. Обычно он работает нормально, но когда я попытался объединить проверку defined? super с крошечным метапрограммированием, это дало мне неожиданные результаты.

Легче показать, чтобы потом описать, так что вот пример, иллюстрирующий проблему:

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

(A и AA классы имеют метод класса .def_f!)

A.def_f!

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

(A.f не имеет супер и AA.f отправляет на A.f, поэтому все ОК до сих пор, но...)

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

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

Может ли кто-нибудь объяснить мне последнюю строку? A.f не имеет супер-метода, то почему он возвращает "super" вместо nil? Это ошибка?

(я пробовал его в 1.9.2 и 1.9.3-такие же результаты)

UPD: Я открыл билет на багтрекере Ruby: http://bugs.ruby-lang.org/issues/6644

4b9b3361

Ответ 1

Хорошо, поэтому @Niklas был прав, я сообщил об этой проблеме в Ruby bugtracker, и они подтвердили и исправили ошибку: https://bugs.ruby-lang.org/issues/6644.

Насколько я понял, исправление будет включено в ruby ​​2.0.0.

Ответ 2

Да, есть несколько причуд с define_method, это не проблема с defined?(super), но больше с define_method. Сказав это, всякий раз, когда я сталкиваюсь с таким случаем, как это с define_method, я обычно просто заканчиваю вычисление строки кода Ruby и всегда заканчивает работу, как ожидалось.

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

Что касается того, почему он работает таким образом, я не достаточно опытен, чтобы узнать источник Ruby, возможно, кто-то, кто знает больше, чем я, может прослушивать. Но для практических целей оценка строки всегда работала для меня.