Hatena::ブログ(Diary)

flashrod このページをアンテナに追加 RSSフィード

2008-01-27

AS3では関数引数はすべて値渡し(call by value)である 23:15  AS3では関数の引数はすべて値渡し(call by value)であるを含むブックマーク

たまに「プリミティブ型は値渡しでオブジェクト型は参照渡し」と解説してあるのもあるけど、その解説は間違いである。間違いである、とずっと思っていたのだけど、どうやら異なる概念を同じ用語で記述しているだけだと最近は考えるようになった。

まずAS3は参照渡し(call by reference)ではない、という現象から説明すると、次のコードで

    public function swap(a:Object, b:Object):void {
        var tmp:Object = a;
        a = b;
        b = tmp;
    }

こいつを次のように呼び出したとする。

        var a:Object = {
            value: "abc",
            toString: function():String { return this.value; }
        };
        var b:Object = {
            value: "xyz",
            toString: function():String { return this.value; }
        };
        swap(a, b);
        trace("a=", a);
        trace("b=", b);

もし本当に参照渡し(call by reference)なら次のようになるはずである。

a= xyz
b= abc

実際にはこうなる。

a= abc
b= xyz

なので、AS3は参照渡し(call by reference)ではない。値渡し(call by value)である。

で、元凶はなんなのか調べていたらlivedocsにたどり着いてしまった。

すべてのパラメータは参照渡しです。

http://livedocs.adobe.com/flex/2_jp/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001834.html#266456

…酷い話だ。

英語版だと In ActionScript 3.0, all arguments are passed by reference と書いてある。

でも言語仕様に噛み付いても勝ち目は薄いと思うので、こいつを好意的に解釈することにすると、おそらく、ここでいう「参照渡し」は「call by value 対 call by reference の参照渡し」とは異なる概念を指している、と思われる。

たぶん、

例えば、Javaは参照型を扱うための『Javaの「参照」』を持つが、これは『参照渡しの「参照」』とは概念が微妙に違うため、『Javaの「参照」』を渡しても参照渡しであるとは言えない。

http://ja.wikipedia.org/wiki/%E5%BC%95%E6%95%B0

と同じことがAS3でも起きている。

その参照とは何かというと、最近だとこのページ

2つの変数は同じオブジェクトを参照しています。

http://www.func09.com/wordpress/archives/176

にある図のようなことを参照と言うと。それは良いのだけどその参照を渡すことを参照渡しとは呼びたくない俺は。でも参照を渡すことを参照渡しと呼んで何が悪い、ということなのだろう。

モダンな言語で call by referenceが無いことが分かりきっている文脈では、参照渡しといえば参照値のコピーということで話はまとまるのかもしれない。あるいは「古典的な参照渡し」とか言わないといけないのかもしれない。

追記(2008-01-29)

ブックマークコメントに返事してみる。

2008年01月29日 bull2 bull2 ネタ, actionscript, as3 ワラタ。これは参照渡しで正解。ポインタの概念がわかってないよ。この例ならJavaでも「Cのポインタ」でも結果は同じだよ。CommentsAdd Star

ワラワレタ。「参照」が渡るという事実を否定しているのではありません。その「参照」が渡ることを「参照渡し」と呼ぶべきではないという主張をしているつもりです。概念モデルや理解の仕方を気にしているのではなく、単に用語に食いついているだけなんです。

CもJavaも結果が同じになるのはCもJavaも「値渡し」だからです。異なる結果になるのはPascalの例が上に掲げたWikipediaに載っています。私が「参照渡し」と呼ぶのはこのPascalの例が示すものだけです。Javaの「参照」が渡ることが「参照渡し」でないことは上に述べたようにWikipediaの同じページにあります。

「『参照』が渡ってるんだから『参照渡し』で正解」とする考え方も理解できますが、合意はできないでしょうね。

2008年01月28日 os0x os0x as3 うーん、値渡しといってしまうのも誤解があるような。例えばswapの中でa.valueを書き換えると元のa.valueも書き換わるよね。CommentsAdd Star

繰り返しますが、おっしゃるとおり確かに「参照」は渡っています。でもそれを「参照渡し」とは呼ばないんです。「参照渡し」とは呼ばないので「値渡し」と呼んでいるんです。

「値渡し」では誤解を生む、といわれて気づいたのですが、たぶん、モダンオブジェクト指向の言語で学習した人は「クラスのインスタンス」が「値」であり、インスタンスを参照しているものは「値ではない」と理解しているのかもしれません。

だから「値渡し」と聞くとインスタンスの複製が起きるような気がするかもしれません。関数呼び出しでインスタンスのコピーは起きない、だから「値渡し」ではない、という考えは分かります。分かりますが、合意はできません。

その「参照」しているものは「参照値」なんです。だから「値」なんです。その「参照値」は「値」なのか「参照」なのかと言われると、call by valueとcall by referenceのどちらかという文脈では「値」であって、クラスのインスタンスかどうかという文脈では「参照」なのでしょう。

追記(2009-05-21)

* shinfukui shinfukui プログラミング よくある誤解。この説明だと、AS3に限らず全ての言語で関数引数はcall by valueになる。call by referenceとは、ポインタを引数に渡すことを指す概念。題材にstringを使ってるのがまた話をややこしくしている。 2009/05/15

id:shinfukui 誤解じゃないです。それを「参照渡し」と呼ぶのは止めようと主張しているんです。ただもうこの主張は通らないなと思っています。参照が渡ることを参照渡しと呼ぶ流れはもう止められないと思います。おっしゃるとおりモダンな言語ではほぼ参照の値渡しなので。「参照渡し」や「値渡し」の違いを意識しないといけないのはPASCALやFORTRANといった昔の言語なんです。

foreignerforeigner 2008/01/30 04:44 It is a matter of scope.
You are missed this keyword.

public function swap(a:Object, b:Object):void {
var tmp:Object = a;
this.a = b;
this.b = tmp;
}

mutamuta 2008/01/30 13:05 勉強になりました。

spiritloosespiritloose 2008/02/01 02:28 ややこしいので私はCの「ポインタ渡し」相当のことを他の言語では「参照値渡し」と呼ぶようにしています。

anonymousanonymous 2009/07/28 11:18 Python のチュートリアルでは、call by value と説明された上で、以下の注が付いていました。

"Actually, call by object reference would be a better description, since if a mutable object is passed, the caller will see any changes the callee makes to it (items inserted into a list)."