Instance_exec

i seems to recall someone came up with an impl of instance_exec (instance_eval
that takes args) a while back - might have even been me! :wink: anyone remember?

-a

···

--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

There is one in Rails' ActiveSupport:

class Object
  unless defined? instance_exec # 1.9
    def instance_exec(*arguments, &block)
      block.bind(self)[*arguments]
    end
  end
end

class Proc
  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

marcel

···

On Sat, Jul 08, 2006 at 02:22:31AM +0900, ara.t.howard@noaa.gov wrote:

i seems to recall someone came up with an impl of instance_exec
(instance_eval
that takes args) a while back - might have even been me! :wink: anyone
remember?

--
Marcel Molina Jr. <marcel@vernix.org>

You did indeed! And so did I. However, Mauricio Fernandez came up with
what seems to be a fairly complete implementation (thread safe,
handles frozen objects, etc.) at:

http://eigenclass.org/hiki.rb?cmd=view&p=instance_exec&key=instance_exec

Regards,
Sean

···

On 7/7/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

i seems to recall someone came up with an impl of instance_exec (instance_eval
that takes args) a while back - might have even been me! :wink: anyone remember?

-a
--

Duh! I'm sitting here screwing with this and the answer's sitting one
directory over.. with only a minor modification (I added recv=nil) I
introduce you to Facets' Proc#to_method:

···

#--
  # Credit for #to_method goes to Forian Gross (flgr).
  #--

  require 'thread'

  class Proc

    MethodMutexes = Hash.new do |hash, key|
      hash[key] = Mutex.new
    end

    # Creates a local method based on a Proc.
    def to_method(name=nil, recv=nil)
      name ||= "!to_method_temp#{self.object_id}"
      recv ||= eval("self", self)
      klass = recv.class
      MethodMutexes[klass => name].synchronize do
        begin
          klass.send(:define_method, name, &self)
          return recv.method(name)
        ensure
          klass.send(:remove_method, name) if not name
        end
      end
    end

  end

Then instance_exec is simply:

  module Kernel

    def instance_exec(*args, &block)
      block.to_method(nil,self).call(*args)
    end

  end

Proof is in the pudding. Facets' really does pay off!

T.

thanks! i just hacked this one out:

   harp:~ > cat a.rb
   class Object
     unless instance_methods.include? 'instance_exec'
       def instance_exec *a, &b
         m = "__instance_exec_#{ Thread.current.object_id.abs }__"
         singleton_class{ define_method m, &b }
         send m, *a
       ensure
         singleton_class{ undef_method m } rescue nil
       end
     end
     unless instance_methods.include? 'singleton_class'
       def singleton_class &b
         sc = class << self; self; end
         sc.module_eval &b if b
         sc
       end
     end
   end

   a =
   a.instance_exec 42 do |elem|
     push elem
   end
   p a

   harp:~ > ruby a.rb
   [42]

regards.

-a

···

On Sat, 8 Jul 2006, Marcel Molina Jr. wrote:

On Sat, Jul 08, 2006 at 02:22:31AM +0900, ara.t.howard@noaa.gov wrote:

i seems to recall someone came up with an impl of instance_exec
(instance_eval
that takes args) a while back - might have even been me! :wink: anyone
remember?

There is one in Rails' ActiveSupport:

class Object
unless defined? instance_exec # 1.9
   def instance_exec(*arguments, &block)
     block.bind(self)[*arguments]
   end
end
end

class Proc
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

--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

This is not thread-safe - relying on time.usec may not work on
sufficiently fast or clock-impaired machines.

Regards,
Sean

···

On 7/7/06, Marcel Molina Jr. <marcel@vernix.org> wrote:

On Sat, Jul 08, 2006 at 02:22:31AM +0900, ara.t.howard@noaa.gov wrote:
>
> i seems to recall someone came up with an impl of instance_exec
> (instance_eval
> that takes args) a while back - might have even been me! :wink: anyone
> remember?

There is one in Rails' ActiveSupport:

class Object
  unless defined? instance_exec # 1.9
    def instance_exec(*arguments, &block)
      block.bind(self)[*arguments]
    end
  end
end

class Proc
  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

marcel
--
Marcel Molina Jr. <marcel@vernix.org>

Marcel Molina Jr. wrote:

···

On Sat, Jul 08, 2006 at 02:22:31AM +0900, ara.t.howard@noaa.gov wrote:
>
> i seems to recall someone came up with an impl of instance_exec
> (instance_eval
> that takes args) a while back - might have even been me! :wink: anyone
> remember?

There is one in Rails' ActiveSupport:

class Object
  unless defined? instance_exec # 1.9
    def instance_exec(*arguments, &block)
      block.bind(self)[*arguments]
    end
  end
end

class Proc
  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

Huh. That looks like the one I wrote a while back (minus the time
stamp).

Mauricio Fernandez's looks better though --think I'll have to rip it
for Facets :wink:

T.

Duh! I'm sitting here screwing with this and the answer's sitting one
directory over.. with only a minor modification (I added recv=nil) I
introduce you to Facets' Proc#to_method:

  #--
  # Credit for #to_method goes to Forian Gross (flgr).

                                    (Florian)

···

On Mon, Jul 10, 2006 at 10:44:32PM +0900, transfire@gmail.com wrote:

  #--

  require 'thread'

  class Proc

    MethodMutexes = Hash.new do |hash, key|
      hash[key] = Mutex.new
    end

    # Creates a local method based on a Proc.
    def to_method(name=nil, recv=nil)
      name ||= "!to_method_temp#{self.object_id}"

                  ================================

This can create a lot of different symbols, leading to large memory leaks.

      recv ||= eval("self", self)
      klass = recv.class
      MethodMutexes[klass => name].synchronize do

        ============================

This makes the memleak even heavier, going from potentially ~70 bytes to
nearly 300 bytes per call...

        begin
          klass.send(:define_method, name, &self)

            ==========

This will fail if the class was frozen.

See my blog for a better implementation.

          return recv.method(name)
        ensure
          klass.send(:remove_method, name) if not name
        end
      end
    end

  end

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

Do - it's the best version for 1.8 so far (IMHO).

Regards,
Sean

···

On 7/7/06, transfire@gmail.com <transfire@gmail.com> wrote:

Huh. That looks like the one I wrote a while back (minus the time
stamp).

Mauricio Fernandez's looks better though --think I'll have to rip it
for Facets :wink:

T.

i just came across a bug in it (it's not re-entrant) - here's the fix:

   harp:~ > cat a.rb
   class Object
     unless instance_methods.include? 'instance_exec'
       def instance_exec *a, &b
         m, n = nil, -1
         loop{
           m = "__instance_exec_#{ Thread.current.object_id.abs }_#{ n += 1 }__"
           break unless respond_to? m
         }
         singleton_class{ define_method m, &b }
         send m, *a
       ensure
         singleton_class{ undef_method m }
       end
     end

     unless instance_methods.include? 'singleton_class'
       def singleton_class &b
         sc =
           class << self; self; end
         sc.module_eval &b if b
         sc
       end
     end
   end

   a =

   a.instance_exec 42 do |x|
     instance_exec x do |y|
       push y
       p size
     end
   end

   harp:~ > ruby a.rb
   1

figured you'd use this if anyone would tom... cheers.

-a

···

On Sat, 8 Jul 2006 transfire@gmail.com wrote:

Mauricio Fernandez's looks better though --think I'll have to rip it
for Facets :wink:

--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

Mauricio Fernandez wrote:

···

On Mon, Jul 10, 2006 at 10:44:32PM +0900, transfire@gmail.com wrote:
This can create a lot of different symbols, leading to large memory leaks.

This makes the memleak even heavier, going from potentially ~70 bytes to
nearly 300 bytes per call...

This will fail if the class was frozen.

Right. I expected as much. But can you apply yuor fixes to
Proc#to_method?

T.

Okay, I think I've improved it some more:

require 'thread'

class Proc
  MethodMutexes = Hash.new do |hash, key|
    hash[key] = Mutex.new
  end

  # Creates a local method based on a Proc.
  def to_method(name=nil, recv=nil)
    unless name
      n = 0
      n += 1 while recv.respond_to?(name = "__to_method_#{n}")
    end
    recv ||= eval("self", self)
    klass = recv.class
    MethodMutexes[klass => name].synchronize do
      begin
        klass.send(:define_method, name, &self)
        return recv.method(name)
      ensure
        klass.send(:remove_method, name) unless name
      end
    end
  end
end

This can create a lot of different symbols, leading to large memory leaks.

> recv ||= eval("self", self)
> klass = recv.class
> MethodMutexes[klass => name].synchronize do
        ============================

This makes the memleak even heavier, going from potentially ~70 bytes to
nearly 300 bytes per call...

I don't understand this though. isn't the memory freed when done? Or is
some symbol getting created in the process, or ?

> begin
> klass.send(:define_method, name, &self)
            ==========

This will fail if the class was frozen.

Ah, I see if the _klass_ is frozen. But that will fail regardless won't
it? You can;t even include a module (ef InstanceExecHelper) in a frozen
class. Right?

Thanks,
T.

[#instance_exec implementation]

The example you gave does work with my implementation too:

  RUBY_VERSION # => "1.8.5"
  RUBY_RELEASE_DATE # => "2006-06-24"
  class Object
    module InstanceExecHelper; end
    include InstanceExecHelper
    def instance_exec(*args, &block)
      mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
      InstanceExecHelper.module_eval{ define_method(mname, &block) }
      begin
        ret = send(mname, *args)
      ensure
        InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
                                                      # ==========
                                                      # thx to this
      end
      ret
    end
  end

  a =

  a.instance_exec 42 do |x|
    instance_exec x do |y|
      push y
      p size
    end
  end

  a # => [42]
  a.size # => 1
# >> 1

I had actually a test for that (see test_instance_exec_nested below). Do you
have any additional assertions handy?
(So far test_instance_exec_with_frozen_obj fails in all the other
implementations I've seen.)

  require 'test/unit'
  class TestInstanceEvalWithArgs < Test::Unit::TestCase
    def test_instance_exec
      # Create a block that returns the value of an argument and a value
      # of a method call to +self+.
      block = lambda { |a| [a, f] }
  
      assert_equal [:arg_value, :dummy_value],
        Dummy.new.instance_exec(:arg_value, &block)
    end
  
    def test_instance_exec_with_frozen_obj
      block = lambda { |a| [a, f] }
  
      obj = Dummy.new
      obj.freeze
      assert_equal [:arg_value, :dummy_value],
        obj.instance_exec(:arg_value, &block)
    end
  
    def test_instance_exec_nested
      i = 0
      obj = Dummy.new
      block = lambda do |arg|
        [arg] + instance_exec(1){|a| [f, a] }
      end
  
      # the following assertion expanded by the xmp filter automagically from:
      # obj.instance_exec(:arg_value, &block) #=>
      assert_equal([:arg_value, :dummy_value, 1], obj.instance_exec(:arg_value, &block))
    end
  end

···

On Sun, Jul 09, 2006 at 03:09:52PM +0900, ara.t.howard@noaa.gov wrote:

>Mauricio Fernandez's looks better though --think I'll have to rip it
>for Facets :wink:

i just came across a bug in it (it's not re-entrant) - here's the fix:

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

Thanks Ara.

Do you have a testcase I can use?

T.

Mauricio Fernandez wrote:

This will fail if the class was frozen.

Actually, it seems to pass the frozen test.

T.

Okay, I think I've improved it some more:

[...]

> > recv ||= eval("self", self)
> > klass = recv.class
> > MethodMutexes[klass => name].synchronize do
> ============================
>
> This makes the memleak even heavier, going from potentially ~70 bytes to
> nearly 300 bytes per call...

I don't understand this though. isn't the memory freed when done? Or is
some symbol getting created in the process, or ?

Two things:
* you're using a klass => name hash as the key (instead of [klass, name],
  which would take less memory)
* MethodMutexes grows monotonically since you don't delete the key => mutex
  associations when you're done, so you keep the keys _and_ the mutexes,
  which are pretty heavy

In the first version, the name included #{object_id}, so many values were
possible (as many as different Procs you call to_method on, modulo object_id
recycling). Different symbols and entries in the MethodMutexes hash would
accumulate.

> > begin
> > klass.send(:define_method, name, &self)
> ==========
>
> This will fail if the class was frozen.

Ah, I see if the _klass_ is frozen. But that will fail regardless won't
it? You can;t even include a module (ef InstanceExecHelper) in a frozen
class. Right?

Yes, that's why InstanceExecHelper must be included in Object (and you only
have to do that once).

Here's an improved (hastily written, not thoroughly tested) version:

class Object
  module InstanceExecHelper; end
  include InstanceExecHelper
end

class Proc
  # Creates a local method based on a Proc.
  def to_method(name=nil, recv=nil)
    recv ||= eval("self", self)
    do_remove = false
    begin
      old, Thread.critical = Thread.critical, true
      unless name
        do_remove = true
        n = 0
        n += 1 while recv.respond_to?(name = "__to_method_#{n}")
      end
      me = self
      InstanceExecHelper.module_eval{ define_method(name, &me) }
      return recv.method(name)
    ensure
      if do_remove
        InstanceExecHelper.module_eval{ remove_method(name) rescue nil }
      end
      Thread.critical = old
    end
  end
end

module Kernel
  def instance_exec(*args, &block)
      block.to_method(nil,self).call(*args)
  end
end

class Dummy
  def f
    :dummy_value
  end
end
Dummy.freeze

require 'test/unit'
class TestInstanceEvalWithArgs < Test::Unit::TestCase
  def test_instance_exec
    # Create a block that returns the value of an argument and a value
    # of a method call to +self+.
    block = lambda { |a| [a, f] }

    assert_equal [:arg_value, :dummy_value],
      Dummy.new.instance_exec(:arg_value, &block)
  end

  def test_instance_exec_with_frozen_obj
    block = lambda { |a| [a, f] }

    obj = Dummy.new
    obj.freeze
    assert_equal [:arg_value, :dummy_value],
      obj.instance_exec(:arg_value, &block)
  end

  def test_instance_exec_nested
    i = 0
    obj = Dummy.new
    block = lambda do |arg|
      [arg] + instance_exec(1){|a| [f, a] }
    end

    # the following assertion expanded by the xmp filter automagically from:
    # obj.instance_exec(:arg_value, &block) #=>
    assert_equal([:arg_value, :dummy_value, 1], obj.instance_exec(:arg_value, &block))
  end
end

# >> Loaded suite -
# >> Started
# >> ...
# >> Finished in 0.00091 seconds.
# >>
# >> 3 tests, 3 assertions, 0 failures, 0 errors

···

On Tue, Jul 11, 2006 at 01:21:47AM +0900, transfire@gmail.com wrote:

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

The example you gave does work with my implementation too:

RUBY_VERSION # => "1.8.5"
RUBY_RELEASE_DATE # => "2006-06-24"
class Object
   module InstanceExecHelper; end
   include InstanceExecHelper
   def instance_exec(*args, &block)
     mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"

If instance_exec is called recursively, like in the example,
the mname for the outer method is reused for defining the inner
method. This isn't really a problem, but conceptually not very
"clean"...

Did it work "by accident", or did you really intent to reuse
the name? ;]

InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil

This "rescue nil" might have been an indication of this "bad
design"... ;]

I wonder, why did you use a module for the context, instead of
the good old meta class?

gegroet,
Erik V. - http://www.erikveen.dds.nl/

> I don't understand this though. isn't the memory freed when
> done? Or is some symbol getting created in the process, or
> ?

define_method creates a symbol, beneath the surface:

symbols1 = Symbol.all_symbols
Module.new.instance_eval{define_method("bar"){}}
symbols2 = Symbol.all_symbols
p symbols2-symbols1 # ===> [:bar]

Yes, that's why InstanceExecHelper must be included in Object
(and you only have to do that once).

You should include the Module before Object gets frozen. Who
wants to freeze Object, anyway?... ;]

Thread.critical = old

AFAIK, we need to be in critical mode when determining the
method name. As soon as we know it, we can (and should...)
return to old_critical. At least before we call the
block/method.

module Kernel
   def instance_exec(*args, &block)

Kernel#instance_exec ? Does that make sense?

About $SAFE: It's possible to do an instance_eval up to level
5, whereas instance_exec fails on level 4. Challenge?... ;]

gegroet,
Erik V. - http://www.erikveen.dds.nl/

Mauricio Fernandez wrote:

Here's an improved (hastily written, not thoroughly tested) version:

Okay, I took your draft and worked on it some more and came up with the
following, but there's something very strange....

require 'thread'

class Object
  module TemporaryMethods; end
  include TemporaryMethods
end

class Proc

  # Creates a local method based on a Proc.
  def to_method(name=nil, recv=nil)
    recv ||= eval("self", self)
    klass = name ? recv.class : TemporaryMethods
    begin
      old, Thread.critical = Thread.critical, true
      unless name
        n = 0
        n += 1 while klass.method_defined?(name = "__to_method_#{n}")
        #n += 1 while recv.respond_to?(name = "__to_method_#{n}")
      end
      me = self
      klass.module_eval{ define_method(name, &me) }
      recv.method(name) #if klass == TemporaryMethods
    ensure
      if klass == TemporaryMethods
        klass.module_eval{ remove_method(name) } #rescue nil }
        #klass.module_eval{ undef_method(name) } #rescue nil }
      end
      Thread.critical = old
    end
  end

end

Notice the two remarks on n+=1... and klass.module_eval...., if you
unremark the first one, the one with recv.respond_to? it doesn't alwasy
see that the method has been removed -- I have to idea why that is
since it certainly has been. If you use undef_method instead of
remove_method, it work again though! That really blows my min b/c I
though undef_method didn;t actually remove the method. So I'm really
confused about that. Here's the test I use for the Symbols:

# This is dependent on other tests! Be aware!

    def test_memory
      a = 2
      tproc = proc { |x| x + a }
      100.times {
        tmethod = tproc.to_method
        assert_equal( 3, tmethod.call(1) )
      }
      meths = Symbol.all_symbols.select { |s| s.to_s =~ /^__to_method/
}
      assert_equal( 1, meths.size )
    end

Also is the 'resuce nil' really needed?

T.

P.S. Is there any reason you use module_eval { define_method... rather
then send(:defined_method?...

Okay, criticizing somebody's work without providing a
"solution", isn't nice at all...

So, here's my version...

gegroet,
Erik V. - http://www.erikveen.dds.nl/

PS: I'm still curious about the reason for using a module.

···

----------------------------------------------------------------

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
         @_instance_exec_count_ += 1
         method_name = "_instance_exec_#{@_instance_exec_count_}_"
       ensure
         Thread.critical = false
       end

       begin
         define_method(method_name, &block)

         res = object.send(method_name, *args)
       ensure
         remove_method(method_name) rescue nil
       end
     end

     res
   end
end

----------------------------------------------------------------