私の唯一誇れる能力は、読解力である。そのため、私がプログラミング言語の規格を読むのを好むのは、自然なことである。このたび、Dartの規格上のバグを発見した。なかなか笑えるので紹介する。もちろん、実装者にとっては洒落にならないが。
以下のコードは、現行ドラフトの文面に従うと、well-formedなDartコードである。
main() { a : { break a ; } b : { continue b ; } }
なぜかというと、現行のDartのドラフト規格は、ラベル付きのbreak文とcontinue文は、label文の中に入ることができるとされている。ラベル文には、文を書ける。また、ブロック文も文である。よって、Label : { } はwell-formedなDartコードであり、その中でbreakやcontinueを使うのもwell-formedである・・・はずだ。
傑作だったのは、現行の実装が、このコードを実際にコンパイルできてしまうということだ。break文の方は、期待通りに動いた。つまり、
a : { print("before") ; break a ; print("after") ; }
は、beforeを出力する。
continue文の方は、コンパイルは通るが、実行時に、不思議なエラーを吐いて強制終了してしまう。もし規格通りに動いていたならば、無限ループになったはずだ。
この件はすでにバグ報告済みである。
何がバグなのかよく分かりません。Javaで、ラベル付きbreakでラベル付きif文から抜ける事ができるように、意図された仕様ではないですか?
ReplyDeletebreakの方は仕様かもしれませんね。
ReplyDeleteただ、continueは、明確にループ構文で使われることを意図している言語が大半なので、さすがに変でしょう。
そういうのは読解力とはいいません。
ReplyDeleteただの揚げ足取り能力です。
そんなことしているヒマがあったらさっさと規格書訳したらどうですか?
その場合の continue は禁止した方がいいという考えには賛成です。
ReplyDeleteしかし、仮に continue が使えた場合の挙動としては無限ループでは無く break と同じになるべきと思います。
例えば for文 で continue を使った場合にはインクレメンタル部 (←正式な名前がわかりませんが、 for に与えるみっつの式の三番目の奴のことです) は評価された上で次のループが開始されることから、ブロックの先頭へのジャンプというよりはブロックの末尾へのジャンプと考えられるからです。
つまり、 break は } の後ろへのジャンプであり、 continue は } のすぐ手前へのジャンプと解釈でき、記事中の例の場合であれば事実上同じとなるのが一貫性のある挙動だと思う次第です。
批判はさておいて、簡易ループ構文としてダーティっていうか、お手軽と言うか・・・。
ReplyDeleteバッドノウハウの部類だと思うので、是正するのが現状正しいと思います。