カテゴリ別 2003年 | 2004年 | 2005年 | 2006年 | 2007年 | 2008年
知り合いサイト: よんだもの / 暴想 / Linuxでやる夫 / 新宿Vipper / 僕だけが幸せになればいいのに。
Ruby初心者スレッド Part 10 と Ruby初心者スレッド Part 11 でメソッドの出口はひとつにしたほうが良いか?という話題が出ています。
結論としては、不用意に call/cc を使ったり例外以外に例外処理を使ったりせず、またメソッドのやる仕事が適切であるならば、読みやすさのために出口を複数にしても良いと思います。また、「出口はひとつ」は「そうできる」といっているだけで、「そうしなければならない」ということではありません。
メソッドの出口が複数であることを気にするよりも前に、メソッドが長すぎないか、条件分岐が不適切で流れがわかりにくくなっていないか、メソッドとして抽出できる部分が存在しないか、ローカル変数がその役割を把握できる名前になっているかなどを気にするべきです。また、例外やガード節を導入すると大抵出口が複数になりますが、エラー処理とメインロジックを分離してコードの見通しをよくするメリットを捨てるべきではありません。
以下長文。読まなくても構いません。
この「出口がひとつ」というのは、構造化プログラミングに由来します(構造化プログラミング)。正確には Boehm と Jacopini によって 1966 に証明された構造化定理です。構造化プログラミングについて簡潔にまとめているサイトがありましたので、構造化定理の部分を引用させていただきます。
全てのプログラムは、一つの入口と出口を持つ形(適正プログラム)に等価変形可能であり、適正プログラムでは任意のアルゴリズムを次の三つの基本的な制御構造で記述できます。
- 順次(Sequence)
- Javaでは、セミコロン区切りの命令(ステートメント)を列挙した構造。
- 選択(Selection)
- 条件式の結果に応じて実行するブロックを変更する条件分岐構造。Javaでは、if文、switch文、try文をサポート。
- 繰り返し(Iteration)
- ブロック内部を繰り返し実行するループ構造。Javaでは、do文、while文、for文をサポート。JDK 5.0では拡張for文を追加。
変換可能といっているだけで、そうしなければならないといっているわけではないことが分かります。制御構造 - Wikipedia : 必要最小限の構造化制御フローによれば、「他の研究により入り口と出口がそれぞれひとつになっている制御構造が他の構造よりも理解し易い」とあるように、プログラムの構造を把握しやすくするのが目的です。守ることで分かりにくくなるなら本末転倒でしょう。
余談ですが当時のプログラミング言語の状況を知るとなぜこのような定理が提唱・証明されたかが分かります。プログラミング言語年表 によれば、1966 年までに開発されている主要な言語には FORTRAN、COBOL、LISP、BASIC などがあります。これらの言語は今も使われていますが(一度広まった言語は非常に息が長いですね)、当時のままではありません。構造化プログラミングが提唱される前に開発された言語なので、あとから構造化プログラミングをサポートする機能を追加しています(LISP は別として)。例えば FORTRAN の JIS 仕様の変遷を読むと時代の流れに合わせて自由プログラム形式やオブジェクト指向などを取り入れていることが分かります。また、Microsoft の BASIC 製品の変遷は MS-BASIC → QuickBASIC → Visual Basic → Visaul Basic .NET といったところですが、同じ BASIC の名を冠していてもそれぞれほとんど別物といえます。当時の言語では困ることがあったので構造化定理が提唱されたり、それに基づいて言語に機能が追加されたわけです。
若い人たちはもう知らないかもしれませんが、昔 NEC の PC-8801/PC-9801 シリーズには N88-BASIC という BASIC 処理系が搭載されていました。IF 文や FOR 文といった制御構文が言語に含まれていましたが構造化プログラミングをするのに十分だったとはいえません。BASIC - Wikibooks : 条件分岐にあるように古い BASIC では IF 文を一行で書かなくてはならないため、複数行にわたるものを実行したい場合には GOTO で別の場所に飛ばす必要がありました。また、プログラム一行一行ごとに行番号が必要であること、GOSUB 命令はあるがサブルーチンに名称は付けられず行番号を指定するといったところから、プログラムを部分に分けるという手法へのサポートが希薄なことがわかります(そういう考えが現れる前に作られた BASIC の仕様を踏襲しているので当たり前ですが)。
構造化定理が提唱された当時は GOTO 文が多用されたプログラムが蔓延していたようです。制御構造を使うことでもっと読みやすく書きやすいプログラムになることは実感として明らかですが、GOTO 文の代わりに(GOTO 文よりも自由さが制限された)制御構造を使ったとしても同じ機能を実現できることを証明する必要があったのだと思います。
Ruby は構造化プログラミング、オブジェクト指向プログラミングを言語仕様でサポートしています。Ruby プログラムとして適切なプログラムを書いていれば、最低限かもしれませんが構造化プログラムあるいはオブジェクト指向プログラムといえます。つまり、if/case/for/while といった制御構文の利用や、メソッド、クラスの作成を行えば、そうしないよりは構造化/オブジェクト指向プログラムといえるだろうということです。構造化定理当時のプログラムを読んだことはありませんが、N88-BASIC でプログラムを書いた経験からすると、平均してそのころの基準からすればはるかに洗練されて読みやすくなっています。構造化プログラミングは十分下地として浸透していると思いますので、GOTO 文不要論も含めて金科玉条のように守ろうとする必要はないんじゃないかなと思います。
最近のコメント:
RSS
![]()
This work is licensed under a
Creative Commons License
(note: text only. w/o web design, citations, (re)distributed softwares).