2009年11月13日金曜日

F# に思うこと

F# http://journal.mycom.co.jp/articles/2009/09/16/vs2010/001.html

OCaml に似た関数型言語。.NET フレームワーク上で動作する。つーか誰が作ってんだろ。
.NET 上、というところが魅力でもあり、ガッカリなところでもあるという気がした。

性能/電力:
性能/電力が重視されるこの時代に .NET や Java 等の VM を使ったソリューションは適合するのだろうか。.NET はともかく Java の VM の性能はかなり高くなっているので、JIT コンパイルのコストはあるとはいえ、ピーク性能時の性能/電力には大差はない(いや、あるだろうけど理想論で考えよう)。JITコンパイルコストも、低負荷時の低電圧動作時にあらかじめコンパイルとかすれば良さそうだ。Java だと VM 自体を起動するコストは馬鹿にならないので、複数のVM間でリソースを共有できる仕組みは必要だろう。JRuby は起動が遅くてがっかりする。

結局のところ、複数のアプリケーション間のリソースの共有がポイントな気がする。VM自体もリソースなので、VMのコストの低減・共有は重要そうだ。でもなあ、Android とか見てると、VM はやっぱ遅い(性能/電力が悪い)気もするな。まあ、用途によるが。

リソース共有:
Go (golang.org) とかを見ていると、VM のコストがない世界というのも魅力的に思える。VM がないと言っても、リソースの共有や基盤の共通化はした世界だ。例えば、GC、リフレクション、ライブラリ等のランタイムは共有する。Objective-C が近いかもしれない。ランタイムと言語は分離する。さらに上に VMが乗ってもかまわないし、スクリプト言語が乗ってもかまわない。

強力な(モダンな)ランタイムを持った高効率な言語があり得るのなら(Goとか)、こういう世界もありかもしれない。VMを捨てる以上、sandbox 的機能はあきらめるか、言語で実現しないといけない。いや、iPhone とかを見るに、言語というよりOS, APIレベルで実現するという感じか。でも、言語が Go だけじゃダメだけど。


まあ、ようするに、F# は言語として魅力的だけど、ランタイムとかの実装は Go みたいなのが良いなあと思った。Go のランタイム・リフレクションは OO, generic, exception が弱そうだけど。

2009年11月12日木曜日

The Go Programming Language 試用中

http://golang.org/

exception がないのはいやですが、ソースコードを見た感じでは作りは良さそうなので、ちょっとは使ってみようかと思う。が、all.bash が通りません。いったいどういうリポジトリを公開してるんだか。まあ一部の test に失敗しているだけのようで、しかも test 自体に問題があるような感じではある。

とりあえず go.y を覗いたところ(文法変える気?)、シンプルな感じ。全体的にソースコードはかなりきれい。exceptionがないぐらいで見捨てるのは忍びない。


以下、お約束:
fib.go:
package main

import fmt "fmt" // Package implementing formatted I/O.

func fib(a int) int {
  if a==0 {return 0}
  if a==1 {return 1}
  return fib(a-1)+fib(a-2);
}

func main() {
     a := 40;
     fmt.Printf("fib(%d) = %d\n", a, fib(a));
}
fib.c:
#include "stdio.h"
int fib(int a){
  if(a==0) return 0;
  if(a==1) return 1;
  return fib(a-1)+fib(a-2);
}
int main(int argc, char **argv){
  printf("fib(40) = %d\n", fib(40));
}
result:
$ 6g fib.go && 6l fib.6 && time ./6.out
fib(40) = 102334155

real    0m2.245s
user    0m2.186s
sys    0m0.017s
$ gcc -O2 fib.c && time ./a.out
fib(40) = 102334155

real    0m2.434s
user    0m2.384s
sys    0m0.014s
気になった点:
  • 関数の引数、戻り値の型は省略できないようだ
  • if 文の{}は省略できないようだ 
  • compile 時間は fib だと gcc の方が早い
使いやすさよりも、まずは処理系に優しい言語という感じ。

2009年11月11日水曜日

The Go Programming Language インストール中

型推論を使った、Script 風味の言語ぽい。これはいいコンセプト。文法が、、、ややがっかり感ありますが。

コンカレンシ、GC、クロージャ等を言語機能として実装することに関しては、
  • concurrency
    • ruby で残念なのはここだな。JRuby があるけど。producer/consumer みたいな、基本的なパターンがシンプルにかけることは重要だと思うので、まあ賛成。
  • GC
    • 現実問題、生産性を考えると必要だと思う、ので賛成。いかに性能を落とさないかだな。
  • クロージャ
    • 性能が気になります。GC の性能が良ければ平気なのかな。
等と妄想しながらインストールしていたのだが、、、
  • Generics
    • まだありません。あー、それで、runtime になんとかする様になってるのね。C++ とかの template は凄いからな。runtime になんとかする方向でいいと思うけどね。いや、でもこれは走りながら考えるべき機能じゃないと思うが。
  • Exception
    • まだありません、、、。それはそれでいいんじゃないですか、、、とはさすがに思えんな。これはどうなんだろ。何かしら代替えが必要かと。
だそうな。まあ、

Who should use the language?

Go is an experiment. We hope adventurous users will give it a try and see if they enjoy it. Not every programmer will, but we hope enough will find satisfaction in the approach it offers to justify further development.
だそうなので、いいんですけどね。 なんか、インストール終わる前に熱が冷めてしまった。

正直なところいったい何がソフトウェアの生産性向上のために必要なのかはわかりませんが、ちょうどいい言語がない気はします。僕は、強い型(推論も可)と、 Ruby の文法(書きやすさ)、C++ 並みの速度、script or コンパイルが早い、とかその程度でいいんですけど。

一生 C++/SWIG/Ruby ってことは流石にないと思うんだよな。

2009年11月10日火曜日

4.29497e+09 in C++

 C++ でプログラムを書いていて、がっかりなバグに出会った。
int main(int argc, char**argv){
#define LOG(X) std::cout << #X << ":" << X << ", " << typeid(X).name() << std::endl
    LOG(-1U);
    LOG(int(-1U));
    LOG(float(-1U));

    std::vector vi(1);
    float a = -vi.size();
    LOG(a); // -1 expected !!!
}
出力:

-1U:4294967295, j
int(-1U):-1, i
float(-1U):4.29497e+09, f
a:4.29497e+09, f
float a = -vi.size(); なんてコードを、なんの疑いもなく書いてしまった。しかも、-1 になることを期待して。僕の頭の中では int operator - (unsigned int); だと思っていた。

int a = -vi.size(); は -1 になる。きっと、こういうコードが結果的に期待する結果になるせいで単項-演算子の型を勘違いして覚えてしまったのだろう、、、。

そんな訳で、4.29497e+09 は覚えておいて損はない値。(かもしれない)

2009年11月2日月曜日

Ruby, HTTP, timeout, rescue のメモ

Ruby で http 経由で画像をダウンロードしようとして色々嵌まった。
嵌まった足跡満載のコード

begin
  uri = URI.parse(uri_str)
  http = Net::HTTP.new(uri.host, uri.port)
  http.open_timeout = 5
  http.read_timeout = 20
  http.start do |http_local|
    begin
      response = http_local.get(uri.path)
      if response["content-type"] =~ /image\/([^\s]+)/
        ext = $1
        fname = IMAGEDIR+"/#{wid}/#{id}.#{ext}"
        open(fname, "w") do |w|
          w.write response.body
        end
      end
    rescue Errno::ETIMEDOUT, TimeoutError, Timeout::Error, Exception
      log.puts $!.inspect
    end
  end
rescue Errno::ETIMEDOUT, TimeoutError, Timeout::Error, Exception
  log.puts $!.inspect
end

  • http.open_timeout は HTTP.start(uri) do ... の中で指定しても意味がない。startでopenされてしまうから。
  • timeout の例外は素の rescue (StandardExceptionを受ける)では拾えない。で、何を投げるかnet/http のドキュメントに書かれてない。
    • ドキュメントにない以上、 おすすめは "rescue Object" だ。がっかり。
  • http.start はスレッドですか?
    • スレッドだとして、終了までブロッキングしますか?。とか迷って http_local とかできてしまった。
    • 例外が捕まらないから Thread からの例外なのかと思って迷走してしまった。

 ドキュメントに載せるサンプルがいまいちなのだと思う。こんなサンプルだったら迷走せずに済んだ。
begin
  uri = URI.parse(uri_str)
  http = Net::HTTP.new(uri.host, uri.port)
  http.open_timeout = 5
  http.read_timeout = 20
  http.start do
    response = http.get(uri.path)
    do_something(response)
  end
rescue Object # orz
  # handle_exception
end
 うーん、いや、サンプルはもっと練られていた方がうれしいな。
open_timeout とかは、HTTP.start の optional 引数(:open_timeout => 5) とかにできた方がいいな。
http.start do はもうブロックにする意味がない。すると start って名前もなんだか。

以下疑似コード。動かないけど、こんな感じであってほしかった。

begin
  uri = URI.parse(uri_str)
  response = Net::HTTP.get(uri.host, uri.port, :open_timeout => 5, :read_timeout =>20)
  do_something(response)
rescue HTTP::TimeoutException
  # handle_timeout
rescue
  # handle_exception
end