Help with UnboundMethod#bind error

Hi gurus and nubys,

I’m having a little problem with unbound methods.
I supposed I could unbound a method from Kernel
and put it in my own module, but it seems’ I’m failing:

this should go in Kernel

def met
p ‘met’+self.to_s
end

m=Kernel.method( :met).unbind
module Mod;end

m.bind(Mod) #failing!
#but M.kind_of?(Kernel.class) #=>true

the error is :
Ruby1:13:in `bind’: singleton method called for a different
object(TypeError)

now: I know that Mod is a different object. Anyway MEthod#bind should
worry just about obj.class, am I wrong ?

Or the problem is that :met is a singleton method ?
If so, why I can’t detach a singleton method ?

Hi,

I’m having a little problem with unbound methods.
I supposed I could unbound a method from Kernel
and put it in my own module, but it seems’ I’m failing:

Although I’m not sure what you really want, try instance_method
instead.

m=Kernel.method( :met).unbind
m=Kernel.instance_method(:met)

now: I know that Mod is a different object. Anyway MEthod#bind should
worry just about obj.class, am I wrong ?

Modules and classes always have metaclasses.

It might be ok to ignore metaclasses have no influence.

Index: eval.c

···

At Mon, 30 Jun 2003 00:31:00 +0900, gabriele renzi wrote:

RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.470
diff -u -2 -p -r1.470 eval.c
— eval.c 28 Jun 2003 03:29:00 -0000 1.470
+++ eval.c 29 Jun 2003 16:34:32 -0000
@@ -7269,4 +7269,8 @@ mnew(klass, obj, id, mklass)
}

  • while (rklass != klass &&
  •  (FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) {
    
  • rklass = RCLASS(rklass)->super;
  • }
    if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass;
    method = Data_Make_Struct(mklass, struct METHOD, bm_mark, free, data);


Nobu Nakada

Although I’m not sure what you really want, try instance_method
instead.

I was wondering of a quick way to decorate a method:

  • unbind the method my_met() from its current object
    (actually, I was thinking about method defined out of class
    definitions, ‘function’-like )
  • put my_met() in a different module
  • define a new my_met() using the old one.

m=Kernel.method( :met).unbind
m=Kernel.instance_method(:met)

well, I just thought the same thing,
I had the thing working in this way:

def met
puts ‘bau’
end
=> nil
m=Object.instance_method(:met)
=> #<UnboundMethod: Object#met>
module M
end
=> nil
m.bind(M)
=> #<Method: Module(Object)#met>

If I try Kernel.instance_method I have a NameError.

now: I know that Mod is a different object. Anyway MEthod#bind should
worry just about obj.class, am I wrong ?

Modules and classes always have metaclasses.

emh… yeah I should have remembered this…

It might be ok to ignore metaclasses have no influence.

cool, that’s the first time that I get a patch just for my own purpose
:slight_smile:

thank you very much

PS
anyway, my idea fails, it would have been to cool if it worked.

If I try to redefine my_met() as a “function” it
gets propagated to MyModule, and I fall in a ‘stack level too deep’
error.

I suppose I need a freeze-like feature to avoid MyModule from
inherithing Kernel for a while… and then inherithing it again…
Ok, I suppose I just need to sleep…

···

il Mon, 30 Jun 2003 01:43:03 +0900, nobu.nokada@softhome.net ha scritto::

Hi,

···

In message “Re: Help with UnboundMethod#bind error” on 03/06/30, nobu.nokada@softhome.net nobu.nokada@softhome.net writes:

It might be ok to ignore metaclasses have no influence.

Check in your change, please.

						matz.

Though I read all messages in this thread, I’m not sure what Nobu’s
patch will change. But since I had some problems re-binding unbound
methods lately I’m interested in this topic. So could someone try to
explain it to me?

Thanks in advance,
Pit

···

On 30 Jun 2003 at 17:18, Yukihiro Matsumoto wrote:

Check in your change, please.

Hi,

Though I read all messages in this thread, I’m not sure what Nobu’s
patch will change.

A Method unbound from an object which has a signleton method
couldn’t be bound to another object which belongs to same
class.

But since I had some problems re-binding unbound
methods lately I’m interested in this topic. So could someone try to
explain it to me?

What problem?

···

At Wed, 2 Jul 2003 16:52:59 +0900, Pit Capitain wrote:


Nobu Nakada

When overriding a method, we normally use alias to save the old
implementation under a new name, so that we can call it later. People
are trying to find obscure names for the aliases to avoid naming
conflicts.

I was trying to find a way to override a method without having to
find a unique name. Instead I wanted to be able to simply call the
old implementation with “super”.

This is a simplified version of what I got (in Ruby 1.8):

class Class
def override( name )
mod = Module.new
mod.send( :define_method, name, instance_method( name ) )
include mod
end
end

As you can see, this creates a module, “copies” the original method
into the module, and finally includes the module. Now you can call
the original implementation via “super”:

class C
def m
puts “original”
end
end

C.new.m # => original

class C
override :m
def m
puts “before(1)”
super
end
end

C.new.m # => before(1), original

So far, so good. But if you do this one more time, you get:

class C
override :m
def m
puts “before(2)”
super
end
end

C.new.m # => before(2), before(1), before(1), …

So it seems that the methods which are moved into the new modules
still “remember” that they originally were defined in class C, and
when they call super they somehow restart the search in the first
ancestor of C, not in the first ancestor of the module they are
currently defined in.

I haven’t had time yet to look further into this, but maybe you know
what’s going on here.

Regards,
Pit

···

On 2 Jul 2003 at 17:14, nobu.nokada@softhome.net wrote:

But since I had some problems re-binding unbound
methods lately I’m interested in this topic. So could someone try to
explain it to me?

What problem?

I was trying to find a way to override a method without having to
find a unique name. Instead I wanted to be able to simply call the
old implementation with "super".

Don't search what you want is called hook ...

svg% cat b.rb
#!./ruby
class C
   def m
      puts "original"
   end
end

puts "====================="
C.new.m
puts "====================="

module M
   def m:before
      puts "before(1)"
   end
end

class C
   include M
end

C.new.m
puts "====================="

class C
   def m:before
      puts "before(2)"
   end
end

C.new.m
puts "====================="
svg%

svg% b.rb

···

=====================
original

before(1)
original

before(2)
before(1)
original

svg%

Guy Decoux

Hi Guy,

yes, I know that you hacked Ruby and that Matz is also working on it,
but for me using the PragProg Ruby installer on Windows nothing of
those I can use right now.

So before I end my search you or Matz would have to release your code
:slight_smile:

Regards,
Pit

···

On 5 Jul 2003 at 20:45, ts wrote:

Don’t search what you want is called hook …

yes, I know that you hacked Ruby and that Matz is also working on it,
but for me using the PragProg Ruby installer on Windows nothing of
those I can use right now.

Write an extension :

svg% cat b.rb
#!/usr/bin/ruby
require 'ovr'

class C
   def m
      puts "original"
   end
end

C.new.m # => original

class C
   override :m
   def m
      puts "before(1)"
      super
   end
end

C.new.m # => before(1), original

class C
   override :m
   def m
      puts "before(2)"
      super
   end
end

C.new.m # => before(2), before(1), before(1), ...
svg%

svg% b.rb
original
before(1)
original
before(2)
before(1)
original
svg%

Guy Decoux

This is the real Guy Decoux we all love and respect!

I know you can do it and maybe I would be able to do so, too, after
spending enough time on it. Thank you for trying to motivate me to
come up with my own solution. But I’m sure this won’t happen. So I’ll
be waiting for Matz’s code. Maybe Nobu will find some time to tell me
why my pure Ruby solution doesn’t work.

Regards,
Pit

···

On 6 Jul 2003 at 21:23, ts wrote:

yes, I know that you hacked Ruby and that Matz is also working on it,
but for me using the PragProg Ruby installer on Windows nothing of
those I can use right now.

Write an extension :

(… demo of Guy’s secret code in action …)

The extension is easy to write (although you’ll have to wait for Guy to
check if my code is a time bomb :-):

override.c:

···

On Sun, Jul 06, 2003 at 11:51:04PM +0900, Pit Capitain wrote:

On 6 Jul 2003 at 21:23, ts wrote:

yes, I know that you hacked Ruby and that Matz is also working on it,
but for me using the PragProg Ruby installer on Windows nothing of
those I can use right now.

Write an extension :

(… demo of Guy’s secret code in action …)

This is the real Guy Decoux we all love and respect!

I know you can do it and maybe I would be able to do so, too, after
spending enough time on it. Thank you for trying to motivate me to
come up with my own solution. But I’m sure this won’t happen. So I’ll
be waiting for Matz’s code. Maybe Nobu will find some time to tell me
why my pure Ruby solution doesn’t work.

===================
#include <ruby.h>
#include <st.h>
#include <node.h>

static
VALUE
class_override(VALUE self, VALUE symbols)
{
int len;
int i;
VALUE meth;
VALUE name;
st_data_t data;

NEWOBJ(proxy, struct RClass);
OBJSETUP(proxy, rb_cClass, T_ICLASS);

len = RARRAY(symbols)->len;

proxy->iv_tbl = st_init_numtable(); /* not needed? */
proxy->m_tbl = st_init_numtable();
proxy->super = RCLASS(self)->super;

RBASIC(proxy)->klass = RBASIC(self)->klass;

for(i = 0; i < len; i++) {
meth = rb_ary_entry(symbols, i);
name = rb_funcall(meth, rb_intern(“to_s”), 0);
if(!st_lookup(RCLASS(self)->m_tbl, rb_intern(RSTRING(name)->ptr), &data))
continue; /* should do something else?? */
st_insert(proxy->m_tbl, rb_intern(RSTRING(name)->ptr), data);
}

RCLASS(self)->super = proxy;
OBJ_INFECT(proxy, self);

return self;
}

void
Init_override()
{
rb_define_method(rb_cClass, “override”, class_override, -2);
}

extconf.rb:

require ‘mkmf’
create_makefile(“override”)

And then…

batsman@tux-chan:~/src/override$ expand -t2 b.rb
#!/usr/bin/ruby
require ‘override’

class C
def m
puts “original”
end
end

C.new.m # => original

class C
override :m
def m
puts “before(1)”
super
end
end

C.new.m # => before(1), original

class C
override :m
def m
puts “before(2)”
super
end
end

C.new.m # => before(2), before(1), original
batsman@tux-chan:~/src/override$ ruby b.rb
original
b.rb:14: warning: method redefined; discarding old m
before(1)
original
b.rb:24: warning: method redefined; discarding old m
before(2)
before(1)
original


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Anyone want the new supermount? :slight_smile:
whats new aboutit
klogd: It cleans whiter than white. :slight_smile:
– Seen on #Linux

Quick fix for the warnings attached:

batsman@tux-chan:~/src/override$ expand -t2 b.rb
#!/usr/bin/ruby
require ‘override’

class C
def m
puts “original”
end
end

C.new.m # => original

puts “=” * 20
class C
override :m
def m
puts “before(1)”
super
puts “after(1)”
end
end

C.new.m # => before(1), original, after(1)

puts “=” * 20
class C
override :m
def m
puts “before(2)”
super
puts “after(2)”
end
end

C.new.m # => before(2), before(1), original, after(1), after(2)
batsman@tux-chan:~/src/override$ ruby b.rb
original

override.c (974 Bytes)

···

On Mon, Jul 07, 2003 at 02:03:42AM +0900, Mauricio Fernández wrote:

On Sun, Jul 06, 2003 at 11:51:04PM +0900, Pit Capitain wrote:

On 6 Jul 2003 at 21:23, ts wrote:

yes, I know that you hacked Ruby and that Matz is also working on it,
but for me using the PragProg Ruby installer on Windows nothing of
those I can use right now.

Write an extension :

(… demo of Guy’s secret code in action …)

This is the real Guy Decoux we all love and respect!

I know you can do it and maybe I would be able to do so, too, after
spending enough time on it. Thank you for trying to motivate me to
come up with my own solution. But I’m sure this won’t happen. So I’ll
be waiting for Matz’s code. Maybe Nobu will find some time to tell me
why my pure Ruby solution doesn’t work.

The extension is easy to write (although you’ll have to wait for Guy to
check if my code is a time bomb :-):

====================
before(1)
original
after(1)

before(2)
before(1)
original
after(1)
after(2)


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

No, that’s wrong too. Now there’s a race condition between the rm and
the mv. Hmm, I need more coffee.
– Guy Maor on Debian Bug#25228

The extension is easy to write (although you'll have to wait for Guy to
check if my code is a time bomb :-):

Well, I've sent in a private email the extension to "Pit Capitain".

For me it has some problems :

  1) you must know where a method is defined when you call ::override

  2) it work actually for Class and not Module, it's easy to change it but
     you'll have the same problem than in [ruby-talk:72510]

Imagine that you want to intercept the method #each for all Enumerable :
instinctively you write

   module Enumerable
      overrive :each
      def each
         puts "before each"
         super
      end
   end

Then you write

   [1, 2].each {|i| p i}

and you'll see that it don't work because Array has defined #each

You don't have these problems the way that matz do it, because you just
write

svg% cat b.rb
#!./ruby
module Enumerable
   def each:before
      puts "before each"
   end
end

[1, 2].each {|i| p i }
{"a" => 1, "b" => 2}.each {|*i| p i }
(1..2).each {|i| p i }
svg%

svg% b.rb
before each
1
2
before each
["a", 1]
["b", 2]
before each
1
2
svg%

You just need to know the relation that it exist between classes (or
classes and modules) and you have this information. Rather than know where
a method is defined (information that you don't have fatally).

Guy Decoux

Hi,

rb_to_id() will help.

···

In message “Re: Help with UnboundMethod#bind error” on 03/07/07, Mauricio Fernández batsman.geo@yahoo.com writes:

ID name;

for(i = 0; i < len; i++) {
name = rb_to_id(rb_ary_entry(symbols, i));
if(!st_lookup(RCLASS(self)->m_tbl, name, &data))
continue; /* should do something else?? */
st_insert(proxy->m_tbl, name, data);

matz.

Thanks.

Is otherwise the code correct? I see two possible problems, but I’m not
sure about them:

  • I believe just copying the NODE* is OK, but rb_alias makes a new one
    NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex)
    NODEs are GCed like any object so just copying should be
    safe, but I’m not really sure
  • is rb_clear_cache_by_name necessary after adding the proxy class?
···

On Mon, Jul 07, 2003 at 07:43:28AM +0900, Yukihiro Matsumoto wrote:

Hi,

rb_to_id() will help.

In message “Re: Help with UnboundMethod#bind error” > on 03/07/07, Mauricio Fernández batsman.geo@yahoo.com writes:

ID name;

for(i = 0; i < len; i++) {
name = rb_to_id(rb_ary_entry(symbols, i));
if(!st_lookup(RCLASS(self)->m_tbl, name, &data))
continue; /* should do something else?? */
st_insert(proxy->m_tbl, name, data);


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

And Bruce is effectively building BruceIX
– Alan Cox