--Multipart_Sat_Mar__2_06:38:05_2002-1
Content-Type: text/plain; charset=ISO-2022-JP

GUI toolkitのような、大きくてかつ一部しか使わないことが多いものを
モジュールにする場合を考えると、なるべくautoloadを残して頂ける方が
よいと思います。

> |>ということで、ほんとはautoloadはなくしたいです。Riteではなく
> |>なるかも。
> |
> |げ、なのかあ。しかし、autoload が require したファイルには
> |多分求める定数の定義がれているので、定数に関しては2度
> |と fallback は呼ばれないので、なに速度は変わらない気がする
> |んだけど、でもないのかな。
> 
> 定数呼び靴里燭咾某謄ラスに聞きに行く前え台瘡赳痺襪梁減澆
> チェックしに行かないといけないような気がします。が馬鹿に
> できないコストのような。

fallbackをチェックしにいく代わりに、
本物のオブジェクトの代わりに autoload することを示すオブジェクトを
代入しておき、const_get でが討たえ 癜闌閨 するのでは
どうでしょうか。

とっくに考えられてい、とも思ったのですが、
とりあえずい討澆泙靴拭ご笑覧下さい;

癜闌閨 犀關酪筱 ♯關迴筮鰲や
module TopMod
  autoload :SubMod, "topmod/submod.rb"	# for TopMod::SubMod
end
が茲泙后

以下、
 - サンプルスクリプト
 - 1.6.6からの差分
を添えます。

--
MOROHOSHI Akihiko


--Multipart_Sat_Mar__2_06:38:05_2002-1
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="altest.rb"
Content-Transfer-Encoding: 7bit

ConstA  
p ConstA			# 1

module ModB
end
p ModB				# ModB

module Foo
    autoload :Bar, "foo_bar.rb"
end

p Foo.const_defined? :Bar	# true
p Foo::Bar			# ./foo_bar.rb is loaded.
				# Foo::Bar
p Foo::Bar::A			# 1

begin
    p Bar::A			# (NameError)
rescue NameError e
    puts "Bar::A not found: #{e} (#{e.class})"
    puts "OK, let's continue...."
end

autoload :Bar, "bar.rb"
p Object.const_defined? :Bar	# true
p Bar::A			# ./bar.rb is loaded.
				# 2

--Multipart_Sat_Mar__2_06:38:05_2002-1
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="foo_bar.rb"
Content-Transfer-Encoding: 7bit

module Foo
    class Bar
	A  
    end
end

puts "#{__FILE__} is loaded."

--Multipart_Sat_Mar__2_06:38:05_2002-1
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="bar.rb"
Content-Transfer-Encoding: 7bit

class Bar
    A  
end

puts "#{__FILE__} is loaded."

--Multipart_Sat_Mar__2_06:38:05_2002-1
Content-Type: application/octet-stream; type=patch
Content-Disposition: attachment; filename="ruby-1.6.6-autoload.patch"
Content-Transfer-Encoding: 7bit

diff -ruN --exclude ext --exclude config* --exclude *.rb --exclude Makefile --exclude *~ --exclude variable.c.* ruby-1.6.6.orig/eval.c ruby-1.6.6/eval.c
--- ruby-1.6.6.orig/eval.c	Fri Dec 21 18:19:47 2001
+++ ruby-1.6.6/eval.c	Sat Mar  2 05:18:26 2002
@@ -3072,9 +3072,6 @@
 	    }
 
 	    klass  ;
-	    if ((ruby_class rb_cObject) && rb_autoload_defined(node->nd_cname)) {
-		rb_autoload_load(node->nd_cname);
-	    }
 	    if (rb_const_defined_at(ruby_class, node->nd_cname)) {
 		klass  b_const_get(ruby_class, node->nd_cname);
 	    }
@@ -3118,9 +3115,6 @@
 		rb_raise(rb_eTypeError, "no outer class/module");
 	    }
 	    module  ;
-	    if ((ruby_class rb_cObject) && rb_autoload_defined(node->nd_cname)) {
-		rb_autoload_load(node->nd_cname);
-	    }
 	    if (rb_const_defined_at(ruby_class, node->nd_cname)) {
 		module  b_const_get(ruby_class, node->nd_cname);
 	    }
@@ -6025,8 +6019,6 @@
 #endif
 }
 
-VALUE rb_f_autoload();
-
 void
 Init_load()
 {
@@ -6040,7 +6032,6 @@
 
     rb_define_global_function("load", rb_f_load, -1);
     rb_define_global_function("require", rb_f_require, 1);
-    rb_define_global_function("autoload", rb_f_autoload, 2);
     rb_global_variable(&ruby_wrapper);
 
     ruby_dln_librefs  b_ary_new();
diff -ruN --exclude ext --exclude config* --exclude *.rb --exclude Makefile --exclude *~ --exclude variable.c.* ruby-1.6.6.orig/inits.c ruby-1.6.6/inits.c
--- ruby-1.6.6.orig/inits.c	Wed Mar 21 17:04:11 2001
+++ ruby-1.6.6/inits.c	Sat Mar  2 03:25:36 2002
@@ -13,6 +13,8 @@
 #include "ruby.h"
 
 void Init_Array _((void));
+void Init_autoload_1 _((void));
+void Init_autoload_2 _((void));
 void Init_Bignum _((void));
 void Init_Comparable _((void));
 void Init_Dir _((void));
@@ -50,6 +52,7 @@
     Init_sym();
     Init_var_tables();
     Init_Object();
+    Init_autoload_1();
     Init_Comparable();
     Init_Enumerable();
     Init_Precision();
@@ -72,6 +75,7 @@
     Init_signal();
     Init_process();
     Init_load();
+    Init_autoload_2();
     Init_Proc();
     Init_Math();
     Init_GC();
diff -ruN --exclude ext --exclude config* --exclude *.rb --exclude Makefile --exclude *~ --exclude variable.c.* ruby-1.6.6.orig/intern.h ruby-1.6.6/intern.h
--- ruby-1.6.6.orig/intern.h	Fri Dec 21 18:19:47 2001
+++ ruby-1.6.6/intern.h	Sat Mar  2 05:34:47 2002
@@ -352,8 +352,6 @@
 void rb_set_class_path _((VALUE, VALUE, const char*));
 VALUE rb_path2class _((const char*));
 void rb_name_class _((VALUE, ID));
-void rb_autoload _((const char*, const char*));
-VALUE rb_f_autoload _((VALUE, VALUE, VALUE));
 void rb_gc_mark_global_tbl _((void));
 VALUE rb_f_trace_var _((int, VALUE*));
 VALUE rb_f_untrace_var _((int, VALUE*));
@@ -374,14 +372,12 @@
 VALUE rb_mod_const_of _((VALUE, VALUE));
 VALUE rb_mod_remove_const _((VALUE, VALUE));
 int rb_const_defined_at _((VALUE, ID));
-int rb_autoload_defined _((ID));
 int rb_const_defined _((VALUE, ID));
 VALUE rb_const_get _((VALUE, ID));
 VALUE rb_const_get_at _((VALUE, ID));
 void rb_const_set _((VALUE, ID, VALUE));
 void rb_const_assign _((VALUE, ID, VALUE));
 VALUE rb_mod_constants _((VALUE));
-void rb_autoload_load _((ID));
 void rb_cvar_declare _((VALUE, ID, VALUE));
 VALUE rb_cvar_defined _((VALUE, ID));
 void rb_cvar_set _((VALUE, ID, VALUE));
diff -ruN --exclude ext --exclude config* --exclude *.rb --exclude Makefile --exclude *~ --exclude variable.c.* ruby-1.6.6.orig/variable.c ruby-1.6.6/variable.c
--- ruby-1.6.6.orig/variable.c	Fri Dec 21 18:20:54 2001
+++ ruby-1.6.6/variable.c	Sat Mar  2 06:10:21 2002
@@ -242,40 +242,6 @@
     rb_iv_set(klass, "__classid__", ID2SYM(id));
 }
 
-static st_table *autoload_tbl  ;
-
-static void
-rb_autoload_id(id, filename)
-    ID id;
-    const char *filename;
-{
-    rb_secure(4);
-    if (!rb_is_const_id(id)) {
-	rb_raise(rb_eNameError, "autoload must be constant name",
-		 rb_id2name(id));
-    }
-
-    if (!autoload_tbl) {
-	autoload_tbl  t_init_numtable();
-    }
-    st_insert(autoload_tbl, id, strdup(filename));
-}
-
-void
-rb_autoload(klass, filename)
-    const char *klass, *filename;
-{
-    rb_autoload_id(rb_intern(klass), filename);
-}
-
-VALUE
-rb_f_autoload(obj, klass, file)
-    VALUE obj, klass, file;
-{
-    rb_autoload_id(rb_to_id(klass), STR2CSTR(file));
-    return Qnil;
-}
-
 char *
 rb_class2name(klass)
     VALUE klass;
@@ -1029,6 +995,117 @@
     return val;
 }
 
+static VALUE autoload_tbl  ;
+static VALUE autoload_target  ;
+#define AUTOLOAD_TARGET		autoload_target
+#define IS_AUTOLOAD_TARGET(obj)	((obj)
utoload_target)
+#define AUTOLOAD_KEY_NEW(klass,id)	rb_ary_new3(2,klass,ID2SYM(id))
+
+static void
+autoload_add(VALUE klass, ID id, VALUE file) {
+    VALUE key;
+
+    rb_secure(4);
+    Check_SafeStr(file);
+    if (!rb_is_const_id(id)) {
+	rb_raise(rb_eNameError, "autoload must be constant name",
+		 rb_id2name(id));
+    }
+    
+    key  UTOLOAD_KEY_NEW(klass, id);
+    rb_hash_aset(autoload_tbl, key, file);
+}
+
+static VALUE
+rb_mod_autoload(VALUE mod, VALUE sym, VALUE file) {
+    ID id  b_to_id(sym);
+
+    if (rb_const_defined_at(mod, id))
+	return Qnil;
+
+    rb_const_set(mod, id, AUTOLOAD_TARGET);
+    autoload_add(mod, id, file);
+    
+    return Qnil;
+}
+
+static VALUE
+rb_f_autoload(VALUE obj, VALUE sym, VALUE file) {
+    ID id  b_to_id(sym);
+
+    /* I use ruby_class as obj as same as NODE_CDECL,
+     * assuming autoload is another representation of rb_const_set.
+     */
+    obj  uby_class;
+
+    if (rb_const_defined_at(obj, id))
+	return Qnil;
+
+    rb_const_set(obj, id, AUTOLOAD_TARGET);
+    autoload_add(obj, id, file);
+    
+    return Qnil;
+}
+
+static void
+autoload_delete(VALUE klass, VALUE id) {
+    VALUE key;
+    key  UTOLOAD_KEY_NEW(klass, id);
+    rb_funcall(autoload_tbl, rb_intern("delete"), 1, key);
+}
+
+static void
+autoload_load(VALUE klass, ID id) {
+    VALUE key, file;
+    
+    if (RCLASS(klass)->iv_tbl) {
+	VALUE value;
+	st_delete(ROBJECT(klass)->iv_tbl, &id, &value);
+	if (! IS_AUTOLOAD_TARGET(value))
+	    rb_bug("autoload_load: removed normal constant: %s::%s",
+		   rb_class2name(klass), rb_id2name(id));
+    } else {
+	rb_bug("autoload_load: AUTOLOAD_TARGET not found: %s::%s",
+	       rb_class2name(klass), rb_id2name(id));
+    }
+	
+    key  UTOLOAD_KEY_NEW(klass, id);
+    file  b_funcall(autoload_tbl, rb_intern("delete"), 1, key);
+
+    if (NIL_P(file)) {
+	rb_bug("autoload file not found for %s::%s",
+	       rb_class2name(klass), rb_id2name(id));
+    }
+
+    if (rb_provided(RSTRING(file)->ptr))
+	return;
+
+    FL_UNSET(file, FL_TAINT);
+    rb_f_require(Qnil, file);
+}
+
+static VALUE
+rb_f_autoload_p(VALUE self, VALUE mod, VALUE sym) {
+    ID id  b_to_id(sym);
+    return NIL_P(rb_hash_aref(autoload_tbl,AUTOLOAD_KEY_NEW(mod,id))) ?
+	Qfalse : Qtrue;
+}
+
+void
+Init_autoload_1() {
+    autoload_target  b_obj_alloc(rb_cObject);
+}
+
+void
+Init_autoload_2() {
+    autoload_tbl  b_hash_new();
+    rb_global_variable(&autoload_tbl);
+
+    rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
+    rb_define_global_function("autoload", rb_f_autoload, 2);
+    rb_define_global_function("autoload?", rb_f_autoload_p, 2);
+}
+
 static int
 top_const_get(id, klassp)
     ID id;
@@ -1039,12 +1116,6 @@
     /* pre-defined class */
     if (st_lookup(rb_class_tbl, id, klassp)) return Qtrue;
 
-    /* autoload */
-    if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) {
-	rb_autoload_load(id);
-	*klassp  b_const_get(rb_cObject, id);
-	return Qtrue;
-    }
     return Qfalse;
 }
 
@@ -1055,7 +1126,12 @@
 {
     VALUE value;
 
+retry:
     if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
+	if (IS_AUTOLOAD_TARGET(value)) {
+	    autoload_load(klass, id);
+	    goto retry;
+	}
 	return value;
     }
     if (klass rb_cObject && top_const_get(id, &value)) {
@@ -1067,22 +1143,24 @@
     return Qnil;		/* not reached */
 }
 
-void
-rb_autoload_load(id)
-    ID id;
-{
-    char *modname;
-    VALUE module;
-
-    st_delete(autoload_tbl, &id, &modname);
-    if (rb_provided(modname)) {
-	free(modname);
-	return;
-    }
-    module  b_str_new2(modname);
-    free(modname);
-    FL_UNSET(module, FL_TAINT);
-    rb_f_require(Qnil, module);
+/* for debugging purpose. */
+static char buf[1024];
+const char *
+print_class_id(VALUE klass, VALUE id) {
+    const char *ptr  ULL;
+    
+    buf[0]  \0';
+    if (RTEST(rb_funcall(klass, rb_intern("kind_of?"), 1, rb_cModule))) {
+	strcpy(buf, rb_class2name(klass));
+    } else {
+	strcpy(buf, "??");
+    }
+    ptr  b_id2name(id);
+    if (ptr)
+	strcat(buf, ptr);
+    else
+	strcat(buf, "(NULL)");
+    return buf;
 }
 
 VALUE
@@ -1097,6 +1175,10 @@
   retry:
     while (tmp) {
 	if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
+	    if (IS_AUTOLOAD_TARGET(value)) {
+		autoload_load(tmp,id);
+		goto retry;
+	    }
 	    return value;
 	}
 	if (tmp rb_cObject && top_const_get(id, &value)) return value;
@@ -1125,6 +1207,7 @@
     VALUE value;
     VALUE ary;
 {
+    /* autoload consideration: include. */
     if (rb_is_const_id(key)) {
 	VALUE kval  b_str_new2(rb_id2name(key));
 	if (!rb_ary_includes(ary, kval)) {
@@ -1149,7 +1232,14 @@
     if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
 
     if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, &id, &val)) {
-	return val;
+	if (IS_AUTOLOAD_TARGET(val)) {
+	    /* cancel autoload and go through.
+	     *
+	     * XXX - should we do autoload and retry?
+	     */
+	} else {
+	    return val;
+	}
     }
     if (rb_const_defined_at(mod, id)) {
 	rb_raise(rb_eNameError, "cannot remove %s::%s", 
@@ -1160,19 +1250,6 @@
     return Qnil;		/* not reached */
 }
 
-static int
-autoload_i(key, name, ary)
-    ID key;
-    const char *name;
-    VALUE ary;
-{
-    VALUE kval  b_str_new2(rb_id2name(key));
-    if (!rb_ary_includes(ary, kval)) {
-	rb_ary_push(ary, kval);
-    }
-    return ST_CONTINUE;
-}
-
 VALUE
 rb_mod_const_at(mod, ary)
     VALUE mod, ary;
@@ -1182,9 +1259,6 @@
     }
     if ((VALUE)mod rb_cObject) {
 	st_foreach(rb_class_tbl, sv_i, ary);
-	if (autoload_tbl) {
-	    st_foreach(autoload_tbl, autoload_i, ary);
-	}
     }
     return ary;
 }
@@ -1214,6 +1288,7 @@
     VALUE klass;
     ID id;
 {
+    /* autoload consideration: include. */
     if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, 0)) {
 	return Qtrue;
     }
@@ -1224,21 +1299,13 @@
 }
 
 int
-rb_autoload_defined(id)
-    ID id;
-{
-    if (autoload_tbl && st_lookup(autoload_tbl, id, 0))
-	return Qtrue;
-    return Qfalse;
-}
-
-int
 rb_const_defined(klass, id)
     VALUE klass;
     ID id;
 {
     VALUE tmp  lass;
 
+    /* autoload consideration: include. */
     while (tmp) {
 	if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) {
 	    return Qtrue;
@@ -1250,7 +1317,7 @@
     }
     if (st_lookup(rb_class_tbl, id, 0))
 	return Qtrue;
-    return rb_autoload_defined(id);
+    return Qfalse;
 }
 
 static void
@@ -1269,8 +1336,12 @@
 	RCLASS(klass)->iv_tbl  t_init_numtable();
     }
     else if (isconst) {
-	if (st_lookup(RCLASS(klass)->iv_tbl, id, 0) ||
-	    (klass rb_cObject && st_lookup(rb_class_tbl, id, 0))) {
+	VALUE value;
+	if (st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
+	    if (IS_AUTOLOAD_TARGET(value))
+		autoload_delete(klass, id);
+	    rb_warn("already initialized %s %s", dest, rb_id2name(id));
+	} else if (klass rb_cObject && st_lookup(rb_class_tbl, id, 0)) {
 	    rb_warn("already initialized %s %s", dest, rb_id2name(id));
 	}
     }
@@ -1295,8 +1366,14 @@
 {
     VALUE tmp  lass;
     
+retry:
     while (tmp) {
-	if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) {
+	VALUE value;
+	if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
+	    if (IS_AUTOLOAD_TARGET(value)) {
+		autoload_load(tmp,id);
+		goto retry;
+	    }
 	    st_insert(RCLASS(tmp)->iv_tbl, id, val);
 	    return;
 	}
@@ -1305,16 +1382,6 @@
     /* pre-defined class */
     if (st_lookup(rb_class_tbl, id, 0)) {
 	st_delete(rb_class_tbl, id, 0);
-	st_insert(RCLASS(rb_cObject)->iv_tbl, id, val);
-	return;
-    }
-
-    /* autoload */
-    if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) {
-	char *modname;
-
-	st_delete(autoload_tbl, &id, &modname);
-	free(modname);
 	st_insert(RCLASS(rb_cObject)->iv_tbl, id, val);
 	return;
     }

--Multipart_Sat_Mar__2_06:38:05_2002-1--