言語女子会2: varは必要?/privateがない?

言語女子会: undefとnullは両方必要?の続編です。

varは必要なの?

とあるプログラミング言語が集う女子会にて:

Python: JavaScriptちゃんってさ、なんでvarだらけなの?
JavaScript: えっ、変?
Python: varなんかいらなくない?私ぜんぜん持ってないよ?
JavaScript: えー、じゃあ変数をどうやって宣言するの?
Python: 宣言っていうか…「x = 1」みたいな代入文があれば変数xが必要なのって自明じゃない?宣言とか必要?
Ruby: 必要ないよね。っていうか変数宣言とか古臭くない?
JavaScript: そうかなー。
Python: 少しダサイかも。ほら断舎離ブームだし要らないものは捨てなきゃ!
JavaScript: 要らないかなぁ、変数宣言。Pythonちゃんは関数がネストしているときに外側のスコープの変数に代入するのってどうやるの?
Python: えっ、それは…関数冒頭でnonlocal宣言を…
JavaScript: えー、何それー、関数冒頭での宣言とか死語じゃない?
Python: (ぐはっ)
JavaScript: ていうかー、確かグローバルスコープの変数に代入するのにも関数冒頭でglobal宣言が必要なんだよねー。その時点で「変数宣言がなくても代入で十分」ってアプローチが間違いでしたと言ってるようなもんじゃない?
Python: (T_T)

Python沈黙

ネストした関数が必要ないんじゃない?

Ruby: いや、それは関数をネストしたあたりがおかしいんじゃないの。なんでネストした関数なんかが必要なの?変態なの?
JavaScript: えっ、たとえばクロージ…
Ruby: クロージャみたいなしょぼいの使ってないでさー、JavaScriptちゃんももうちょっとオブジェクト指向にお金掛けたほうがいいよー
JavaScript: …クロージャしょぼくないよ?
Ruby: しょぼいよ、まともなクラスがないから関数のネストで無理やりオブジェクト指向してるんでしょ。
JavaScript: えー。クラスなんてただの化粧品じゃない。プロトタイプでなにが悪いの?
Ruby: え、えっと…それは……そう、privateがないわ!あなたはなんでもかんでもpublicでしょ。ハレンチだわ!
JavaScript: private…
Ruby: あの恥知らずのPythonですらアンスコで隠すのよ!*1
JavaScript: でもさぁ、Rubyちゃんってオープンクラスよね。privateを付けて「違うクラスからアクセスできません」って言っても、クラス自体にメソッドの追加はできちゃうんでしょ。それって「ウチの中でしか服を脱がないわ!」って言いながら家の扉は全開、誰でもウェルカムってことじゃないの?
Ruby: (ぐはっ)

Ruby沈黙

型宣言は必要ない?

そのころ隣のテーブルで:

Java: 私から見ればvarだけで済ませているのも十分ゆるふわだけどねぇ…なんであんなに型をないがしろにするのかしらねぇ。一見無駄に見えても、型を重んじることで、やまとなでしこのたおやかな立ち振舞いが…
Haskell: 型があることと型宣言が必須なことは別物だにゅ。オバサンたちはさっさと退場すればいいにゅ。
Java: うーん、型宣言いらないとか言うけど、エラーメッセージが意味不明になるって言われて、結局関数ごとに型宣言されてるじゃない?
Haskell: わたしの気持ちを理解出来ないバカな男子は死ねばいいにゅ
Java: あなた、そういうこと言ってると婚期逃すわよ
Haskell: …(-_-)
Java: 男ってのは愚かな生き物なのよ。それなのにプライドが高くて、自分の過ちを認められないのよ。だから男が間違えた時には下手にでて、わかりやすくエラーメッセージを出さなきゃいけないのよ。
Haskell: そんなバカ男に媚びてわたしの純粋性を汚すなんてできないにゅ
Java: はぁ…あなたは自分の純粋さって仮面に酔ってるみたいだけど、結局男にはunsafePerformIOとか許しちゃうんでしょ*2
Haskell: (-_-)

Haskell沈黙

JavaScript: (隣のテーブルから移ってくる) Javaちゃん、ダメだよー、unsafePerformIOはHaskellちゃんのトラウマなんだよー。あんまりいじったら心が壊れちゃう!

Javaのprivate丸見え事件

Java: そもそもみんなアクセス制御が適当すぎるわ。私なんかprivateな着替えは子供からも見えないように一人寝室でしてるのよ。*3
JavaScript: あれ?もしかしてJavaちゃん無自覚なの?
Java: え、なに?
JavaScript: 最近大きな姿見を買ったでしょ?
Java: うん、買ったけど…
JavaScript: あの鏡の反射で大通りから寝室が見えるらしいわよ*4
Java: ガーン(-o-|||)

Java沈黙

まとめ

Python, Ruby, Haskell, Javaが全員どんよりしている中、ひとり元気なJavaScript:

JavaScript: うーん、privateかぁ…。書き換えられないものなんかあったかなぁ…。あっ、そうだ!ローカル変数は外から書き換えられない!やったーわたしハレンチじゃないよー

(しかし誰も聞いていない)

追記: Perl登場

ちょっと所用で席を外していたPerlさんが戻って来ました

Perl: JavaScriptちゃんのvarってわたしのmyみたいなものでしょ?ourとかlocalとかuse varsみたいなのはないの?
JavaScript: んー、えっとねー、わかんない☆
Ruby: Perl姉さんが言ってるのは、わたしたちの採用している「スコープはソースコード上でひとかたまり」*5 って戦略じゃなくて「呼び出し先にも伝わる」*6とか、他にもいろいろあったほうがよくない?ってことよ。よく知らないけど
Python: 使えると便利なケースがあることはわからなくはないけど、それをスコープを使ってやる必要はないんじゃないかなぁ。明示的にやったほうがいいよ。
Perl: うーん、あなたたちにはそもそもできないことだから話が平行線ね…
JavaScript: あっ、スコープの話か!わたしわかるよ!varを省略するとグローバルスコープだよ!
他全員: ………。

(thanks @mattn_jp, id:delphinus35)

追記: Rubyクロージャ

Ruby: あれ、わたしがクロージャ作れないって誤解させちゃった?もちろん作れるわよ、わたしに不可能なんてないのよ。だからJavaScriptにできることは私にだってできるのよ!
Python: えー、でもRubyちゃんの場合、fooって書いたらfooを0引数で呼び出しちゃうじゃん?わたしやJavaScriptだと関数foo自体になるから楽チンだけど。
Ruby: それは…
Python: あ、知ってるよ、シンボルだかなんだかを使ってごにょごにょするんでしょ。まあ、うん、できなくはないよねー
Ruby: (ぐぬぬ…)

反響まとめ

  • アセンブリばあちゃん(あたしらはvarやprivateで隠れることもできなくて、着替えが丸見えだったもんだと遠い目)by id:raitu thanks! *7
  • 一応、清楚(Strictモード)なJSちゃんはprivateがFutureReservedWordsとして名乗りを上げるのでビッチではなくなる意志はある。ということにしておこうw (by id:teramako thanks!)
  • JavaScriptさんはjQueryさんという強力なスタイリストがいるからその態度を取っていられる事をもう少し自覚したほうが良い (by id:yosuke_furukawa thanks!)
  • Perl「TPOに合わせてno strictくらいは使えないと」by @muimiPro thanks!
  • Vim scriptちゃん「ネストした関数がなければ宣言は必要ないよねー(ただし私の場合代入にletが必要だけど)」by @thinca thanks!
  • Rubyはprocやブロック構文使いまくるしprivateとかわりと空気なので自分を見失ってる (by @uu59 thanks!)
  • perlもVB6も変数宣言なしで使えるけど、変数の宣言を強制させる宣言があるな…。Option Explicit とか。perl6は強制になるし (by @imatake_jp thanks!)
  • PythonさんもRubyさんもツッコミ役なんだけどPythonさんがバッサリ突っ込むのに対してRubyさんは「まぁできるけど、でもこういう考えのほうがいいと思うの」とネチネチ言うタイプ(ぁ (by @mongrelP thanks!) --- なるほど、無自覚だったけどそういうキャラづけもいいかもですね
  • nonlocal すら使えなくてリストや辞書で誤魔化す Python 2 ちゃんが泣いてる姿が見えました。(by @raimon49 thanks!)
  • JavaScript ちゃん関数冒頭での変数宣言 dis るなら hoisting どうにかしようぜ (by @kei_s thanks!) --- なるほど、こういう現象があるんですね: ref: JSLintとJSHintとhoisting
  • Haskellが型宣言書くのは、エラーメッセージじゃなくてドキュメントのためだと思います。プログラマがドキュメントとして書いた型と、コンパイラが推論した型が一致することを確認シたものじゃないと、多分ドキュメントとしては嬉しくないから。 (by @tanakh thanks!)
  • JavaScriptちゃんは、キツネ耳を装着するかもう少しお姉さんになれば、letによるブロックスコープも覚えるんだけどなーとか思った (by @dynamitter thanks!)
  • Pyhonは__slots__ ("__foo","__bar") でもアクセス制御できそうな? もしくはデスクリプタ? (by @kusanoha thanks!)

あとがき

前回の女子会について「Python圧勝」とかいう意図しない反応があったのでとりあえず早々にPythonが退場するようなネタで第2回をしてみました。しかしRubyにいいところがなさすぎる…今度はRubyが勝てるような話題を考えなきゃ…。

「関数冒頭での宣言」に関しては「代入よりも前に宣言しないといけない」と書くのが正確でした。Pythonのglobal宣言は代入文とセットにすることができず、またその変数を参照するよりも先に宣言しておく必要があるのでJSちゃんいわく「ダサい」ということですが、若干言い過ぎでした。

def good_function():
    global x
    x = 1

def bad_function():
    global x = 1  # SyntaxError: invalid syntax

def bad_function():
    print x
    global x  # SyntaxWarning: name 'x' is used prior to global declaration
    x = 2

興味を持った方には僕の書いた「言語設計の基礎知識」を含む60冊分のPDFが1冊にまとまったWebDB Press 総集編がオススメ:

*1: 女子テニス選手のprivateなところを隠しているアンダースコートのこと…ではなく「アンダースコア2つで始まる名前はネームマングリングで擬似的に隠される」のほう: Name mangling thanks @suno88

*2: see: 第31回 禁断の機能「unsafePerformIO」の深淵 - 本物のプログラマはHaskellを使う:ITpro

*3: 子供から見えるならprivateじゃなくてprotectedだろ、という趣旨。ま、その区別はRubyにもある。

*4: リフレクションでsetAccessible(true)したらprivateでもアクセスできる

*5: my宣言するとレキシカルスコープ

*6: local宣言すると動的スコープ

*7: 全てがグローバル(レジスタとメモリ)