Delphi
Up one level関数内関数欲しいな
(Goを)さわってみた感想は次回書きます。Pascalが好きではない人に何か言ってやろうと思ってたんですが、勝てそうにないんで代わりに以前書いたDelphiのプログラムを貼ってお茶を濁すことにしました。
唐突ですが私の得意言語はDelphi(Object Pascal)です。
Goで好きになれそうにないところは関数内関数がないあたりです。
とりあえずコード書いて、似たようなコードやレイヤーが違うコードを関数内関数で括り出しといて、汎用的に使えそうならグローバルやprivateな関数にする、というプロセスは慣れるとなかなかいいものです。
Lispもlabelsを使うCommon Lispより普通に関数が書けるSchemeの方が好きです。
ちなみにGoの
var f := func() {
fmt.Printf("closure %c", a[0]);
};
を関数内関数と呼ぶには抵抗があります。最適化と慣れの問題かもしれませんが。
関数内関数を作れるとその関数ポインタをどうするのか、という問題が発生します。
Delphiでは関数内関数のポインタをとれないことにして問題を解決しています。
正確に言うとこんな感じだったはず(未テスト)。
// 普通の関数を変数に入れるのはOK
procedure Hoge;
begin
Writeln('hello');
end;
type
TProc = procedure;
var
hoge: TProc;
begin
hoge := Hoge;
end.
// 関数内関数を変数に入れるのはコンパイルエラー
procedure Test;
procedure Hoge;
begin
Writeln('hello');
end;
var
hoge: TProc;
begin
hoge := Hoge; // コンパイルエラー
end;
// これはOK、ただしHoge内でTestのローカル変数を触ると実行時エラー
procedure Test;
procedure Hoge;
begin
Writeln('hello');
end;
var
hoge: TProc;
begin
hoge := @Hoge;
end;
しかしytqwerty氏の発明した関数内関数渡しの方法を使うと親関数のローカル変数を触れるようになります。
正確に理解できてはいないのですが、関数内関数を呼ぶ時のスタックのポインタを連れ回してCallする前に書き換えてしまう技のようです。
これをつかってprototype.jsのEnumerable的なものをDelphiで作成してみたのがこれです。
enumerable.zip
IEnumerableを実装するとEnumerableをmixinしたのと似たようなことになります。
Javaな人は「interfaceを実装することがなんでmixinなんだ?」と思われるかもしれませんが、Delphiには「委任」という便利な機能があるのです。
(この辺の「Delphiのinterfaceは使えない」という世間の認識に対してもそのうち何か言いたい)
まあ作ってみたはいいものの実用には使わないと思います。
ちなみに最近のDelphiだと無名関数が使えるらしいです。
やっぱり単なる慣れの問題なのかなあ?
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/uchida/95a26570518595a265706b3230573044306a/tbping