静かなる名辞

pythonとプログラミングのこと


もう参照の値渡しとは(無条件では)言わせない

 注意:この記事では「参照の値渡し」がどういうものか、という点については説明しません。あくまで「参照の値渡し」を理解している方が対象読者です。

概要

 「参照の値渡し」という言葉がありますが、この言葉に関してはずっとモヤモヤ感を抱いていました。

 某所での議論を通じて、自分の考えがある程度まとまったので、記録しておきます。

 結論を先に要約すると、

  • 「参照の値渡し」は無条件で使える言葉ではない。むしろこの言葉が独り歩きするのであれば、かなり問題があると考える
  • 個人的には「共有渡し(call by sharing)」というネーミングを推す

 です。

 それぞれの理由について以下で述べます。

 目次

「参照の値渡し」の問題点

 これはもともと「参照渡し」と「参照の値渡し」を混同して使うな! という文脈で流行りだした言葉なのだと思うのですが、呼び方として「参照の値渡し」が良いとは思えない理由がたくさんあります。

 幾つか挙げます。

「参照の値」が定義されていない言語では使うべきではない

 「参照の値渡し」という言葉を好んで使う方は、おそらく「参照値」というものがあり、それを値渡ししている……というイメージを明確に持っています。というか、ぶっちゃけ「参照値=メモリ番地」というイメージまではっきり持っているでしょう。

 ただし、メモリ番地どうこうというのは(相対的に見て)低水準の話です。よって、高級言語、特にLLのようなものでは、メモリ番地をプログラマから直接見る手段がないようなものが幾らでもあります。

 ワーストケースでは、言語仕様上で「参照の値」の定義が存在しておらず、実装に委ねられている、ということがあり得ます。そういうケースでは当然「参照の値渡し」とは書けない。そもそも内部的に「参照の値渡し」である保証すらない(同様の動作の実装方法は「参照の値渡し」に限らないかもしれない)。

 逆に、「参照の値」が定義されている言語ではこの問題はありません。たとえば、この話題に関して検索すると割と上の方に出てくるJavaに関する記事*1では、この点が明確です。

Java で「参照 (references)」といったら「参照値 (reference values)」という「値」のことです。

もう参照渡しとは言わせない - Qiita

 「参照の値渡し」に関して言えば、Javaはかなり有利な立ち位置にいると言えます。・・・というか、Javaの人たちは「参照の値渡し→参照値の値渡し→そもそも値渡しである」という話の方に向かってしまう場合があります(上の記事もそうです)。こうみなすと、プリミティブ型にしろ参照型にしろ値渡しという一つの方法で扱われると言えるのですっきりするのです。

 問題は、このように「値渡し」とみなしても、特に良いことのないばかりか悪いことまで出てくる言語もたくさんある、ということです。

 私の好きなpythonはその代表格で、

  • すべての変数は参照型、というかオブジェクト

 →「参照の値渡し」の部分は裏側に引っ込んでしまうので、あえて値渡しと呼称してもメリットはない

  • 当たり前だが「参照値」なんて定義されていないし、プログラムから触る手段もない

 →実際は(少なくともCPythonでは)変数表のdictのvalueのポインタがそれに相当する。ただし、pythonのレイヤでは完全に見えない

 という事情があります。なので、pythonで「参照の値渡し」という言葉を使うインセンティブはありません。

「参照」と「値渡し」を理解していないとわからない

 「参照の値渡し」という言葉の残念な点は、それが「参照」と「値渡し」という概念に依存していることです。どちらも重要な概念で、しかも初心者のつまづきポイントです。

 つまり、「ヤツらに参照渡しと参照の値渡しを区別してほしい!」と思っている対象の「ヤツら」はそもそも「参照」も「値渡し」もちゃんと理解していない可能性が相応にある、ということです。ということは、「参照の値渡し」も理解してくれませんよね。

 また、一例として、これまでまったくプログラミングをやったことがない人とか、小学生とかにpythonを教えることを考えてみましょう。

 「参照」は理解してもらうしかないでしょう。すべての変数が参照型である以上、やむを得ません。でも、「値渡し」は上述した通りpythonのレイヤでは意識する必要がないので、教える必要はありません*2。しかし、「値渡し」を教えないと問題が発生します。「参照の値渡し」は引数の渡り方という超重要なトピックなので必ず教える必要があり、そのためには「値渡し」を教えないといけない・・・なにかが破綻しています。純粋に「参照の値渡し」という言葉が悪いのです。

そもそも言葉が抽象化されていない

 もっとも根本的な問題です。「参照の値渡し」は何も抽象化していない言葉です。「参照値が値渡しされる」と言っているのと同じですから。

 これは、「値渡し」と言う代わりに「実引数の値がコールスタックにpushされて・・・」と言うのと同じことです。単に動作を説明しているだけです。

 モジュール化して適切な名前を付け、ブラックボックスにして抽象化し、使いやすくする、というのはプログラミングにおいては極めて重要なことです。これを否定する人はいないでしょう。なのに、そういう大切な原則が守られていない言葉なのです。

 この言葉に対して私が個人的に抱いているモヤモヤ感も、けっきょくその辺りに起因する気がします。「名前」が「動作の説明」になってはいけません。

共有渡しを推してみる

 上で述べた通り、「参照の値渡し」はまずい点の多い言葉です。ただし、この言葉を使わないのであれば、代わる候補を探す必要があります。

 ということで、共有渡しを推します。

  • オブジェクトが(あるいはメモリ領域が)関数の間で共有される、という現象を捉える上で自然な言葉。
  • 上述した「参照の値渡し」の問題がない。
  • 英語圏ではもともと「call by sharing」が「参照の値渡し」とほぼ同じ意味で使われており、ならばこれの訳語を使うのが自然*3

 特に異論はないと思います。「共有渡し」唯一の難点は日本語圏ではまったく流行っていないことですが、どうせ「参照の値渡し」もリアルでは通じないことの方が多いでしょうから、大きな問題ではないでしょう。

「参照の値渡し」を使っていいとき

 この記事でこれまで述べてきた通り、「参照の値渡し」という言葉にはかなり問題があります。なので、使用場面は本来は極限されるべきであると考えます。

  • 参照値が定義されている言語で、
  • 共有渡しより通じやすい可能性があり、
  • 共有渡しより文脈上適当と考えられ、
  • その他の他の候補と比べて適切であると認められる場合*4

 上で挙げたJavaの例などはこれに当てはまる可能性があります。ただし、この場合も、「(一般名詞の)『参照の値渡し』と呼ばれる動作です」と言うよりは、「参照値が値渡しされます」と説明的に書いた方がはるかに親切でわかりやすいことに留意してください。

 つまり、理想論を言えば使途はかなり限定されるべきであろう(=ほぼ使われるべきではない)、ということです。

 ただし純粋に呼び方の問題でしかないので、理想論を押し通したところで、得られるメリットはほとんどありません。それが最大の難点です。「まあ細かい齟齬はあるかもしれないけど、『参照の値渡し』でも別にいいんじゃない?」と言われたら何も言い返せません。正しくはないと思うけど、自分の思う正しさを押し付ける蛮勇を振るうのは大変です。ぶっちゃけいまいち積極的になれません(という気分がタイトルにもにじみ出ているのを感じ取っていただければ)。

 この記事を読んだ上で、いろいろな理由で「それでも私は『参照の値渡し』と呼ぶ」と決意する方がいれば、私から言うことは特にありません。あくまでもこれは消極的な提言であるとご理解ください。できれば共有渡し派が増えてくれると嬉しいのですが・・・

 けっきょく、この記事にしてもこういう思いを共有してくれる人に向けて書いているだけなのです。(なんつーオチだ)

まとめ

 「参照の値渡し」という言葉は考えれば考えるほどケチがつけられるので、やっぱり問題含みだと思う。

関連記事

 (昔書いたものなので、今見ると拙い部分もあります。この記事のアップに伴って多少修正しましたが、私自身100%内容に満足している訳ではないことはご理解ください。)
共有渡しと参照の値渡しと - 静かなる名辞

*1:タイトルのパクり元・・・

*2:もちろんプログラミングを続けるのであれば、いずれ理解する必要が生じるでしょうけど

*3:callとpassは英語でもどちらでも良いものらしいので、問題にはなりません

*4:たとえば「ポインタ渡し」や「アドレス渡し」という言葉もあり、Cであればこちらを使った方が良いと思われます