$SAFE=4$B$N>l9g$N(BReadline::HISTORY.each

knu e$B$5$s$Xe(B

e$B9bHx9(<#$G$9!#e(B

knu e$B$5$s$,e(B r16125 e$B$K$F!"e(B
Readline::HISTORY.each e$B%a%=%C%I$r%V%m%C%/$J$7$G8F$S=P$7$?$H$-$K!"e(B
Enumerable::Enumerator e$B$rJV$9$h$&$K=$@5$5$l$?$HG’<1$7$F$$$^$9!#e(B
e$B$=$N=$@5$Ge(B $SAFE e$B$,e(B 4 e$B$N>l9g$G$b!"e(B
each e$B%a%=%C%I$r8F$S=P$9$3$H$,$G$-$k$h$&$K$J$j$^$7$?!#e(B
e$B$?$V$s!"e(B$SAFE e$B$,e(B 4 e$B$N>l9g$O!“e(B
each e$B%a%=%C%I$r8F$S=P$7$?;~E@$GNc30e(B SecurityError e$B$,e(B
e$BH/@8$7$?$[$&$,$h$$$N$G$O$J$$$+$H;W$$!”%Q%C%A$r:n@.$7$^$7$?!#e(B
knu e$B$5$s$K=$@5FbMF$r3NG’$$$?$@$-!“e(B
e$BLdBj$,$J$$$h$&$G$”$l$P%3%_%C%H$7$?$$$H9M$($F$$$^$9!#e(B
e$B$$$+$,$G$7$g$&$+!#e(B

e$B$J$*!"8=:!"e(B$SAFE e$B$,e(B 4 e$B$N>l9g$Ke(B
each e$B%a%=%C%I$r%V%m%C%/$J$7$G8F$S=P$9$3$H$O$G$-$^$9$,!"e(B
e$BJV$jCM$Ne(B Enumerable::Enumerator
e$B$KBP$7$F%a%=%C%I8F$S=P$7$r$9$k$H!"e(B
e$BNc30e(B SecurityError e$B$,H/@8$7$^$9!#e(B
e$B$3$N$?$a!"Nc30$,H/@8$9$k%?%$%
%s%0$,CY$$$H$$$&$@$1$G!"e(B
e$B<B32$O$J$$$H9M$($F$$$^$9!#e(B

e$B0J2<$NNc$G$O!"%Q%C%AE,MQ8e$Oe(B(1)e$B$GNc30$,H/@8$7!"e(B
e$B%Q%C%AE,MQA0$Oe(B(2)e$B$GNc30$,H/@8$7$^$9!#e(B

require “readline”
Readline::HISTORY.push(“a”, “b”, “c”)
$SAFE = 4
e = Readline::HISTORY.each # (1)
e.each do |s| # (2)
p s
end

e$B0J>e$G$9!#e(B

----- e$B$3$3$+$ie(B -----
Index: ext/readline/readline.c

— ext/readline/readline.c (revision 18314)
+++ ext/readline/readline.c (working copy)
@@ -640,9 +640,8 @@
HIST_ENTRY *entry;
int i;

  • RETURN_ENUMERATOR(self, 0, 0);
  • rb_secure(4);
  • RETURN_ENUMERATOR(self, 0, 0);
    for (i = 0; i < history_length; i++) {
    entry = history_get(history_get_offset_func(i));
    if (entry == NULL)
    Index: test/readline/test_readline_history.rb
    ===================================================================
    — test/readline/test_readline_history.rb (revision 18314)
    +++ test/readline/test_readline_history.rb (working copy)
    @@ -48,6 +48,7 @@
    [“push”, [“s”]],
    [“pop”, []],
    [“shift”, []],
  •   ["each", []],
      ["length", []],
      ["delete_at", [0]],
      ["clear", []],

e$B@>;3OB9-$G$9!#e(B

At Sat, 2 Aug 2008 00:50:00 +0900,
Takao K. wrote:

require “readline”
Readline::HISTORY.push(“a”, “b”, “c”)
$SAFE = 4
e = Readline::HISTORY.each # (1)
e.each do |s| # (2)
p s
end

require “readline”
Readline::HISTORY.push(“a”, “b”, “c”)
e = nil
proc {
$SAFE = 4
e = Readline::HISTORY.each # (1)
}.call
e.each do |s| # (2)
p s
end

e$B$N$h$&$J>l9g$N5sF0$,JQ$o$j$=$&$G$9!#e(B

e$B9bHx9(<#$G$9!#e(B

On 2008/08/03, at 1:38, Kazuhiro NISHIYAMA wrote:

e$B%Q%C%AE,MQA0$Oe(B(2)e$B$GNc30$,H/@8$7$^$9!#e(B
Readline::HISTORY.push(“a”, “b”, “c”)
e = nil
proc {
$SAFE = 4
e = Readline::HISTORY.each # (1)
}.call
e.each do |s| # (2)
p s
end

e$B$N$h$&$J>l9g$N5sF0$,JQ$o$j$=$&$G$9!#e(B

e$B$4;XE&$NDL$j$G$9$M!#e(B
e$B%Q%C%AE,MQA0$O!"@>;3$5$s$NNc$G$O%R%9%H%j$NMzNr$r<hF@$G$-$F$7$^$$$^$9$M!#e(B

e$B85!9$NA0ED$5$s$,=q$+$l$?e(B Readline::HISTORY.each
e$B%a%=%C%I$G$O!“e(B
$SAFE=4 e$B$G$”$l$PNc30e(B SecurityError e$B$rH/@8$5$;$k$3$H$re(B
e$B0U?^$5$l$F$$$?$N$G$O$J$$$+$H;W$$$^$9!#e(B
knu e$B$5$s$,e(B Enumerable::Enumerator
e$B$rJV$9$h$&$K=$@5$5$l$?$H$-$Ke(B
e$B5sF0$,JQ$o$C$?$H9M$($i$l$^$9!#e(B
e$B$D$^$j!"@>;3$5$s$NNc$G!“e(B
e$B%R%9%H%j$NMzNr$r<hF@$G$-$k$3$H$O%P%0$N2DG=@-$,$”$j$^$9!#e(B

e$B;d$N=$@5$K$h$j!"85!9$Ne(B Readline::HISTORY.each e$B%a%=%C%I$Ne(B
$SAFE=4 e$B$N$H$-$NA[DjDL$j$K$J$k$H9M$($F$$$^$9!#e(B

At Sat, 2 Aug 2008 00:50:00 +0900,
Takao K. wrote:

いかがでしょうか。
 現在のところ、同様のメソッド(多数)に関して、引数チェックおよび
$SAFE チェックを(Enumerator 生成の)前に行うかどうかは統一されて
いません。

ã€€ãƒ¡ã‚½ãƒƒãƒ‰å†’é ­ã¸ã® RETURN_ENUMERATOR() ã®è¿½åŠ ã®ã¿ã§æ¸ˆã¾ã›ã‚‹ã“ã¨ã§
たまたま呼出時チェック(生成時は無チェック)になっているものが多い
ですが、そこはもちろん個別のメソッドの事情で決めてよいでしょう。
ç‰¹ã«ã€å¼•æ•°ã®æ•°ã‚„åž‹ã®ãƒã‚§ãƒƒã‚¯ãªã©ã¯ç”Ÿæˆæ™‚ã«ã™ã‚‹ã®ãŒæœ›ã¾ã—ã„å ´åˆã‚‚
多いはずです。

 ただ、 Enumerator 自体は状態を持つものではなく、 enumerate する
ための補助装置に過ぎないので、挙動はイテレータ実行時に決定される
のが原則だとは思っています。

e$B9bHx9(<#$G$9!#e(B

On 2008/08/04, at 16:37, Akinori MUSHA wrote:

e$B!!8=:_$N$H$3$m!"F1MM$N%a%=%C%Ie(B(e$BB??te(B)e$B$K4X$7$F!"0z?t%A%’%C%/$*$h$Se(B
$SAFE e$B%A%’%C%/$re(B(Enumerator e$B@8@.$Ne(B)e$BA0$K9T$&$+$I$&$+$OE}0l$5$l$Fe(B
e$B$$$^$;$s!#e(B

e$B!!%a%=%C%IKAF,$X$Ne(B RETURN_ENUMERATOR() e$B$NDI2C$N$_$G:Q$^$;$k$3$H$Ge(B
e$B$?$^$?$^8F=P;~%A%’%C%/e(B(e$B@8@.;~$OL5%A%’%C%/e(B)e$B$K$J$C$F$$$k$b$N$,B?$$e(B
e$B$G$9$,!"$=$3$O$b$A$m$s8DJL$N%a%=%C%I$N;v>p$G7h$a$F$h$$$G$7$g$&!#e(B
e$BFC$K!"0z?t$N?t$d7?$N%A%’%C%/$J$I$O@8@.;~$K$9$k$N$,K>$^$7$$>l9g$be(B
e$BB?$$$O$:$G$9!#e(B

e$B$4@bL@$"$j$,$H$&$4$6$$$^$9!#e(B
e$B>u67$,J,$+$j$^$7$?!#e(B

e$B!!$?$@!"e(B Enumerator e$B<+BN$O>uBV$r;}$D$b$N$G$O$J$/!"e(B enumerate e$B$9$ke(B
e$B$?$a$NJd=uAuCV$K2a$.$J$$$N$G!"5sF0$O%$%F%l!<%?<B9T;~$K7hDj$5$l$ke(B
e$B$N$,86B’$@$H$O;W$C$F$$$^$9!#e(B

e$B>e5-$N86B’$K=>$&$J$i$P!"e(BReadline::HISTORY.each e$B%a%=%C%I$O!"e(B
e$B8=:_$N5sF0$,NI$$$h$&$G$9$M!#;d$O>e5-$N86B’$KG<F@$7$^$7$?!#e(B
e$B$H$$$&$3$H$G!"e(BReadline::HISTORY.each
e$B%a%=%C%I$O=$@5$7$^$;$s!#e(B

e$B$J$*!">e5-$N86B’$Oe(B knu e$B$5$s$N$9M$($J$N$+!"e(B
e$B$=$l$H$be(B ruby (e$B$N3+H/<Te(B?)
e$BA4BN$H$7$F$N$b$N$J$N$+$I$A$i$G$7$g$&$+$M!#e(B
e$B:#8e!"3+H/$r$9$k>e$GCN$C$F$
$$$?J}$,$h$$$H;W$C$?$N$G<ALd$7$F$$$^$9!#e(B

At Tue, 5 Aug 2008 21:54:54 +0900,
Takao K. wrote:

 ただ、 Enumerator 自体は状態を持つものではなく、 enumerate する
ための補助装置に過ぎないので、挙動はイテレータ実行時に決定される
のが原則だとは思っています。

 状態を持つものでないという表現は正確ではなかったですが、要は、
元のオブジェクトをありのまま包んで列挙の補助を行うもので、代入等
ã›ãšã«ãã®å ´ã§ãƒ¡ã‚½ãƒƒãƒ‰ãƒã‚§ãƒ¼ãƒ³ã‚’ç¶šã‘ã¦ä½¿ã†ã‚ˆã†ãªä½¿ã„æ–¹ã‚’ä¸»ã«æƒ³å®š
しています。

 ただ、一方では「『列挙だけができる何か』に抽象化する入れ物」と
しての性質があるのも確かで、たとえば「何らかの列挙子を受け取る」
メソッドに Enumerator を渡すようなケースが想定されます。しかし、
それを受け取る側は、(もらったものが Enumerator だったとして)その
中身が何でどんな例外が起き得るのかということは分からない(知って
いるべきでもない)ので、例外が発生する可能性があるものは受け渡し
には適さないと思います。もちろん、呼び出し側が責任をもって例外を
捕捉するのなら構いませんが。

上記の原則に従うならば、Readline::HISTORY.each メソッドは、
現在の挙動が良いようですね。私は上記の原則に納得しました。
ということで、Readline::HISTORY.each メソッドは修正しません。

なお、上記の原則は knu さんのお考えなのか、
それとも ruby (の開発者?) 全体としてのものなのかどちらでしょうかね。
今後、開発をする上で知っておいた方がよいと思ったので質問しています。

 enumerator を提案して最初の実装を書いた私はそう見ていますが、
開発者全体のものかというと分かりません。別のより使いやすい方向が
示されれば、そちらにシフトすればいいと思います。