- PR -

VBでcontinueの代わりって…

投稿者投稿内容
菊池
会議室デビュー日: 2004/11/15
投稿数: 19
投稿日時: 2005-01-21 00:01
最初に極論を

んー、continue 程度で見通しが悪いというなら else も却下するべきだな。
elseもelse blockに飛び込むためのラベルでしょ。
長大でわけわかめなループ書いてるからcontinueがgotoに見えるだけだと思う。

んで穏当なのを後に

ループ内のコードを関数として抽出しましょう。
break にしても continueにしてもreturn 値で何を返すかで制御できます。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2005-01-21 08:56
unibon です。こんにちわ。

見方によっては continue のほうが break(VB では Exit Do/For) よりも簡素だと思います。なぜなら、for や while ループの場合だと、continue はそれ以降をスキップするがループは抜けずに続行する、けど、break はそれに加えてループを抜ける、という機能があるとも言えるからです。だから、break は使って良いのなら continue を使うのをためらう必要はないのではないでしょうか。

また、goto が悪いのは、
(1) プログラムの見通しが悪くなる。
(2) 縦横無尽に動き回るような goto があると、変数のスコープ等の扱いが複雑になる。コンパイラーの負担になる。
という2つの理由があるかなと思います。しかし (2) がない範囲なら、貧弱な制御文を補うために goto を使うのもそれほど悪くないと思います。しかし、一旦、使い出すと、禁酒・禁煙が難しいようなもので、とりとめがなくなる恐れがなるので、だからやっぱり使うのは全面的に避けるか、決めたルールの範囲内だけで使うようにしたほうが良いでしょう。
なお(1)についてですが、順方向(forward 方向)と逆方向(backward 方向)も、複雑さが違うかなと思います。逆方向の複雑さに比べれば、順方向の goto はわりと見やすいです。
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2005-01-21 12:08
ぼのぼのです。

引用:

じゃんぬねっとさんの書き込み (2005-01-20 14:44) より:
私は、C でも Java でも continue を使わない派 (^-^

たつごろーさんの書き込み (2005-01-20 15:20) より:
たしかにめったにつかわなければならないような状態にはなりませんしね。


ふと思ったんですが、「continue使いたい人=ブロックのネストが深くなることをやたらと忌み嫌う傾向がある人」なんでしょうか?かく言う私もそのひとり。実は私にとってcontinueを使うことの最大のメリットは、それ以降の処理のブロックの深さを1つ浅くできることにあります。

そしてそんな「ブロックのネストが深くなることをやたらと忌み嫌う傾向がある人」は、サブルーチン化しても同じことをやります。つまり、飛ばしていいケース(例えば文字列チェック系で入力文字列が空文字の時とか)では容赦なく関数の冒頭でreturnします。

昔読んだなんかの参考書で、「読み易い関数を書きたければ出口はひとつにしろ。出口をたくさん作るな」と書かれていたのですが、私にとって読み易いコードを書くための優先順位は「ブロックのネストが浅いこと」の方が「出口が少ないこと」より高いので、ブロックのネストを浅くするためなら容赦なくreturnします。絶対実行しなきゃならない後処理があるならFinallyブロックに書いとけばいいわけですし。

#まぁreturnは「この条件の時はここで終わり」という明確な意思表示にもなるため、
#浅くすることが目的の全てではないのですが…

そして、continueの代替手段として最もネストの深さに影響を与えないのはgotoなんですが、じゃあなんでgotoが嫌かというと、一つの関数内に複数のループがあったら、ループの数だけ異なるラベルを用意しなければならないから。以下のようなコードで、「もしGoto LOOP_END1と書かなければならないところを間違えてLOOP_END2と書いてしまったら…」とか考えてしまうと、やっぱ精神衛生上良くないですよね。

コード:

For i = 1 To 10
    If cond1 Then Goto LOOP_END1
    '中略
    For j = 1 To 10
        If cond2 Then Goto LOOP_END2
        '中略
    LOOP_END2:Next
LOOP_END1:Next

For i = 1 To 10
    If cond3 Then Goto LOOP_END3
    '中略
LOOP_END3:Next


最後に、変な例えかもしれませんが…

「ろうそくに火をつけたい。マッチと火炎放射器なら持っている。
マッチは燃えがらを捨てるのがめんどくさいけど、火炎放射器は… ああ、ライターがあればいいのになぁ。」
菊池
会議室デビュー日: 2004/11/15
投稿数: 19
投稿日時: 2005-01-21 14:57
引用:

そしてそんな「ブロックのネストが深くなることをやたらと忌み嫌う傾向がある人」は、サブルーチン化しても同じことをやります。つまり、飛ばしていいケース(例えば文字列チェック系で入力文字列が空文字の時とか)では容赦なく関数の冒頭でreturnします。



 いわゆるガード句ですね。
 私もガード句をよく使います。

引用:

昔読んだなんかの参考書で、「読み易い関数を書きたければ出口はひとつにしろ。出口をたくさん作るな」と書かれていたのですが、私にとって読み易いコードを書くための優先順位は「ブロックのネストが浅いこと」の方が「出口が少ないこと」より高いので、ブロックのネストを浅くするためなら容赦なくreturnします。絶対実行しなきゃならない後処理があるならFinallyブロックに書いとけばいいわけですし。



 その参考書は構造化プログラミングを変な解釈してますね。
 どんな関数でも出口を通り抜けた結果は「呼び出し元」の一箇所です。
 関数の中で無理やり変形しようがしまいが結果は一緒なので returnはいくつ書いても入り口ひとつの出口ひとつの原則を崩しません。

 で、ガード句に話を戻しますが、ガード句は続くコードを読む(書く)ときに意識しないですむ状況の列挙になります。コードが意識する状況が減れば減るほどコードは簡単になり理解しやすくなります。
 ネストが減るという見かけでなく、状況を制約する事で本質的にコードは簡単になるのです。
 このメリットと制御パスに多少の操作を加える事のデメリットを天秤に載せて検討して必要であれば何でも使えばいいと思います。

 continue が必要な部分はほとんど抽出操作ですのでGenericsが普通になればFindAllの中にcontinueは隠れてしまうと思います。
たつごろー
ぬし
会議室デビュー日: 2004/10/25
投稿数: 496
投稿日時: 2005-01-24 11:19
> 容赦なく関数の冒頭でreturn
うわっ。
心を読まれてる。

_________________
たつごろー
codeseek
こみゅぷらす
skulker
ベテラン
会議室デビュー日: 2004/06/08
投稿数: 67
投稿日時: 2005-01-24 11:29
引用:

菊池さんの書き込み (2005-01-21 14:57) より:
引用:

昔読んだなんかの参考書で、「読み易い関数を書きたければ出口はひとつにしろ。出口をたくさん作るな」と書かれていたのですが、私にとって読み易いコードを書くための優先順位は「ブロックのネストが浅いこと」の方が「出口が少ないこと」より高いので、ブロックのネストを浅くするためなら容赦なくreturnします。絶対実行しなきゃならない後処理があるならFinallyブロックに書いとけばいいわけですし。



 その参考書は構造化プログラミングを変な解釈してますね。
 どんな関数でも出口を通り抜けた結果は「呼び出し元」の一箇所です。
 関数の中で無理やり変形しようがしまいが結果は一緒なので returnはいくつ書いても入り口ひとつの出口ひとつの原則を崩しません。


それこそ詭弁。構造化プログラミングを曲解しているような。
関数に限らず、ブロックの入口も出口も一つの方が読みやすい。

この手のルールはいつ破るかの見極めが大切ですが。
Moo
大ベテラン
会議室デビュー日: 2004/04/12
投稿数: 118
お住まい・勤務地: 地球・港
投稿日時: 2005-01-24 12:23
たつごろーさん
>> 容赦なく関数の冒頭でreturn
>うわっ。
>心を読まれてる。

今まさに書いていたのですがまったくかぶったので。
処理するための前提条件をクリアしていないのに
そのロジックに入っていっても無駄ですよね。

テストケースについても無駄に多くなりますし。
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2005-01-24 13:17
>skulkerさん
自分の中で消化しきれてないので確認させてください。
「関数に限らず、ブロックの入口も出口も一つの方が読みやすい。」とは、下記の@よりAの方が読み易いということでしょうか?
コード:
'@
Public Shared Function ConvertDBStr(ByVal obj As Object) As String
    If IsDBNull(obj) Or IsNothing(obj) Then
        Return ""
    End If
    Return CStr(obj)
End Function

'A
Public Shared Function ConvertDBStr(ByVal obj As Object) As String
    Dim retval As String
    If IsDBNull(obj) Or IsNothing(obj) Then
        retval = ""
    Else
        retval = CStr(obj)
    End If
    Return retval
End Function


そういう意味ではないよ、ということならごめんなさいです。でも、その通りだというなら意義ありです…

スキルアップ/キャリアアップ(JOB@IT)