早めのreturn

例えば、C言語で

int foo()
{
  int ret;
  if (bar()) {
    /* (行数的に)短い処理 */
    ret = 1;
  }
  else {
    /* (行数的に)長い処理 */
    ret = 0;
  }
  return ret;
}

こんな風な書き方をする人と、

int foo()
{
  if (bar()) {
    /* 短い処理 */
    return 1;
  }
  /* 長い処理 */
  return 0;
}

こんな風な書き方をする人、どちらが多いんでしょうか。
私は早めにreturnで関数を抜ける方が読み易いし、
長い処理のネストが一段浅くなるので、後者の方を好んで使いますが、
一部業界では「関数にreturnは1個しか書けない」という謎の規約があるため、
前者のような書き方を強要されるそうです。
Common Lispでも同様に

(defun foo ()
  (cond ((bar)
    ;短い処理
    1)
  (t
    ;長い処理
    0)));

のような書き方をするか、

(defun foo ()
  (when (bar)
    ;短い処理
    (return-from foo 1))
  ;長い処理
  0)

のような書き方をするか選べます。私はこれも後者を好んで使います。
けど、Lispの入門書ではこのようにreturn-fromを使ってるのをあまり見ない気がします。
Schemeだとreturnがないのでcall/ccを使うことになります。

(define (foo)
  (call/cc
    (lambda (ret)
      (if (bar)
        (begin
          ;短い処理
          (ret 1)))
      ;長い処理
      0)))

ただ、この書き方だと結局ネストが深くなってしまうので、
引数として継続を受け取った方が自然かもしれません。

(define (foo ret)
  (if (bar)
    (begin
      ;短い処理
      (ret 1)))
  ;長い処理
  0)
(call/cc foo)

Schemeのcall/ccを利用した早めのreturnも好きなんですが、
その目的のためだけにcall/ccはちょっと重たいかもしれません。
脱出専用なので、処理系がどうにかして効率のいい実行をしてくれないのかな。

3 Responses to “早めのreturn”

  1. yabai より:

    私の会社ではreturn1つです。さらに出向かい先ではバラバラです。do, while(0)で囲んでretにエラーコード入れて途中でbreakで抜けたりすることも。LispやSchemeの場合規約はあるんでしょか

  2. zick より:

    > do, while(0)で囲んでretにエラーコード入れて途中でbreakで抜けたり
    やっぱり、苦労されてるんですね。
    ちょっと違う話ですが、
    PostScriptにはswitch-caseに相当する構文がなく、
    if-elseで書くとネストが非常に深くなるので、
    loopの中でifを書いてbreakした覚えがあります。
    > LispやSchemeの場合規約はあるんでしょか
    それは仕事でLispを書いてる人に聞いてみないと分かりません(笑)

  3. どようび より:

    途中returnはfreeとかのし忘れが怖いので、自分はreturnの代わりにgoto文で関数の最後に飛ばすかC++に逃げることが多いです。

Leave a Reply