From: Yusuke Endoh Date: 2010-05-19T23:25:13+09:00 Subject: [ruby-core:30313] [Bug #2502] strange behavior of anonymous class inside a proc Issue #2502 has been updated by Yusuke Endoh. Hi, 2009/12/19 caleb clausen : > I have a problem in 1.9.1 when I run this code, extracted from a larger project: > $VERBOSE=1 > > class SubSeq > def initialize > @first=11 > @first or fail > end > > def subseq > @first or fail > end > end > > class Indexed > def subseq > SubSeq.new > end > end > > Overlaid =proc do > p self > class< def subseq > super.instance_eval(& Overlaid) > end > end > end > > mid=Indexed.new > mid.instance_eval(&Overlaid) > mid.subseq > p mid > mid.subseq > > The output I get is like this: > # > # > # > subseq_first_nil.rb:10: warning: instance variable @first not initialized > subseq_first_nil.rb:10:in `subseq': unhandled exception > from subseq_first_nil.rb:24:in `subseq' > from subseq_first_nil.rb:33:in `
' > > This code should run without raising an exception, and does in ruby 1.8. The exception is raised from within the last line, the second call to mid.subseq. Both mid.subseq calls should behave exactly the same. The first appears to do all the right things. But in the second, it goes all awry. They should both call first the anonymous class's #subseq, then (via the super) Indexed#subseq, which ultimately returns a SubSeq object, also decorated by the anonymous class. SubSeq#subseq itself should never be called, but somehow (given the top line of the exception traceback and the warning) it is. SubSeq's @first should never be nil, since it is initialized in the constructor and never changed, but somehow it is. > > This is the last remaining (serious) problem in porting redparse to 1.9. It causes redparse to incorrectly handle certain here documents which work fine when run in 1.8. I'd appreciate it very much of this problem can be fixed. Definitely, this is a bug. But it is very difficult to fix because this is a design flaw of YARV. Each method definition (more precisely, rb_iseq_t) has information of class that the method belongs to. This information is used to identify the parent class and method when super is called. This information belongs to each *lexical* method definition. Your code uses the same definition of method `subseq' twice, to an instance of Indexed, and to an instance of SubSeq. The first definition sets the information to Indexed, and the second *overwrites* it to SubSeq. This causes inconsistency between class of self and class that a super'ed method belongs to. To fix this issue, the information must be moved from rb_iseq_t to stack frame, which requires major upgrade. So, towards 1.9.2 release, we plan to pass on the fix of this issue, by prohibiting super in such a situation (the above code raises an NotImplementedError). We will fix it in 1.9.3 or later. You can use Module#include as a workaround (`subseq' belong to the Workaround module, so the above issue does not occur): module Workaround def subseq super.instance_eval(& Overlaid) end end Overlaid =proc do p self class< ---------------------------------------- http://redmine.ruby-lang.org/issues/show/2502 ---------------------------------------- http://redmine.ruby-lang.org