R.Tanaka.Ichiro's Blog

主にC# な話題です

目次

Blog 利用状況

ニュース

ガード句

最近、よく次のような書き方をしています。


public int GetCode() {
  if (this.Text != String.Empty) {
    int i = 0;
    if (int.TryParse(this.Text, out i)) {
      return i;
    }
  }
  return 0;
}


理由は簡単で、こちらの方が完結にかけるからです。

しかし、僕は今まで、次のように書くことを意識してきました。


public int GetCode() {
  if (this.Text == String.Empty) {
    return 0;
  }
  int i = 0;
  if (! int.TryParse(this.Text, out i)) {
    return 0;
  }
  return i;
}


つまり、GetCode という目的に対して、必ず主体となる処理を最後に書くように意識してきたのです。

しかし、この書き方だと、return 0; となる部分が複数できてしまいます。これは、複数の return が点在することになります。

そしてある日、「このように return があちこちに複数点在する書き方は、あまり良い書き方ではないのだろうか?」と思った訳です。

そして、最初のサンプルコードのような書き方が多くなりました。

結局のところ、何が言いたいのかというと

皆さんはどう?

ということなのです。

どうでもいいと言われれば、それまでのことですが、統一した書き方をすべきなのか、ケースバイケースなのか、統一しているなら前者の書き方なのか、後者の書き方なのかを教えていただけると助かります。

関連リンク(@IT会議室)
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=26940&forum=3&9

投稿日時 : 2007年2月19日 18:42

Feedback

# re: ガード句 2007/02/19 19:04 えムナウ

パラメーターエラーは入り口でチェックしてExceptionか異常値で返す。
当然でしょうね。

# re: ガード句 2007/02/19 19:05 じゃんぬねっと

return 0; なんて書くことはありませんが、return false; が点在することは多々あります。
メソッドの仕様にもよりますが、私は仕様変更時の対応に優れたガード句が好きです。
ですので、その心の移り変わりに反対しておこうと思います。

# re: ガード句 2007/02/19 19:14 シャノン

パラメータのチェックくらいなら前者でもいいんですが、これがメソッド本体にあって、処理Aが成功したら処理B、処理Bも成功したら処理C…っていうパターンだと、前者の形ではネストが深くなりすぎます。
俺も後者がいいかなぁ、と。

# re: ガード句 2007/02/19 20:54 とっちゃん

「ガード句」を入れるのならおいらは後者のパターンですね。

でもその場合、ガード句の前にアサーション入れます(デバッグ版は遅くなっても確実にエラーチェックしたいのでw)。
なので、例示のコードの場合なら

public int GetCode() {
  Debug.Assert( !String.IsNullOrEmpty( this.Text ), "ハァ?なんで空なわけ?ありえないから!!!" );
  if ( String.IsNullOrEmpty( this.Text ) ) {
    return 0;
  }
  int i = 0;
  if (! int.TryParse(this.Text, out i)) {
    return 0;
  }
  return i;
}
って感じになりますね。
そもそもからして、null がない保証もないしw
#1.1 なら仕方ないんで != null && != Empty ですがw

でも、コントロールのメソッド(あるいはプロパティ)として作るのなら、例外投げます。
public int GetCode() {
  return int.Parse( this.Text );
}
なので、たったの1行で終わりw
例外投げてほしくないというのなら逆にTryParseパターンを適用して
public bool GetCode( out int result ) {
  // 中身は 上のコードとほぼ同じ。
}
という感じです。

# re: ガード句 2007/02/19 22:07 ghost_shell

以前はコンパクトな書き方(前者)を目指していたけど、今は後者かな。

  極力ネストを避けたいので。
  (保守が行われるなら、えムナウ さんやじゃんぬさんの意見を加えて)

>「このように return があちこちに複数点在する書き方は、
>あまり良い書き方ではないのだろうか?」と思った訳です。

僕も思ったことがあります。でも分岐を含む構造ではreturnをまとめるのは無理なのだから(※)と頭を切り替え、そういった場合は1つ1つ石橋を叩いて渡ります。
出口が何個かあっても、そのいくつかは考えなくて済むだろうと思って。

(※)3項演算子という手があるが、そのこだわりのためだけに使うっていうのはない(このサンプル程度でもちょいキツイと思う)よね。

# re: ガード句 2007/02/19 23:19 επιστημη

case by case と言っちまえば身も蓋もないんだけど、
僕は概ね「本筋に到達できないダメ条件はその都度お引取りいただく」ように書いてるみたい。

# re: ガード句 2007/02/20 9:06 シャノン

> 「このように return があちこちに複数点在する書き方は、あまり良い書き方ではないのだろうか?」

「構造化プログラミングというやつに『入口は一つ、出口も一つ』と謳われているから、1つの関数に return は1つにすべきだ」というのは間違いだ、というのをどこかで読んだ。
関数の中に return がいくつあろうと、そこから戻る呼び出し元の地点は常に1つなのだから、「出口も一つ」は達成されている、という理由だった。

# re: ガード句 2007/02/20 9:29 かずくん

私も後者。
手続きは、基本的に、入力→処理→出力と進みます。
適切な個所でとっととお帰りになってもらった方が、変な値が次フェーズにもぐりこむことがなく、バグを誘発しにくいかなと思うので。

入力チェックが長くなれば、そこだけ切り出して、別メソッドにすることもできますし。

> 1つの関数に return は1つにすべきだ」というのは間違いだ、
関数のインターフェースとして、戻り値はひとつだから、問題なしと思ってる。実装の詳細がどうなっていようとも。
数学においても、条件により、複数の解を返すことがあるんだし。
#と、いかにももっともそうなことを、適当にぶち上げておく

# re: ガード句 2007/02/20 13:08 NAL-6295

私も、後者ですね。

一度に考えなくてはいけない内容も、複雑度も小さくすみますので、ガード句は好んで使っています。

# re: ガード句 2007/02/20 13:31 ひろえむ

私もケースバイケースなのでこのコードだけで回答は難しいですが、基本的には後者かなぁ・・・・。
ネストが深くなるのがちょっとイヤなのと、用事もないのにうろちょろされるのもイヤなので・・・。

要件によってはとっちゃんが書いたように
public int GetCode() {
return int.Parse(this.Text);
}
でも、いいかなという気も。

できるだけ単純にしたいのであまり必要のないブロックも避けるかな(^^;
if(String.IsNullOrEmpty(this.Text)) return 0;
という感じで。

ま、戻り値にマジックナンバーはあれですが(^^;;;;

# re: ガード句 2007/02/20 13:59 R・田中一郎

えムナウ さん

了解です。
元のスタイルに戻そうと思います。
ありがとうございました。

--------------------------------------------
じゃんぬねっと さん

>メソッドの仕様にもよりますが、私は仕様変更時の対応に優れたガード句が好きです。

この一言がすべてを物語っていますね。
ありがとうございます。

--------------------------------------------
シャノン さん

早速、目前のコードから実施開始です。

--------------------------------------------
とっちゃん

いつもわかりやすいご説明を、ありがとうございます。
お忙しいのに。
早速、参考にさせていだきます。

--------------------------------------------
ghost_shell さん

>極力ネストを避けたいので。

確かに行数は減りますが、読みにくいですよね。桁数も増えますし。

>(※)3項演算子という手があるが、そのこだわりのためだけに使うっていうのはない(このサンプ

これもちらっと頭をかすめたのですが、ghost_shell さんと同じ理由で使わないようにしています。

--------------------------------------------
επιστημη さん

>僕は概ね「本筋に到達できないダメ条件はその都度お引取りいただく」ように書いてるみたい。

今までの僕の書き方も、この方法が多かったのです。
なので、嬉しかったりります。

--------------------------------------------
シャノン さん

>関数の中に return がいくつあろうと、そこから戻る呼び出し元の地点は常に1つなのだから、「出口も一つ」は達成されている、という理由だった。

なるほど、確かにそうですね。

--------------------------------------------
かずくん(さんは不要ですか?)

>入力チェックが長くなれば、そこだけ切り出して、別メソッドにすることもできますし。

そうか、メソッドアウトしやすいですね。
言われてみて改めて気づきました。

--------------------------------------------
NAL-6295 さん

>一度に考えなくてはいけない内容も、複雑度も小さくすみますので、ガード句は好んで使って

確かに。
ひとつひとつが完結していますもんね。

--------------------------------------------
ひろえむ さん

>if(String.IsNullOrEmpty(this.Text)) return 0;

ひろえむさんは、上記は書き方は「アリ」でしたね。
僕も、ガード句で、if が続くような場合などは、上記の書き方が好きです。

>ま、戻り値にマジックナンバーはあれですが(^^;;;;

そうですね^^;
サンプルコードは、出来るだけ短くしたいので、0 としたのですが、有識者の方には逆に「?」になってしまいますね。

# re: ガード句 2007/02/20 14:20 とっちゃん

今時のフォームアプリなら、バリデータを使ってというのもありですな。
ということについ先ほど気がついたw

ガード句を入れるのなら、
public static int func( int a, int b )
{
if( b == 0 ) return int.MaxValue;
return a / b;
}
とか
あえて、バリデータを使わずに
private void button1_Click( ... )
{
if( String.IsNullOrEmpty( this.FilePath.Text ) ){
MessageBox.Show( "ファイル名がねーよ!” );
return;
}
if( !File.Exists( this.FilePath.Text ) ){
MessageBox.Show( "ファイルがねーよ!");
return;
}
MessageBox.Show( "/// 工事中 ///\nすんません。ほんとすんません。これから実装です。" );
}
って感じにするくらいかなぁ...w

# re: ガード句 2007/02/20 22:31 RAPT

同じく後者です。
C++でCOMとか使っていると、ネストが深くなりすぎてよく分からなくなります。
後処理が必要なら、ブロックに入れます。(例外は使用していないので。)
do {
if ( !spDispatch ) {
break;
}

CComQIPtr< IHTMLDocument2> spDocument = spDispatch;
if ( !spDocument ) {
break;
}

// TODO: なにか
} while ( false );
// 共通後処理をここに書く。(finally)

# re: ガード句 2007/02/21 11:45 R・田中一郎

とっちゃん

バリデータという言葉を、実は初めて知りました。
早速調べてみます。
ありがとうございました。

--------------------------------------------------
RAPT さん

ネストが深くなるのは、やはり厳しいですよね。
サンプルのコードのような処理は、僕も時々使いますね。
他に、共通処理部分をメソッドアウトしちゃうという手もありますよね。

# re: ガード句 2007/02/21 17:14 シャノン

ご意見頂戴。
ガード句派の人は、ループの時も、

foreach( Item item in collection )
{
 if( item.Hoge )
 {
   何か処理
 }
}

ではなく、

foreach( Item item in collection )
{
 if( ! item.Hoge )
 {
  continue;
 }

 何か処理
}

って書く?
  

# re: ガード句 2007/02/21 17:53 とっちゃん

>ループの時も、
ループ内なら、基本的には前者ですね。<おいら
continue ではなくて break になるなら、後者のパターンもあるけど。

いくつかの条件判定が重なるという場合は、処理しろフラグを設ける場合もあるw
この辺はケースバイケースですね。その程度の速度遅延ならそれこそ、10万回ループとかでもなければ、気にしなくても済む程度の時間差しかないし、C++ だと最適化されてフラグいなくなっちゃうしw

# re: ガード句 2007/02/21 18:39 とっちゃん

>バリデータという言葉を、実は初めて知りました。
おろ?あんまり使わないのかな。
Validator と書けば見たことがあるはずなんだが。。。

# re: ガード句 2007/02/21 22:03 NAL-6295

>ガード句派の人は、ループの時も、

ループの時は、いつもではないですが、
ループの中の処理をメソッドにして、
メソッドの中で、ガード句を使うことがあります。

# re: ガード句 2007/02/22 11:44 R・田中一郎

シャノン さん

僕は前者ですね。
そう言われてみると、continue って、あまり使ってないなぁ・・・

-------------------------------------------------
とっちゃん

>Validator と書けば見たことがあるはずなんだが。。。

あっ、見たことあります^^;
意味がわかったところで、改めてコメント読み直してみました。
なるほど、なるほど。

-------------------------------------------------
NAL-6295 さん

>ループの中の処理をメソッドにして、
>メソッドの中で、ガード句を使うことがあります。

確かに。
僕もこちらの書き方が多いですね。

# re: ガード句 2007/02/23 1:31 RAPT

continue も結構使っています。でも、
>ループの中の処理をメソッドにして、
>メソッドの中で、ガード句を使うことがあります。
の方が使い勝手が良いと思います。

# re: ガード句 2007/02/23 15:59 R・田中一郎

そうですね。
だから、僕も continueって殆ど使わないんですね。(などと客観的に言ってみるテスト)

# re: ガード句 2007/02/23 19:20 とっちゃん

>ループの中の処理をメソッドにして、
>メソッドの中で、ガード句を使うことがあります。

ループの性格にもよるけど、メソッド切り出しはあんまりしないかなぁ...
ループがどのくらいのものかにもよるけど、メソッドを呼ぶというコストはかなり高い。

最も今時のマシンならそこまで意識しなくてもいいんだろうけどwww

# re: ガード句 2007/02/26 13:35 R・田中一郎

>ループがどのくらいのものかにもよるけど、メソッドを呼ぶというコストはかなり高い。

確かに。
汎用的に使いたいものなら、なおさら意識しますよね。
僕の場合は、あまり気にせずに書いてしまって、後でチューニングすればいいや的な・・・^^;

# re: ガード句 2007/02/26 18:56 とっちゃん

>汎用的に使いたいものなら、なおさら意識しますよね。
>僕の場合は、あまり気にせずに書いてしまって、後でチューニングすればいいや的・・・^^;

後にチューニングを必要とするコードは、最初からそれを想定して作ってないと最適化できないです。
最近の開発のトレンド(やれ工業化だとか、やれ再利用だとか)なんて世界とはまったくもって無縁ですからww

どちらかというと組み込みと同じ世界ですよw
バイナリを1バイト削るために...0.1秒速く動くために...
どれだけの先人が命を落としてきたことか<おい!

# re: ガード句 2007/02/27 11:23 R・田中一郎

>どれだけの先人が命を落としてきたことか<おい!

なるほど、とっちゃんの普段の明るさの裏には、そんな悲しい過去があったのですね(ぉぃ)

# hwKzBtaVTsvSb 2011/12/13 17:32 http://www.birthcontrolremedy.com/birth-control/ya

Cool:) I would say say it exploded my brain..!

# UdegTuKrxDeD 2011/12/22 21:42 http://www.discreetpharmacist.com/

Rezygp This article is for professionals..!

# Cheap Oakley Sunglasses 2013/03/17 20:05 http://cheapoakleyfrogskinssunglasses.webs.com/

It is tomorrow that they will have a meeting.What's wrong with you? I went there three days ago.She likes Mike a lot, but she doesn't want to get married so early.Jean is a blue-eyed girl.I'm certain he'll go to see the film, because he's bought a ticket.I'm certain he'll go to see the film, because he's bought a ticket.This is only the first half.The road divides here.I had to sit up all night writing the report.

タイトル  
名前  
Url
コメント