Java
Ruby
Python
JavaScript
参照渡し

なぜ、Java、JavaScript、Python、Ruby等で「参照渡し」の言葉を使うべきではないのか?

私の考える理由はただ一つ「C++、C#、PHP等の『参照渡し』と混同するから」です。

Java、Python、Ruby、JavaScript(ECMAScript)等としていますが、この記事では、それらの代表として主にJavaを取り上げます。しかし、他の言語についても同様のことが言えるため、同じく「参照渡し」の言葉を使うべきではありません。

本当の参照渡しとは?

C++での参照渡しの例です。

#include <iostream>
using namespace std;
void f(int x) {
  x = 1;
}
void g(int &x) {
  x = 2;
}
int main(void) {
  int n = 0;
  cout << n << endl; // => 0
  f(n);
  cout << n << endl; // => 0
  g(n);
  cout << n << endl; // => 2
}

fが値渡し、gが参照渡しです。値渡しでは、仮引数への代入は実引数に何の影響も与えませんが、参照渡しでは、仮引数への代入が実引数そのものへ代入した事になります。参照渡しでは、仮引数は実引数の別名(alias)と見なすこともできます。

混同するとどうしていけないのか?

Javaの参照型の渡し方は「参照渡し」だという説明を受けた人が、C++の参照渡しを見たとき、上のコードを理解できないからです。Javaにおいて、仮引数が参照型であっても、仮引数そのものの代入で実引数を変更することはできません。つまり、C++において参照渡しと言っているものとは全く異なる動作であるということです。それを同じ名称で呼んでしまえば、どちらが正しい動作なのかが理解できなくなります。

なぜ、Javaでも「参照渡し」と呼ぶ人が続出しているのか?

C++でも参照型という表現をします。しかし、Javaの参照型とは「参照」の意味が異なります。C++で「参照」と言った場合「変数1への参照」ですが、Javaで「参照」と言った場合「オブジェクト(の実体)への参照」を表すからです2。この違いを理解せずに、そのまま「参照」という言葉だけが一人歩きした結果、「参照渡し」という言葉を再発明してしまったと考えられます。

言語によって意味が異なってもいいのではないか?

確かに、上記の「参照型」のように、言語やその言語のコミュニティーによって意味が異なる用語というのは存在します。ですが、ほとんどの場合は、誤解を生まないように、根本的な意味は言語間で共通であり、その言語特有の事情によって異なっているに過ぎません。仕様等により厳密に定義されているわけでも無ければ、なるべく言語によらない意味で使用すべきです。そもそも、Javaの参照型の渡し方はC++での参照渡しとは全く異なる動作であり、根本的に共通とも言い難いものです。

それでも、言語が異なるのだから、両方とも「参照渡し」でいいのではないかという人もいるでしょう。その場合は、C#について考えるべきです。C#では、参照型の渡し方はJavaと同じですが、それとは別にC++での参照渡しも可能です。もし、JavaとC++の両方とも「参照渡し」という用語を使うのであれば、C#では異なる渡し方の両方を「参照渡し」と言ってもいいとなってしまいます。かといって、一方を別の呼び方をした場合、同じ動作なのに言語によって名称を変えなければならないとなり、更なる混乱を呼び込み、その動作の理解はさらに難しくなるでしょう。

私は混同しないから、使ってもかまわない。

あなたが良くても、あなたが書いた記事を読んだ人は混同するかも知れません。少なくとも注意書き等が無ければ、何も知らない人は混同すると思います。そのような、人を混乱させるような記事を書くのであれば、あなたには他人に対して説明するような文章を書く能力が無いと言わざるを得ません。

それでも「参照渡し」という言葉を使いたい!

C++、C#、PHP等の言語を生涯使わないことを誓って下さい。あなたが書く記事の最初に「C++、C#、PHP等の別の意味での『参照渡し』がある別言語を生涯使うことがない人以外は読まないでください。」の一文を追加することを推奨します。そうすれば、あなたも、あなたの記事を呼んだ人も、混同することは永遠に無いでしょう。

Javaが正しくC++が間違っている。正すべきはC++だ。

C++での参照渡しの概念は古く、少なくともFORTRAN IIまでは遡れます。ただ、当時から「参照渡し」と呼ばれていたかは不明ですが、少なくとも、最初のC++ができる頃には「値渡し」と区別するためにも「参照渡し」の言葉はあったと思われます。Javaができたのはその10年以上後になります。言葉というのは最初に呼んだ人の勝ちです。以前からあった言葉の意味を変えるのは難しく、そちらを別の呼び方に変えるというのは厳しいでしょう。

ただ、言葉というのは移り変わりが激しいものですので、頑張って啓蒙すれば、10年後ぐらいには意味が変わっている可能性はあります。私は応援しませんし、賛同もしませんので、勝手に頑張ってください。

では、何という言葉を使えばいいのか?

私は主に「参照の値渡し」や「共有渡し」と呼んでいますが、本当にこれでいいのかどうかはわかりません。teratailで質問をしたのですが、あまり回答が集まらなかったです。もし、こう呼ぶべきという意見をお持ちであれば、ぜひ、下記質問に回答をお願いします。もちろん、それでも「参照渡し」と呼ぶべきと言う回答でもかまいません。

オブジェクトを共有できる形で渡す(呼ぶ)評価戦略の名称

参考: もう参照渡しとは言わせない


  1. 正確には左辺値への参照です。また、C++11以降は右辺値参照というまた別の「参照」があります。 

  2. Javaの参照型はC++のポインター型に近いです。変数に入るのは「参照」ではなく「参照値」であることからも、実際の値であるポインターと近い物があります。対して、C++の「参照」は変数にポインターのような値が入ることを意味するものではありません。