「参照渡し」まとめ

以前に「参照渡し (call by reference)」と言う言葉の使われ方の歴史が気になったので調べた事がありました.以下は,そのメモです.

Pascal

Pascal では,値渡し (call by value) と参照渡しの両方が存在します.ただし,Pascal では「参照渡し」と言う言葉が使われる事はなく変数渡し (call by variable) と呼ばれるのが一般的なようです.

仮引数仕様を書く場合に,予約語 var をつける場合とつけない場合とで仮引数の機能が異なる.var をつけた仮引数は,手続き本体では与えられた実引数そのものを表わす.このような引数を変数引数 (variable parameter) と言う.
・・・(中略)・・・
一方,仮引数に var をつけない場合は,その仮引数と対応する実引数は別のもので,仮引数の値を変更しても実引数の側には何の影響もない.手続き呼出しの際に,実引数を評価した値が仮引数の初期値として代入されてから手続き本体の実行が始まる.このような引数を値引数という.

基礎 PASCAL

「変数渡し (call by variable)」と「参照渡し (call by reference)」はどう違うのだろうと気になって調べたところ,Wikipedia で下記のような記述を見つけました.

変数渡し(へんすうわたし、call by variable)は、変数そのもの(左辺値)を渡す方法で、この場合は仮引数に対する操作がそのまま実引数(渡された変数)に影響する。

参照渡し(さんしょうわたし、call by reference)はその実装手段の一つで、変数に対する参照(アドレス情報)を渡す方法である。(これは言語側が勝手に行う。Cのように明示的にアドレス演算子を使うものは参照渡しとは呼ばない。)その他、値渡しと同じようにコピーを渡しておいて、関数/サブルーチンからのリターン時に元の変数に変更結果をコピーしなおす方法もある。PL/Iでは、どちらの方法で実装しても良いと規定されている。

引数 - Wikipedia

「参照渡し (call by reference)」と言う言葉を最初に使うようになったプログラミング言語を探そうと持ったのですが,これはよく分かりませんでした.K&R を読むと Fortran なのかなと言う気もしますが確証はありません.

C

C では全ての引数は値渡しです.これは K&R にもはっきりと明記されていました.

Cでは、すべての関数の引数が“値で”受渡しされる。
・・・(中略)・・・
Fortranのような“call by reference(参照による呼び出し)”の言語やPascalのvarパラメータとは、Cの性質は違ったものになっている。おもな違いは、Cでは、呼ばれた関数が呼んだほうの変数を変えることはできないという点にある。

プログラミング言語 C

それにも関わらず「C は参照渡しもできる」のような記述はしばしば目にします.気になったので,近くの書店で並べられていた C の入門書を 5冊ほど確かめてみたのですが,何の注釈もなく「参照渡し」と言う言葉を使っている本が 1冊ありました(残りは,2冊が「参照渡しのようなもの」と言う微妙な言い回しで,2冊が「参照渡し」と言う言葉を使わずに説明していた).

問題となっているのはいずれも「関数の引数にポインタが指定された場合の動作」を説明する部分でした.これは,いくつかの理由がありそうですが,その中の一つに「C では参照演算子(&) や逆参照演算子(*,もしくは間接参照演算子)と言う言葉があるために(参考:Pointers - C++ Tutorials),筆者自身も混同してしまっている」と言うものがあるような気もしました.

この点に関しては,私自身も C++ で参照型を知るまでは関数の引数にポインタを指定する事を参照渡しと呼ぶと誤解していました(Pascal の変数渡しと区別しているんだなと言う勘違いが,さらにこの誤解を大きくしていた).

Java

Java も全ての関数(メソッド)の引数は値渡しされます.ネイティブ型以外のクラス変数を関数の引数に指定する事は,C のポインタを指定する形に近いようです(Java ではポインタではなく「参照」と呼ばれている模様).しかし,Java は参照(C のポインタに近いもの)からの逆参照をそうとは気づきにくいように構文を工夫しているため,「参照渡しをしている」と言う誤解を抱きがちになります.

参照型は参照渡しとは無関係で、C や C++ の知識があるなら、むしろ「メンバに .(ドット) でアクセスするポインタ型*3」と考えた方が分かりやすい*4。

*3:ただしポインタ演算はできない
*4:ちなみに、C++ の「参照」とは全くの中別物なので注意が必要

値渡しと参照渡し (と参照の値渡し) - ぐるぐる~

これは私自身もつい最近まで誤解しており,気をつけないと誤解しやすい部分の一つだろうと思います.ちなみに,ここを誤解すると「Java はネイティブ型のみ値渡しである」と言う誤解も同時に持つ事となり,Java の関数(メソッド)への理解を妨げる一因となります.

C++

C++ では「参照」(型の最後に&を付ける)と呼ばれるものが追加されました.そして,関数の引数に参照を指定する事によって「参照渡し」が可能となりました.

前述しましたが,私はここで初めて「参照渡し」への誤解に気づきました.関数の引数にポインタを指定する場合と参照を指定する場合とでは扱い方が異なるのに同じ「参照渡し」と呼ぶのは何かおかしい・・・と.

C#

C# では予約語 ref (out も?)が導入され,C++ と同様に「参照渡し」も可能となったようです.構文は参照渡しを行いたい型の前に ref (または out)を記述するといったもので,構文的にはどちらかと言うと Pascal に近いと言う印象です(ただし,実引数の前にも ref (または out)が必要).

感想

「参照」と言う言葉が様々な言語で様々な意味を持ってしまっているため,「参照渡し」に限らず「参照」と言う名の付く言葉は注意深く読まないと誤解しやすいと言う印象を持ちました.「参照」と言う単語が出てきたときには注意したいものです.