do-whileステートメントとか使っていますか?
あんまり実際に使われているコードを実務で見たことはなく。
使われていないキーワードランキング的にもdo
は使われてない方から数えて27位。
もしかしたら使われないどころか存在を忘れてる人すらいるんじゃないかというこの文法。
「使ってる?」とか人に聞いてみたところ、 「初心者の頃にちょっと」「もしかしたら初心者ほど使ってるかも」とかいう回答も得られたり。 確かに、入門書とか(うちのサイト含めて)には書かれてますもんね。書かれてば使うか。
たぶん、徐々に、以下のように while (true)
になっていくのかなぁとか。
まあ、そもそも、ループの大半が foreach
ですけど。do-while
どころか while
もそこそこレア。
while (true)
{
// 前にも書きたいことあるし、
if (条件) break;
// 後ろにも書きたいことある
}
while (true)
{
// というか、メソッド抽出して return する方が多いかも
if (条件) return ...;
}
さて、そんなdo-while
がなぜあるか、ですが。
確かにdo-while
の「最低1回は実行したい」という要件はそもそも出番が少ない上に、やろうと思えばwhile
だけで書けます。
要するに、レアケースのために専用構文がある意味はあったのかという問題が。
ご存知の通り、この構文はC言語からあります。 「その当時ならば使ったのか」と言われると、やっぱりそんなに使いはしなかったと思うんですけど…
実は、生成されるコードがwhile
よりもdo-while
の方が短いんですよね。
ということで、おそらく、do-while
があるのは、そういうパフォーマンス上の理由かなぁと思います。
どういうことかというと、例えば、do-while
は以下のように展開されます。
static void DoWhile(int x)
{
do
{
--x;
} while (x > 0);
}
// ↓
static void DoWhileCompiled(int x)
{
BEGIN_DO_WHILE:;
--x;
if (x > 0) goto BEGIN_DO_WHILE;
}
これに対して、while
だと以下のように、goto
(IL 的には br
命令。x64 系 CPU のネイティブコード的には jmp 命令)が1個多く展開されたりします。
static void While(int x)
{
while (x > 0)
{
--x;
}
}
// ↓
static void WhileCompiled(int x)
{
goto END_WHILE;// この goto がいまいち好きになれない
BEGIN_WHILE:;
--x;
END_WHILE:;
if (x > 0) goto BEGIN_WHILE;
}
この、while
、do-while
を使ったものと、展開結果のgoto
を使ったものが本当に一緒になるかも確認してみましょう。
上記コードをコンパイルして、ildasmを掛けた結果は以下の通りです。
上がwhile
、下がdo-while
。
左が展開前、右が展開後。
ついでに、do-while
の方が数バイト小さくなることもわかります。
ここではILしか出していませんけども、たいていのCPUで、ネイティブ コードでもやっぱりdo-while
の方が短くなると思います。
とはいえ、この微々たる要件のためにいまだにこの構文が必要かと言われると微妙なラインですかね。