2005 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
2014 1 2 3 4 5 6 7 8 9 10 11 12
2015 1 2 3 4 5 6 7 8 9 10 11 12
2016 1 2 3 4 5 6 7 8 9 10 11 12
2017 1 2 3 4 5 6 7 8 9 10 11 12

ホーム

2006年12月31日

大晦日だっつーのに、こんなページ見て。
大掃除は終わったの?

本家Permlink


2006年12月30日

sodiumさんとこがはてなアンテナで拾えてない。

--

カッパTシャツほしい!

『草凪純の間違い探し』、バッカじゃねぇか (笑)

--

あんまりWindowsばっかりでプログラミングしてると、
せっかくのAMD64 Linuxマシンが泣くというもの (でも
32ビット・モードだけどね)。

というわけでWine。Wine、今まで一度も使ったことが
なかったんです。使う必要もなかったし、評判もあんまり
よろしくなかったですから。でも、最近ではちょっと
事情が違ってきてるみたい。まぁ、わりとまともに動く
ようになってるみたいです。時間は夢を裏切らないって
ヤツですな (笑)。

で、sidでwine関係をdselect。やりたいことは、既存の
WinプログラムをLinux上で走らせることじゃなくって、
Linux上でのWindowsをターゲットとしたクロス開発。

サンプル・プログラムは:

http://www.kumei.ne.jp/c_lang/index_sdk.html

日本語コードは面倒を引き起こすかもしれないんで、
とりあえずASCII限定で。

で、まぁ、軽いノリでMakefile書いたんですけど:

sample01:
        g++ -Wall -I/usr/include/wine sample01.cpp

これがデンデンだめ。やたら警告は出るわ、リンクに失敗
するわで、ギャフン。

ちょっとWebで調べてみると、winegccっていうのがある
って書いてありました。もうsidにはインストール
されてるはずだと思って、シェルで補完してみると、
winegcc, wineg++ってのが見つかりました。

で、最終的には:

SHELL=/bin/sh

CXX=wineg++

sample01:
        $(CXX) -Wall $@.cpp -lgdi32

でビルドできました。gdi32が必要だっていうのは、
/usr/lib/wineでgrepして見つけました (笑)。

で、ビルドされたものを見ると2つあって、a.outと
a.out.exe.so。まぁ、フツーはa.outなんで:

$ wine ./a.out

とかやったんですけど、これがダメ。じゃあってんで:

$ wine ./a.out.exe.so

でようやっとウィンドウが表示されました。

で、何に腹が立つって、こういうことがどこにも書かれて
ないのね。少なくとも/usr/share/doc/wine-docには、
どこにも書かれてない。そりゃ西田さんじゃなくっても
キレるっちゅーねん。なにか? Linux上でWindowsプロ
グラムを作っちゃいけねーってことか? そんなんだから、
いつまで経っても『Wine、ありゃダメだろ?』みたいに
いわれるんじゃねぇの?

本家Permlink


2006年12月28日1

まあ、ありていにいって、小学生や中学生で『テストが
好き!』なんていうのは出木杉くんくらいしかいない。
でも、クイズが好きな子は結構いるもんだ。

学生だけじゃなくって、プログラマだってテストは嫌い
なんだ。『○付けなんて退屈だ』程度にしか思ってない。
確かに、出来上がったプログラムのテストは退屈だ。

でも、TDDのテストは、期末テストともクイズとも違う。
TDDのテストは、答えを自分で決めるんだ。『こういう
答えがほしい』っていうことを先にコードに書いちゃう。

だから、TDDのテストっていうのは、問題を解くという
よりも、問題を作るというほうが近い。

問題を作って、問題を解く。どっちも自分でやんなきゃ
いけない。だから、解けないような難しい問題を作っても
意味がない。自分でも解けそうな問題を作る。それが
TDDのミソでもあるんだね。

いきなり難しい問題を作るんじゃなくって、ちょっと
がんばればできそうな問題を作る。で、それがクリア
できたら、またちょっとがんばればできそうな問題を
作る。そうやって足元を確かめながら、ちょっとずつ
前に進むんだ。

作るときは『これは大丈夫だろう』と思った問題でも、
いざ実際に取りかかってみると意外と手こずることもある。
そんなときは、問題をもうちょっとやさしくしてみる。
問題が難しすぎたときは、たいてい、問題の素、根っこを
よく理解できてないときなんだ。だから、やさしめの
問題を作って、問題の素をよく噛み砕いてみるんだね。

こんな短い文章じゃ伝わらないだろうけど、TDDの
テストが、みんなの知ってるテストとはちょっと違うっ
ていうことをちょっとは感じてくれたかな。

--

なんかさー、語り口調で書くと、みんなP.Grahamっぽく
なっちゃうんだよなー。上のは意識して変えてみたけど。

一応いっとくけど、ここの基本は『です・ます調』だから (笑)。

半ギレ調のときは、あくまでもイレギュラーだから (笑)。

本家Permlink


2006年12月28日

SBPPは「Smalltalk Best Practice Patterns」の
ことです。

日本語訳は「ケント・ベックのSmalltalkベストプラクティス・パターン—シン
プル・デザインへの宝石集」です。

本家Permlink


2006年12月27日1

マヌケなことに、今ごろになって小林『野良犬』聡の
引退を知る。嗚呼。

--

http://www.cs.princeton.edu/~bwk/testing.html

あれ? ;login:ってまだ発行してるんだ。

これから読む。

しかし、Kernighan氏に教えてもらうとは、なんとも
幸せな話だなあ。まぁ、学生の諸君にとって、それが
どれだけ幸せなことかはわからないだろうけど。

ダイクストラかく語りき。『テストを実施することに
よってバグを見つけることはできるが、それをもって
してバグが存在していないとはいえない』。

(以降、『テストの実施』を『テスティング』とする)

しかし、Kernighanは、『テスティングを考えている
プログラマは、そもそもが正しいコードを書くようだ』
と考えている。

(以降、『Kernighan』を『K氏』とする)

K氏がテスティングに興味を持ったのは、Awkがきっかけ
だった。Awkのために1000以上のテストを作り出し、
それらの実施は自動化されていた。

自動テストというアプローチは、小さなプログラムを
大きなプログラムにスケールアップするのに適していた。
さらに、このアプローチは、プログラミングのテクニック
を教えるのにも適していた。

今でもK氏はオリジナルのAwkのメンテナである。Awkの
コードは6700行だが、そのテストは7000行ある。

テストで主なカテゴリは、機能単独のテストである。昔の
Awkはそれで十分だった。しかし、Awkで大きなプログラムが
書かれるようになり、機能の組み合わせのテストが必要に
なった。

古いバージョンと新しいバージョンの両方を走らせて
みて、ごく簡単なパフォーマンス・テストをやる。

バグが1つ見つかるたびに、1セットのテストが追加される。
新しい機能が追加されるときにも、新しいテストが追加
される。

『境界条件』でエラーがよく見つかる。ストレス・テスト
もやっている。(一般的な) セオリーとして、重要なもの
については制限を設けないようにする。Awkもそのセオリー
に従っているので、ストレス・テストが有効になる。

有効なテクニックの1つに、プログラム内部の制限を
小さくするというものがある。たとえば、ハッシュ・
テーブルの初期サイズを1にするなど。

ASCII 1文字だけからなるAwkプログラムを実行する
テストも有効だった。

コマンド行引数もすべてテストされている。

gcovを使ってすべての行のカバレッジ・テストも試みた
が、240行ほどがカバーできていない。

テストの基本的なやり方は、何らかの手段によって予め
正解を作り、新しいバージョンのAwkがそれと同じ答えを
出すかどうか調べるというものである。

テスト・データのほとんどは、通常使われる形式のもの
である。

空ファイルなどの境界条件用のデータもある。

ストレス・テスト用の巨大なデータは、テスト・コード
内で作り出すこともある。

プログラムによって生成されるランダム・データも
あり、一種のストレス・テストに用いられる。

テストというのは、できる限り自動化したいものだ。

回帰テストとして、古いバージョンのAwkと新しい
バージョンのAwkとに同じデータを喰わせ、2つの出力を
比べるということやる。違う実装 (Gawk) による比較も
有効だ。

正解をまったく別の方法 (たとえばシェルス・クリプト)
で作成するのも有効だ。ただし、この手法には移植性に
欠けるという難点がある。

テストがシェル・スクリプトやAwkそのもので書かれる
ので、Unixやコマンドの使い方の勉強にもなり、小さな
ツールの有効性を学ぶことにつながる。

もっとも興味深いテストは、特殊な言語を用いて、
テスト・ケースとその正解を生成するというものである。
Awkの正規表現は、このやり方でテストされている。

特殊な言語によるテストは、テスト・ケースの追加も
楽で、テーブル駆動テストも可能になる。

一貫性チェックのためのテストもある。NRやNFが正しく
動いているか、deleteで配列の要素をすべて消せるか
など。この種のテストは、事前条件、事後条件による
表明に似ている。

アドバイス:

* 機械化 (mechanize) 重要

* テストには自明な出力をさせろ (何をテストしていて、
  何がエラーになったか)

* 失敗するテストを再現できるように注意する (各
  テストはきれいな状態で始めること)

* 1つのバグごとにテストを用意する

* 新しい機能や変更を1つ加えたら、テストも (1個以上)
  加える

* テストを捨てるな

* テスタには進捗報告させろ

* 壊すものを警戒しろ (テスト・フレームワークは頑丈に)

* テストは移植性を高くしろ

* 頻繁にテストと足元をチェックしろ (足元 (scaffold)
  はテスト・フレームワークのことか)

* 記録を残せ (何を直したか記録する)

生徒に小さめの正規表現のコードを書かせてみた。その
中で、先に紹介した特殊な言語によるテストと似たような
ものも書かせた。

ユニット・テストも試してみたが、特殊な言語による
テストのほうが上の正規表現のコードには向いていた。

Base64のデコード、エンコードを課題として出した。
そのとき、ナスティ・テストを生成するプログラムを
書かせてみた。(ナスティ・テストとは、デタラメな
データを読み込ませるようなテストのことか?)

別の課題として、既存の大きなプログラムを、その機能を
変えずに、ちょっとした変更を加えさせてみた。当然、
生徒たちは自明なテストを書くことになった。

プログラムをテストするのは大変だ。しかし、K氏の
経験上、最初にちょっとがんばってテストを書いて、
(より大切なことだが) テストを自動的に走らせるように
しておいて、あとはちょっとずつやったとしても、多大な
恩恵をこうむるものだ。

--

結局のところ、プログラマが幸せになれないシステムは
ダメなんじゃないだろうか。

旧Mac OSにしても、Mozillaにしても、プログラマは
幸せになれなかったんじゃなかろうか。

これは広い意味でいっていて、『テストしにくい
システムは悪いシステム』の延長線上にある。
テストしやすいほうが幸せだし、機能追加しやすい
ほうが幸せだし、保守しやすいほうが幸せだし、
そもそもバグを生み出しにくいほうが幸せだ。

本家Permlink


2006年12月27日


本家Permlink


2006年12月26日2

まぁ、そんなことよりJBを聞こう。

--

技術というのは、その存在を知らなければ使われることが
少ない。自分で技術を発見できることもあるが、やはり
知ることのほうが多い。たとえばデザイン・パターンは
1つの技術だが、それを自分で発見するよりは本で学ぶ
ことのほうが多いだろう。

したがって、あるテクニックを知っているにもかかわらず、
周囲のレベルに合わせて使わないというのは、周囲の学習の
機会を奪っているわけで、ひどく傲慢な行為ということに
なる。

もちろん、テクニックを披露することが目的ではない。
必要のない複雑さは取り除かなければならない。

もちろん、複雑さというのは相対的なものだ。自分に
とっては単純でも、他人にとっては複雑ということもある。
けれども、そこでためらうべきではない。

結局、ソフトウェア開発とは何か? それは学習する
過程に外ならない。だから、自分はチーム・メンバに
学習することを期待する。

ここでいっている学習とは、なにも自宅に帰って本を
開くということではなく、仕事をする中で学ぶという
ことだ。他人のコードを見て、良いところをマネて、
わからなければ尋ねる。そういうことを繰り返すのが
ソフトウェア開発における学習ということだ。

--

B.W.Kernighan氏の教えの1つに『標準に固執しろ』が
ある。だから、STLを学ぶことはこの教えに適ったもの
である。だから、MFCを使うよりも<map>, <string>, 
<vector>を使うのだ。だから、MFCを使うよりもBoostを
使うのだ。

我々は独立したプログラマであり、MSのためにプロ
グラムを書いているわけではない。だから標準に固執
するのだ。

C++を愛するものに標準以外の選択肢などあろうか?

--

もちろん、自分はC++を愛してるわけじゃないですよ (笑)。
でも、自分の周りには『おまえ、C++ラブだろ?』みたいな
ヤツがいっぱいいるんですけど、そういうヤツらが案外
標準に無頓着なもんで、見てて非常に歯痒い。ほんっとに
仕事の枠から出たがらないっつーか。こういうヤツらは
日本には特に多いんだろうなぁと。そういう意味じゃ、
オープン・ソースに人が来ないのもおんなじような理由から
なんだろうなぁと。

--

なに? g++だとwstringとかwostringstreamとか使えないの?

本家Permlink


2006年12月26日1

グチってもしょうがない。

本家Permlink


2006年12月26日

うわ、まじぇ? JBが?

--

プログラミング言語を大体わかったら、次にやることは
SBPP読むことだろ。デザイン・パターンなんかまだ早い
っつーの。

次にやるべきことは、設計についての勉強で、そのため
には「いい設計とはどんなものか」っていうのと、
「いい設計を達成するためにはどうすればいいか」って
いうことを学ばなきゃいけないじゃん。そういうのは
「デザイン・パターン」はあんまり教えてくれないの。
SBPPは、それを教えてくれる。

SBPPで、リファクタリングとかデザイン・パターンの
足がかり作って、それから次に進んだほうがいいって。
いきなりデザイン・パターンとか行っちゃうと、頭
デッカチになっちゃって、お絵描きばっかりやっちゃう
エセプログラマになりかねない。

--

ああ、ちょっとウソを書いたかもしれない。「次に学ぶ
べきは設計」っていうのはウソかもしれない。それよりも
TDDを先に学んだほうがいいかもしれない。TDDは「プロ
グラミングの進め方」だから。

--

って、おんなじことを何度も書いてるんだけど、一向に
同意が得られないのがなぜなのか、ほんっとに不思議に
思う。UML派がいつまでも幅を利かせてる。そんなに
オレがバカなのか。

本家Permlink


2006年12月25日

しかし、まぁ、今どきでも『オブジェクト指向』と
いうだけでシーメが食えるとは、ははノンキな世の中
だね、こりゃこりゃ。

なんか勘違いしてない? オブジェクト指向が難しいん
じゃなくって、プログラミングそのものが難しいんでしょ?
その難しいプログラミングに、オブジェクト指向とかいう
のをかぶせたって、そんなにゲキテキにプログラミングが
やさしくなるわけねーじゃん?

オブジェクト指向って、モジュール化の技術じゃん?
それ以上でも以下でもねーんじゃねーの? だから、
コード書かずにオブジェクト指向だなんだいったって
空しすぎるでしょ。

UML描けば型が見えてくるの? だれ、そんなウソいうのは?
型のヒントっていうのは、たいていはコードの中にある
もんでしょ? 最初に思いつきで出てきた型なんて、
まぁ、ぶっちゃけいって、UMLなんて描かねーでも出て
くるじゃん? こことあそこのコードが似通ってるなぁ
とか、ここらへんのいっぱいあるパラメータは1つに
まとめたほうがラクだよなぁとか、そういうヒントを
シカトして、お絵描きなんかやって、そりゃ楽しいだろう
けど、そんなんでモノが作れるのか?

つーか、『オブジェクト指向は難しい!』っていうのは
一種の陰謀だよな。本とか雑誌とか売るための。だってさ

array.size

とか

array.empty?

とか

array[0]

とか

array.index("a")

とか、むずかしいことなんて1つもないじゃん?

こういうすでにあるオブジェクトを使っていくうちに、
自分でもなんとなくオブジェクトが作れるようになる
んだしさ。そんなもん、一足飛びにスバラシイクラスとか
できるわけねーっての。

ニッケーのヤツら、聞いてるか?

本家Permlink


2006年12月24日

ああ、一応区別というのはあって、ハッカーはきれいな
コードは求められないんですね。彼が実現する機能なりが
素晴らしければ、コードはどんなに汚なくっても許される。
そもそも『ハック』というのは『切り刻む』という意味で、
ぶっちゃけいえば『やっつけ仕事』がハッカーの身上と
いうこともできます。

一方、プログラマというのは、コードのきれいさが
求められます。彼が実現する機能なりが何かということ
よりも、彼が書いたコードが問われる。たとえば、可読性
だとか、保守容易性とか。

ただし、例によって、両者の境界は曖昧で、きれいな
コードを書こうとするハッカーもいます。けれども、
汚ないコードを書くプログラマはニセモノです (笑)。

でも、きれいなコードを書くっていうのは、簡単に
できるわけじゃないですよね。天才と呼ばれるような
文筆家でも、何度も何度も推敲を繰り返すものでしょう。
それと同じで、コードだって何度も何度も推敲を繰り
返してきれいになっていくものです。

XPで知られるK.Beck氏は、『あるリファクタリングに
数年かかったこともあった』と述べています。氏の
ように、リファクタリングやパターンに精通した人物でも、
満足の行くコードにたどりつくまでに時間がかかる
こともあるんですね。

今、『満足の行くコード』と書きましたけど、大抵の
場合、『きれいなコード』の『きれいさ』っていうのは、
自分が判断します。だから、数年前の自分と今の自分と
では判断が違うのも当然ですよね。よく『昔書いた
コードは見たくない』っていう人がいますけど。だから、
今きれいなコードが書けなくっても、数年後の自分なら
書けるかもしれないでしょう。だから、今精一杯やって
ダメだったら、それはそれで胸にしまっておけばいい
ことなんじゃないでしょうか。あとになって、そのときの
経験が活きると信じて。

--

文明が目指しているのは、人間が生き生きと働ける
社会にすることでは? 人間をペットのように飼うことが
文明の目的だなんて悲しすぎる。

世界中にはいろんな人たちがいて、農業やったり、牧畜
やったりしてる。彼たちをその労働から解放してやる
ことが文明なの? それで彼らは喜ぶの?

--

ああ、『ビンボーはビンボーなままでいろ』っていって
るわけじゃないのよ、もちろん。

でも、そんなこといったら、みんな米国とか日本とかに
移住すりゃいいじゃんって話になるでしょ。そうじゃ
なくってね。

本家Permlink


2006年12月23日1

非常に今さらなんですけど、BOOLってナニ? (笑)

BOOL  Boolean variable (should be TRUE or FALSE). 
      This type is declared in WinDef.h as follows:

        typedef int BOOL;

でもって、TRUEは1で、FALSEはゼロ。

ほんでもって、GetMessageはBOOLなくせに-1返すとかいう
ワケワカラン仕様。

いや、おっそろしー世界があったもんだなー。

本家Permlink


2006年12月23日

思ってたより古くなかった。テヘ。ちょこちょこ書き
加えてたりもしてたんで。rsh + CVSの説明をssh + CVSに
変えておきました。わかりにくいかもしれませんけど。
でも、sshがフツーに使えてれば、Emacs VCで気になる
ことってないはずなんですよね。だから、ssh-agentで
パスフレーズなしで済ますまでが大変なだけで、それも
そんなに大変ってわけじゃない。UNIXならば、の話なん
ですけど (笑)。

これは``since 99.10.20''ってのを信じれば、もう8年
前の文書なんですね。で、いまだにメンテしてると。
自分でも泣ける (笑)。

本家Permlink


2006年12月22日

時間なんかあったって、やりたいことの10分の1もできや
しない。それができるのは才能のある人間だろう。
だから、フツーは、すでに選んでしまった仕事をやりたい
ことにしてしまう。

もちろん、単純作業のような仕事を『やりたいことに』に
することは難しいだろう。幸い、自分はプログラマという
職業を得ることができた。決してお金がいいわけじゃ
ないが、仕事は楽しい。今はそれで十分だ。

--

ああ、いっとくけど、自分は『作りたいものを作る』と
いうプログラマじゃなくって、いってみればフツーの
プログラマ。だから、創造性や芸術性といったものには
乏しいかもしれない。ただ、自分の興味はソフトウェア
開発そのものにあるわけで、いってみれば『何を作るか』
よりも『どうやって作るか』に興味があって、だからこそ
XPを学んだりしている。

本家Permlink


2006年12月21日


本家Permlink


2006年12月20日3

自分みたいなシガナイプログラマがこんなことを書いても
意味なんてないんだろうけど。

今中学生、高校生の君が、5年後、10年後、自分がどう
なってるか考えるのはむずかしいことかもしれない。
でも、むずかしいのは、可能性にあふれているから
なんだね。決して先行きが暗いからじゃない。道が
まばゆいくらい輝いていて目がクラクラしちゃうんだ。

ついこないだ引退しちゃったけど、ビル・ゲイツが
いつ仕事を始めたか知ってるかい?

http://ja.wikipedia.org/wiki/%E3%83%93%E3%83%AB%E3%83%BB%E3%82%B2%E3%82%A4%E3%83%84

これによると高校生のときだそうだ。今君が15才だと
して、3年後にはもうプログラミングで稼いでたんだ。
で、入った大学を中退してMicrosoftをはじめた。
これが20才のときだ。15才のビツ・ゲイツ少年にしたって、
自分の5年後を想像するのはむずかしかったはずだ。

もちろん、ビル・ゲイツは特別な人だ。才能もあったし、
チャンスにも恵まれていたんだろう。でも、自分の
可能性を信じていたからこそ成功したということは
いえるんじゃないかな。

Microsoftのライバル、Appleはどうだったろうか:

http://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%83%E3%83%97%E3%83%AB%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF

ウォズは25才、ジョブズにいたっては20才のときに
Apple Iを作り出したそうだ。みんなの5年後、10年後が
そうならないなんて誰にも否定できないんだ。

ビルとAppleの2人は、確かに時代に恵まれていたという
こともある。でも、じゃあ、Googleはどうだろう:

http://ja.wikipedia.org/wiki/Google

創業者の2人が最初の検索エンジンを作ったのは、2人が
23才のときだそうだ。もし君が17才の高校生なら、5年後
ってことになる。実際にビジネスをやりはじめたのはもう
ちょっとあとなんだけど、そのころはYahooがすっかり定番
になってた。でも、それを引っくり返しちゃったわけだ。

そう、ITはまだ若いんだ。若いからこそ、君たちみたいな
若い力が必要なんだ。自分の可能性を信じて、自分の手で
ITの未来を切り拓いてほしい。それができるのは君たち
若い世代だけなんだから。

本家Permlink


2006年12月20日2

#ifndef DIContainer_hpp_guard
#define DIContainer_hpp_guard

#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>

using namespace std;

class Prototype {
public:
    virtual ~Prototype() {}

    virtual Prototype* newInstance(map<string, Prototype*>& args) = 0;

    virtual ostream& display(ostream& os, int nspace) {
        string spaces(nspace, ' ');
        os << spaces << "Prototype";
        return os;
    }
};

class Dependency {
private:
    Prototype* prototype;
    vector<string> dependencies;

public:
    Dependency() : prototype(0) {}

    Dependency(Prototype* prototype, vector<string>& dependencies) :
        prototype(prototype), dependencies(dependencies) {}

    virtual ~Dependency() {}

    virtual vector<string> getDependencies() { return dependencies; }

    virtual Prototype* newComponent(map<string, Prototype*>& args) {
        return prototype->newInstance(args);
    }

    virtual void deletePrototype() { if (prototype) delete prototype; }
};

class DIContainer {
private:
    map<string, Dependency> services;
    map<string, Prototype*> instances;

public:
    virtual ~DIContainer() {
        deleteServices();
        deleteInstances();
    }

    virtual void regist(string name, Prototype* prototype,
                        vector<string>& dependency) {
        if (services.count(name) > 0) throw runtime_error("double register");
        Dependency dep(prototype, dependency);
        services.insert(make_pair(name, dep));
    }

    virtual Prototype* getInstance(string name) {
        if (instances.count(name) > 0) return instances[name];
        Dependency dep = services[name];
        vector<string> names = dep.getDependencies();
        map<string, Prototype*> args;
        for (vector<string>::iterator it = names.begin();
             it != names.end(); ++it) {
            Prototype* comp = getInstance(*it);
            args.insert(make_pair(*it, comp));
        }
        Prototype* result = dep.newComponent(args);
        instances.insert(make_pair(name, result));
        return result;
    }

private:
    virtual void deleteServices() {
        for (map<string, Dependency>::iterator it = services.begin();
             it != services.end(); ++it) {
            it->second.deletePrototype();
        }
    }

    virtual void deleteInstances() {
        for (map<string, Prototype*>::iterator it = instances.begin();
             it != instances.end(); ++it) {
            delete it->second;
        }
    }
};

#endif //  DIContainer_hpp_guard

#include "DIContainer.hpp"

class Cc : public Prototype {
public:
    Cc() {}
    Cc(map<string, Prototype*>& args) {}

    virtual ~Cc() {}

    virtual Prototype* newInstance(map<string, Prototype*>& args) {
        return new Cc(args);
    }

    virtual ostream& display(ostream& os, int nspace) {
        string spaces(nspace, ' ');
        os << spaces << "Cc" << endl;
        return os;
    }
};

class Bb : public Prototype {
private:
    Cc* c;

public:
    Bb() : c(0) {}
    Bb(map<string, Prototype*>& args) : c(0) {
        if (args.count("Cc") > 0) c = reinterpret_cast<Cc*>(args["Cc"]);
    }

    virtual ~Bb() {}

    virtual Prototype* newInstance(map<string, Prototype*>& args) {
        return new Bb(args);
    }

    virtual ostream& display(ostream& os, int nspace) {
        string spaces(nspace, ' ');
        os << spaces << "Bb" << endl;
        if (c) c->display(os, nspace + 2);
        return os;
    }
};

class Aa : public Prototype {
private:
    Bb* b;
    Cc* c;

public:
    Aa() : b(0), c(0) {}
    Aa(map<string, Prototype*>& args) : b(0), c(0) {
        if (args.count("Bb") > 0) b = reinterpret_cast<Bb*>(args["Bb"]);
        if (args.count("Cc") > 0) c = reinterpret_cast<Cc*>(args["Cc"]);
    }

    virtual ~Aa() {}

    virtual Prototype* newInstance(map<string, Prototype*>& args) {
        return new Aa(args);
    }

    virtual ostream& display(ostream& os, int nspace) {
        string spaces(nspace, ' ');
        os << spaces << "Aa" << endl;
        if (b) b->display(os, nspace + 2);
        if (c) c->display(os, nspace + 2);
        return os;
    }
};

int
main()
{
    DIContainer container;

    vector<string> aDep;
    aDep.push_back("Bb");
    aDep.push_back("Cc");
    container.regist("Aa", new Aa(), aDep);

    vector<string> bDep;
    bDep.push_back("Cc");
    container.regist("Bb", new Bb(), bDep);

    vector<string> cDep;
    container.regist("Cc", new Cc(), cDep);

    Prototype* compo = container.getInstance("Aa");
    compo->display(cout, 0);
    return 0;
}

本家Permlink


2006年12月20日1

http://opensource.adobe.com/

ふ〜ん。最初にレイアウト・エンジンを公開して、
それからGUIライブラリを作ってるのか。で、今はMacの
を作ってる最中?

C++はやっぱり古い言語で、今注目を集めてるテンプ
レート・プログラミングとは無関係にこれまでもたくさんの
ライブラリが作られてきたわけで。特にGUIなんかは
そうで、そんなもんだから当時はコレクション・クラス
なんかも自前で用意するのが当たり前だったわけで。
そこらへんで今の熱いC++と比べると、かなり冷たい
GUIライブラリが多い。MFCなんかは典型なんだけど、
MSはそれの打開策としてCLRっていう奥の手を出してきて、
そこらへんが生粋のC++好きのカンに触ったんじゃないか
と思う。

新しいC++によるGUIライブラリっていうのは、今1つの
トレンドになってるみたいで、Ultimate++とか、Whisper
とかが出はじめてて、そんな中でもやっぱりAdobeの
Widgetライブラリが本命になるかもしれない。

それにしても、MacがC++の最前線で使われているという
のも感慨深いものがある。g++でしょ?

いや、感慨どころの話じゃないんだな、多分。すでに
明らかな傾向ではあったんだけど、つまりは、本物の
プログラマがMacを選んでいるということだ。Mac好きの
Adobeというこもあるし、もちろんすべての本物の
プログラマというわけでもないけど。

本家Permlink


2006年12月20日

風邪で寝込んじゃって、ヒマなもんで『プログラミング
言語 AWK』読んでたんですけど。

最初にAwk知ったとき、何が何だかサッパリわからな
かったことを覚えてます。あの、パターン/アクション
っていう概念ですね。sedも知りませんでしたから。
言語の構造をデータ構造に合わせちゃうという大胆な
発想。

そうそう、『序』で次のように書かれてるんです:

  Awkは、確かに完璧ではない。この言語は、不揃いや手抜き、それにま
  ったく悪いアイデアとしか言いようのないものも受け継いでいるうえに、
  ときには耐えられないほど遅い。しかし、awkは豊かで多才な言語であ
  り、驚くほどいろいろな場面で役に立つ。われわれと同じように、この
  言語が価値あるものだと読者が認めてくれることを希望している。

だからRubyはAwkの後継だと自分はいってるわけで (笑)。
まぁ、この引用に当てはまらないスクリプト言語のほうが
少ないでしょうけど。

そういえば、最近はXML扱うAwkもあった気がしたんで
調べてみたら、gawkの拡張版だったんですね:

http://home.vrweb.de/~juergen.kahrs/gawk/XML/xmlgawk.html

でも、自分が思ってたのとイメージが違う感じ?
自分は:

<book> && ${lang} == "en" { nenglish++ }

みたいな感じでできるのかと。これはbookノードで、
その中のlang属性がenであるパターンで、それにマッチ
したらnenglishをインクリメントするっていうこと。

まぁ、Awkなんだし、あんまり細かいことができても
うれしくないんじゃないですかね。ザッと見ただけの
印象なんで間違ってるかもしれませんけど。

--

シレンなんだけど、まだ表が終わっただけなんだけど、
これだったら、GBの砂漠の魔城のほうが面白かったし、
GBAのネコ2、ネコ3のほうが面白かった。いくらWi-Fiが
目玉だからって、やっぱりスーファミの焼き直しは
手抜きだったという印象。なんでこんなんで年末まで
待たなきゃいけなかったのかと。

本家Permlink


2006年12月16日1

へー、ゲーム業界はIT業界とは違うらしい。
バカか?

--

http://gotom.jp/~gotom/diary/#200612150

多分Googleのことなんだろう。うかいさんつながりで。

--

http://itpro.nikkeibp.co.jp/article/COLUMN/20061122/254696/?ST=develop&P=1

あいかわらずバブリーな記事書くねー。
さすがニッケークオリチー。

--

反省会というのは、KPTとかいろいろなやり方がある
んだけど、どんなやり方を採るにしても、目的は
『で、次からどうすんの?』ということを決めること。

だから、問題点を洗い出すだけで終わりにしないこと。
まず、洗い出した問題点が、本当に問題なのかを吟味する。
で、そこで本当に問題だと納得できたら、その問題点を
解消するためにどういう行動を取るかを決める。

当たり前のことなんだけど、改めて書いてみました。

本家Permlink


2006年12月16日

組織の視点と個人の視点をゴッチャにしちゃいけない。
そこを勘違いしてる経営陣がたくさんいそう。

最近ここでよく書く『受託開発縮小傾向』みたいな問題を
解決するには組織の視点が必要。受託とかSESが組織の
方針だったら、そんなもん個人がいくらがんばったって、
得られる利益には限界がある。

絶対的な限界があるのに、それを超えろというのでは、
悪い意味での精神論でしかない。組織と個人の視点を
ゴッチャにしちゃってる。

本家Permlink


2006年12月15日1

きっちりとしたウォーターフォールのほうがうまくいく
という場合のほうがマレな気がするんですけどね。
その状態はすでに病んでるというか。

さっきの話の続きですけど、ビジネスのためのソフト
ウェア開発というのは、つまりはソフトウェアの価値を
高めるっていうこと。作る人とそれを使ってお金を稼ぐ
人の間の距離が離れてると、作る人は、ソフトウェアの
価値に関して無関心になりがち。

少なくともXPっていうのは、そのあたりにまで踏み込んで
いるわけでしょ。システムは早く独り立ちさせなさいとか。
初期投資は抑えなさいとか。それは結局は作ったソフト
ウェアの価値を高めてるわけ。ソフトウェアの価値って
いうのは、それに関わる組織によって様々なんだけど、
でも、早く使えたほうがいいし、徐々にお金を出すほうが、
うれしいわけでしょ。そこらへんのことをいってるわけ。

--

どんな方法論であっても、計画はトップダウンなのに
変わりはなくって。XPが違うのは、その計画を修正する
頻度なわけ。

--

自分がここでagileっていう言葉を使わないのは、XP
以外の方法論を知らないからで、他意はない。

本家Permlink


2006年12月15日

いまだにXPE2を読み終えてないんですが (笑)。

XPE1は受託開発の色が濃すぎたんだな。まぁ、受託開発に
携わる人は多いんだけど。でも、ソフトウェア開発って
いうのは受託開発が本道じゃないんだよな。本道じゃ
ないっていうのは言い方がアレだけど。いいたいのは、
もっとビジネスに密接に関わるのがソフトウェア開発の
本道だということ。ビジネスの成否とは無関係に報酬を
もらうようじゃ本道とはいえない。

映画と比べたらすぐわかる。映画を作ったらお金が入る
んじゃない。作った映画がヒットしてはじめてお金が
入る。映画の撮影技術の話も大切だけど、それだけじゃ
食っていけないわけで、ビジネスの話もやっぱり大切な
わけだ。

本家Permlink


2006年12月14日2

また知識のないことなのに勢いだけで書いてしまった。
反省。

オープン・ソースのライセンスは免罪符にはならない
だろう。ただ、悪用される可能性を本人が認識し、
なおかつ実際に悪用されたというだけで、作者が罪に
なるならば、それについてオープン・ソース的に対処する
なら、ライセンス条項に『悪用しないでください』などと
明記しておかないといけなくなるし、包丁にしてもその
パッケージに『悪用しないでください』と明記しなくちゃ
いけなくなる。明記しなければ、『悪用を許した』という
解釈になってしまうのだから。

事例的には、包丁なんかよりも、『自殺マニュアル』に
似ているのだろう。その著者は、あるいはその出版社は
罪に問われたのだろうか。『自殺マニュアル』の場合、
明白に営利目的なので、Winnyより悪質だろう。

--

というか、この雨の中、仕事の帰りにチャリをチャリ
チャリこぎながらシレンを買ってきたので、Winny
どころじゃないのだ。

--

『ドロボーのまねごと』て、まんま泥棒やんけ。
わーい、ホージョだ、ホージョだ。

--

あちゃー、スーファミの焼き直しだったのか。
まーいーけど。

本家Permlink


2006年12月14日1

http://d.hatena.ne.jp/Cryolite/comment?date=20061213#c

巡回している先のつながりのない人たちの間で、
ある日突然のように接点が生まれるという瞬間を
目撃した。

こういうのがあるから日記巡回は止められない。

--

だとすれば、もしWinnyがオープン・ソース、というか
ソースだけの形態で配布されていたとしたらどうか。
それでも幇助の意図があると断定できるのか。

あるいは、gccにしても、悪用されることは十分考えられる
話だし、悪用される、あるいは実際にされていることはgccの
作者も認識してるだろうし、それとWinnyとどこが違うか
サッパリわからん。主たる目的云々いうなら、Winnyだって
主たる目的は著作権法違反ではないことは、はっきりといって
るわけで。

そもそも犯罪というのは、犯す、犯さないの二択なんだし、
「被害が大きいから有罪」というのがまかりとおるようでは
法治国家ではない。

結局のところ、あまりにも曖昧な基準で人を裁いている
としか思えん。

「まーダトーな結論か」みたいにいってるヤツの神経を疑う。

--

ふむ。確かに「殺意があったかどうか」が重要であることは
確かだ。しかし、上にも書いたように、たいていの技術と
いうものは善用も悪用もできるし、その作者の意図とは
無関係に直接的にその技術を悪用したものを罰すべきだろう。

オープン・ソースというのは悪用を禁じていない。ならば、
オープン・ソースのライセンスを採用するということは、
すでにそれだけで悪事を幇助していることにもなる。そんな
バカなことがあるか。

本家Permlink


2006年12月14日

#ifndef Calcin_hh_guard
#define Calcin_hh_guard

#include <algorithm>
#include <functional>
#include <iostream>
#include <sstream>
#include <string>
#include <stdexcept>
#include <vector>

using namespace std;

class ExprNode {
public:
    virtual int getValue() = 0;
};

class NumberNode : public ExprNode {
private:
    int value;

public:
    NumberNode(vector<string>& tokens) : value(0) {
        if (tokens.empty()) throw runtime_error("missing number (NumberNode)");
        string digits = tokens[0];
        tokens.erase(tokens.begin());
        istringstream input(digits);
        input >> value;
        if (!input.good() && !input.eof()) {
            ostringstream output;
            output << "expected number, but was " << digits;
            throw runtime_error(output.str().c_str());
        }
    }

    virtual ~NumberNode() {}

    virtual int getValue() { return value; }
};

class OperatorNode : public ExprNode {
protected:
    ExprNode* left;
    ExprNode* right;

public:
    OperatorNode(ExprNode* left, ExprNode* right) : left(left), right(right) {}

    virtual ~OperatorNode() {
        delete left;
        delete right;
    }

    virtual int getValue() = 0;
};

class MulNode : public OperatorNode {
public:
    MulNode(ExprNode* left, ExprNode* right) : OperatorNode(left, right) {}

    virtual int getValue() {
        return left->getValue() * right->getValue();
    }
};

class DivNode : public OperatorNode {
public:
    DivNode(ExprNode* left, ExprNode* right) : OperatorNode(left, right) {}

    virtual int getValue() {
        return left->getValue() / right->getValue();
    }
};

class AddNode : public OperatorNode {
public:
    AddNode(ExprNode* left, ExprNode* right) : OperatorNode(left, right) {}

    virtual int getValue() {
        return left->getValue() + right->getValue();
    }
};

class SubNode : public OperatorNode {
public:
    SubNode(ExprNode* left, ExprNode* right) : OperatorNode(left, right) {}

    virtual int getValue() {
        return left->getValue() - right->getValue();
    }
};

class Calcin {
public:
    virtual int calc(string exp) {
        if (exp.empty()) return 0;
        vector<string> tokens;
        split(exp, tokens);
        ExprNode* node = expr(tokens);
        if (!tokens.empty()) {
            string msg("invalid expression: ");
            string e = join(tokens, " ");
            msg.append(e);
            throw runtime_error(msg);
        }
        return node->getValue();
    }

    virtual ExprNode* expr(vector<string>& tokens) {
        ExprNode* left = term(tokens);
        while (tokens[0] == "+" || tokens[0] == "-") {
            string op = tokens[0];
            tokens.erase(tokens.begin());
            ExprNode* right = term(tokens);
            if (op == "+") left = new AddNode(left, right);
            else left = new SubNode(left, right);
        }
        return left;
    }

    virtual ExprNode* term(vector<string>& tokens) {
        ExprNode* left = factor(tokens);
        while (tokens[0] == "*" || tokens[0] == "/") {
            string op = tokens[0];
            tokens.erase(tokens.begin());
            ExprNode* right = factor(tokens);
            if (op == "*") left = new MulNode(left, right);
            else left = new DivNode(left, right);
        }
        return left;
    }

    virtual ExprNode* factor(vector<string>& tokens) {
        if (tokens.empty()) runtime_error("missing number (factor)");
        string token = tokens[0];
        if (tokens[0] == "(") {
            tokens.erase(tokens.begin());
            ExprNode* result = expr(tokens);
            if (tokens.empty() || tokens[0] != ")") {
                throw runtime_error("missing right paren (factor)");
            }
            tokens.erase(tokens.begin());
            return result;
        }
        return new NumberNode(tokens);
    }

    virtual NumberNode* number(vector<string>& tokens) {
        return new NumberNode(tokens);
    }

    virtual void split(string str, vector<string>& out) {
        istringstream input(str);
        string s;
        while (input >> s) {
            out.push_back(s);
        }
    }

    virtual string join(vector<string>& tokens, string sep) {
        ostringstream output;
        for (size_t i = 0; i < tokens.size(); ++i) {
            output << tokens[i];
            if (i != tokens.size() - 1) output << sep;
        }
        return output.str();
    }

    virtual void prints(string str) {
        cout << str << endl;
    }
};

#endif // Calcin_hh_guard

#include <cassert>
#include <iostream>
#include <stdexcept>
#include <vector>

#include "Calcin.hh"

class CalcinTest {
private:
    Calcin target;

public:
    virtual void testOne() {
        assert(1 == target.calc("1"));
    }

    virtual void testEmpty() {
        assert(0 == target.calc(""));
    }

    virtual void test2mul3() {
        assert(6 == target.calc("2 * 3"));
    }


    virtual void test2_3() {
        try {
            target.calc("2 3");
            assert(0);
        } catch (runtime_error& e) {}
    }

    virtual void test2mul3mul4() {
        assert(24 == target.calc("2 * 3 * 4"));
    }

    virtual void test1plus2() {
        assert(3 == target.calc("1 + 2"));
    }

    virtual void test1plus2plus3() {
        assert(6 == target.calc("1 + 2 + 3"));
    }

    virtual void test1plus2mul3() {
        assert(7 == target.calc("1 + 2 * 3"));
    }

    virtual void testParen() {
        assert(9 == target.calc("( 1 + 2 ) * 3"));
    }

    virtual void test6minus3minus2() {
        assert(1 == target.calc("6 - 3 - 2"));
    }

    virtual void test24div4div2() {
        assert(3 == target.calc("24 / 4 / 2"));
    }

    virtual void testInvalidExpr() {
        try {
            target.calc("1 2 3");
        } catch (runtime_error& e) {
            string msg(e.what());
            assert(msg == "invalid expression: 2 3");
        }
    }

    virtual void testSplit() {
        vector<string> tokens;
        target.split("", tokens);
        assert(tokens.empty());

        target.split("a", tokens);
        assert(1 == tokens.size());
        assert(tokens[0] == "a");

        tokens.clear();
        target.split(" a\t\tbc  d\r\nefg\n\n", tokens);
        assert(4 == tokens.size());
        assert(tokens[0] == "a");
        assert(tokens[1] == "bc");
        assert(tokens[2] == "d");
        assert(tokens[3] == "efg");
    }

    virtual void testJoin() {
        vector<string> tokens;
        string actual = target.join(tokens, " ");
        assert(actual == "");

        tokens.push_back("a");
        actual = target.join(tokens, " ");
        assert(actual == "a");

        tokens.push_back("bc");
        actual = target.join(tokens, " ");
        assert(actual == "a bc");
    }

    virtual void run() {
        testOne();
        testEmpty();
        test2mul3();
        test2_3();
        test2mul3mul4();
        test1plus2();
        test1plus2plus3();
        test1plus2mul3();
        testParen();
        test6minus3minus2();
        test24div4div2();
        testSplit();
        testInvalidExpr();
    }
};

int
main()
{
    try {
        CalcinTest test;
        test.run();
    } catch (runtime_error& e) {
        cout << e.what() << endl;
    }
    return 0;
}

本家Permlink


2006年12月13日1

自分なんかは酒が入ると思考力は鈍るんだけど、
でも、プログラミング意欲が湧いちゃうんだな。

これはあれだ、酒飲むと性欲は湧くのにチンポが
勃たないっていうのに似てる。

本家Permlink


2006年12月13日

12/14、つまり明日はシレンの日。

本家Permlink


2006年12月11日3

http://japanese.joins.com/article/article.php?aid=82627&servcode=300§code=300

お茶吹いた (笑)

本家Permlink


2006年12月11日2

http://ja.wikipedia.org/wiki/%E5%B0%8F%E4%B9%85%E4%BF%9D%E8%A3%95%E7%B4%80

小久保=鉄ちゃん (笑)。

東スポで知ったんだけど、本人必死で否定してる (w

--

どうやらまた地雷を踏んづけたようで (笑)。
virtualのようでvirtualじゃない、半virtual (笑)。

いや、たいしたことをやろうとしてるわけじゃないん
ですよ、ほんとうに。いや、ちょっと調子に乗って
Prototypeパターンとか使ってみちゃったりしてはいる
んですけど、それだってそんなに珍しいことじゃでしょ。
だいたい、こっちだってC++の仕様を確かめたくって
コード書いてるわけじゃないし、サックリ出来るんなら
それに越したことないわけだし。いくらC++が『本物の
プログラマご用達』とかいったって、いくらなんでも
限度ってもんがあるんじゃないの?っていったら、
刺されちゃうかもしれないけど。ああ、まったくオレっ
てばシロートだし、それで十分なんだけど、そうは
いっても仕事がらみだしね。ほんっとに世間が少しでも
早くシロートでも十分な言語に目覚めてくれることを
願わずにはいられない。

#include <iostream>

using namespace std;

class Base {
public:
    Base() { doit(); }
    virtual ~Base() {}
    virtual void doit() { cout << "Base" << endl; }
};

class Derived : public Base {
public:
    Derived() : Base() {}
    virtual ~Derived() {}
    virtual void doit() { cout << "Derived" << endl; }
};

int
main()
{
    Base* obj = new Derived();
    obj->doit();
    return 0;
}

--

あー、Prototype使えば、C++でもDIできそうな気がしてきた。

--

知ってると思うけど、自分は『潰れろ』派。今さら
具体的な名前は出さないけど、今でも潰れたほうが
いいと思ってる企業はたくさんある。

でも、『大企業を潰して人材を流動化しろ!』って
いうのは全然うなずけない。自分が『潰れろ』といってる
のは、それが資本主義の原則だからであって、儲かってる
企業を潰せっていってるわけじゃない。

大体、イノベーションがそんなにいいことなの?
自分なんか、イノベーション崇拝が日本に合ってるとは
思えないんだけど。

日本の革新っていうのは、技術的なことばっかりじゃ
なくって、社会全体が豊かになる、社会的革新とでも
いうべきものなんじゃないの? 技術的革新でも社会
全体を豊かにすることはできるけど、それは日本に
合わないんじゃないの?

最近流行りの談合みたく、横並び意識っていうのは
害悪にもなるんだけど、『みんなで良くなろうよ』って
いうこと自体は悪いことじゃない。少なくとも『オレが
オレが』よりは日本人に好まれる。

日本の社会的革新の正体っていうのはカイゼンでしょ?
日々精進し続けることで、5年後、10年後には素晴らしい
飛躍となるような。

ソフトウェア業界に人がいないっていうのは、人材育成の
方法論の話で、だったら『大企業を潰せ』とかっていう
ネゴトじゃなくって、もうちょっと現実的な話をした
ほうがいいんじゃないの?

本家Permlink


2006年12月11日1

いや、だから、みんな、月曜休むの止めようよ (笑)。

本家Permlink


2006年12月11日


本家Permlink


2006年12月10日2

書き直し。

デザイン・パターンはフェルマー予想みたいなのが多く
って、LispやSmalltalkでできることをいかに静的型で
実現するか、もっといえばPoor OOPLで実現するか、
みたいなのが多い。

こないだはMix-inとDecoratorのことを書いたけど、
今日はPrototype。生成するオブジェクトの型を動的に
変えたいことがたまにあるんだけど、そういうのは
Classオブジェクトがあればすぐにできちゃう。でも、
そういうのがないC++とかだと、Prototypeとかでやん
ないといけない。さらに、Prototypeっていうのはコピー
なもんだから、C++だとメモリ管理もからんでくる。

--

C++がマルチパラダイム、というか、OOPから逃げ出した
のは、ある意味必然だったのかもしれない。動的な
サポートを行わないというのが前提の言語である以上、
これ以上OOPにこだわっていても生産性が上がらない。
もちろん、テンプレートの威力ということもあるけど、
どちらかというと渡りに舟、地獄に仏みたいな感じだっ
たんじゃないか。ただ、OOPから逃げ出して関数型の
世界に行ったとしても、どれだけの人がついてくるかは
わからない。というか、ヒジョーにビミョー。OOPでさえ
いまだについていけない人がいるというのに、さらに
そこへもってきて関数型では。ストラウストラップ氏は
そこでふるいにかけるつもりなんだろうけど、ふるいの
目が細かすぎて、誰も落ちてこないということも十分に
ありえる。

--

http://ja.wikipedia.org/wiki/%E8%B0%B7%E5%B1%B1%E8%B1%8A

失敗に価値があるといっても、やっぱりいい失敗と悪い
失敗っていうのがあるんだろう。でも、やっぱりいい
失敗を犯すっていうのはむつかしい。

--

あははは、usingだって! もう、ほんっとにC++に
関しては次から次に『実はそれはこうやれば・・・』
的なものが出てくる (笑)。

でも、上で『ふるいの目が細かすぎる』って書きました
けど、それぐらいじゃないといけないのかもって気が
しないでもないです。ぶっちゃけ、自分みたいな半分
シロートみたいなのがプログラマやっちゃっていいの?
みたいな (笑)。

まぁ、自分みたいなのは世代的に最後でしょうけど。
8ビット・パソコンいじって、趣味が高じて仕事に
しちゃいましたっていう感じなのは。

今の子たちは、プログラマ志すんなら、それなりに
覚悟持ってると思うんですよね。自分らのころみたく、
コンピュータ雑誌には必ずプログラミング記事がある
なんてことはもうないわけで。それでもって、周りには
とても自分には作れないようなソフトウェアもあるし。
それでもプログラマやりたいっていうんだから、もう
それだけで資格は十分あると思えるんですけどね。

--

見積もりは計画の一部であって、リスクを考慮しない
計画は計画じゃない。

--

準備というのは大切なんだけど、準備のための準備じゃ
ダメ。出発するための準備なんだし、いつかは出発し
ないといけない。

--

まぁ、でも、そんなに卑下することもないか。
一口に技術者といっても、町工場で働いてる人も立派な
技術者なんだし。ソフトウェアが大量に必要なら、
それだけプログラマも必要なんだし、大量にいるんなら、
そのレベルや得意分野も様々なわけだ。もし、Googleが
ぜんぶのソフトウェアを提供してくれるんなら、こっちは
商売上がったりだけど、そんなわけねーしな。
『プログラマはもういらない』みたいな意見がチラホラ
あるけど、とても現実を見てるとは思えないし。逆に、
これからどんどんプログラマが必要になる気がしてならない。
デジタル化っていうと、すでに陳腐な臭いがするんだけど、
それは今でも真実なわけで。つまり、それはプログラマブルな
データが大量にあるってことだし。そのデジタル化される
データっていうのは、それこそ会社の数だけなきゃ
おかしいし、それだけプログラマが必要になるってこと
しか考えられない。

本家Permlink


2006年12月10日1

まぁ、結局のところ、ゲーム機、というかコンピュータの
枠を広げようとしている任天堂と、従来の枠の中でやろうと
しているソニーとの差だわな。

残念ならが、枠を広げる試みっていうのは、もうPCの
世界じゃ全然やられてないわけで。少なくとも商業レベル、
コンシューマ・レベルで成功したものはない。

--

Web2.0以降の主役となるべきはPCじゃないのは明らかだし。
サービス、サービスいうても、そのサービスをどういう
媒体で届けるかっていう問題もあるし。老若男女を
問わずWeb、あるいはネットを、ことさら意識しないで
使えている状態の中で、どういうインタフェースが
優れているかということを考えてかないといけない。

本家Permlink


2006年12月10日

うわ、これでコンパイル・エラーになるのか。かんべんしてほしい。

#include <iostream>
#include <sstream>

using namespace std;

class Base {
protected:
    int value;

public:
    Base(int value) : value(value) {}
    virtual ~Base() {}
    virtual int getValue() { return value; }
    virtual void getValue(int* out) { *out = value; }
};

class Derived : public Base {
public:
    Derived(int value) : Base(value) {}
    virtual ~Derived() {}
    virtual void getValue(int* out) { *out = value; }
};

int
main()
{
    Derived* d = new Derived(10);
    cout << d->getValue() << endl;
    return 0;
}

多重定義されているメンバ関数をオーバーライドするときは、多重定義されて
いるすべてのメンバ関数をオーバーライドしなければならない。

ってこと? ちょっとにわかには信じられない。これが事実だとしたら、メン
バ関数の多重定義はやるなっていってるのとおんなじじゃん。

本家Permlink


2006年12月09日

深さ優先のメリットは:

* システムを早く動かすことができる。
* 先の見通しが立てやすい。

の2点。

システムを早く動かすことができる。つまり、システムが
お金を早く生み出すことができる。そうなれば、開発
プロジェクトがキャンセルされる可能性も減る。

また、早く動かせるということは、システムが早く目に
見えるようになるということでもある。誰かに『今どこ
まで進んだの?』と尋ねられたときに、動くシステムを
見せながら『ここまで進んでいます』ということが
できる。幅優先でも『ここまで進んでいます』という
ことはできるが、その裏付けは『誰か』にはわからない。

先の見通しが立てやすい、というとちょっと誤解される
かもしれない。いいたいのは、先が見えないときには
深さ優先のほうがいいということ。

もちろん、ここでいっている深さ優先というのは、
このページで何度も取り上げているスパイクでいう深さ
優先のこと。このあいだ、『深さ優先ってのがあるんです
よ』と話したら、どうも『詳細優先』のことと誤解された
らしく、話が噛み合わなかった。『仕様を深く考える』とか、
『実装を深く考える』とか、そういう『深さ』もあるんだと
教えられた。

考えてみれば、ここでいっている『深さ』というのも、
『複数の層を貫く』という意味での深さなわけが、それを
『複数の層にまたがる』という表現をすれば『横断』と
いうことになり、言葉としては『幅優先』ということも
できる。

自分は『層』という言葉が曖昧で嫌いだというのもある。
上とか下とか、そんなの場面場面で違う。横で聞いてて
よく混乱する (笑)。

考え方の基準としては、ストーリーであり、ビジネスと
いうこと。ビジネスのゴールに近いほうが深さということ。

--

そう、建築ならば、インフラに投資しても、それは目に
見える。土台をコンクリで固めていたとしても、それが
必要なのは誰の目にも明らかだ。しかし、ソフトウェアは
違う。

--

結局、ビヨルネさんがいいたいのは『トーシロはC++
使うんじゃねぇ!』ってことじゃないのか?

--

まぁ、でも、タイプ量だけでいったら、静的型言語が
動的言語より少ないことだってあり得るんですよね。
静的型言語っていうのは、IDEなんかでも支援しやすい
わけで。

動的言語を自分が好きなのは、やっぱり気楽にできる
からなんじゃないかと思うんです。そういうことに
価値を置かない人が多いってことも知ってますし、
それはそれで尊重しますけど。でも、自分に関しては、
気楽にできたほうがバグも少ないし、開発もサクサク
進むし、いいことづくめ。人によっては動的言語の
ほうがバグが増えちゃうっていうこともあるんでしょう
けど、少なくとも自分はそういうことがない。それは
開発の進め方が違うからで、言語の違いじゃない。

--

shell + bangで「しぇばんぐ」じゃなかったの?

本家Permlink


2006年12月08日1

RubyみたいなMix-inができるんなら、Decoratorパターンは
ほとんどいらないんじゃないか。Decoratorのミソ、というか
大きな制約は、ComponentとDecoratorが同じインタフェースを
持つことなわけだけど、それがいらなくなる。Componentと
Decoratorを同じ型にする必要はない。Decoratorパターンでは
DecoratorがComponentのインタフェースを満たしてやるために
ConcreteComponentオブジェクトへの移譲をしなきゃいけない
んだけど、それも必要ない。

本家Permlink


2006年12月08日

まぁ、でも、UNIXもCもいいものはたくさん生んだしね。

逆に、「バッドノウハウだ!」と騒がれるくらいになら
ないと一世を風靡したとはいえないのかもしれない。

--

ケッ。スルー力があるんなら日記巡りなんかやんねーって。

本家Permlink


2006年12月07日1

下みたいなのができないと、Mixinとしてあんまりうれしく
ないのか。

module Mod
  def doit
    p @value
  end
end

class Obj
  include Mod

  def initialize(value)
    @value = value
  end
end

Obj.new(10).doit

本家Permlink


2006年12月07日

製造業の、いわゆる「カイゼン」っていうのは、非常に
幅広いんだなあ。

製品の品質そのものについてはもちろんだけど、生産
効率を上げるためとか、ヒヤリハットをなくすための
工夫であるとか、環境問題だとか、製造に関するすべての
活動をより良くしようとしている。

それでもって、そうしたカイゼンを表彰したりして、
みんなに広めようとしている。

ひるがえって自分らソフトウェア業界はどうか。その
文脈で語られるカイゼンっていうのは、製造業のそれとは
大きく異なるように思える。いや、範囲が小さいんだな。
ほとんどが製品の品質をいかに上げるかっていうことに
集中しちゃってる。だから、生産効率を上げるための
工夫とかが軽視されちゃうんだ。

たとえばcron + シェル・スクリプトでビルドが自動化
できたとしても、「ヘー、それで?」っていう反応に
なっちゃう。そういう雰囲気である時点ですでにダメ。

小さい工夫を尊ぶことがカイゼンの第一歩なんだと思う。

本家Permlink


2006年12月06日1

帰ってきて『C++標準ライブラリ チュートリアル&
リファレンス』見たんですけど、もう笑うしかない
ですね。ワケワカラン。

で、mem_fun1って古い名前なんじゃないですかね?
sidのg++-4.1だとコンパイルできませんでした。
mem_funに変えると通りました。

仕事先で確かめたときはVC 2005 Expressで、それは
mem_fun1で通ったんですけど。

mem_fun1は、上記の本でも紹介されてないです。

--

C++といえば、ちょっと思ったことがあって。

C++って、なまじっか古いじゃないですか。んなもん
だから、古い人でも新しいC++の使い方知らないことが
あるんですよね。

たとえば、sstreamとか、知っときゃ使えるのに。
atoiとかいらないでしょ? 安全だし。

#include <iostream>
#include <sstream>

using namespace std;

int
main(int argc, char* argv[])
{
    istringstream in(argv[1]);
    int i, j, k;
    in >> i >> j >> k;
    cout << i << "," << j << "," << k << endl;
    return 0;
}

(良い子のみんなはちゃんとエラー処理しましょうね。)

行単位の処理もラクだし:

#include <iostream>
#include <sstream>

using namespace std;

int
main(int argc, char* argv[])
{
    string str;
    int c;
    while ((c = cin.get()) != EOF) {
        str.append(1, (char) c);
    }

    istringstream in(str.c_str());
    string line;
    while (getline(in, line)) {
        cout << line << endl;
    }
    return 0;
}

もちろん、自分なんか、全然C++知らないんですけど。
だから、メタテンプレートとかワケワカラン世界も
あるにはあるんですけど、新しい標準ライブラリで
ラクになる部分もたくさんあるんですよね。

ここで大事なのは、標準ライブラリを学ぶのに躊躇する
理由がないっていうこと。もちろん、膨大な量だし
腰が引けちゃうんだけど、でも、『それが標準』という
だけで学ぶ理由には十分なるわけです。

--

ああ、ちょっとわかった。algorithmとかを使えば、
長ったらしい型宣言を書かないで済むんですね。

void
CDrawAppDoc::makeRects()
{
    for (std::vector<RectModel*>::iterator it = models.begin();
         it != models.end(); ++it) {
        GeomRect* rect = new MovableRect(*it);
        rects.push_back(rect);
    }
}
 
void
CDrawAppDoc::activateTop()
{
    if (rects.empty()) return;
    for (std::vector<GeomRect*>::iterator it = rects.begin();
         it != rects.end(); ++it) {
        (*it)->beInactive();
    }
}

みたいなのが:

void
CDrawAppDoc::makeRects()
{
    for_each(models.begin(), models.end(),
             bind1st(mem_fun(&CDrawAppDoc::addRect), this));
}

void
CDrawAppDoc::activateTop()
{
    for_each(rects.begin(), rects.end(), mem_fun(&GeomRect::beInactive));
    rects[0]->beActive();
}

みたくなると。最初のほうは、あんまり短くなって
ませんけど、でも、まぁ、気分は数段いいです。

こういうやり方だと、lots of little piecesが促進され
そうです。

--

最近、自分がバカだと痛感させられることが多くて。
いや、前からわかっちゃいたんですけど。やっぱり
バカだなと。

本家Permlink


2006年12月06日

さすがC++、奥が深い (笑)。

本家Permlink


2006年12月05日2

for_eachへの関数ポインタ引数っていうのは、メンバ
関数ならstaticじゃなきゃダメってこと?

#include <iostream>
#include <vector>

using namespace std;

class Foo {
public:
    void doit(vector<int>& vec) {
        for_each(vec.begin(), vec.end(), printi);
    }

    static void printi(int i) {
        cout << i << endl;
    }
};

int
main()
{
    vector<int> vec;
    vec.push_back(0);
    vec.push_back(1);
    vec.push_back(2);

    Foo foo;
    foo.doit(vec);
    return 0;
}

--

よくいわれることだろうけど、知識には習得段階というのが
あって。まず単に『知っている』というレベル。次に
実際に『使える』というレベル。そして最後に誰かに
『伝える』というレベル。『伝える』というのは、より
正確にいうと『伝わる』。いろいろしゃべっても相手に
理解されないんじゃ『伝わらない』のと同じ。

本を読めば『知っている』というレベルにはなる。本で
読んだことを実際に自分の仕事に活かせば、『使える』と
いうレベルにはなる。で、その知識を仕事仲間に伝えれば
『伝える』レベルになる。

ただ、一番効果的に伝えることができるのは、その知識が
活きるとき。でも、そういうチャンスはいつ来るか
わからないし、チャンスというくらいだから逃すと
次はないかもしれない。

知ってるのが偉いんじゃなくって、知ってることを
伝えられるのが偉いんだ。

--

設計っていうのはコードの話ですよね。ってことは、
それはレトリックの話も含まれるってことになります。

レトリックというと上辺だけのような印象を受ける
でしょうけど、それがコードという事実から導きだされる
当然の結論なんですね。

コードの重複にしても、それはレトリックとして下手な
わけです。リファクタリングなんかは、ほとんどが
レトリックの話ですよね。仕様どうこうじゃなくって、
コードの中だけで解決できる話。機能を変えないんだから
当たり前の話ですけど。

他にもデメテルの法則とか、責任の所在とか、そういう
のもほとんどがレトリックがらみですよね。メソッド・
チェーンが長かったらデメテルの法則に反してるとか、

def dosomething(foo)
  foo.doit
  foo.dothat
  foo.dothis
end

みたいなメソッドがあったら、それはfooのやるべき
ことじゃないかとか、そういうコードを見ただけで
わかることをレトリックといってるわけです。

もちろん、もっと大きなリファクタリングもあるんです
けど、そういうのは小さいリファクタリングができて
からでも遅くない。lots of little piecesやって、
once and only onceやって、そうすれば大きな
リファクタリングの筋道が見えてくるかもしれないじゃ
ないですか。少なくとも小さなリファクタリングが
損になることはありません。

--

システム開発、特に複雑なシステム開発で大切なのは、
システムを理解すること。言い替えれば、システムを
学ぶこと。『学ぶ』というからには、失敗することも
ある。だから、失敗を恐れちゃいけない。

失敗にもいろいろあるけど、ありふれた失敗の1つが
手戻り。古典的な開発では、いかに手戻りを生じさせ
ないかに心を砕いたんだけど。でも、今みたいな複雑な
システムだと手戻りは避けられない。となると、手戻りの
戻る幅をいかに小さくするか、ということに焦点を合わせ
ないといけない。違う見方をすれば、いかに早い段階で
失敗し、その失敗から学ぶかが大切ということ。

--

『働きがい』ということでしょうか。

プロジェクトXみたいなのは、まぁ、特殊なケースです
よね。

結局のところ、技術職の原点というのは、自分が作った
ものを誰かに使ってもらって喜んでもらえること、
なんでしょうね。

そう考えると、何も富士山は必要ないし、使ってくれた
人から『ありがとう』みたいなことをいわれれば十分
なんでしょうけど。

まぁ、これは個人差があって、技術的困難に挑戦して
克服したいっていう人も大勢いるでしょうけど。ただ、
そういうのはordinaryじゃない (笑)。

まぁ、だから、せいぜい高尾山くらいでいいかなぁ、と (笑)。

--

結局、ウサギとカメとじゃ走り方が違うんだし、ウサギの
ほうが速くて当たり前。しかも、おなはしと違って、
ウサギが走るのをサボったりはしない。

だから、肝心なのは勝負をあきらめないこと。なおかつ、
あくまでも勝つために走り続けること。守るっていうのは、
自分が優位なときに取れる手段なんだし、こっちが守る
ために立ち止まってたら、ウサギはどんどん先に行っちゃう。

幸い、まだカメでも食べていけてる。

本家Permlink


2006年12月05日1

プログラミング言語をチャンポンする、というか、
そもそも複数の言語を学ぶことが嫌いな人がほとんど
なんですね。「ほとんどの」というのは、職業
プログラマ全体も含めての話。これは短い職業プログラマ
経験の中から気づいた数少ない真実の1つ。それが
いわゆる「フツーの感覚」なんだと思いましたね。

だから、新しい言語を学ぶのは、仕事で仕方なくって
いうのがほとんどだと思うんですよ。

--

何か勘違いしてるような。

複数人で開発するときに、もっとも大切なのは、
いうまでもなく、計画だ。

なぜなら、人が集まれば、人それぞれに都合というものが
あり、一般常識では、そうした個人個人の都合という
ものを無視してはいけないことになっている。それを
無視すれば独裁とか全体主義とかいわれることになる。
であるから、個人個人の都合を擦り合わせなければ
ならない。つまり、それが計画ということになる。

繰り返すが、人が集まって開発するときに、もっとも
大切なのは計画だ。どういうツールを使うかというのは、
極端にいってしまえば、枝葉の問題に過ぎない。計画を
どのように立てるかという太い柱があって、はじめて
それを支えるツールというものが選ばれる。

アジャイルというのは、ツールの選定の仕方ではなく、
人の問題の扱い方であり、その中でも計画 (planning) は
重要な位置を占める。

逆をいえば、計画の立て方が確立されていなければ、
それは開発方法が確立しているとはいえない。断じて。

本家Permlink


2006年12月05日

iteratorとreverse_iteratorとを別物にしなきゃいけない
理由がわからない。

多分、C++的な発想としては、次のような関数が好まれる:

void
doit(vector<int>::iterator beg, vector<int>::iterator end)
{
    while (beg != end) {
        ...
        ++beg;
    }
}

他の言語なら:

void
doit(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin();
         it != vec.end(); ++it) {
        ...
    }
}

と書くのがフツー。

で、最初にあげたような書き方が好まれるとした場合、
iteratorとreverse_iteratorとを区別していることが
不便になる。なぜなら、もしiteratorとreverse_iteratorとを
区別していなければ、vectorを逆順にたどらせたいとき
には:

doit(vec.rbegin(), vec.rend());

と書けば済む。しかし、現実にはiteratorとreverse_iterator
とは区別されているから:

void
rdoit(vector<int>::reverse_iterator beg, vector<int>::reverse_iterator end)
{
    while (beg != end) {
        ...
        ++beg;
    }
}

といった別の関数を用意しなくちゃいけない。
やっていること、つまりdoitの本体とrdoitの本体の
字面はまったく同じなのに。

何か自分が間違えてる?

--

上のコードを実際に適用してみたんだけど:

void
CDrawAppView::drawRects(CDC* dc, std::vector<GeomRect*>::reverse_iterator rbeg,
                        std::vector<GeomRect*>::reverse_iterator rend)
{
    while (rbeg != rend) {
        (*rbeg)->draw(dc);
        ++rbeg;
    }
}

どう見てもキチガイが書くコードにしか見えないよな。
たかが配列を逆順にアクセスするだけなのに、なんで
こんなに狂ったようにタイプしなきゃいけないの?
IDEが助けてくれるとか、そういう問題じゃないよな。
情報量が多いっていうだけで、それは害悪なんだから。
typedefで回避するっちゅーのが常套手段なんだろう
けど、でも、それもなんか小手先っぽいしな。

でもって、C++で何が絶望的かというと、こうした問題が
解決されるのは少なくとも今世紀中にはなさそうだという
こと。このあたりは言語の改善速度が速いJavaとは対照的。

ひょっとしたら、今C++が盛り上がってるように見えて
いても、やっぱり一時的なものなのかも。いや、どんな
言語でもピークっていうのは一時的なものなんだけど。
でも、自分はちょっとC++を買いかぶっていたかも。

結局のところ、Cのオブジェクト指向拡張言語として
使われるC++ではダメなわけで、それはJavaに覇権を
奪われたことで証明済み。少なくとも今C++が盛り上がって
いるように見えるのは、マルチパラダイム言語の面で
あって、でも、それはニッチだし、そこを使いやすく
しようとすれば言語を大幅に変えないといけないし、
それは標準化という十字架を背負っているC++にはほぼ
不可能。

これは繰り返しになるけど、C++最大のパトロンだった
MSがC++から徐々に手を引こうとしていることからしても、
今後のC++については悲観せざるを得ない。

--

C++はまだまだ全然知りませんから、間違ったことを
書いてるかもしれません。何かあればご指摘ください。

本家Permlink


2006年12月04日

『将棋世界』の1月号。『名人戦の真実』、面白い。

特に感動したのが瀬川四段の記事。プロとしての覚悟を
感じさせてくれました。逆に『何じゃこりゃ?』なのが
加藤一二三九段 (笑)。

移管問題については、その遠因の1つが新聞販売部数の
減少にあるとのこと。すなわちそれはネットととも
無縁ではないわけで、それこそ『ネットが新聞を殺す』
以外にも『ネットが将棋を殺す』ということも十分に
考えられるわけで。ちょっと考えさせられましたね。

もちろん、自分は囲碁のほうなんですけど、これと
おんなじ構図がそのまま囲碁にも当てはまるわけで。
幸い、囲碁のほうには海外という外圧があるんで、
自浄作用みたいなものが働きやすいんですけど、でも
やっぱり座しては死を待つばかりでしょうね。

--

ちなみに、叫ぶのは『快哉』だからね。

喝采は浴びる、浴びせる。

本家Permlink


2006年12月03日

うわ。F3、予約されてた。F9あたりに変更。

--

今さらですけどMFC。仕事なもんでね。

自分がMFCの筋や定石を知らないっていうことを差っ
引いても、なんかきゅうくつな気がします。

自分、『MVCは嫌いだ』って何度も書いてますけど、
それはやっぱりMFCにも当てはまりました。っていうか、
なんで自分がMVCを嫌いなのか、その理由がちょっと
わかった気がします。

モデルとか、ビューとか、そういうのっていうのは、
ごくありふれた存在なんですよね。なんでもモデルに
したいし、なんでもビューにしたい。そうなると、
フレームワークから押しつけられてるモデルとかビュー
とかっていうのが疎ましくなるんです。そいつらは粒が
デカすぎるんですね。

たとえばテキスト・ファイルから四角形のデータを
読み込んだら、その四角形はモデルでしょう。それは
CDocumentなんかとは無関係にモデルなわけです。で、
その四角形を描くのがいるわけでしょう。それがビュー
なわけです。そのビューは、CViewからCDCをもらって
描画するだけで、CViewの派生クラスっていうわけじゃ
ない。そこでもうMFCの枠をはみ出ちゃってる気が
するんですよね。だったら、もっと軽いフレームワークの
ほうがいいじゃんっていう。

それと個人的な好みでいえば、リソース・エディタなし
では苦しいMFCより、テキスト・エディタだけで書ける
Swingとかのほうがやっぱり好きなんですよね。単純な
ものなら、決して遅くはないですし。でも、これは
本当に好みの問題だから。

本家Permlink


2006年12月02日

リファクタリングの1つに、『オブジェクトが持つ
コレクション・メンバを直接返さない』っていうのが
あります。正式名称は確かEncapsulate Collection。

で、それをC++でやろうとしてたんですけど。その結果が
これ:

void
CDrawAppDoc::getModels(std::vector<RectModel*>& out)
{
    std::vector<RectModel*>::iterator where = out.begin();
    std::vector<RectModel*>::iterator first = models.begin();
    std::vector<RectModel*>::iterator last = models.end();
    out.insert(where, first, last);
}

どう見ても狂ってるようにか見えないんで、ここで怒りを
ブチまけようとしたんですけど、すぐに正しいやり方が
わかりました:

void
CDrawAppDoc::getModels(std::vector<RectModel*>& out)
{
    out = models;
}

--

いろいろあがいてみたけど、結局のところ、
vsvars32.batに書かれている内容をコンパネの環境変数に
登録するしかなさそうだという結論。それでCygwinの
makeでdevenvとかvcbuildとかが走るようになる。

対話だけだったら、VS用のcmd.exeを使えばいいんだけど、
そうじゃないから。

--

(defun my-c++-mode-hook ()
  (c-set-style "stroustrup")
  (setq c-basic-offset 4)
  (setq indent-tabs-mode nil)
  (local-set-key [f3] 'switch-c++-buffer))
(add-hook 'c++-mode-hook 'my-c++-mode-hook)

(defun switch-c++-buffer (&optional buffername)
  (interactive)
  (if (not buffername)
      (setq buffername (buffer-name)))
  (let ((basename (file-name-sans-extension buffername))
        (extension (file-name-extension buffername)))
    (let ((filename (concat basename "." (c++-paired-extension extension))))
      (find-file filename))))

(defun c++-paired-extension (extension)
  (cond ((string= "h" extension) "cpp")
        ((string= "cpp" extension) "h")
        ((string= "hh" extension) "cc")
        ((string= "cc" extension) "hh")
        ((string= "hxx" extension) "cxx")
        ((string= "cxx" extension) "hxx")
        ((string= "H" extension) "C")
        ((string= "C" extension) "H")
        (t nil)))

ちなみに、何度も書いてるけど:

(setq indent-tabs-mode nil)

するなら:

(defun my-c-common-mode ()
  (define-key c-mode-base-map "\C-cc" 'compile)
  (define-key c-mode-base-map "\C-ce" 'next-error)
  (c-toggle-hungry-state 1))
(add-hook 'c-mode-common-hook 'my-c-common-mode)

みたくc-toggle-hungry-stateをセットしておくように。

本家Permlink


Copyright © 1905 tko at jitu.org

バカが征く on Rails