From: Sean O'Dell Date: 2004-06-26T04:51:40+09:00 Subject: class= and type checks when casting Matz, I'm not sure if you followed the discussion in ruby-talk about having a "class=" method. We were just talking about changing the class of an object, and what problems would/would not arise in so doing. When I tried implementing "class=" on my own, Ruby crashed pretty badly in a lot of places. Then I realized the reason was because so much code casts VALUEs to RFILE, RHASH, etc. without checking that the types were actually valid. So I changed many of the casts in ruby.h (RHASH, RFILE, RSTRING, etc.) to perform a quick type check. That solved the problem of crashing the built-in types when the class was changed. I ran some tests; 100,000x calling file#read with and without checking that the file object's class was truly T_FILE, and I noticed no time difference. I don't think the extra check adds any noticable overhead. The implementation I came up with allows you to do silly things like: class ClassA def initialize @var = "hello, world" end end class ClassB def test_method p @var end end a = ClassA.new a.class = ClassB a.test_method # ==> "hello, world" For reference, the changes I made as a patch against the CVS: Index: object.c =================================================================== RCS file: /src/ruby/object.c,v retrieving revision 1.153 diff -r1.153 object.c 201a202,209 > VALUE > rb_obj_class_set(obj, new_class) > VALUE obj, new_class; > { > RBASIC(obj)->klass = new_class; > return new_class; > } > 2546a2555 > rb_define_method(rb_mKernel, "class=", rb_obj_class_set, 1); Index: ruby.h =================================================================== RCS file: /src/ruby/ruby.h,v retrieving revision 1.105 diff -r1.105 ruby.h 415,420c415,420 < #define RMODULE(obj) RCLASS(obj) < #define RFLOAT(obj) (R_CAST(RFloat)(obj)) < #define RSTRING(obj) (R_CAST(RString)(obj)) < #define RREGEXP(obj) (R_CAST(RRegexp)(obj)) < #define RARRAY(obj) (R_CAST(RArray)(obj)) < #define RHASH(obj) (R_CAST(RHash)(obj)) --- > #define RMODULE(obj) (Check_Type(obj, T_MODULE), RCLASS(obj)) > #define RFLOAT(obj) (Check_Type(obj, T_FLOAT), R_CAST(RFloat)(obj)) > #define RSTRING(obj) (Check_Type(obj, T_STRING), R_CAST(RString)(obj)) > #define RREGEXP(obj) (Check_Type(obj, T_REGEXP), R_CAST(RRegexp)(obj)) > #define RARRAY(obj) (Check_Type(obj, T_ARRAY), R_CAST(RArray)(obj)) > #define RHASH(obj) (Check_Type(obj, T_HASH), R_CAST(RHash)(obj)) 422,424c422,424 < #define RSTRUCT(obj) (R_CAST(RStruct)(obj)) < #define RBIGNUM(obj) (R_CAST(RBignum)(obj)) < #define RFILE(obj) (R_CAST(RFile)(obj)) --- > #define RSTRUCT(obj) (Check_Type(obj, T_STRUCT), R_CAST(RStruct)(obj)) > #define RBIGNUM(obj) (Check_Type(obj, T_BIGNUM), R_CAST(RBignum)(obj)) > #define RFILE(obj) (Check_Type(obj, T_FILE), R_CAST(RFile)(obj))