unite-outline の近況: 空行の挿入を控えめにした

クラスのような大きなまとまりどうしの間には依然として空行を入れるが、単に見出しの種類が違うというだけでは間に空行を入れないことにした。

元々この機能は、ハイライトによる見出しの色分けがまだできなかったとき*1に考案したもの。C のソースから見出しを抽出したときに、見出しの一覧がフラットにびっしりと並び、何が関数で何がマクロで何が構造体なのやら見分けにくかったので、見出しの種類が異なるものどうしの間に空行を入れて視覚的にグループ分けしようしたのが始まり。

見出しの種類をハイライトで表現できるようになった今、過剰な空行の挿入がかえってうるさく感じられるようになったので、前述のとおり、クラスのような大きなまとまりどうしの間を除き、単に見出しの種類が違うというだけでは間に空行を入れないことにした↓



以下はこれまでの見出し一覧。空行が多い*2


ハイライトがなかった時は後者の方がみやすかったと思うが、今となって見出しの種類はハイライトで一目瞭然だし、前者が特に見にくいとも感じられないだろう。むしろ余計な空行が入らない分、空間の利用効率も上がってすっきりしたと思う。

*1:unite-outline に見出しのハイライト機能が実装されたのは先月のことで、実はまだ新しい機能。

*2:ちなみに、マクロどうしの間に空行が入って、マクロと関数の間に空行が入っていない場合があるのは、関数形式のマクロを関数と同じグループにカテゴライズしていたから。

unite.vim の file_rec でプロジェクトのファイルを一望する

unite.vim 使ってる人はみんな似たことやってるんじゃないかと思いつつ……

現在編集中のファイルが所属するプロジェクトのトップディレクト*1を起点に unite.vim で file_rec する設定。([unite] は unite.vim に割り当てている prefix)

これで、[unite]p とやると、プロジェクトのファイル一覧がずらずらと出てきます。後はキーを二三叩いて unite.vim おなじみの絞り込みを行えば、瞬時に目的のファイルを選択できます。

nnoremap <silent> [unite]p :<C-u>call <SID>unite_project('-start-insert')<CR>

function! s:unite_project(...)
  let opts = (a:0 ? join(a:000, ' ') : '')
  let dir = unite#util#path2project_directory(expand('%'))
  execute 'Unite' opts 'file_rec:' . dir
endfunction

これがあればはっきり言って project.vim なんぞいらないです。

*1:.git があったり Makefile があったり、configure があったりするディレクトリのことです。

alignta の整列回数指定の {1} とか {+} とかって覚えにくいし打ちにくいよね……

もっと簡略な記法がいい。囲まなければならない、というのがもう嫌なんだ。しかも { } を入力するためにはシフトキーも使わなければならない。嫌じゃあ!*1

こんなのはどうだろうか。

pattern{1} → pattern/1
pattern{+} → pattern/g

こっちの方がはるかに打ちやすい上に、/g などは意味的にも :sustitute コマンドのフラグのそれに近く、わかりやすいのではないだろうか。

というか、そもそもなんで {1}, {+} みたいな記法にしたんだっけ?

マージン指定の @ もそうだけど、何かの記法を考えて、それにある記号を用いることにしたときに、その記号の選ばれ方が合理的でない場合が多々あって、それが覚えにくさの原因になる。記号の選択に合理性がない(つまり、(1) や [1] でなくて {1} でなければならない理由を説明できない)場合、それは覚えにくくて使いにくいということになる。

それに比べれば、/1, /g というのは :substituteコマンドのフラグ指定に倣ってそうした、という説明ができる。そしてそれは、Vim のユーザーにはすんなり受け入れられそうだ。

そうだ。そのようにしよう。

もちろん、後方互換性のためにこれまでの記法も残す。

*1:自分で決めておいてこのザマであるw

「ガベージコレクションのアルゴリズムと実装」を読んだ 〜実装編〜

ガベージコレクションのアルゴリズムと実装」を読了。前半の「アルゴリズム編」で GC の基本アルゴリズムを網羅的に解説し、後半の「実装編」では実際の処理系のソースを追いながら GC の実装を見てみるという構成で、非常に面白かった。

ガベージコレクションのアルゴリズムと実装

ガベージコレクションのアルゴリズムと実装

以下、読みながら思ったこと、メモしたことなどをまとめてみる。主に後半の「実装編」から。本書の中で解説されているバージョンは1年以上前のものなので、最新の実装にはあてはまらないかも。

Python

採用されているアルゴリズム

  • 参照カウント
  • マークスイープGC(循環参照したゴミの回収用)

記述言語:

  • C

Python のエンドユーザーのレベルでは GC の恩恵でメモリについては何も考えなくていいのに、C のレベル(Python自体の実装のレベル)だと参照カウントを意識しつつのプログラミングになってプログラマの負担が結構大きいなという印象。プログラマがメモリ管理している感がありあり。

特に参照を受け渡す境界部分で、参照の「所有権」を「渡す」のか「貸す」のか「乗っ取る」のかという判断。多分、参照の所有権の扱いについては紳士協定というか、規約のようなものがあって、この場合は「渡し」て、あの場合は「貸す」、それ以外は「乗っ取る」んだ、みたいなことが決まっていて、どこかにちゃんと文書化されていると思うんだが、勝手がわからないと簡単にメモリをリークさせそうな気がする。

DalvikVM

採用されているアルゴリズム

  • マークスイープGC
  • ビットマップマーキング

記述言語:

  • C

マークビットマップのビットでイテレートするのでマーク関数を再帰的に呼び出す必要がない点と、

オブジェクトビットマップとマークビットマップの差分を XOR で取って死んだオブジェクトをイテレートして回収する辺りは、なかなか巧妙な仕掛けになっていて面白いなと思った。

ただちょっと気になったのは、CLZ のような、先頭からのゼロビットの数を数えるための機械語命令の存在を前提としたアルゴリズムになっている点。

  • Android端末の CPU は ARM と決まっているのでこれでいい
  • この手の命令は大体どんなプロセッサにもあるのでこれでいい

ということなんだろうか。この辺りまで低レベルになってくると不勉強で知識が足りなくて困る。勉強しないと。*1

後、ちょっと気になったこととして、C のマクロ(複数行にわたる比較的大きなもの)が読み難かったというのがある。特に、引数以外に呼出側のローカル変数などが使われているもの。これをやられるとマクロを抽象化された手続きとして読めないので、慣れていないとちょっと戸惑う。

Rubinius

採用されているアルゴリズム

  • 世代別GC
    • マイナー:コピーGC
    • メジャー1:ImmixGC
    • メジャー2:マークスイープGC
  • 正確な GC

記述言語:

世代別GC を採用しており、使用するアルゴリズムとヒープ領域が多段構成。確保したいメモリのサイズによって割り当て時に使用するヒープを切り替えるなど、構造が複雑な印象。

が、ミューテータは ObjectMemory という抽象的なインターフェース(Facade)を介してメモリの割り当てと解放を行うので、使用する GCアルゴリズムについては関知する必要がない。よって、GC部分の実装をいじるのでなければ、記述言語である C++ のレベルでは GC の恩恵の元に開発が行える。その点、参照カウントの Python より開発者の(メモリ管理の)負担が小さい。

一方、正確な GC であることと、C の拡張ライブラリとの相性は悪く、拡張ライブラリからの参照をハンドラで別途管理するなどの苦心が見られる。(この辺は CRuby用に C で書かれた拡張ライブラリに対応したいという Rubinius特有の事情)

組み込みクラスのメンバ変数のアクセサ関数をプリプロセッサマクロで生成しているのが面白い。C/C++メタプログラミング的なことをしようとするとこうなるんだっていう驚きが。と同時に、このマクロで生成するセッターにライトバリアを仕込む辺り、うまいなと思った。

他にも一部のメソッドを Ruby によるテキスト処理でコード生成しているとのこと。

プリプロセスにおけるテキスト処理でコード生成、本当の意味で「メタ」プログラミングじゃねーか、という新鮮な驚きがあった。

本書で解説されているのはコピーGC の部分だけ。世代別GC の全容を把握するには実際のソースをさらに読んでみる必要がある。特に ImmixGC の実装と、大きなサイズのオブジェクトをマークスイープでどう扱っているのか見てみたい。

V8

採用されているアルゴリズム

  • 世代別GC
    • マイナー:コピーGC
    • メジャー1:マークコンパクトGC
    • メジャー2:マークスイープGC
  • 正確な GC

記述言語:

ヒープの構造が複雑でぱっと見で挫けそうになった(笑)

メモリをどう割り当てるかによってクラス階層の大元を分けるという構成。インスタンスをヒープに割り当てるものはすべて HeapObject を継承する、といった具合。これは、オブジェクトシステムの設計(クラス階層の構成など)とメモリ管理戦略の設計が不可分であるということであり、相当慎重に設計しないと後々いろいろ破綻をきたすと思う。

ハンドルスコープではコンストラクタ/デストラクタが呼び出される仕組みをうまく使ってコールスタックとハンドルスコープを同期させている。この辺もうまい。コンパイラが仕込んでくれるイベントフックというわけ。

フィールド制御。なんとハックなやり方。コンパイラ任せにできないとなるとこういう工夫が必要になるのか。コンパイラから制御を奪いとって自分でフィールドを配置するという。やはり言語処理系を作るともなれば、この手の逸脱行為は往々にして必要になってくるのか。

後、Rubinius 同様、やはりアクセサ関数はプリプロセッサマクロで生成していた。この辺は定石なのか。DRY原則重要がここにも。

本書で解説されているのはマークコンパクトGC の部分だけ。世代別GC の全容を把握するには実際のソースをさらに読んでみる必要がある。

EncodeForwardingAddresses() 以降はちょっと待てよと思った。そこまでやんのかと。ここで使われているテクニックのミソは要は相対アドレッシングで、アドレスをどこかに設定した基準からのオフセットとして表現すれば、アドレスの表現に必要なビット数を減らせるというもの。それ自体はへーなるほどなーって感じなんだけど……

そこまでしないといけないのかっ! という驚き。すべてのオブジェクトに 4バイトのフィールド、これが許容されない世界なんだなあと。ミューテータが生成するオブジェクトの数を考えたらまあ納得なんだけれども、まあなんとも泥臭い世界だ。

まとめ

「実装編」を読み終えて思うことは、やっぱり実際の処理系の GC は複雑で大掛かりで、実装上の工夫は総じて泥臭いということ。うまいなあ、なるほどなー、巧妙な仕掛けだなー、と思わされることはたくさんあるが、エレガントとか、美しいとか、そういうのとはちょっと方向性が違う。世代別ともなれば、ほんとにもう色々ごちゃごちゃしていて、本当に参ったという感じになる。

けれど、ソースコードを丹念に読んでいけば、ひとつひとつの処理は「探索」「マーク」「走査」「コピー」といったことに還元されていくわけで、GC は地道に愚直な処理をせっせとやっている、とても複雑で、巧妙な仕掛け、メカニズムだ。

それが動いて機能をなす、というのがなんとも面白い。

自分で GC を実装するのは、きっと面白いだろう。どんなアルゴリズムを採用しようかとか、ヒープの構成どうしようかとか、ちょっと考えただけでもなんだかワクワクしてくる。バグで生きているはずのオブジェクトを消し去ったりなんかした日には!

はやくそこまで行きたい。

*1:と言ってなかなかやらないわけですけど……

alignta でパターンを正規表現として解釈、は本当に使いやすいのか?

試行錯誤の自問自答中。

を受けて、別ブランチにて作業を開始し、パターンを(デフォルトで)正規表現として解釈するように修正したところ、(当然のごとく)テストがこけるようになった。見てみると

Alignta /* */

みたいなやつが軒並みこけていた。当然。なぜなら * は正規表現のメタ文字だからだ。これまでは ! を付けなければパターンは字面通りの文字列として解釈(正規表現のメタ文字はエスケープ)されていたので、これでよかったのだが、

新しい仕様ではこれを正規表現として解釈するので /* は 0回以上の / という意味のパターンになってしまう。これをエスケープするには

Alignta -e /* -e */

または

Alignta -E /* */

としなければならない。こうして見ると結構めんどくさい気がする。というか、うっかりエスケープの指定忘れが頻発しそうな予感。

厄介なことに * は C言語のコメント開始/終了に使われている記号なので、このミス(エスケープの指定忘れ)、やる人が多いんじゃないかなー。

やっぱり、こういう意図しない整列が行われてしまう可能性があるので、デフォルトが正規表現になっているのはちょっとまずいかも知れないと考えている。デフォルトとしては字面通りの文字列として解釈されることを保証して、一部正規表現を使用したいところで、安全装置を解除する的な仕様の方がいいのではないだろうか。

コマンド名に ! を付けたら正規表現として解釈、というのは元々そういう発想にもとづいたものだった。ただ、「それって2つのコマンドの使い分けだよね」、「一括指定しかできないの」、というところが元々の問題意識だったはず。

だったら逆に、正規表現として解釈したいものの前に -r とか -R とかを付けるようにした方がいいのではないか。(-regexp, -Regexp ね)

Alignta -r \d\+

だがこれも、うっかり -r を忘れるというミスが頻発しそうな予感。あちら立てればこちら立たず、ぬーん。

こうなったら、正規表現っぽく見えるものは正規表現として解釈、みたいな仕組みを取り入れてみようか。例えば、\ でエスケープされた文字があればそれは正規表現のメタ文字(である可能性が大)なので、それは正規表現と解釈するとか。そうすれば、エスケープの指定やら、正規表現としての解釈の指定やらをしなくても

Alignta \d\+ /* */

こんなのが通るようになる。で、この自動的な解釈の振る舞いを抑制するのに -e とか -r とかを使うようにすればいい感じになるのではないか。

日本語プログラミング言語探訪 〜プロデル〜

プロデル

概要

プロデルとは


プロデルは、日本語で簡単・気軽にソフトウェアを
「造る」ことができるプログラミング言語と開発環境です。


フランス語で「造る」「生産する」といった意味がある動詞"Produire"を
呼びやすく「プロデル」と名付けました。


前シリーズであるTTSneoの良さを活かしつつ、
プロデルでは、より日本語らしい文法の導入やオブジェクト指向的概念の導入、
処理速度の改善など、さまざま点が一新しました。

サンプル

資料[2] より。

値段は、250
「消費税込みの値段は、[値段*1.05]円です。」を表示
内容は、「a,b,c,d,e,f,g」
配列は、(内容を「,」で区切ったもの)

配列を要素へそれぞれ繰り返す
: 要素を表示
繰り返し終わり
3回、繰り返す
 「ワン」を表示
 繰り返しを続ける
 ーーこれ以降は実行されません。
 「ニャン」を表示
繰り返し終わり
メモ
  • TTSneo の後継(だが互換性はほとんどない)
    • オブジェクト指向プログラミングが可能に
      • クラスに相当する「種類」を定義し、オブジェクトを生成する。
  • .NET Framework を用いて開発されている。
    • ということで、やっぱり Windows がプラットフォーム
    • 多くのウィンドウ部品がWindows 7/Vista/XPのテーマに対応
  • WindowsGUIアプリ作成が主な用途?
    • プロデルデザイナという開発環境が付属
      • エディタ
      • フォームデザイナ
  • Webアプリが開発可能
    • Webアプリ構築キット
      • プロデルで書かれたWebアプリケーションを、動作させることができるプロデル専用Webサーバがある。

日本語プログラミング言語探訪 〜TTSneo〜

TTSneo

概要

TTSneo公式サイト


日本語プログラミング言語「TTSneo」は、日本語で気軽にプログラムを作ることができるスクリプト言語です。


* テキストエディタメーラー、イメージビューアなどソフト作りに最適
* プログラミング未経験の方でも分かりやすいマニュアルとサンプル
* ファイルの整理や圧縮、データ処理など操作を自動化
* マウスでウィンドウをデザインする機能など開発環境も充実
* プラグインを使って機能の拡張可能

サンプル

公式サイトより。

ウィンドウ1の作成
ウィンドウ1を表示する
待機する

手順は ウィンドウ1の作成
’<ウィンドウ1>
ウィンドウ1を使う
  その名前を「ウィンドウ1」へ変える
  その背景を&h8000000Fへ変える
’<メニュー>
  メニュー 「ウィンドウ(&W)」を作れ
  サブメニュー 「常に手前」を手前チェックとして作れ
’
  ウィンドウ1の中の大きさを(304,209)へ変える
’
終わり
手順は ウィンドウ1のウィンドウ(&W)の手前チェックをクリック
  状態は、メニューのウィンドウ(&W)の手前チェックのチェック
  状態は、1−状態
  メニューのウィンドウ(&W)の手前チェックのチェックは、状態
  ウィンドウ1の最前面を状態に変える
終わり
メモ
  • Visual Basic で開発されており、実行に Visual Basic 6.0ランタイムが必要(フルパッケージ版にはランタイムが同梱されている)
    • ということで、Windows をプラットフォームとする言語(というか環境?)
  • プラットフォームは Windows と割り切っている分、Windows との親和性が高い
    • Visual Basic に用意されているほとんどのGUI部品を利用可能
    • 外部DLL や Windows API との連携も可能
  • WindowsGUIアプリ作成が主な用途?
    • TTSneoデザイナという開発環境が付属
      • エディタ
      • フォームデザイナ
  • 個人が趣味で開発とのこと
    • しかし、公式サイトの充実度はすごい!

最後の資料より。

  • ウイルスの開発に使われたという実績(?)がある。