* EssenRev4 の基本的なアイデア
-(by [[K]], 2018.03.05)
** (0) はじめに
-EssenRev1:
--セキュリティキャンプ2017で作っていたバージョン1
-EssenRev2:
--セキュリティキャンプ2017で作っていたバージョン2 JITコンパイル方式
-EssenRev3:
--その後迷走したバージョン
-EssenRev4:
--これから作るバージョン
** (1) 基本的なアイデア
-「変数、型、関数だけではなく、構文や演算子を自由に作れる言語」という基本はまったく変わらない。
-まず最大の違いとして、動的型付き言語から静的型付き言語に変更。
--なぜ?それはそのほうがJITコンパイル時に高速なコードが容易にできそうだから。
--Rev1のころは速度を重視しなかったけど、速いのはやっぱり重要だと思った。あまりに遅いと便利でも使ってもらえない。
--C言語並みに早くなっている必要はないけど、C言語比で処理時間が10倍とかだと使う気が無くなる可能性がある。
-Rev3以前のように型を気にしないプログラミングがやりたいときは、var型か何かを作って、それはつまりなんでも型で、それを使うことで動的型付き言語として使えるようにしよう。でもきっと少し遅いだろうけど(実行時にバインディングを解決するので)。
-速度を出すためにJITコンパイルを基本に考えるけど、生成したコードをそのまま出力するのもありで、その場合は単一の.exeファイルになる。つまりコンパイル型の言語としても機能できる。
-ここで、なぜRev1のころは動的型付き言語を指向していたのかをメモしておこうと思う。静的型付き言語では、ほぼ同じ操作をしているだけなのに、対象の型が変わればコードも生成しなければいけない。たとえば整数でのソート、実数でのソート、文字列型でのソートがあった時に、それらは区別される。C++になればテンプレート型引数が使えるようになって、ユーザは記述しないで済むようになったものの、そんなの動的型付き言語であれば気にせず普通に書けば実現できることなので、それこそ目指すべき姿だろうと考えたのだ。
-Rev4ではそういうときはvar型の引数にしておけばいいと思っている。
** (2) 上位構文の目標(1) - カッコ
-みなさんはLISPという言語をご存知だろうか。私はこの言語はおそらくシンプルかつ多機能さという意味で究極の言語だろうと思う。しかしLISPで書かれたプログラムは(私にとっては)読みにくい。書きやすいとも感じられない。・・・どうしてそう感じるのか、ずっと考えてきた。理由もなく嫌っているのは、ただのわがままや難癖と大差ないと思うから。
-LISPで書かれたプログラムはカッコが多い。カッコのネストはちょっとしたことでもすぐに深くなり、インデントを工夫したり、もしくはエディタの支援なしでは対応関係が分からなくなってくる。そしてそれこそが、読みにくさの本質ではないかと今の私は考える。
-そのことを説明するために、いったんLISPを離れよう。数学では、計算は左から右へ順番にやる・・・というふうにはなっていない。足し算引き算よりも掛け算や割り算が優先されるし、べき乗はもっと優先される。なぜそんなことにしたんだろうか。私は少なくとも昨年まではこの習慣に批判的だった。もしすべての優先順位が同じなら、つまり演算子の優先順位なんかなければ、式を処理するプログラムはすごくシンプルになる。なぜ人類はこんなくだらない習慣を捨てられないのか。などと思ってきた。・・・しかし今は違う。この習慣は大変合理的である。プログラムがこれをどうにかするために努力することも必要なコストである。
-なぜそんなややこしい習慣があるのかと言えば、数式においては 2*a^2+3*a*b-c みたいな式が頻出し、その際にカッコを書きたくないかだ。そうに違いない。もしすべての演算子に優先順位がなければ、 2*(a^2)+(3*a*b)-c と書かなければ値が違ってしまう。このカッコを書きたくなかったから、ややこしい演算子の優先順位を作ったのだ。・・・つまり人類はカッコが大嫌いなのだ。カッコをなくすために代償を払ってもいいと思っているのだ。そしてLISPはこの原則を無視しているのだ。だから私はLISPが好きになれなかったのだと思う。
-私はビット演算が得意なプログラマなので、C言語でこんなコードをよく書く。
if ((flag & 1 << 12) != 0 && ((a ^ b) & 15) == 0) { ... }
-なんだこれは。カッコが多いじゃないか。これはひとえに、C言語における&や|の優先順位が低すぎることによる。まずはそこを改善しなければいけないと思っている。
-さらに関数の呼び出しでもカッコは必要だし、ifやforで多用する { } だって、中カッコではあるけど、カッコはカッコだと思っている。これを減らすすべはないだろうか。インデントもそんなにすぐれた解決法だとは思わない。スペースやタブの量でプログラムの意味が変わるなんて、ネタ言語である「Whitespace」を笑えないではないか。インデントはプログラマの自由であるべきだ。
-こうして「何がダメなのか」はおおよそわかっているものの、「じゃあどうしたらいいのか」はほとんどわかってない。ノーアイデアである。数学に学ぶとすれば、数学は引数(添え字とか)を下付き文字にしたり、上付き文字にしたり、省略したりと、いろいろ工夫している・・・ように見える。それを真似するといいんだろうか??
-まずカッコを減らす簡単なアイデアとしては、代入がある。
ここで A = a+b-c とおく
-みたいなやつである。これをやればカッコは減る。もしかしたら見通しもよくなるかもしれない。
-ではなぜこれをやらないのかというと、なんか変数を減らしたいという衝動があるから・・・かな?違うかもしれないけど、仮にそうだとしよう。変数を減らしたい衝動としては、記述量が増えてしまうから?変数が増えてしまうから?変数の型を決めなければいけないから?宣言がめんどくさいから??
-いずれにせよ、その衝動を抑えるような仕組みが必要だろう。それさえあればこの問題は解決に向かうはずだ。
** (3) 上位構文の目標(2) - 変数名を渡す仕組み
-C言語では、変数aとbの値を確認したいときにこんな風に書くだろう。
printf("a=%d, b=%d\n", a, b);
-しかし私はこの書き方が気に入らない。なぜaやbを二度書くのか?こんなのはミスの温床だ。そうじゃなくて、こう書けるようになりたい。
dump(a, b);
-これで変数名とその値が表示できたらどんなに便利だろう。・・・ああそうとも、#defineマクロを使えば同じことはできるだろうさ。でもそれでいいのか。プリプロセッサなど使わずに、純粋な言語機能だけでこれをやりたいのだ。関数は実引数名(もしくは式)を受け取れたら素敵じゃないか。
** (4) 下位機能での目標(1) - ポインタなど
-プログラミング言語を作ろうという時に、ポインタなんかなくしてしまおう、あんなものがあるからバグやセキュリティホールの温床になるんだ、みたいな考え方がある。もしくは、intだってどんどん多倍長化して、どんなに大きな数でも入れられるようにしよう、そうすればオーバーフローに悩まされることはない!という考え方がある。・・・これは確かにその通りで、私もそのように考えていた時期があったが、今はそうは思わない。
-EssenRev4では、ポインタはあるしポインタがおかしくなることもありうるし、オーバーフローも起こりうる。しかし、それらはすべて容易に検出できる。そこがC言語とは違う。Essenは過保護な言語を目指さない。できることは一通りできるが、おかしなことをやってしまった時に教えてくれるのだ。それを目指す。
--なお、このポインタのチェックやオーバーフロー検出などは、以前作った OSECPU-VM rev2 でかなり試したので、うまくいく自信がある。
** (5) 型情報の提供
-CやC++の言語処理系は、構造体のメンバ情報などをすべて知っているくせに、それをプログラムに渡してはくれません。ある構造体のポインタが渡されたとして、メンバ名、メンバへのオフセット、型などを全部教えてくれたらすごく便利だとは思いませんか?汎用のオブジェクトダンプツールが簡単に作れます。でも既存の処理系はこれらの情報を全くよこさないのです。けしからん!
-CやC++の言語処理系は、構造体のメンバ情報などをすべて知っているくせに、それをプログラムに渡してはくれない。ある構造体のポインタが渡されたとして、メンバ名、メンバへのオフセット、型などを全部教えてくれたらすごく便利だとは思わないだろうか?汎用のオブジェクトダンプツールが簡単に作れるようになる。でも既存の処理系はこれらの情報を全くよこさない。けしからん!
* こめんと欄
#comment