Feature #3627
closedcatchのブロックを再実行するメソッド
Description
=begin
catchとthrowで、ネストを飛び越えたbreakのようなことができるわけですが、同様のネストを飛び越えたnextのようなもの、を現在のrubyでやるのは少々面倒です。
retryを利用して、
tag = Class.new Exception
begin
...
raise tag
...
rescue tag
retry
end
という手もないではありませんが無理矢理っぽいです。
throwのかわりに、なにか別のメソッド(rewindという名前はどうでしょう?)を実行すると、catchのブロックが再実行される、というのはどうでしょうか?
=end
Updated by matz (Yukihiro Matsumoto) over 14 years ago
=begin
まつもと ゆきひろです
In message "Re: [ruby-dev:41892] [Feature #3627] catchのブロックを再実行するメソッド"
on Thu, 29 Jul 2010 17:33:11 +0900, Makoto Kishimoto redmine@ruby-lang.org writes:
|throwのかわりに、なにか別のメソッド(rewindという名前はどうでしょう?)を実行すると、catchのブロックが再実行される、というのはどうでしょうか?
基本的なアイディアを否定するわけではありませんが、
- catchブロックの再実行が必要なユースケースが示されていない
- rewindという名前はいろいろなところで使われているので望ま
しくない
ので、現時点では賛成しません。
=end
Updated by metanest (Makoto Kishimoto) over 14 years ago
=begin
きしもとです
|throwのかわりに、なにか別のメソッド(rewindという名前はどうでしょう?)を実行すると、catchのブロックが再実行される、というのはどうでしょうか?
基本的なアイディアを否定するわけではありませんが、
- catchブロックの再実行が必要なユースケースが示されていない
- rewindという名前はいろいろなところで使われているので望ま
しくないので、現時点では賛成しません。
ユースケースですが、The Art of Multiprocessor Programming の、
ロックフリースキップリストの find メソッド(Fig. 14.13)を Ruby で書いた
ものを示します。(begin と rescue と retry で同等のものを実装しています。
元の Java コードではラベル付きの continue でした)
def find key, before_list, after_list
retry_tag = Class.new Exception
begin
pp = nil
p = @head
@level_max.downto(0){|level|
pp = p.links[level].get_link
loop {
ppp, mark = pp.links[level].get
while mark do
snip = p.links[level].compare_and_set pp, ppp, false, false
unless snip then
raise retry_tag
end
pp = ppp
ppp, mark = pp.links[level].get
end
if pp.key.__send__(@cmp_op, key) == -1 then
p = pp
pp = ppp
else
break
end
}
before_list[level] = p
after_list[level] = pp
}
if pp.key.__send__(@cmp_op, key) == 0 then
pp
else
nil
end
rescue retry_tag
retry
end
end
private :find
また、しばらく考えてみたのですが、C言語で do { continue; } while (0); が
ループにならないことを考えると、デフォルトでは1回きりの実行が期待されている
catch との組み合わせはあまり良くないように思えてきました。
loop のブロックが引数を取るようにして、
loop {|tag|
...
continue tag
...
}
というかたちではどうでしょうか?
あと、名前ですが、continue の他に loop と対になるので pool ...というのは
ダメですね多分。
=end
Updated by nobu (Nobuyoshi Nakada) over 14 years ago
=begin
なかだです。
At Sat, 31 Jul 2010 19:06:51 +0900,
KISHIMOTO, Makoto wrote in [ruby-dev:41906]:
loop のブロックが引数を取るようにして、
loop {|tag|
...
continue tag
...
}というかたちではどうでしょうか?
こんなのではどうでしょうか。
class Loop
def loop
begin
t, val = catch(self) {
yield self
false
}
end while t
val
end
def next(*values)
Kernel.throw(self, [true, values])
end
def break(*values)
Kernel.throw(self, [false, values])
end
def self.loop(&block)
new.loop(&block)
end
end
i = 0
Loop.loop do |tag|
p(i += 1)
tag.next if i < 3
p "end"
tag.break
end
--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦
=end
Updated by metanest (Makoto Kishimoto) over 14 years ago
=begin
きしもとです
こんなのではどうでしょうか。
ありがとうございます。
while で catch を囲んだら、というアイディアは%rubyでいただいていたのですが、
うまく抽象化できるのですね。
=end
Updated by shyouhei (Shyouhei Urabe) about 14 years ago
- Status changed from Open to Rejected
=begin
提案事態はrejectしますのでもし新しいアイディアができたらまた登録してください。
=end