From: nobu.nakada@... Date: 2002-09-01T10:16:14+09:00 Subject: [ruby-dev:18122] Re: Object#become なかだです。 At Sun, 1 Sep 2002 02:26:18 +0900, Koji Arai wrote: > > cloneでは特異メソッドも含めて引き継ぎます。cloneでもdupでも > > インスタンス変数は引き継ぎます。 > > これは、clone の話ですかね? become に関して言えば、 > > class Foo > @v = 1 > end > > klass = Class.new.become(Foo) > p klass > klass.instance_eval { p @v } > > => ruby 1.7.3 (2002-08-30) [i586-linux] > # > -:7: warning: instance variable @v not initialized > nil > > のように引き継がないようですが、まだ 2002-08-30 では実装が不 > 完全ってところでしょうか。 たぶんrb_mod_clone()とrb_mod_dup()も、becomeで置き換えるべきな のでは。 > ちなみに、以下のようにすると SEGV するのですが、きっとまつも > とさんの手元では直ってるかな?、 > > class Foo > end > > p obj = Foo.new > obj.instance_eval { @v = 1 } > p obj.become(Foo.new) > obj.instance_eval { p @v } > > => ruby 1.7.3 (2002-08-30) [i586-linux] > # > -:6: [BUG] Segmentation fault > ruby 1.7.3 (2002-08-30) [i586-linux] become先がインスタンス変数テーブルを持ってないときに、開放した 古いテーブルを指したままになってるからですね。 Index: class.c =================================================================== RCS file: /cvs/ruby/src/ruby/class.c,v retrieving revision 1.43 diff -u -2 -p -r1.43 class.c --- class.c 27 Aug 2002 08:31:05 -0000 1.43 +++ class.c 1 Sep 2002 01:05:53 -0000 @@ -60,36 +60,37 @@ clone_method(mid, body, tbl) VALUE -rb_mod_clone(module) - VALUE module; +rb_mod_become(module, orig) + VALUE module, orig; { - NEWOBJ(clone, struct RClass); - CLONESETUP(clone, module); + if (module == orig) return module; + + if (TYPE(orig) != T_CLASS) { + rb_raise(rb_eTypeError, "wrong argument class"); + } - RCLASS(clone)->super = RCLASS(module)->super; + RCLASS(module)->super = RCLASS(orig)->super; if (RCLASS(module)->iv_tbl) { + st_free_table(RCLASS(module)->iv_tbl); + RCLASS(module)->iv_tbl = 0; + } + if (RCLASS(module)->m_tbl) { + st_free_table(RCLASS(module)->m_tbl); + RCLASS(module)->m_tbl = 0; + } + if (RCLASS(orig)->iv_tbl) { ID id; - RCLASS(clone)->iv_tbl = st_copy(RCLASS(module)->iv_tbl); + RCLASS(module)->iv_tbl = st_copy(RCLASS(orig)->iv_tbl); id = rb_intern("__classpath__"); - st_delete(RCLASS(clone)->iv_tbl, &id, 0); + st_delete(RCLASS(module)->iv_tbl, &id, 0); id = rb_intern("__classid__"); - st_delete(RCLASS(clone)->iv_tbl, &id, 0); + st_delete(RCLASS(module)->iv_tbl, &id, 0); } - if (RCLASS(module)->m_tbl) { - RCLASS(clone)->m_tbl = st_init_numtable(); - st_foreach(RCLASS(module)->m_tbl, clone_method, RCLASS(clone)->m_tbl); + if (RCLASS(orig)->m_tbl) { + RCLASS(module)->m_tbl = st_init_numtable(); + st_foreach(RCLASS(module)->m_tbl, clone_method, RCLASS(orig)->m_tbl); } - return (VALUE)clone; -} - -VALUE -rb_mod_dup(mod) - VALUE mod; -{ - VALUE dup = rb_mod_clone(mod); - - RBASIC(dup)->flags = RBASIC(mod)->flags & (T_MASK|FL_TAINT|FL_SINGLETON); - return dup; + return (VALUE)module; } Index: intern.h =================================================================== RCS file: /cvs/ruby/src/ruby/intern.h,v retrieving revision 1.92 diff -u -2 -p -r1.92 intern.h --- intern.h 19 Aug 2002 05:56:05 -0000 1.92 +++ intern.h 1 Sep 2002 00:37:31 -0000 @@ -94,6 +94,5 @@ VALUE rb_big_rand _((VALUE, double*)); VALUE rb_class_boot _((VALUE)); VALUE rb_class_new _((VALUE)); -VALUE rb_mod_clone _((VALUE)); -VALUE rb_mod_dup _((VALUE)); +VALUE rb_mod_become _((VALUE, VALUE)); VALUE rb_singleton_class_new _((VALUE)); VALUE rb_singleton_class_clone _((VALUE)); Index: object.c =================================================================== RCS file: /cvs/ruby/src/ruby/object.c,v retrieving revision 1.85 diff -u -2 -p -r1.85 object.c --- object.c 27 Aug 2002 08:31:06 -0000 1.85 +++ object.c 1 Sep 2002 01:09:16 -0000 @@ -140,5 +140,8 @@ rb_obj_become(obj, orig) } if (type == T_OBJECT) { - if (ROBJECT(obj)->iv_tbl) st_free_table(ROBJECT(obj)->iv_tbl); + if (ROBJECT(obj)->iv_tbl) { + st_free_table(ROBJECT(obj)->iv_tbl); + ROBJECT(obj)->iv_tbl = 0; + } if (ROBJECT(orig)->iv_tbl) { ROBJECT(obj)->iv_tbl = st_copy(ROBJECT(orig)->iv_tbl); @@ -1355,6 +1358,5 @@ Init_Object() rb_define_method(rb_cModule, ">", rb_mod_gt, 1); rb_define_method(rb_cModule, ">=", rb_mod_ge, 1); - rb_define_method(rb_cModule, "clone", rb_mod_clone, 0); - rb_define_method(rb_cModule, "dup", rb_mod_dup, 0); + rb_define_method(rb_cModule, "become", rb_mod_become, 1); rb_define_method(rb_cModule, "to_s", rb_mod_to_s, 0); rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦