2013-05-21

とりあえず10分、を始めて1年

自習できる人をうらやましがっている増田がいました。

会社を定時上がりしてもダラダラパソコンやったり携帯見てしまう

無駄な時間だと思っててもあとちょっとだけを繰り返して23時

文章どおり受け取り、かつ、勝手に妄想で補完すると、自習自体ができないんじゃなくて、取りかかるのが億劫なんだと思います。それにはとても共感します。自分もずーっとそんな感じだから。想像するだけだでしんどさ、面倒くささに圧倒されて、結局何もやらずに済ませていまいます。

そんな自分もとりあえず10分だけやるというのを実践しはじめて、1年くらいたちました。10分たったたらどんなに進展がなくてもやめてもいい、というルールもつけてます。

よいニュースと悪いニュースがあります。ほんとに何もできずに終わる日もありますが(ほとんどがこのパターン)、気分が乗ってきて数時間続けている日もあります。Better than nothing と言い聞かせて、あんまりしんどい思いをせずに、少しずつだけど何らかの意味ある活動に時間を費やせるようになりました。悪いニュースは、この活動が直接的に昇給など、目に見える結果には反映されていないことです。闇雲に仕事をしたからって昇給しないのと同じですね。

さてさて。こういうプラクティスを、TODO管理ツールなりカレンダーなり、しくみやツールに自然に組み込めるといいんだろうな、と思っています。

2013-05-10

Go で関数に型っぽく渡す

先日、Go の型は First-class ではないことを、ぐずぐず書いていたら、こんなコメントがありました。

もともと困っていたのは、型を引数にできないことでした。そして、見たところ Go は型(int とか、type Foo struct{...} の Foo とか)を引数にできません。できないのですが、やりたいことは「型をわたすこと」ではありません。

やりたいことは、「クエリ対象の指定をもうちょい安全にしたい」です。NewQuery(c, "Foo") だと "Eoo" と書いて渡してもコンパイルを通ってしまい実行時にエラーになるけれど、すでに定義してある Foo 型を使うのだ、と記述することができれば少しは安全側に倒れるのではないか、と考えたわけです。その仮定で、型を知らせるために、使いもしない変数を定義することに居心地の悪さを感じていました。

そこで @mattn さんの &Foo{} という書き方ですよ。f(&Foo{}) や f(Foo{}) と書けば型を知らせているのだ、と分かりやすいし、余計な変数宣言もないしで、なかなかいい。たぶん Foo 型の値が生成されそうで、要らないメモリだろうと思ったりもしましたが、自分が書くコードではもっと別なボトルネックがありそうです。そんなわけで、この書き方いいなぁと思っています。

あとですね。そもそも型を渡して〜というアプローチが、 Go の考え方に合っていない気がしています。先日のブログにも書いたのですが、ここではクエリを発行して、そのあとデータストアから Foo の配列に値を取ってくるわけです。非同期に実行するとしても chan を使うでしょう。なので Foo の型情報を持った変数が、文脈上あとで必ず出てきます。であれば、ここからここまでで Foo 配列に対する操作をしまっせー、という中にクエリ発行が出現する、という書き方もできて、それが合っている気もしてきました。

2013-05-08

Go の型は First-class ではない

Go の型は First-class ではない、ということにゴールデンウィーク最終日に気づき、悶々としています。(何も Go が悪いわけではない)

ことの発端は、以下の様な関数を定義したところから始まります。

func getName(x interface{}) string {
  return reflect.TypeOf(x).Elem().Name()
}

この関数に、任意の型のポインタをわたすと、型の名前を取得できます。けど、ポインタを渡さなければならないのですね。

  var foo *Foo
  name := getName(foo)

foo は使わないのに! 使わないというのはウソですね。けど、ちょっと違うんですよ。まあこれは私がPython 脳だからであって、別にGoが悪いわけじゃない。

何をしたいかと言うとですね、Google App Engine datastore のクエリの生成をラップしたいのです。標準ライブラリを使うと、以下のように書きます。

  c := appengine.NewContext(r)
  q := datastore.NewQuery("Foo")  // ☜(◉ɷ◉ )
  q.Filter("Y =", "xaxtsuxo")
  foos := make([]Foo, 0, 10)
  keys, err := q.GetAll(c, &foos)

Foo が型が定義されているのに、文字列で "Foo" を渡すのが悔しいわけです。そこはコンパイル時にスペルミスをひっかけて欲しいわけですよ。ストアされているデータと、Foo の定義が違うと、それはそれで実行時エラーになるんだけど。なので、

func createQuery(AnyType) *datastore.Query

のような関数を定義したいな、と思ったのですね。ところが、型は渡せないのです。以下のような方法に落ち着きます。

func createQuery(x interface{}) *datastore.Query {
  kind := reflect.TypeOf(x).Elem().Name()
  q := datastore.NewQuery(kind)
  return q
}

…

  var foo *Foo
  q := createQuery(foo).Filter("Y =", "xaxtsuxo")
  var foos := make([]Foo, 0, 10)
  keys, err := q.GetAll(c, &foos)

あぁ foo 使わないのに。いや、 配列の foos があるんで、そっち使えよって話なんだけど。なんなら GetAll せずに、foo を使ってイテレートするのが筋なのかも知れません。

ああ、そんなこと言い出したら、Filter にだって文字列を渡してるぞ。そう考えると GAE/Python の NDB はよくできてるなぁ、あのライブラリ作った人は Python のことよく分かってるなぁ。薄いラッパにしたかったんだけど、やっぱり厚くなってしまうのかなぁ。PropertyList とか PropertyLoadSaver をうまく使ったらよいのか? ぎゃぁ。というわけで連休が終わってしまったので、ペースダウンしていきます。

2013-05-06

Go の struct に任意の名前のフィールドがあるか調べる

静的型付け言語たる Go ですが、実行時にごにょごにょすることを reflection と言うらしく、reflect パッケージが標準で入っています。

v := Foo{}
structField, found := reflect.TypeOf(v).FieldByName("x")

Foo 型に x フィールドが存在すれば、found に true が入ります。http://play.golang.org/p/F9TY4RcBEC

値とポインタは異なった型なので、もとの struct にたどり着くまでの道筋が異なります。 http://play.golang.org/p/_V19gURisU

v := Foo{}
typeFromValue := reflect.TypeOf(v) 

p := new(Foo)
typeFromPointer := reflect.TypeOf(p).Elem()

それから struct 定義のとき、各フィールドにタグをつけられますが、これも reflect パッケージを使って取得できます。http://play.golang.org/p/K__zcCZ7Nd

type Foo struct {
 int
 x string `wozozo:"show" hoge:"fuga"`
}

func main() {
 v := Foo{}
 t := reflect.TypeOf(v)
 field, _ := t.FieldByName("x")
 fmt.Println(field.Tag)  // => `wozozo:"show" hoge:"fuga"`
 fmt.Println(field.Tag.Get("wozozo")) // => show
}

フィールドにつけるタグは文字列ならなんでもいいのですが、key:"value" のフォーマットをスペース区切りにしたものを定義すると、structTag.Get(key) で value を取得できます。Google App Engine では、エンティティのフィールド定義に struct を書くときに、インデックスしてくれるな、とか、struct には含むけどエンティティとして保存するな、のような指示に使われています。