From: Mikael Brockman Date: 2004-06-29T02:15:31+09:00 Subject: Re: Is it considered Harmful? "Sean O'Dell" writes: > On Monday 28 June 2004 10:06, Mikael Brockman wrote: > > "Sean O'Dell" writes: > > > On Monday 28 June 2004 09:27, Austin Ziegler wrote: > > > > On Tue, 29 Jun 2004 00:58:22 +0900, Sean O'Dell > > > > > wrote: > > > > > #class= can only be called on existing objects, so it can't > > > > > prevent initialization from happening (it already happened > > > > > before you can even make the call). The takeover class > > > > > inherits an already-initialized object. I'm not sure how else > > > > > to say that. The object is already initialized, #class= cannot > > > > > prevent that. Both classes, the old and the new, work with an > > > > > already-initialized object. > > > > > > > > So ... with your modifications, I can safely do: > > > > > > > > foo = Object.new > > > > foo.class = Tempfile > > > > foo.write "bar" > > > > > > Safely, yes. Usefully, no. Tempfile can't do much with just an > > > Object instance, and since its methods expect its own data and > > > nothing else, it really would just complain that it can't do > > > anything useful. > > > > > > However: > > > > > > socket.class = SocketLogger > > > > > > ...would be a case where something useful DID happen. Assume you > > > get socket in a callback method of, say, an HTTP server framework. > > > You can't figure out why your client code isn't getting the data > > > you think your callback method is sending through the socket > > > object. So, as a debugging trick, you swap out the socket object > > > with a SocketLogger, which still sends data through the socket, > > > but also logs everything sent by your method as well as the > > > framework, so you can see everything going out by just analyzing a > > > logging file. From that point on out, every method call made on > > > the socket object would be handled by the SocketLogger class; no > > > calls could slip through to the old Socket class and go unnoticed > > > accidently. > > > > > > Both #class= and #become, I think, would serve this purpose. I > > > like #become for its safety, but I boggle at how you would located > > > every single reference to an object both in Ruby and in C > > > extensions. Also, there's the chance that an object could #become > > > to another class and still be assigned methods which expect > > > certain data to be initialized which is not, and you could still > > > end up with the same dangers as #class=. > > > > > > Sean O'Dell > > > > evil.rb implements #become without traversing the entire set of live > > references; it simply alters the objects in place, I think. > > > > With just #become (no class=), you can't create objects whose > > #initialize is not called. It's just like swapping variables, except > > all variables that point to the pointee are affected. > > You can't do that with #class= either. You can only call #class= on > objects that exist, hence they've been initialized. The new class > might not know what to do with the object, but the object certainly > has already been initialized. > > Sean O'Dell By "whose #initialize", I meant "whose current class's #initialize". | class A | def initialize | @name = 'a' | end | end | | class B | def initialize | @name = 'b' | end | end | | a1 = A.new | a2 = A.new | b = B.new | | a1.class = B | # a1's @name is now 'a', but its class is B | | a2.become b | # a2's @name is now 'b', and its class is B mikael