2006-11-06
● [mixiより転載] 企画
この1年ほど、時間があるのをいいことに*1様々な企画を立ててきました。思い返すと、アメリカ旅行に始まり、飲み会とか飲み会とかひたすら飲み会とか、ほかにも山登りやらスキーやら。
もちろん今も現在進行形の企画がいくつかあります。そんな中からいくつか:
Worse:
- 「でも〜」「もしかしたら〜」と逆説の接続詞ばかり使う人は、結局最後まで参加表明しない。
- 募集期間が1ヶ月間の企画は、最初の1週間で参加者のほとんどが集まる(残り3週間は意味なし)。
- 「○○さんが行くなら行く」という人は、呼んでも呼ばなくても同じ。というか、呼ぶだけ手間がかかって時間の無駄。
- 「またの機会にお誘いください」(=漠然と誘われるのを待っている←「次の○○の時はぜひ」という具体性がない)という人は、たぶん次回も来ない。
- 計画段階で話し合いに参加しない人は、現地でも足手まといになることが多い。(自分がその日どこで何をするのか把握してない)
Better:
- 「○月×日に○○しようと思うけどどう?」と聞いてその場で予定が返ってくる人は大抵参加してくれるし、その企画ではダメだとしても次回以降誘うと参加してくれる可能性大。
- いろいろ誘ってくれる人は、こちらが誘っても乗ってくれる。
- 本当に誘いたい人は、あらかじめ予定を聞いておいて、まずその人たちが全員参加できる日程を押さえる。
ま、そんな1年。
tour2006なるメーリングリストを作ってから350日が過ぎましたよ。
*1 まぁ、別に捨てるほど時間が余っているわけではないんですが…
2006-11-07
● [プログラミング] C++でiconvを
まぁ、もっともC++らしい使い方としては、最近のperlみたくstreambufの拡張としてiconvを組み込むことなんでしょうが、でもiconvってコンストラクタで変換先・変換元の文字コードを指定したら最後までそれを使いまわす必要があるわけで、そうするとネットワークプログラミングのように「(入力など)処理する文字列」と「プログラム中にハードコードされている文字列」が異なる場合にはあまり向いていないようにも思う。
iconv(3)の伝統的な使い方は、
iconv_t cd = iconv_open(to_code, from_code);
でオープンしたデスクリプタを使って、ひたすら
size_t s = iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft);
して、最後に
iconv_close(cd);
するんだけど、ポインタがたくさん出てくるし outbuf をどれだけ確保すれば良いかが直感的にわかりにくい。もちろん最長のパターンはおそらく "aあaあ" みたいな文字列を euc-jp → iso-2022-jp にする場合で、この場合だと6文字→18文字ってことで高々3倍なのはわかるんだけど。
そこで、勝手にバッファを確保してデストラクタで勝手に解放してくれるようなクラスってことで、iconverter を作ってみた。とりあえずこんなんでいいや。ストリームバッファの拡張だと柔軟性に欠ける。
iconv.hpp:
/* * iconv.hpp: character-set converter (header) * by Norihisa Washitake <nori at washitake.com> * $Id: iconv.hpp,v 1.1.1.1 2006/10/30 07:43:09 wassy Exp $ */ #include <iconv.h> #include <string> #include <iostream> class iconverter { public: iconverter(); ~iconverter(); std::string convert(std::string src, std::string tocode, std::string fromcode); protected: iconv_t open(const char* tocode, const char* fromcode); void close(); private: iconv_t cd; char* tocode_cache; char* fromcode_cache; };
iconv.cc:
/* * iconv.cc: Character-set converter * by Norihisa Washitake <nori at washitake.com> * $Id: iconv.cc,v 1.1.1.1 2006/10/30 07:43:09 wassy Exp $ */ #include <iconv.h> #include <string> #include <iostream> #include "iconv.hpp" iconverter::iconverter() { cd = 0; tocode_cache = NULL; fromcode_cache = NULL; } iconverter::~iconverter() { close(); } iconv_t iconverter::open(const char* tocode, const char* fromcode) { if (cd > 0) close(); iconv_t ret = iconv_open(tocode, fromcode); if (ret > 0) { cd = ret; tocode_cache = new char[strlen(tocode) + 1]; strcpy(tocode_cache, tocode); fromcode_cache = new char[strlen(fromcode) + 1]; strcpy(fromcode_cache, fromcode); } else cd = 0; return cd; } void iconverter::close() { if (cd > 0) { iconv_close(cd); cd = 0; } if (tocode_cache) { delete [] tocode_cache; tocode_cache = NULL; } if (fromcode_cache) { delete [] fromcode_cache; fromcode_cache = NULL; } } std::string iconverter::convert(std::string src, std::string tocode, std::string fromcode) { std::string ret; if (!tocode_cache || !fromcode_cache || tocode != tocode_cache || fromcode != fromcode_cache) { open(tocode.c_str(), fromcode.c_str()); } char* psrc = const_cast<char*>(src.c_str()); size_t srclen = src.size(); char* dst = new char[srclen+1]; char* pdst = dst; size_t dstlen = srclen; size_t dstmax = srclen; while (srclen > 0) { char* psrc_org = psrc; size_t n = ::iconv(cd, &psrc, &srclen, &pdst, &dstlen); if ((n != (size_t)-1 && srclen == 0) || (errno == EINVAL)) { srclen = 0; ret.append(dst, 0, dstmax-dstlen); } else { switch (errno) { case E2BIG: ret.append(dst, 0, dstmax-dstlen); pdst = dst; dstlen = dstmax; break; case EILSEQ: ret.append(dst, 0, dstmax-dstlen); ret.append(psrc, 0, 1); psrc++; srclen--; pdst = dst; dstlen = dstmax; break; default: ret.append(psrc_org); srclen = 0; break; } } } pdst = dst; dstlen = dstmax; if (::iconv(cd, NULL, NULL, &pdst, &dstlen) != (size_t)-1) { ret.append(dst, 0, dstmax-dstlen); } delete [] dst; return ret; }
使い方は、
#include "iconv.hpp" iconverter ic; string euc_str = ic.convert(sjis_str, "shift_jis", "euc-jp");
そんだけ。
しかしiconv(3)の問題点は、文字コードの判定ができないということで、このために結局独自アルゴリズムなりnkfなりを利用する必要があるってこと。うーん、これはなんだかよろしくない。かといってiconvで「適当な文字コードから(utf8へ)変換できるかどうか」で判定するのは重すぎる。もっとも、今回作ったのはメールのヘッダのBase64デコードなので、文字列中にちゃんとどの文字コードを使っているかが書いてあるから、そういう心配は要らないんですが。
キャスト演算子を使ったり使わなかったりしているのはご愛嬌。
2006-11-14
● [社会] 現代社会という科目
高校での履修不足問題が話題になった*1が、しかし高校は義務教育ではないのに要領に縛られる理由は何なんだろうか。必修科目なのであれば、それは義務教育で学ぶべきものなんじゃないだろうか。
思い返すと、自分が高校生だった頃は社会全体が緩く寛容だったこともあってか、高校そのもので現代社会という授業を受けた記憶がない*2。でも、法体系だとかについては人一倍詳しい。そんなものは習うより慣れろ、なんだと思う。
くだらない現在の個別の仕組みを学ぶ前に、日本における法体系の基礎を学ばせるべきだと思う。あとは、「人を殺してはいけないのは何故か」について考えさせれば、人間として生きていくには十分な社会的素養は身につくと思うのだけど。昔の人なら社会契約説を持ち出してくるんだろうけど、もはや社会契約説では説明ができないことは自明なわけで、大人が議論しても一つの結論に至ることはないだろう。もっとも、大人になっても深く考え続ける人は多くないのだろうけど、思考を止めてしまった大人たちが大人たちでいられてしまうことが現在の日本の一番の問題なんだと思う。
社会は暗記教科だと言われるが、どの教科目をとっても根底にあるのは問題を見つめ、考えることだけだ。
…という話に耽った秋の夜長。
2006-11-19
● [開発] 日本ユーザ会
当初はどこの日本ユーザ会も、「日本語(そのもの)が使えるようにすること」こそが目的だった。特に日本語は処理系によってEUC-JPやらShift_JISやらISO-2022-JPやらがあって、プラットフォームを特定しないサーバウェアなどになればなるほど日本語処理などが面倒だった経緯もあって、一時期は日本ユーザ会がたくさんあった。Unicodeが出てきても、しばらくは(Unicodeの)機種依存文字というわけのわからないものが残っていて、やはり日本ユーザ会のサポートというのは多少なりとも必要だった。
今は、UnicodeやUTF-8の諸問題がとりあえず無視できてしまうためかぼんやりと妥協点ができあがってしまっており(でもまだ問題は介在している)、またどのUNIXにも(そしてWindowsにも)libiconvが当たり前のように導入され日本語処理は共通のライブラリによって行われるようになったこともあって、日本語サポートは特段の考えがなくても可能になってきた。そうして、日本ユーザ会は役割を一つ失った。
で、必然性がなくなってしまったから、各日本ユーザ会の活動はどんどん下火になっているのが現状。日本語サポート機能追加ラッシュの時は開発側参加者もまた日本語サポートが必要だったけど、翻訳の場合は「翻訳できる人は和訳されたドキュメントを必要としない」というジレンマを有しているので、以前ほどユーザ会としてうまく機能しなくなっているように思う。少なくとも、日本のユーザーの特質として、対価を支払わなくてもそこそこ使えているものを、あえて自分が汗水を垂らしてより良いものにしていこうという奇特な人は少ない*1ので、ただのボランティアによるユーザ会はこれ以上持続しないだろう。
さて、そんなことを考えて、翻訳プロジェクトを再開すべきかどうか、判断に迷っているのだが、どうしたものか。
*1 つまり、「こんな機能が必要だから作ったんだけど、他のサイトでも使えそうだからコミットしてあげる」という人はいても、「何かできることがあるはずだから、参加してみよう」という精神はなかなか難しい、ということ。
2006-11-25
● [酒] しばらく解禁
一人酒はしないということにしているのだけれど、今の摂酒ペースのままだと忘年会・新年会シーズンを突破できないような気がするので、しばらく(一人でも)強制的に飲むことにします。これぞ胃腸ハック?
2006-11-26
● [プログラミング] Ajax
先日のネットワーク技術検討会(社内会議)で、「今後のインターフェイスはAjaxが当然のように使われる」とかいう話があったけど、本当にそうだろうか。盲目的にAjaxという言葉を使っているだけのような気もする。
Ajaxが技術として有効だと思われるのは、ユーザーの入力によってどんどん状態が遷移していくような場合(Google MapやGoogle Earthのようなもの)であって、単純なグラフ描画だとかにAjaxを利用するのは開発・デバッグともに複雑になって非常に効率が悪いと思う。確かに、今までサーバー側で行っていた作業をクライアント側に行わせるという意味ではサーバー側の負荷を下げることにはなるが、それ以前にまずサーバーのアップグレードを検討するべきだろう。
● [プログラミング] C/C++/Perl/Ruby/Python/Java の起動時間
さて、Web2.0だとかの話はともかくとして、プリミティブなCGIの世界では結局どの言語を使うべきなんだろうという話があって、計算時間についてはC/C++のような静的型の言語のほうがperl/rubyのような動的型の言語より速いというのは想像がつきますが、その言語のライブラリなりインタープリタなりの起動時間はどうなのよ、ということでなるべく最小のプログラムでの起動時間を比較してみました。
まずは結果:
言語 | real(≒user+sys) | user | sys |
C | 0m1.008s | 0m0.350s | 0m0.660s |
C++ | 0m2.590s | 0m1.630s | 0m0.960s |
Perl | 0m4.141s | 0m1.680s | 0m1.200s |
compiled-Perl | 0m5.551s | 0m2.820s | 0m1.380s |
sh | 0m7.939s | 0m6.230s | 0m1.700s |
Ruby | 0m8.569s | 0m6.160s | 0m1.610s |
Python | 0m27.741s | 0m23.250s | 0m4.140s |
Java | 0m33.046s | 0m22.790s | 0m5.910s |
おもしろいのは、Perlスクリプトをコンパイルしても必ずしも速くならないどころか若干遅くなっていること。C++も、読み込むライブラリが増えれば、下手をすると(コーディングする人の技術レベルによっては)Perlより遅くなりそう。また、Rubyはかなり軽いかと思っていたけど、軽いのはプログラミング作業であって、実行時間でいうとまだまだ改善の余地はありそう。Python/JavaはIOにも時間がかかっているのが特徴。てゆーかJava遅い…これはサーブレットのような体系でしか使えませんね。
従って、現時点で開発効率と実行速度の両方を考えるなら、まだまだPerlでCGIを作るというのはアリだと思います。ソースが読みにくくて引き継ぎが面倒なのが難点かなぁ。
ソース
ちなみに、ソースはこんな感じ:
C (test.c; gcc -O3 && strip)
#include <stdio.h> int main(int argc, char** argv) { printf("%s\n", "OK"); return 0; }
C++ (test.cc; g++ -O3 && strip)
#include <iostream> int main(int argc, char** argv) { std::cout << "OK" << std::endl; return 0; }
Perl (test.pl)
#!/usr/bin/perl printf "%s\n", "OK";
compiled-Perl (perlcc -O3 test.pl && strip)
test.pl と同じ
bash (test.sh)
#!/bin/sh echo "OK"
Ruby (test.rb)
#!/usr/bin/ruby printf("%s\n", "OK");
Python (test.py)
#!/usr/bin/python print "OK"
Java (test.java; gcj -O3)
class test { public static void main(String[] args) { System.out.println("OK"); } }
これらのスクリプトを、bashのforループで1000回まわしてtimeコマンドで計測した。計算自体はほとんど行われていないので、実質的にこれが言語それぞれの起動時間ということになると思う。もちろん、実際にはC/C++などは使用するライブラリによるのですが…。
■ fjsg [mod_(perl|ruby)使うと結構変わる?]
■ wassy [たぶん劇的に変わるはず。 が、それは言語系の「起動時間」は計測しないことになるので、 ちょっと趣旨は外れるような気も..]