PS: I'm still curious about the reason for using a module.
I think the idea was to save frm creting a singleton class, but at the
expense of a module I don't see why either. Anyway, here the version I
put in Facets. Please evaluate.
module Kernel
# Like instace_eval but allows parameters to be passed.
···
#
# The implementation is thread-safe thanks to the
# Thread.current.object_id trick, but it doesn't work with
# immediate values (Fixnums and friends), and most
# importantly it bombs when given a frozen object.
def instance_exec(*args, &block)
mname =
"__instance_exec(#{Thread.current.object_id},#{caller.object_id})"
Object.class_eval{ define_method(mname, &block) }
begin
ret = send(mname, *args)
ensure
Object.class_eval{ undef_method(mname) }
end
ret
end
On Mon, Jul 10, 2006 at 07:33:34PM +0900, Erik Veenstra wrote:
class Object
def instance_exec(*args, &block)
object = self
res = nil
class << self
self
end.instance_eval do
begin
Thread.critical = true @_instance_exec_count_ ||= 0
======================
adds an instance variable for each object to which we send the instance_exec
message (fails for frozen objects, pollutes and costs more memory)
=======================
The old Thread.critical value is lost, so this could easily break
multi-threaded code... It should be
begin
old, Thread.critical = Thread.critical, true
...
ensure
Thread.critical = old
end
end
begin
define_method(method_name, &block)
res = object.send(method_name, *args)
ensure
remove_method(method_name) rescue nil
end
end
All in all, this implementation is the second best one as far as space
efficiency is concerned
I don't like having to point to my own site repeatedly, but you should really
have a look at
So far all the implementations I've seen posted were worse than the one shown
there (and than the original one in my older blog entry). It's the only
thread-safe, reentrant, bounded-space, frozen-object-safe implementation as
far as I know.
Anyway, here the version I put in Facets. Please evaluate.
# The implementation is thread-safe thanks to the
# Thread.current.object_id trick, but it doesn't work with
# immediate values (Fixnums and friends),...
(You're version _does_ work with immediate versions.)
Mmh... The Module version does work for immediate versions,
too. That might be a good reason... ;]
Mine doesn't...
# ...and most
# importantly it bombs when given a frozen object.
Object.class_eval{ define_method(mname, &block) }
This pollutes the global class Object. Not funny... ;] But,
yes, it does work...
The Module versions only pollutes the class Object with one,
dedicated Module. That's not too bad.
If we want to handle immediate values and we can't create
singleton classes for them, we have to abuse something.
Maybe, after all, the Module version isn't that bad... ;]
PS: I'm still curious about the reason for using a module.
I think the idea was to save frm creting a singleton class, but at the
expense of a module I don't see why either. Anyway, here the version I
put in Facets. Please evaluate.
module Kernel
# Like instace_eval but allows parameters to be passed.
#
# The implementation is thread-safe thanks to the
# Thread.current.object_id trick, but it doesn't work with
# immediate values (Fixnums and friends), and most
# importantly it bombs when given a frozen object.
def instance_exec(*args, &block)
mname =
"__instance_exec(#{Thread.current.object_id},#{caller.object_id})"
Object.class_eval{ define_method(mname, &block) }
begin
ret = send(mname, *args)
ensure
Object.class_eval{ undef_method(mname) }
end
ret
end
end
--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama
> PS: I'm still curious about the reason for using a module.
* it allows instance_exec to work on frozen objects and immediate values
* it doesn't pollute Object with several methods (even if temporarily), only
one module
I think the idea was to save frm creting a singleton class, but at the
expense of a module I don't see why either. Anyway, here the version I
put in Facets. Please evaluate.
module Kernel
# Like instace_eval but allows parameters to be passed.
#
# The implementation is thread-safe thanks to the
# Thread.current.object_id trick, but it doesn't work with
# immediate values (Fixnums and friends), and most
# importantly it bombs when given a frozen object.
def instance_exec(*args, &block)
mname =
"__instance_exec(#{Thread.current.object_id},#{caller.object_id})"
Object.class_eval{ define_method(mname, &block) }
begin
ret = send(mname, *args)
ensure
Object.class_eval{ undef_method(mname) }
end
ret
end
end
heh you copied the comment from my blog entry[1] but that's not the
implementation it applied to ;). The above does work with immediate values and
frozen objects. But I now consider it flawed nonetheless, read
> Anyway, here the version I put in Facets. Please evaluate.
>
> # The implementation is thread-safe thanks to the
> # Thread.current.object_id trick, but it doesn't work with
> # immediate values (Fixnums and friends),...
(You're version _does_ work with immediate versions.)
Mmh... The Module version does work for immediate versions,
too. That might be a good reason... ;]
Mine doesn't...
> # ...and most
> # importantly it bombs when given a frozen object.
>
> Object.class_eval{ define_method(mname, &block) }
This pollutes the global class Object. Not funny... ;] But,
yes, it does work...
It should delete it when done, so it's a temporary pollution. But I
think to do that right, instead of undef_method that should be
remove_method: