戻り文

コンピュータプログラミングにおいて、return文実行を現在のサブルーチンから離脱させ、サブルーチンを呼び出した命令の直後のコード位置(戻りアドレス)から再開します。戻りアドレスは呼び出し元ルーチンによって保存され、現在は通常、プロセスコールスタックまたはレジスタに保存されます。多くのプログラミング言語のreturn文では、関数を呼び出したコードに返す戻り値を指定できます。

概要

CおよびC++において、(は式は関数にプログラムの実行を呼び出し元の関数に戻し、 の値を報告するよう指示するです。関数の戻り値の型がvoidの場合、return文は値なしで使用できます。その場合、プログラムは現在の関数から抜け出し、呼び出し元の関数に戻ります。[ 1 ] [ 2 ]同様の構文は、 Modula-2 [ 3 ]Python [ 4 ]などの他の言語でも使用されています。return exp;expexp

Pascalにはreturn文はありません。関数や手続きは、最後の文に到達すると自動的に戻ります。関数からの戻り値は、関数名と同じ名前の識別子への代入によって関数内で提供されます。[ 5 ]しかし、Pascalの一部のバージョンでは、関数から即座に値を返したり、引数なしで手続きから即座に値を返したりするための特別な関数が提供されています。 [ 6 ]Exit(exp);

Pascalと同様に、FORTRAN IIFortran 66Fortran 77、およびそれ以降のバージョンのFortranでは、関数名への代入によって戻り値を指定しますが、return文も持っています。この文は戻り値を指定せず、関数の場合は関数名に割り当てられた値を返します。[ 5 ] [ 7 ] [ 8 ]

他の言語では関数識別子の代わりにユーザー定義の出力パラメータが使用される。 [ 9 ]

OberonOberon-07)では、return文の代わりにreturn節が採用されています。return節は、手続き本体の最後の文の後に配置されます。[ 10 ]

LispPerlRubyなどの式指向プログラミング言語では、明示的なreturn文を省略し、代わりに最後に評価された式をサブルーチンの戻り値として指定することができます。それ以外の場合、明示的なreturn文がない場合はNull値が返されます。Pythonではreturn文が省略された場合に値が返されますが[ 4 ] 、 JavaScriptでは値が返されます。 Noneundefined

Windows PowerShellでは、キャプチャされないすべての評価済み式 (変数への代入、voidへのキャスト、または$nullへのパイプなど) は、サブルーチンから配列内の要素として返されます。キャプチャされていないオブジェクトが 1 つだけの場合は、単一のオブジェクトとして返されます。

Perl では、サブルーチンの戻り値は、呼び出されたコンテキストによって異なります。最も基本的な違いは、呼び出しコードが 1 つの値を期待するスカラーコンテキスト、呼び出しコードが値のリストを期待するリストコンテキスト、呼び出しコードが戻り値をまったく期待しないvoidwantarrayコンテキストです。サブルーチンは関数を使用してコンテキストを確認できます。引数なしの return という特別な構文は、スカラーコンテキストでは未定義値を返し、リストコンテキストでは空のリストを返します。スカラーコンテキストは、ブール値、数値、文字列、およびさまざまな参照型のコンテキストにさらに分類できます。また、コンテキスト依存のオブジェクトは、スカラー値の遅延評価を伴うコンテキスト戻りシーケンスを使用して返すことができます。

多くのオペレーティングシステムでは、プログラムがプロセス終了時に(通常の出力とは別に)結果を返すことができます。これらの値は終了ステータスと呼ばれます。この方法で渡せる情報量は非常に限られており、実際には成功または失敗の通知のみに限定されることがよくあります。プログラム内からこの戻り値を返すには、通常、Exit(システムコール)を呼び出す必要があります(C言語でも一般的で、C言語ではメイン関数から戻るという代替メカニズムが利用可能です)。

構文

return文には様々な形式があります。最も一般的な構文は次のとおりです。

言語 戻り文 値が省略された場合は、
AdaBourne shell[ a ] CC++JavaPHPC#JavaScriptD
戻り;
Bourneシェルでは、関数内で最後に実行されたコマンドの終了値

C [ 1 ]およびC++ [ 2 ] では、関数が値を返す場合の 未定義の動作

PHPでは、[ 12 ]NULL

Javascriptでは、[ 13 ]は値を返すundefined

JavaおよびC#では、関数が値を返す場合は許可されません

ベーシック
戻る
Lisp
戻り
最後のステートメントの値
PerlRuby
@valuesを返します$valueを返します戻り値:

または文脈的な戻りシーケンス

最後のステートメントの値
PL/I
return(式); 戻る; 
プロシージャが値を返すように宣言されている場合、 未定義の動作が発生します
パイソン
戻り
None[ 4 ]
雑談
^
Tcl
return return $value return - code error "エラーメッセージ"

あるいはより複雑なオプションの組み合わせ

最後のステートメントの値
ビジュアルベーシック.NET
戻り
Windows PowerShell
戻り;
物体
x86アセンブリ
ret
eaxレジスタの内容(慣例による)

一部のアセンブリ言語、たとえばMOS Technology 6502のアセンブリ言語では、ニーモニック「RTS」(ReTurn from Subroutine) が使用されます。

複数の return 文

明示的な return 文を持つ言語では、同じ関数内に複数の return 文が存在する可能性があります。これが良いことかどうかは議論の余地があります。

構造化プログラミングの熱心な支持者は、各関数が単一の入口と単一の出口を持つことを確実にします(SESE)。そのため、サブルーチンのテキスト末尾以外では明示的なreturn文の使用は避けるべきだと主張されています[ 14 ]。これは、return文を「早期復帰」のために使用すると、GOTO文で発生するのと同じ種類の問題が発生する可能性があるためです。逆に、return文の使用によって、より深いネストなど、より複雑なコードになり、可読性が損なわれる可能性がある場合は、return文を使用する価値があると主張することもできます。

2004年の教科書で、デイビッド・ワットは「単一エントリ・マルチエグジット制御フローはしばしば望ましい」と述べている。テネントのシーケンサというフレームワーク概念を用いて、ワットは現代のプログラミング言語に見られる制御フロー構造を統一的に記述し、マルチエグジット制御フローの文脈において、特定の種類のシーケンサが他のシーケンサよりも優れている理由を説明しようとしている。ワットは、制限のないgoto(ジャンプシーケンサ)は、プログラムの読者がジャンプのターゲットとなる実際のラベルまたはアドレスを見つけて調べるまで、ジャンプ先が自明ではないため、好ましくない、と述べている。対照的に、リターンシーケンサの概念的な意図は、その先を調べなくても、それ自体の文脈から明らかである、とワットは主張する。さらにワットは、 「テキストで囲まれたコマンドまたはプロシージャの実行を終了するシーケンサ」と定義されるエスケープシーケンサと呼ばれるシーケンサのクラスは、ループからのブレーク(マルチレベルブレークを含む)とreturn文の両方を包含すると述べている。ワットはまた、ジャンプシーケンサ(goto)はC言語のような言語では、ターゲットがローカルブロック内かその外側のブロック内に限られるなど、ある程度の制限があるものの、その制限だけではC言語のgotoの意図を自己記述的にするには不十分であり、依然として「スパゲッティコード」が生成されると指摘している。ワットはまた、例外シーケンサがエスケープシーケンサやジャンプシーケンサとどのように異なるかについても考察している。詳細については、構造化プログラミングに関する記事を参照のこと。[ 15 ]

エリック・S・ロバーツが引用した実証研究によると、学生プログラマーは、複数の終了点を許さないPascalのような言語では、いくつかの単純な問題に対して正しい解を導き出すのに苦労した。配列内の要素を線形検索する関数を書く問題に関して、ヘンリー・シャピロによる1980年の研究(ロバーツが引用)では、Pascalが提供する制御構造のみを用いた場合、被験者のわずか20%しか正しい解を導き出せなかったのに対し、ループの途中からreturn文を記述できる場合、この問題に対して誤ったコードを書いた被験者はいなかったことが明らかになった。[ 16 ]

ケント・ベックマーティン・ファウラーなどの研究者は、関数の先頭近くにある1つ以上のガード句(条件付きの「早期終了」戻り文)が、他の方法よりも関数を読みやすくすると主張している。[ 17 ] [ 18 ] [ 19 ] [ 20 ]

早期終了における最も一般的な問題は、クリーンアップ文や最終文が実行されないことです。例えば、割り当てられたメモリが解放されていない、あるいは開いているファイルが閉じられていないなど、リークが発生します。これらの処理は各戻り先で実行する必要があるため、脆弱性があり、簡単にバグが発生する可能性があります。例えば、後続の開発段階で開発者がreturn文を見落とし、サブルーチンの終了時に実行されるべきアクション(例えばtrace文)が必ずしも実行されない可能性があります。標準のPascalなど、return文のない言語ではこの問題は発生しません。C++やPythonなどの一部の言語では、戻り時(または例外スロー時)に自動的にアクションを実行するという概念が採用されており、これらの問題の一部を軽減しています。これらは「try/finally」などと呼ばれることがよくあります。これらの「finally」節のような機能は、サブルーチンの単一の戻り先へのgoto文によって実装できます。別の解決策としては、関数の終了時に通常のスタック アンワインド (変数の割り当て解除) を使用して、ローカル変数のデストラクタなど、または Python の "with" ステートメントなどの同様のメカニズムを使用してリソースの割り当てを解除します。

オリジナルの Pascal や C などの言語の初期の実装では、コンパイラを簡素化するために、関数によって返される型が制限されていました (レコード型構造体型をサポートしないなど) 。

Java 、およびJavaScriptのようなJavaをモデルにした類似言語では、 try-catch構造finallyブロックが常に実行されるため、return文の後でもコードを実行することが可能です。したがって、tryブロックまたはcatchブロック内にreturn文が記述されている場合、 finallyブロック内のコード(追加されている場合)が実行されます。また、exitも後から実行されるため、非プリミティブ型(既に返されたオブジェクトのプロパティ)の戻り値を変更することも可能です。[ 21 ]

利回り明細書

return文の類似文にyield文があります。return文はサブルーチンを終了させ、yield文はコルーチンを一時停止させます。コルーチンは、後で再度呼び出された場合、一時停止したところから再開されます。コルーチンの実装はサブルーチンよりもはるかに複雑であるため、yield文はreturn文ほど一般的ではありませんが、多くの言語で使用されています。

呼び出し/戻りシーケンス

ハードウェア命令セットに応じて、次のようなさまざまな呼び出し/戻りシーケンスが可能です。

  1. この命令は、次のCALL命令のアドレスをスタックにプッシュし、指定されたアドレスに分岐します。この命令は、スタックから戻りアドレスを命令ポインタにポップし、そのアドレスから実行を再開します。(例: x86PDP-11 ) Motorola 96000などのアーキテクチャでは、スタック領域は、メインメモリのアドレス空間とは別に、スタックメモリ空間と呼ばれる別のアドレス空間に割り当てられる場合があります。[ 22 ] NEC μPD7720も独自のアドレス空間を持つスタックを備えています[ 24 ]RETURN
  2. この命令は、次のCALL命令のアドレスをレジスタに格納し、指定されたアドレスへ分岐します。命令シーケンスは、レジスタからの戻りアドレスを命令ポインタに格納し、そのアドレスから実行を再開します。(例:IBM System/360およびz/Architectureを介した後継機種、ほとんどのRISCアーキテクチャ)RETURN
  3. この命令は、呼び出しアドレスの記憶領域に次の(または現在のCALL)命令のアドレスを格納し、指定されたアドレス+1に分岐します。命令シーケンスは、サブルーチンの最初の命令への間接ジャンプによって戻りアドレスに分岐します。(例: IBM 1130SDS 9XXPDP-8RETURN

参照

注記

  1. ^ Bourneシェルでは、0~255の範囲の整数のみが返される可能性がある[ 11 ]

参考文献

  1. ^ a b「return ステートメント (C)」Microsoft Docs。2023年1月25日。
  2. ^ a b「return ステートメント (C++)」Microsoft Docs。2021年8月3日。
  3. ^ Gleaves, R. (2012). Modula-2 for Pascal Programmers . Springer. p. 71. ISBN 9781461385318
  4. ^ a b c Martelli, Alex (2006). Python in a Nutshell: A Desktop Quick Reference (第2版). O'Reilly Media. p. 73. ISBN 9781449379100
  5. ^ a bスコット、マイケル・L. (2006).プログラミング言語語用論. モーガン・カウフマン. p. 432. ISBN 9780126339512
  6. ^フランダース、ハーレー (2012). Scientific Pascal . シュプリンガー. p. 35. ISBN 9781461224280
  7. ^ ANSI x3.9-1966. USA Standard FORTRAN (PDF) . American National Standards Institute. p. 14. 2011年5月15日時点のオリジナル(PDF)からアーカイブ。 2010年5月5日閲覧{{cite book}}: CS1 maint: 数値名: 著者リスト (リンク)
  8. ^ ANSI x3.9-1978.米国規格 - プログラミング言語 FORTRAN . 米国規格協会. 15.8 RETURN文. 2013年10月29日時点のオリジナルよりアーカイブ2007年12月11日閲覧。{{cite book}}: CS1 maint: 数値名: 著者リスト (リンク)
  9. ^ Sakkinen, Markku (1989年3月). 「関数の値を最もよく返す方法」 . ACM SIGPLAN Notices . 24 (3). Association for Computing Machinery: 55–56 . doi : 10.1145/66083.66087 .
  10. ^ Wirth, Niklaus (2016年5月3日). 「10. 手続き宣言」.プログラミング言語Oberon (PDF) (レポート). p. 11.
  11. ^ 「return - 関数またはドットスクリプトからの戻り値」。Single UNIX Specification
  12. ^ 「PHP: return - マニュアル」 . PHPマニュアル. PHPグループ. 2013年3月26日閲覧
  13. ^ 「Return - Javascript」 . MDN Javascriptリファレンス. Mozilla Developer Network . 2013年3月27日閲覧
  14. ^ Swartz, Fred. 「C++ Notes: Function return Statement」 . 2007年1月3日時点のオリジナルよりアーカイブ
  15. ^ Watt, David Anthony; Findlay, William (2004). 『プログラミング言語設計コンセプト』 John Wiley & Sons. pp.  215– 221. ISBN 978-0-470-85320-7
  16. ^ Roberts, E. (1995年3月). 「ループ終了と構造化プログラミング:議論の再開」 . ACM SIGCSE Bulletin . 27 (1): 268– 272. doi : 10.1145/199691.199815 .
  17. ^マーティン・ファウラー、ケント・ベック、ジョン・ブラント、ウィリアム・オプダイク、ドン・ロバーツ (2012). 『リファクタリング:既存コードの設計改善』(Google eBook) . アディソン・ウェズリー. pp. 237, 250. ISBN 9780133065268. ... 1 つの終了ポイントの考え方 ... 私はメソッドからの 1 つの終了ポイントに関するルールに従いません。
  18. ^ Kent Beck (2007). 「7: 動作」.実装パターン. ピアソン・エデュケーション. 「ガード条項」セクション. ISBN 9780132702553
  19. ^ 「複数のreturn文」。Javaプラクティス
  20. ^ Fred Swartz. 「Returnステートメントと単一の出口幻想」 。2020年2月23日時点のオリジナルよりアーカイブ
  21. ^ 「finallyブロック」。Javaチュートリアル
  22. ^ 「DSP96002 32ビットデジタルシグナルプロセッサ ユーザーズマニュアル」(PDF) p. 3-4 。 2023年12月24日閲覧
  23. ^ 「DSP96002 32ビットデジタルシグナルプロセッサ ユーザーズマニュアル」(PDF) p. 4-11 。 2023年12月24日閲覧
  24. ^ 「μPD77C20A、7720A、77P20デジタルシグナルプロセッサ」 p. 3a-4 。 2023年12月25日閲覧