今日のScalaハマりポイント: for 式内の変数束縛のタイミングが直観に合わない。 挙動をちゃんと知っていれば理解は出来るけれど、気を使って書かなければいけないのはデメリット。

gist.github.com

普通に読むと、iを束縛した後、bestを束縛して、jを回す、それが終わったらまたiを束縛してbestを束縛して…と読めて、結果としてWrappedArray(21, 22, 23, 24, 25)が出力されるはずだと思うわけだけど、実際にはそうはならず、WrappedArray(1, 2, 3, 4, 5)が出力される。

scala -Xprint:parser で for式の部分を見てみると、

gist.github.com

となっていて、最初のループは foreach ではなくて、 map に変換されているのが分かる。 つまり、jのループが回る前に bestiのmapとして固定されてしまうわけだ。 for内の要素が不変である事が前提ならば特に問題ないのだけど、 上記のようにループ中に要素が変更される場合には、一般的な二重ループの直観とずれが生じてしまう。 期待する結果を得るには、

gist.github.com

のように書かなければならない。これは期待通り foreach に変換される。

gist.github.com

あるいは、すこしオーバーヘッドが出そうだが

gist.github.com

のような書き方をしても

gist.github.com

と、期待通りの動作となる。