type declaration とか cast とか

最近の弾さんのエントリってなんか無茶苦茶じゃね?

例えば、ポインターの参照、そして変数の型宣言を後置にするとか。たとえば以下のような感じ。

i is int;
p is unsigned char*;

こうすると何がいいかというと、変数宣言がそのまま型宣言にもなるのだ。これで型推論が非常にやりやすくなる。推論ではなく、単に返り値の型をそのまま「代入」するだけなのだから楽である。

host = gethostbyname('HOME'); /* home is char * because getenv() returns char * */

型宣言の前置、後置と型推論の話がどうつながるというのか。まったく別のことだ。そもそも宣言と同時に代入できるとも限らないので、こんなことが半端にできてもあんまりうれしくないし、オブジェクト指向ならあえてより抽象的な型の変数に代入したいときだってある。*1

オブジェクト指向との相性もいい。型を変換するのも「タイプキャスト」ではなく「メソッド」ということにしてしまえばいいのだから。

buf = malloc(p.size).char*; /* char *buf = (char *)malloc(sizeof(p)) */

仮に

buf = malloc(p.size).(char *);

と書いたとしても、「char *にキャストされたmalloc()の結果をbufに代入する」よりも、「mallocの結果をchar *に『変換』し、それをbufに代入する」の方がよほどわかりやすいではないか。

これまた、前段とのつながりがよくわからないが、たしかに cast operator の記述方法は工夫したほうがいいかもしれない。が、別に C++

buf = reinterpret_cast<char*>(malloc(p.size));

みたいのでいいと思う。たしかに Ruby なんかでは obj.to_i と書いたりするが、cast にも int => double のように、実際の型変換が発生するタイプ(C++ でいう static_cast)と void * => char * のようにコンパイラに変数の取り扱い型を指示するためだけで演算の発生しない*2 cast (C++ でいう reinterpret_cast, const_cast) があるわけで、いっしょくたにメソッドのようにするのはいかがなものか。
あと、瑣末なこと。

Cに関しては、特に強かった呪縛は->演算子。そしてなぜこれが呪縛になったかというと、単項(unary)の*、すなわちポインター参照が前置だったから。

単項の * は dereference。reference は &

*1:たとえばCollection<String> c = new ArrayList<String>();

*2:Cの場合。Javaでは型チェックがはいる