On Tue, Sep 19, 2006 at 06:56:24AM +0900, Christian Neukirchen wrote:
> Devin Mullins <twifkak / comcast.net> writes:
> > Also, once you find an incompatibility, you can write code that works
> > in both versions. Simple example from Rails:
> >   unless defined? instance_exec # 1.9
> >     def instance_exec(*arguments, &block)
> >       block.bind(self)[*arguments]
> >     end
> >   end
> > (Runtime #ifdef, if you will.) So you shouldn't need to maintain
> > multiple versions of the code.
> 
> OT: I must be dumb, but if it was that easy, why did Mauricio
> Fernandez need almost a page of code to produce a good instance_exec?

For the sake of future googlers...

Getting a more or less working implementation is easy, but things become harder if
you try to make it:
* thread-safe
* work with immediate objects
* work with frozen objects
* bounded-space (i.e. not leak memory on each call)
...
[And anticipating such corner cases is even harder :)]

As said elsewhere in this thread, Rails' version relies on Proc#bind, defined as 

class Proc #:nodoc:
  def bind(object)
    block, time = self, Time.now
    (class << object; self end).class_eval do
      method_name = "__bind_#{time.to_i}_#{time.usec}"
      define_method(method_name, &block)
      method = instance_method(method_name)
      remove_method(method_name)
      method
    end.bind(object)
  end
end

This implementation
* is not strictly thread-safe (in practice, it will be, since I doubt Ruby
  will switch contexts in under 1us on any machine)
* doesn't work with immediate (Fixnums, etc.) nor frozen objects
* leaks memory [1] (around 70 bytes per #instance_exec call)

I've analyzed several #instance_exec implementations [2] and written a
thread-safe, bounded-space one that works with frozen and immediate objects [3]. 

1. http://eigenclass.org/hiki.rb?ruby+symbols+memleak
2. http://eigenclass.org/hiki.rb?instance_exec
3. http://eigenclass.org/hiki.rb?bounded+space+instance_exec

-- 
Mauricio Fernandez  -   http://eigenclass.org   -  singular Ruby