What's the difference between passing by reference vs. passing by value? Ask Question

What's the difference between passing by reference vs. passing by value? Ask Question

What does it mean to say that a parameter is passed "by reference" or "by value"? How do such parameters differ?

ベストアンサー1

First and foremost, the "pass by value vs. pass by reference" distinction as defined in the CS theory is now obsolete because the technique originally defined as "pass by reference" has since fallen out of favor and is seldom used now.1

Newer languages2 tend to use a different (but similar) pair of techniques to achieve the same effects (see below) which is the primary source of confusion.

A secondary source of confusion is the fact that in "pass by reference", "reference" has a narrower meaning than the general term "reference" (because the phrase predates it).


Now, the authentic definition is:

  • When a parameter is passed by reference, the caller and the callee use the same variable for the parameter. If the callee modifies the parameter variable, the effect is visible to the caller's variable.

  • When a parameter is passed by value, the caller and callee have two independent variables with the same value. If the callee modifies the parameter variable, the effect is not visible to the caller.

Things to note in this definition are:

  • "Variable" here means the caller's (local or global) variable itself -- i.e. if I pass a local variable by reference and assign to it, I'll change the caller's variable itself, not e.g. whatever it is pointing to if it's a pointer.

    • This is now considered bad practice (as an implicit dependency). As such, virtually all newer languages are exclusively, or almost exclusively pass-by-value. Pass-by-reference is now chiefly used in the form of "output/input arguments" in languages where a function cannot return more than one value.
  • The meaning of "reference" in "pass by reference". The difference with the general "reference" term is that this "reference" is temporary and implicit. What the callee gets is a "variable" that is somehow "the same" as the original one. How specifically this effect is achieved is irrelevant (e.g. the language may also expose some implementation details -- addresses, pointers, dereferencing -- this is all irrelevant; if the net effect is this, it's pass-by-reference).


Now, in modern languages, variables tend to be of "reference types" (another concept invented later than "pass by reference" and inspired by it), i.e. the actual object data is stored separately somewhere (usually, on the heap), and only "references" to it are ever held in variables and passed as parameters.3

Passing such a reference falls under pass-by-value because a variable's value is technically the reference itself, not the referred object. However, the net effect on the program can be the same as either pass-by-value or pass-by-reference:

  • If a reference is just taken from a caller's variable and passed as an argument, this has the same effect as pass-by-reference: if the referred object is mutated in the callee, the caller will see the change.
    • However, if a variable holding this reference is reassigned, it will stop pointing to that object, so any further operations on this variable will instead affect whatever it is pointing to now.
  • To have the same effect as pass-by-value, a copy of the object is made at some point. Options include:
    • The caller can just make a private copy before the call and give the callee a reference to that instead.
    • In some languages, some object types are "immutable": any operation on them that seems to alter the value creates a completely new object without affecting the original one. So, passing an object of such a type as an argument always has the effect of pass-by-value: a copy for the callee will be made automatically if and when it needs a change, and the caller's object will never be affected.
      • In functional languages, all objects are immutable.

As you may see, this pair of techniques is almost the same as those in the definition, only with a level of indirection: just replace "variable" with "referenced object".

There's no agreed-upon name for them, which leads to contorted explanations like "call by value where the value is a reference". In 1975, Barbara Liskov suggested the term "call-by-object-sharing" (or sometimes just "call-by-sharing") though it never quite caught on. Moreover, neither of these phrases draws a parallel with the original pair. No wonder the old terms ended up being reused in the absence of anything better, leading to confusion.4

(I would use the terms "new" or "indirect" pass-by-value/pass-by-reference for the new techniques.)


NOTE: For a long time, this answer used to say:

たとえば、Web ページをあなたと共有したいとします。URL を伝えると、参照渡しになります。その URL を使用すると、私が見ているのと同じ Web ページを見ることができます。そのページが変更されると、両者ともその変更を確認できます。URL を削除しても、そのページへの参照が破壊されるだけで、実際のページ自体は削除されません。

ページを印刷してその印刷物を渡す場合、値渡しになります。あなたのページは元のページの切り離されたコピーです。その後の変更は表示されず、あなたが行った変更 (印刷物への落書きなど) は元のページには表示されません。印刷物を破棄すると、オブジェクトのコピーは破棄されますが、元の Web ページはそのまま残ります。

これは、「参照」の狭い意味、つまり一時的かつ暗黙的であるという点を除けば、ほぼ正しいです (必ずしもそうである必要はありませんが、明示的および/または永続的であることは追加機能であり、上で説明したように、参照渡しセマンティクスの一部ではありません)。より近い例えは、ドキュメントのコピーを渡すのと、オリジナルでの作業に招待するのとでは異なります。


1 Fortran または Visual Basic でプログラミングしていない限り、これはデフォルトの動作ではなく、現在使用されているほとんどの言語では、真の参照呼び出しは不可能です。

2高齢者のかなりの数もこれを支持している

3最近の言語の多くでは、すべての型が参照型です。このアプローチは 1975 年に CLU 言語によって開拓され、それ以来 Python や Ruby を含む他の多くの言語で採用されてきました。また、C#、Java、JavaScript など、一部の型が「値型」で他の型が「参照型」であるハイブリッド アプローチを使用する言語も数多くあります。

4適切な古い用語を再利用すること自体は何も悪いことではありませんが、そのたびにどの意味が使用されているかを何らかの方法で明確にする必要があります。そうしないと、混乱が続くことになります。

おすすめ記事