Scala で 20.minutes.ago [Scala]
Ruby で整数型にメソッドを付け足したりすると 20.minutes.ago みたいな書き方ができるけど C# 3.0 でもそういうことができるようになるという話 [1] [2] [3] を読んだ。
Scala だと既存クラスを拡張するという形ではなく暗黙の型変換 (View) を定義してあげることによって同じことができる。
scala> import java.util._
import java.util._
scala> class TimeSpan(n:long) { def ago = { new Date((new Date).getTime - n) } }
defined class TimeSpan
scala> class ExtendedInt(n:int) { def minutes = { new TimeSpan(n * 1000 * 60) } }
defined class ExtendedInt
scala> implicit def int2eint(n:int):ExtendedInt = { new ExtendedInt(n) }
int2eint: (int)ExtendedInt
scala> 20.minutes.ago
unnamed0: java.util.Date = Thu May 31 20:32:50 JST 2007
scala> new Date
unnamed1: java.util.Date = Thu May 31 20:52:53 JST 2007
仕組みはこうだ。整数型には minutes というメソッドはないので Scala コンパイラは整数型を minutes メソッドを持つ型に変換できないかと思って暗黙の型変換メソッドを検索する。そこで int2eint というメソッドを見つけてこれを使って ExtendedInt に変換し、その ExtendedInt 型のオブジェクトの minutes メソッドを呼ぶようにする。このメソッドは TimeSpan 型のオブジェクトを作って返す。以降は説明不要と思う。
ついでに Ruby らしい構文と思われる 3.times do ~ end みたいなものも同様にして作れる。
scala> class Loop(n:int) { def times(x:()=>Unit):Unit = {for (i <- 1 to n) x() } }
defined class Loop
scala> implicit def int2loop(n:int):Loop = { new Loop(n) }
int2loop: (int)Loop
scala> 3.times { () => Console.println("cheer"); }
cheer
cheer
cheer
unnamed0: Unit = ()
で、ここまで書いておいてなんだけど個人的には 20.minutes.ago とか 3.times みたいな書き方はまだあまり好きになれない。この感じを説明するのは難しいけど、「高度に自然言語に似せたコードは出鱈目と区別がつかない」とでもいうものだろうか。コードが「確かにこれでいい」という感じがつかめなくなる気がするのだ。慣れの問題かもしれないけど。
Ruby にしたってコードの大抵の部分は全然英語の構文通りじゃない見かけをしているわけで、そこにひょっこり 20.minutes.ago が出てきてもそんなにうれしいかなあと思う。短く書けるというだけならもっとプログラミング言語として無難な表現方法はありそうだし。
[1] http://haacked.com/archive/2007/05/24/ruby-like-syntax-in-c-3.0.aspx
[2] http://www.rubyist.net/~matz/20070526.html#p01
[3] http://haacked.com/archive/2007/05/28/the-only-universal-language-in-software-is-english.aspx
コメント 0