foreach range statement

D言語 の foreach range statement について。直感に反する動作。
1

バグにはまったら、まず @repeatedly さんに聞くのが最善。

大堀龍一 (Ryuichi OHORI) @__DaLong

@repeatedly foreach (i; 0..10){i-=1; writefln("%d", i); } は無限ループになるのでしょうか。もしなるならなぜですか。

2012-06-11 01:49:31
SKS rep @repeatedly

@__DaLong 試した?ならないはずだけど

2012-06-11 01:51:13
大堀龍一 (Ryuichi OHORI) @__DaLong

@repeatedly 全く同じではないのですが、 http://t.co/MENLFEgJ が AC, http://t.co/3A3vJr5S が TLE しました。先ほどの例と何か違うのでしょうか。

2012-06-11 01:56:31
SKS rep @repeatedly

@__DaLong あー,dmdがforeachをforに展開した時に同じ変数使い回してんのかなぁ.通常はrange的なアプローチだから影響しないけど,整数のforに関しては特別に高速なコードを生成している可能性が高い.iota(10)なら多分無限ループしない.

2012-06-11 02:04:16
大堀龍一 (Ryuichi OHORI) @__DaLong

@repeatedly iota にしたら通りました。だいたいわかった気がしますが、わりと嵌まりそうです・・・。

2012-06-11 02:08:42
大堀龍一 (Ryuichi OHORI) @__DaLong

やっぱ1日に1回くらい落とし穴に落ちる。

2012-06-11 02:10:18
SKS rep @repeatedly

@__DaLong まぁループのインデックスを操作する人なんて普通いないでしょ,というのが今までの言語の経験から得た結果なので,より高速なコードを生成するためにその辺のガードを緩めるのは仕方ない気もする.

2012-06-11 02:13:23
大堀龍一 (Ryuichi OHORI) @__DaLong

0..N というのは配列リテラルみたいなものだと思ってたけど、そういうわけじゃないのか。foreach とスライスにしか使えない特別な表記ってことかな。 #d_lang

2012-06-11 02:27:23
大堀龍一 (Ryuichi OHORI) @__DaLong

@repeatedly 観戦に忙しいところ、どうもありがとうございました。

2012-06-11 02:27:51
大堀龍一 (Ryuichi OHORI) @__DaLong

とりあえず ARC 001 の C 問題を通すことができたし、D 言語に関する知見も増えたし、満足して寝ることにしよう。

2012-06-11 02:29:07
SKS rep @repeatedly

@__DaLong いやいや,こっちも普通にそれは問題ないと思っていたので,知見が増えて感謝

2012-06-11 02:30:22
大堀龍一 (Ryuichi OHORI) @__DaLong

たしかにループカウンタに代入を行いたいのは重複順列をコードしての全探索を簡単に書きたいときくらいだな。

2012-06-11 02:35:03

翌日:

大堀龍一 (Ryuichi OHORI) @__DaLong

昨日わかったことを書いた。D: Foreach Range Statement http://t.co/M6zdofmA #d_lang

2012-06-11 15:09:07
SHOO @mono_shoo

@__DaLong 無限ループになるのはバグじゃないかと…だって、これ、だれも無限ループになって得する人はいないでしょう…?

2012-06-11 19:34:51
SHOO @mono_shoo

C言語やC++なら「未定義動作」かもしれないが、D言語なら「バグ」

2012-06-11 19:35:55
大堀龍一 (Ryuichi OHORI) @__DaLong

@mono_shoo それは具体的には何と何とが不一致であるバグという意味ですか? マニュアルと実際の挙動とが一致していることには納得しましたが、たしかに私は無限ループになっても得をすることはないと思います。

2012-06-11 21:51:57
大堀龍一 (Ryuichi OHORI) @__DaLong

foreach (i; 0..n) が foreach (i; iota(n)) の略記なのか、for (i = 0; i < n; i += 1;) の略記なのかという問題な気がしています。どちらであるべきかは決めにくいかと。 #D @mono_shoo @repeatedly

2012-06-11 21:55:51
hara kenji @9rnsr

@__DaLong @mono_shoo @repeatedly foreachの列挙変数はrefをつけない限り、列挙対象の値のコピーのように動作すべきです。従ってこの場合、変数iの変更がループ回数に影響を与えるのはバグだと思います。

2012-06-11 22:06:39
SHOO @mono_shoo

@__DaLong 「iが書き換えられるのはおかしい」ですかね。

2012-06-11 22:07:21
SHOO @mono_shoo

@9rnsr そのとおり。私もそう思いました。

2012-06-11 22:08:07
SKS rep @repeatedly

個人的にはforeach (i; 0..n) {…}でiが書き換えられるのはD言語らしくないけど,Rangeじゃなくて整数範囲ステートメントを使った場合は高速に動作します!も悪くはないかな,と思わなくもない.というかコンパイラが最適化してくれればそれで良い.

2012-06-11 22:10:07
SKS rep @repeatedly

foreach (i; 0..n) {…}の…でiが書き換えられる場合はiをコピー,書き換えない場合はいつものforで

2012-06-11 22:11:05