うぎゃー

javascriptディレクトリ以下が全部吹っ飛んだ……。
カリー化とか関数型パラダイム全般とか数学とかFSMとかのライブラリが全部飛んでしまった。
一番イタイのは作ってる最中だったゲーム用ライブラリががが。

駆け足で始めるjavascriptのその他 - カプセル化だとかインターフェイスだとかADT寄りの話 -


たとえばこういうコード
function f(o){
 o.numCount = 10;
}
問題、関数fはoの詳細(実装)を知っているか?
答えはNOである。YESと答えた人はOOPからやり直しなさい。

fはoにnumCountと言うメッセージを送信しているに過ぎないので実装は知る由もない。
むしろこのコードには実装を知る術は全く含まれていない。

なぜならoにはnumCountというセッタがあるかもしれないし、はたまたoがProxyかもしれない。

こういうことだ──
// アクセサの仕様はes5でとっくに固まっている
var o = {
 _numCount: 0,
 get "numCount"(){
  return this._numCount;
 },
 set "numCount"(v){
  this._numCount = v;
 }
};

// これはcatch-all proxyではなくdirect proxy
var o = new Proxy({ _count:0 }, {
 get: function(target, name, receiver){// receiver[name]
  if(name == "numCount") return target._count;
 },
 set: function(target,name,val,receiver){
  if(name == "numCount" && name in tartget){
   target._count = val;
  }
 }
});
思い出してほしい、関数fのどこに実装を知っているコードが出てきた?
fはnumCountがセッタだと知っているか?
fはoの内部メソッド[[Set]]を知っているか?

これらすべての答えはNOである。

ではo.numCountとは何か?上記例ではセッタである。セッタが実際にアクセスしているのは_numCountの方でfはoの_numCountにはアクセスしていない。また、fはoのnumCountがアクセサだとは知らない。fから見ればただの(破壊的)代入だ。

fがnumCountの詳細を知るにはObject.getOwnPropertyDescriptor()しなければならない。
"set" in Object.getOwnPropertyDescriptor(o, "numCount")として初めてnumCountがゲッタであると知ることになる。

さらに下記例ではより複雑だ。proxyは元のオブジェクトの型として振る舞うのでfからはわからないし各種内部メソッドはProxyがオーバーライドしているので好きにできる。これが意味することはカプセル化の概念がないjavascriptでもカプセル化が出来るという事で、これがメタプログラミングの力である。

カプセル化されているということはnumCountはただのインターフェースであり、実装の詳細は知らない。しかし、proxyはメッセージ送信をオーバーライドするのでインターフェースではなく(メタ的なのでそれよりも強力だが)メッセージ転送に近い。

したがって、javascriptでは実装が丸見えだという考え方は古い、それはもはや通用しない。そして、重要なのはjavascriptのアクセサやProxyはメッセージ送信の過程をハンドルする。なのでメッセージ送信が比喩的なものである言語とは違ってその動作原理を理解する必要が出てくるということだ。javaのクラスメソッドはただのクラススコープの静的関数だがjavascriptのObject.getOwnPropertyDescriptorなどは違う。オブジェクトにメッセージを送っている。

さらにjavaのクラスメソッドならメソッドはクラスに属するがjavascriptの関数はどこかに属するという概念は持たない。これはメッセージ送信と別の概念だが、メッセージ送信と、とても相性がいい。属するという概念はないがメッセージ送信によってオブジェクトと紐付することが出来るからだ、javascriptのスコープが動的なのはここら辺が関係している。(前にも言ったように実際には静的であるように振る舞うので気になるなら仕様書へ)

というわけでメッセージ送信やメタプログラミングを理解しよう!

色々エッセンシャル

javascriptはメッセージ送信やってるよ
スロットとメンバは違うよ
関数とメソッドは違うよ
メッセージ転送もあるけど標準化されてないよ

まず、メッセージ送信されるとスロットを見に行く、そのメッセージに対応したスロットがあればそれが[[Get]]される。
次になければprototypeチェーンをたどる。Prototypeオブジェクトじゃないよ。

let多相だけど値制限ないよそもそも副作用許すよ。破壊されるよ。const付けろよ。freezeしろよ。