単一エントリ、単一出口(SESE)のこの概念は、Cやアセンブリなどの明示的なリソース管理を備えた言語に由来します。Cでは、次のようなコードはリソースをリークします。
void f()
{
resource res = acquire_resource(); // think malloc()
if( f1(res) )
return; // leaks res
f2(res);
release_resource(res); // think free()
}
このような言語では、基本的に3つのオプションがあります。
クリーンアップコードを複製します。
あー 冗長性は常に悪いです。
を使用しgoto
て、クリーンアップコードにジャンプします。
これには、クリーンアップコードが関数の最後のものである必要があります。(そして、これが、あるgoto
場所がその場所を持っていると主張する理由です。そして、それは確かに– Cで。)
ローカル変数を導入し、それを介して制御フローを操作します。
欠点は、(だと思うの構文を介して操作その制御フローであるbreak
、return
、if
、while
変数の状態を介して操作制御フロー(あなたがアルゴリズムを見たときに、これらの変数は状態がないので)よりも従うことがはるかに簡単です)。
アセンブリでは、その関数を呼び出すときに関数内の任意のアドレスにジャンプできるため、さらに奇妙です。これは、事実上、任意の関数へのエントリポイントがほぼ無制限にあることを意味します。(これが役立つ場合があります。このようなサンクは、C ++の複数継承シナリオで関数this
を呼び出すために必要なポインター調整をコンパイラーが実装するための一般的な手法virtual
です。)
リソースを手動で管理する必要がある場合、どこからでも関数の開始または終了のオプションを利用すると、コードが複雑になり、バグが発生します。したがって、よりクリーンなコードとより少ないバグを取得するために、SESEを広めた一連の思考が現れました。
ただし、言語が例外を備えている場合、(ほぼ)すべての関数が(ほぼ)任意の時点で途中で終了する可能性があるため、いずれにしても早期復帰の準備をする必要があります。(私が思うにfinally
、主にJavaで、そのために使用され、using
実装時に(IDisposable
、finally
; C ++の代わりに採用してC#で)そうでない場合はRAIIをあなたがこれを行った後、あなたが。)することができないため、早期に自分の後にクリーンアップに失敗するreturn
ので、何がおそらく、声明SESEを支持する最も強力な議論は消滅しました。
それは読みやすさを残します。もちろん、半ダースのreturn
ステートメントがランダムに散りばめられた200 LoC関数は、プログラミングスタイルとしては適切ではなく、読みやすいコードにはなりません。しかし、そのような関数は、それらの早すぎる戻り値なしでは理解しにくいでしょう。
リソースが手動で管理されない、または管理されるべきではない言語では、古いSESE規則を順守することにほとんど価値がないか、まったく価値がありません。OTOH、私が上で議論したように、SESEはしばしばコードをより複雑にします。(Cを除く)今日のほとんどの言語にうまく適合しない恐竜です。コードの理解を助ける代わりに、それを妨げます。
なぜJavaプログラマーはこれにこだわるのですか?私は知りませんが、私の(外部の)POVから、JavaはC(それらが理にかなっている)から多くの規約を取り、それをOOの世界(役に立たないかまったく悪い)に適用しました。それらは、どんなに費用がかかります。(すべての変数をスコープの先頭で定義する規則と同様です。)
プログラマーは、不合理な理由であらゆる種類の奇妙な表記法に固執しています。(深くネストされた構造ステートメント(「矢印」)は、かつてPascalなどの言語では美しいコードと見なされていました。)これに純粋な論理的推論を適用すると、それらの大部分が確立された方法から逸脱することを納得させることができないようです。そのような習慣を変える最良の方法は、おそらく従来のやり方ではなく、最善を尽くすことを早い段階で教えることでしょう。プログラミングの先生であるあなたは、それを手にしています。:)