[#950] ruby 1.1b0 released — matz@... (Yukihiro Matsumoto)

まつもと ゆきひろです

33 messages 1997/12/05

[#998] ruby 1.1b1 released — matz@... (Yukihiro Matsumoto)

まつもと ゆきひろです

48 messages 1997/12/09
[#1011] Re: ruby 1.1b1 released — Kazuhisa Yanagawa <katze@...> 1997/12/10

in message-id: <199712090833.RAA31727@picachu.netlab.co.jp>

[#1013] Re: ruby 1.1b1 released — matz@... (Yukihiro Matsumoto) 1997/12/10

まつもと ゆきひろです

[#1028] Regexp#operators (Re: ruby 1.1b1 released) — Shin-ichiro HARA <sinara@...> 1997/12/10

原です。

[#1030] Re: Regexp#operators (Re: ruby 1.1b1 released) — matz@... (Yukihiro Matsumoto) 1997/12/10

まつもと ゆきひろです

[#1033] Re: Regexp#operators (Re: ruby 1.1b1 released) — Shin-ichiro HARA <sinara@...> 1997/12/10

原です。

[#1049] Re: Regexp#operators (Re: ruby 1.1b1 released) — Shin-ichiro HARA <sinara@...> 1997/12/11

原です。

[#1064] Re: Regexp#operators (Re: ruby 1.1b1 released) — matz@... (Yukihiro Matsumoto) 1997/12/12

まつもと ゆきひろです

[#1097] Re: Regexp#operators (Re: ruby 1.1b1 released) — Shin-ichiro HARA <sinara@...> 1997/12/15

原です。

[#1002] Object#bind — shugo@... (Shugo Maeda)

前田です。

39 messages 1997/12/09
[#1008] Re: Object#bind — matz@... (Yukihiro Matsumoto) 1997/12/10

まつもと ゆきひろです

[#1023] Re: Object#bind — shugo@... (Shugo Maeda) 1997/12/10

前田です。

[#1026] Re: Object#bind — matz@... (Yukihiro Matsumoto) 1997/12/10

まつもと ゆきひろです

[#1044] Re: Object#bind — keiju@... (石塚圭樹 ) 1997/12/11

けいじゅ@日本ラショナルソフトウェアです.

[#1051] Re: Object#bind — shugo@... (Shugo Maeda) 1997/12/11

前田です。

[#1063] Re: Object#bind — matz@... (Yukihiro Matsumoto) 1997/12/12

まつもと ゆきひろです

[#1079] Re: Object#bind — keiju@... (石塚圭樹 ) 1997/12/14

けいじゅ@日本ラショナルソフトウェアです.

[#1084] Re: Object#bind — matz@... (Yukihiro Matsumoto) 1997/12/15

まつもと ゆきひろです

[#1087] Re: Object#bind — keiju@... (石塚圭樹 ) 1997/12/15

けいじゅ@日本ラショナルソフトウェアです.

[#1088] Re: Object#bind — matz@... (Yukihiro Matsumoto) 1997/12/15

まつもと ゆきひろです

[#1085] [Req] object refference — keiju@... (Keiju ISHITSUKA)

けいじゅ@日本ラショナルソフトウェアです.

12 messages 1997/12/15

[ruby-dev:1002] Object#bind

From: shugo@... (Shugo Maeda)
Date: 1997-12-09 17:04:13 UTC
List: ruby-dev #1002
前田です。

ちょっと前にメソッドのオブジェクト化の話がありましたが,
レシーバと結合されたメソッドを,

obj.bind(:foo)

で取り出せるようにするのはどうでしょう。
試しにちょっと実装してみたのでメールの末尾に添付します。

前に例に出た

def function(func)
  proc { |*x| send(func, *x) }
end

と違って,

rbc0> def foo
rbc1>   puts "foo"
rbc1> end
nil
rbc0> foo
foo
nil
rbc0> $foo = bind(:foo)
#<BoundMethod:0x400f6038>
rbc0> def foo
rbc1>   puts "overriden"
rbc1> end
nil
rbc0> foo
overriden
nil
rbc0> $foo.call
foo
nil

のようにメソッドがオーバーライドされても,bindした時点での
メソッド定義が保存されるので,多少は意味があるような気がします。

# ちなみにbindという名前はちょっとbindingと紛らわしいような気もし
# ますが,Satherのbindから連想しました。

unbound methodも同様に取り出せそうですが,考えないといけない問題が
多そうですね。

-- 
前田 修吾

Attachments (1)

eval.c.diff (4.05 KB, text/x-diff)
--- eval.c.orig	Tue Dec  9 23:51:49 1997
+++ eval.c	Wed Dec 10 01:53:12 1997
@@ -484,6 +484,7 @@
 static NODE *compile();
 
 static VALUE rb_call();
+static VALUE rb_call0();
 VALUE rb_apply();
 VALUE rb_funcall2();
 
@@ -2929,14 +2930,11 @@
     VALUE *argv;		/* OK */
     int scope;
 {
-    NODE *body, *b2;		/* OK */
+    NODE *body;
     int    noex;
     ID     id = mid;
     struct cache_entry *ent;
-    volatile VALUE result = Qnil;
-    int itr;
     enum node_type type;
-    static int tick;
 
   again:
     /* is it in the method cache? */
@@ -2955,16 +2953,6 @@
     if (noex == NOEX_PRIVATE && scope == 0)
 	return rb_undefined(recv, mid, argc, argv, CSTAT_NOEX);
 
-    switch (the_iter->iter) {
-      case ITER_PRE:
-	itr = ITER_CUR;
-	break;
-      case ITER_CUR:
-      default:
-	itr = ITER_NOT;
-	break;
-    }
-
     type = nd_type(body);
     if (type == NODE_ZSUPER) {
 	/* for re-scoped/renamed method */
@@ -2987,6 +2975,34 @@
 	goto again;
     }
 
+    return rb_call0(class, recv, mid, id, argc, argv, scope, body, type);
+}
+
+static VALUE
+rb_call0(class, recv, mid, id, argc, argv, scope, body, type)
+    VALUE class, recv;
+    ID    mid, id;
+    int argc;			/* OK */
+    VALUE *argv;		/* OK */
+    int scope;
+    NODE *body;
+    enum node_type type;
+{
+    NODE *b2;		/* OK */
+    volatile VALUE result = Qnil;
+    int itr;
+    static int tick;
+
+    switch (the_iter->iter) {
+      case ITER_PRE:
+	itr = ITER_CUR;
+	break;
+      case ITER_CUR:
+      default:
+	itr = ITER_NOT;
+	break;
+    }
+
     if ((++tick & 0xfff) == 0 && stack_length() > STACK_LEVEL_MAX)
 	Fatal("stack level too deep");
 
@@ -4359,6 +4375,94 @@
     return result;
 }
 
+VALUE cBoundMethod;
+struct BOUND_METHOD {
+    VALUE class;
+    VALUE recv;
+    ID id;
+    NODE *body;
+};
+
+static void bm_mark(struct BOUND_METHOD *data)
+{
+    gc_mark(data->class);
+    gc_mark(data->recv);
+    gc_mark(data->body);
+}
+
+static VALUE obj_bind(VALUE obj, VALUE vid)
+{
+    VALUE method;
+    VALUE class = CLASS_OF(obj);
+    ID mid, id;
+    NODE *body;
+    int noex;
+    struct cache_entry *ent;
+    enum node_type type;
+    struct BOUND_METHOD *data;
+
+    if (TYPE(vid) == T_STRING) {
+	mid = rb_intern(RSTRING(vid)->ptr);
+    }
+    else {
+	mid = NUM2INT(vid);
+    }
+    id = mid;
+
+  again:
+    /* is it in the method cache? */
+    ent = cache + EXPR1(class, mid);
+    if (ent->mid == mid && ent->class == class) {
+	class = ent->origin;
+	id    = ent->mid0;
+	body  = ent->method;
+    }
+    else if ((body = rb_get_method_body(&class, &id, &noex)) == 0) {
+	return rb_undefined(obj, mid, 0, 0, 0);
+    }
+
+    type = nd_type(body);
+    if (type == NODE_ZSUPER) {
+	/* for re-scoped/renamed method */
+	mid = id;
+	if (RCLASS(class)->super == 0) {
+	    /* origin is the Module, so need to scan superclass hierarchy. */
+	    struct RClass *cl = RCLASS(class);
+
+	    class = RBASIC(obj)->class;
+	    while (class) {
+		if (RCLASS(class)->m_tbl == cl->m_tbl)
+		    break;
+		class = RCLASS(class)->super;
+	    }
+	}
+	else {
+	    class = RCLASS(class)->super;
+	}
+	goto again;
+    }
+
+    method = Data_Make_Struct(cBoundMethod, struct BOUND_METHOD,
+			      bm_mark, 0, data);
+    data->class = class;
+    data->recv = obj;
+    data->id = id;
+    data->body = body;
+
+    return method;
+}
+
+static VALUE bmethod_call(int argc, VALUE *argv, VALUE method)
+{
+    struct BOUND_METHOD *data;
+    enum node_type type;
+
+    Data_Get_Struct(method, struct BOUND_METHOD, data);
+    type = nd_type(data->body);
+    return rb_call0(data->class, data->recv, data->id, data->id,
+		    argc, argv, 1, data->body, type);
+}
+
 void
 Init_Proc()
 {
@@ -4371,6 +4475,11 @@
     rb_define_global_function("proc", f_lambda, 0);
     rb_define_global_function("lambda", f_lambda, 0);
     rb_define_global_function("binding", f_binding, 0);
+
+    cBoundMethod = rb_define_class("BoundMethod", cObject);
+    rb_undef_method(CLASS_OF(cBoundMethod), "new");
+    rb_define_method(cBoundMethod, "call", bmethod_call, -1);
+    rb_define_method(mKernel, "bind", obj_bind, 1);
 }
 
 #ifdef THREAD

In This Thread

Prev Next