Golang: 構造体がインタフェースを実装しているかコンパイル時にチェックする

構造体がインタフェースを実装しているかコンパイル時にチェックする話。公式のFAQ [1] や Effective Go [2] ではすでに説明されているが、知らなかったのでメモ。

go1.0.3 を想定。以下のような Animal インタフェースがあるとする。

type Animal interface {
    Bark()
    Move()
}

Animal を実装するためには、Animalで定義されているメソッドの集合、Bark()とMove() を実装する必要がある。例えば、Cat という独自の型 (構造体) を定義して、それが Animal を実装するとする。

type Cat struct {}

Move() メソッドの実装を忘れて、Bark() メソッドだけを呼び出す場合

このとき、もし Bark() だけを実装して昼ご飯に行って、うっかりMove() の実装を忘れたする。そして、Bark() だけを実際のコードで呼び出したとする:

package main

import "fmt"

type Animal interface {
    Bark()
    Move()
 }

type Cat struct{}

func (_ *Cat) Bark() { fmt.Printf("にゃーん\n") }

func main() {
    var c Cat
    c.Bark()
}

link: http://play.golang.org/p/t7TZfQeGMx

上のコードをリンク先で実行してみると分かるが、Goのコンパイラは、型CatがメソッドMove() の実装をし忘れたにもかかわらず、エラーを起こすことなく正常に終了する。

未定義のMove()メソッドを呼び出した場合

では、上記のコードのmain関数でMove() を呼び出してみるとどうなるか?

package main

import "fmt"

type Animal interface {
    Bark()
    Move()
}

type Cat struct{}

func (_ *Cat) Bark() { fmt.Printf("にゃーん\n") }

func main() {
    var c Cat
    c.Bark()
    c.Move() // error
}

http://play.golang.org/p/AWW92b7-Jq リンク先のコードを実行してみるとコンパイルエラーが発生して、以下のようなメッセージが表示される。

prog.go:17: c.Move undefined (type Cat has no field or method Move)

今回の例ではインタフェースとCat、Move() の呼び出す関数 (main.main) が同じパッケージ内にあり、インタフェースを実装すべきメソッドが二つしかないという状況なので、コンパイルエラーの原因はインタフェースが定義している Move() の実装し忘れのせいだと気づくことができる。しかし上記のメッセージでは、Cat がインタフェースのメソッドのMove() を実装し忘れてエラーになっているのか、Cat独自のメソッドとしてのMove() の実装し忘れているのか、どちらがエラーの原因なのか区別がつきにくい。インタフェースで定義されているメソッドがもっと多い場合や、インタフェースとそれを実装する型のパッケージが違うパスにある場合には、さらにエラー原因の特定が難しくなると思う。

もっと問題なのは、先ほどの例にもあったように、もし、未定義の c.Move() を呼び出す実際のコードがない場合(Cat の単体テストで Move() に対するテストを書いていない場合など)、エラーが発生しないということ。

対応策

そこで、[2] でも説明されているが、コンパイル時に CatがAnimalインタフェースのメソッドをすべて実装しているかどうかチェックするための方法(一種のhack)として、以下の行を Cat を定義する同じパッケージ(今回の場合は main)に追加する。

var _ Animal = (*Cat)(nil)

これを一般的 (?) に書くと、

var _ インタフェース = (*独自の型)(nil)

となる(イコールの右側は nil から「インタフェースを実装している型へのポインタ」への型変換することを意味する [3])。 上のテクニックを先ほどのコード例に適用したものを以下に示す。

package main

import "fmt"

type Animal interface {
    Bark()
    Move()
}

type Cat struct{}

// Cat implements the Animal interface.
// See: http://golang.org/doc/faq#guarantee_satisfies_interface
var _ Animal = (*Cat)(nil)

func (_ *Cat) Bark() { fmt.Printf("にゃーん\n") }

func main() {
    var c Cat
    c.Bark()
    // c.Move()
}

http://play.golang.org/p/sjs-5dXIAS

このコードを実行してみると分かるが、このテクニックを使うと、実際に Move() を呼ぶコードがなくても、インタフェースを実装すべきメソッドが不足しているという旨のコンパイルエラーが表示される:

prog.go:14: cannot use (*Cat)(nil) (type *Cat) as type Animal in assignment:
    *Cat does not implement Animal (missing Move method)

詳しい説明は以下のリンク先を参照のこと。

追記: コード例が一部間違っていたので、修正。

ブラケット表記された句構造木をtikz-qtree形式に変換するツールを作った

img

 

ブラケット表記された句構造木を tikz-qtree 形式 (正確には Qtree 形式) に変換するツールを作りました。ネーミングが微妙ですが...。出力された LaTeX ファイルを pdflatex などでコンパイルすると上図のような構文木が得られます。

 

https://github.com/tetsuok/bracket-to-tikz-qtree

 

使い方は

$ ./bracket_to_tikz_qtree.py [options] FILE

または

$ ./bracket_to_tikz_qtree.py [options] [FILE] -

入力となる FILE はブラケット表記された構文木を含むテキストファイルです。なお、出力された LaTeX ファイルをコンパイルするには tikz-qtree をインストールしておく必要があります。

 

また、`--enable-pdf` オプションを指定すると、入力ファイルに複数の文の解析結果が含まれている時に、各構文木ごとに pdf ファイルを直接出力できるようにすることができます。注意点として、python から subprocess モジュールを使って `pdflatex` を実行するので、pdflatex がインストールされていないと動きません。

$ ./bracket_to_tikz_qtree.py --enable-pdf FILE

 

品詞のタグや句構造木の詳細については Penn Treebank のマニュアルをご参照下さい。

なぜこれを作ったか?

最近よく句構造木を眺める機会が増えてきました。Penn Treebank や Stanford parser, Berkeley parser の解析結果はブラケット表記であり、個人的には上図の木構造の方が分かりやすく、またスライド作成や論文に載せる時に便利だと思い作りました。別に括弧の嵐が嫌いではないのですが、長い文の解析結果を見るときはさすがにシンドイので。

CoNLL-X フォーマットの依存構造木のデータを tikz-dependency で描画するためのツールを作った

最近朝晩はめっきり寒くなってきました。CoNLL-X フォーマットの依存構造木のデータを tikz-dependency で描画するためのツールを作りました。

https://github.com/tetsuok/conllx-to-tikz-dep

image

機能は単純で入力として CoNLL-X のデータを与えると、latex のファイルを標準出力に出力するというものです。出力されたファイルを pdflatex や xelatex などでコンパイルすると、依存構造木の pdf ファイルができます。現在のところ、3種類の実装を用意していて、python 版と Go 版と C版があります。python と Go のコードのみ吐き出す latex ファイルをオプション指定して一部調整ができます。出力された latex ファイルをコンパイルするには、tikz-dependency のパッケージが必要です。

 

 

LaTeX で画像だけの PDF を生成する

 f:id:tetsuok:20120912051557j:plain

LaTeX のソースで \documentclass で  standalone クラスを指定して pdflatex や xelatex でコンパイルすると, TikZ などで図を作るときに図の周辺の余白を切り取った pdf ファイルを生成してくれるので便利です [1,2].

図は日本語と英語の文に対して単語アライメントをとったものです.

[1] http://stackoverflow.com/questions/2701902/standalone-diagrams-with-tikz

[2] http://www.texample.net/tikz/examples/glider/

図の TeX のソースは以下の通りです.

 

OS X で gdb 7.4 がクラッシュする話

OS Xgdb 7.4 をビルドして C/C++ のプログラムをデバッグしていると, 同じセッションで2回プログラムを実行すると悲しいことが起きます:

長らく何でだろうと思っていたところ,  [1] でバグとして報告されていました. エラーを見ると分かると思いますが, malloc されていない間違ったポインタを free していたことが原因のようです.  件の問題を修正するパッチが開発版の方にチェックインされたようです [2] . 修正点は gdb/solib-darwin.c の 関数 darwin_bfd_open() の return res; の前に一行を加えるというものです. [2] の変更は gdb 7.4.1 のソースにも適用することができます. これにより先のクラッシュの問題を修正することができます.

ちなみに [1] のバグリポートを読むと  gdb のバックトレースを得るために, gdb を使って gdb をデバッギとして走らせて, その上でテストプログラムを実行しているのが面白いです.

[1] http://sourceware.org/bugzilla/show_bug.cgi?id=13619

[2] http://sourceware.org/ml/gdb-patches/2012-02/msg00098.html

golang でビルド時に最適化をオフにする

Go のプログラムのデバッグ時に gdb が便利だよということは Debugging Go code with GDB に書いてあるのですが, gdb で変数の調査をしようとしたときに, ローカル変数の値がレジスタに載っていて表示されない場合があります. もちろんレジスタを見れば分かるわけですが... 今回はレジスタを見ずに変数の調査をしたい場合があると仮定することにします. メーリングリストあたりを検索したところ go build に -gcflags '-N -l' をつけると最適化をオフにすることができるようです [1,2]

例を見てみましょう. 以下のような 1 から 9 までの整数の和を求めるコードがあったとします. 

 

このコードの 14 行目の変数 n の値を調査したいとします. コードをコンパイルして gdbデバッグすると以下のような結果になります. 使用した Go のバージョンは 1.0.2 です.

40行目を見ていただくと分かるように, n の値は "No symbol "n" in current context." となっていて print では値がわかりません. この場合, 変数 n の値はレジスタに載っているのでレジスタを参照する必要があります. 

 

それではビルド時に -gcflags '-N -l' をつけて最適化をオフにしてビルドしてみます.

 37, 38 行目を見てもらうと分かる通り, n の値が print で表示できるようになりました. ちなみに関数 sum() 内のローカル変数 sum の値も表示できるようになります.

とここまで書いておいてなんですが, 実はレジスタを参照して n の値を調べるのは難しくはありません. 例を以下に示します (もちろん変数 sum の値を調べることも可能です).

41 行目で rip レジスタ (インストラクションポインタ) の内容を調べると, 43 行目で関数 sum が呼ばれることが分かるので, 44行目でその結果が ecx レジスタに格納されるという予想がつきます.  実際に ecx レジスタの値を表示すると関数 sum の結果が入っていることがわかります (57, 58 行目).

ちなみに gdb を使ったデバッグの仕方については以下の本の 2章 (0x200) プログラミングの部分に分かりやすく書かれています.

Hacking: 美しき策謀 第2版 ―脆弱性攻撃の理論と実際

Hacking: 美しき策謀 第2版 ―脆弱性攻撃の理論と実際

[1] https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/6m8bZYik8Ss

[2] http://code.google.com/p/go/issues/detail?id=3363

TikZ-dependency で 係り受け木を描く

f:id:tetsuok:20120630035011j:plain

自然言語処理の本や論文を読んでいると, 綺麗な曲線で係り受け木を描いてあるものがあります. 一体どうやって書いているんだろうとずっと以前から思っていたところ, 先日 tikz-dependency という LaTeX のパッケージを見つけました. これは PGF/Tikz (以下 tikz) のラッパーとなっていて, 係り受け木を描くために特化したものとなっています. 論より証拠ということで, 日本語の文の係り受け木を描く例のコードを示します.

係り受け木を描く機能は dependency 環境を使います. オプションとして "theme = simple" というのがありますが,これは係り受け木の見栄えを変えるものです. 続いて入力となる文を deptext 環境内に書きます.コードの例では,文節単位の日本語の係り受けを考えているため,文節単位で区切っています.  そして, 各文節間の係り受け関係を \depedge 命令で指定します. \depedge は "係り元文節ID", "係り先文節ID", "ラベル" の 3つの引数が必要です. この文節 ID は 先の deptext 環境内に書いた各文節のインデックスです. インデックスは 1 から始まるようになっており, tikz-dependency 側で勝手に割り当てられるようになっています. 上のコードを XeLaTeX でコンパイルすると記事の最初にあるような図が出来上がります. 個人的には power point や Keynote で頑張って曲線を描いていたときよりもずっと楽に書けると思います (卓越したマウスやトラックパッドによる微調整も不要です).