角川書店のハルキ文庫が気になる今日この頃。
なにせ、永らく文庫から姿を消していた小松左京の作品群が読めるんである。といっても、長編(日本沈没
とか果しなき流れの果に
とか)はあらかた読んでいる(し持っている)ので、本当に気になるのは短編集の方である。で、時間物を集めた時の顔
の目次を見てたら、見慣れないタイトルホムンよ故郷を見よ
を発見。最初の数行を見てまだ読んでいない事が分かったので、即レジへ。
ちなみに、未見の小松作品がどれくらい珍しいかというと、つい最近読んだケイブンシャ文庫の小松左京ショートショート全集 1〜3
に収められた196篇の内、既読のもの190篇。短編では逃ける
を読んで以来、4年振りの未読作品である。
読者歴が長いと、読んでいない作品を見つけるだけでも一苦労。
それはともかく、ホムンよ故郷を見よ
は作品全体の若々しい感じがいいなぁ。首都消失
辺りの枯れた文章も好きだけど、こっちもいいやね。1000円分の価値は十分ありました。
HBI-J1が届く。
SONY製の漢字ROM&MSX-JE Cartridgeだが、これを使うとZero Typeが飛ぶという話がある。そんなわけで、確認とデバッグの為に捜し続けていたのだが、ようやく手に入れることが出来た。
で、早速スロットに差して電源を入れ、Zero Typeを起動。適当に入力して変換しようとすると見事に飛んだ。見た感じでは、割り込みを禁止したまま、どこかに吹っ飛んだようである。こんな症状、思い当たることが多すぎて、どこから手を着ければよいのやら。
年内に解決してver0.50(正式版)を上げたいところだけど、無理だろうなぁ。そ〜いや、FDを読みに行ってそのまま終了しちゃうなんてバグもあったなぁ。
Effective C++
の続編であるMore Effective C++
を読み終えた。
前作と同じく、C++の正しい使い方に関する指針が列挙されているのだが、今一つ分かり難い。内容が高度になっているのも大きな要因だが、むしろ訳文がこなれていないのが主な原因だと思う。全体に何を言いたいのか分からない文章が多く、同じ文章を何度も読み返さないと理解出来ない。内容的には充実しているだけに、かなり勿体無い。
それはそうと、CP/M版HI-TECH Cを使ってみたのだが、ANSI C型式の関数定義が使えるだけで、全体的にANSI C準拠には遠い気がする。C++気分で、#defineの代わりにconst変数を使おうと思ったら、何故かcompileできないんである。調べてみたら、const型修飾子はANSI Cで追加されたそうで、それに対応してないって事はANSI C準拠なわけがない。
昔、TOMBOYのQ&Aで「HI-TECH CはANSI C完全対応じゃない」と書いたのが正しかったのか、長いこと気になっていたのだが、とりあえずスッキリした。Cでconstが使えても、あまり嬉しくないけどね。
個性とは何か?
Webの世界(の極一部)を見た限りでは、個性=他と違う部分という定義でやっている人も少なくないみたいだが、そ〜ゆ〜人の中には個性的と称しつつ、単に奇をてらっただけのサイトを運営している人もいて、はっきり言って見苦しい。回りが縦だから自分は横、といった程度の薄っぺらな考えしか持っていないように見えるんである(しかも横にした事に満足して、(他が縦を選ぶのには理由があるにも関わらず)その結果を考えない)。
私が考えるところ、個性とは他と異なる部分と他と同じ部分の総和であり、そのobject(人とか機械とかbit列とか)の性質そのものである。人間について考えれば、その人がいい物を作ろうとした結果が平凡な物であったとしても、それはその人の個性であり、逆に(一般的な意味で)個性的な人が作った物は、深みのある味を醸し出している(ことが多い)。そこには、(例え平凡なものであったにせよ)他と異なる事を第一とするが故の底の浅さは存在しない(と思う)。って、今回やたらに括弧が多いな。
結局、個性的であろうとする行為は徒労であり、いい物を作ろうという態度こそが真の個性的を引き出すってのが結論なわけだが、これって楽観的過ぎるような気がするなぁ。所詮、成り行き任せ(進む方向間違えなきゃ何とかなる)が私の個性。
Effective C++ 2nd Edition
を読み終えた。
C++を使い始めて7ヶ月。プログラミング言語C++
だの、ARM(注解C++リファレンス)
だの、C MAGAZINE
やDDJ
のバックナンバーだの、色々参考になる本を読んできたが、その中でも特に使えるという手応えを感じさせる本である。OOP指南という点で食い足り無さは残るものの、C++固有の機能についてはARM以上に詳しい(解説されている部分に関しては、だが)。
で、これを読みながら1998/12/02に書いたInterface(とその実装)の後付け機構(テンプレート継承)について考えていたのだが、これを使う必要はないという結論になった。
あの例では、objectの表示を行う純粋仮想関数Print()を宣言する方法として、Interfaceの後付けを考えたのだが、これは抽象化の方向を誤っている。必要なのは表示手段を持つclassではなく、自身をstream化できるより汎用性の高いclassである。その為には、operator<<()をstream化用のfriend関数として定義すれば良い。実際はこれも結構面倒な実装になるのだが、とりあえず後付けよりは美しい。基本的に必要な物だしね。
C++の基本ともいえるobjectのstream化を、今の今まで失念していたのが、Interfaceの後付けなどという無意味にややこしい機構を考え出す原因となったわけだが、まぁこれはこれで何かの役に立つかも知れない。ど〜ゆ〜役に立つのか、見当がついていないのだが。
Top pageのおえらびください
を少しいじってみた。
今までは、Web browserの対応しているHTML versionを知らなければ、運任せで選ぶしかなかった。見に来る人全てがHTMLの知識を持っていればこれでも良いのだが、実際はそういうわけにもいかないらしい。そこで、とりあえずの策として、HTML3.2 / HTML4.0 Strict固有の<TABLE>要素を使い、見た目で選べるようにしてみた。
この<TABLE>要素の使い方は表としての論理的意味を完全に無視しており、後々問題になりそうな気もするが、まぁ仕方がない。
他の策として、CGIで自動判別するというのを考えたのだが、Browserが対応HTMLを教えてくれるわけではないので却下。Browser名称で判別するのも一つの手だが、私の知らないBrowserが多いこと、CGIに渡すBrowser名などいくらでも偽れる(例えばMSXturboR
という名前のBrowserが過去に発見されている)ことから、これも断念。場当たり的な対応に感じられるのも理由の一つである。
Java scriptを使って判別する手もあるが、結局CGIと同じ問題があり、更にJava scriptに対応していないBrowserに対する処理という更なる問題が発生するので、この場合は解決にならない。
足掛け三ヶ月に及んだNT Serviceなプログラムがポシャった。
System accountでデスクトップとの会話
を許可すると、表示されているService processのWindowがLog offした時に終了してしまう。その為、Log in状況に関わらずBack groundで走り続けるというNT Serviceの(daemon的な)要求を満たせない。これはNTを使う限り付き纏う根源的な問題であり、解決しようがないのでプロジェクトその物が消滅という事になった。結構楽しめたとは言え、脱力する終わり方になり残念。
他にも、System accountでは標準のプリンタ
を獲得できないとか、Network Printerが使えないとか、解決出来そうにない問題があったのだが、一緒にトドメを刺された。まぁ、普通のアプリをNT Serviceとして走らせようというアイデアその物に問題があったような気がするけど。
ちなみに、どこを見ても標準のプリンタ
の獲得にはGetProfileString()を使えと書いてあるが、System accountで実行されるprocessでは見事に失敗する(win.iniからregistryをたどると理由が納得出来る)。Win32 APIのHelpを見ると、EnumPrinters()で列挙したPrinterの中からdefault printer属性を持つものを捜せそうだが、これも期待通りには動いてくれないので駄目。でもって、Microsoft純正のSNA Server4にあるPrint Server Serviceでは、標準のプリンタ
が指定出来ないという逃げに出ている。
Think Blue
のバグをようやく修正できた。
バグの修正というやつはどうしても場当たり的になりがちで、後で見るとわけが分からないものが多いのだが、今回はかなりマシな直し方ができたと思う。場当たり修正がもたらす悪夢はZero Type
で散々経験しているので、半ば本能的にそれを避けるようになったというのもある。
ちなみにZero Type
にはいくつか妙なバグが残っているのだが、スパゲッティ化著しいソースでは原因が分かろうはずもなく、未だにほったらかしである。まぁ、普通に使っている分には支障ないみたいだし(言い訳)。
ロボットの操縦法について、しょ〜もないことを思い付いた。
例えばマジンガーZだと、パイルダーという飛行機の操縦系のまま、ロボットを動かしているが、そんなもので格闘ができるほどの複雑な制御はできない。というのがよく言われる説なのだが、これは間違っているような気がする。
単純な操作系統の代表例として、ボタン1個で制御するロボットを考えてみる。走る|止まるとか、座る|立つとかしか出来ないように思えるが、それはボタンを1bit RAMのように考えているからである。これをシリアル通信の0と1と考えれば、どんな制御も可能である事が分かる。イメージ的には、モールス信号で制御するロボットといったところだろうか。
パイルダーで言えば、操縦棹がボタンの役割を果たす事になる。つまり、適当な間隔で操縦棹を前や後ろ倒してbit列を送信するわけだ。よく使う操作は短い符号に割り当てるべきなので、可変長符号を使う事になると思う。
もっとも、こんな制御系のロボットで戦えるかどうかは保証出来ないが。
Aレジスタの下位4bit(上位4bitは不定)を7バイトでASCIIの'0'-'F'に変換せよ。
あぁ、これがあのときの!てな感じであった。
SCF ! RL C を2バイトで行なえ。
とゆ〜のもあるのだが、こっちはさっぱり分からない。ひょっとして未定義命令?
Win32のregistryを読み書きするclass群を作っていて、ちょっとした事を思い付いた。
このclass群は、CRegObjectというregistryへの入出力を行うclassを抽象基底として、CRegDWord / CRegString / CRegBinaryという三つの派生classに、それぞれ変換関数operator DWORD() / operator CString() / operator BYTE*()を実装したものとなっている。つまり、それぞれの派生classはregistryへのインターフェイスであると同時に、その値を保持する変数でもあるわけだ。
具体的にはこんな感じ。
CRegString strReg; strReg.LoadRegValue(HKEY_LOCAL_MACHINE, "SOFTWARE", "MICROSOFT"); printf("HKEY_LOCAL_MACHINE¥¥SOFTWARE¥¥MICROSOFT=%s", (CString) strReg);
上の例ではstrRegの値をprintf()に渡して表示を行っているわけだが、やはりここはstrReg.PrintFormated()等として表示を行うのが筋というものである(表示法はobject自身が知っているべき)。が、CRegtringに表示法を実装するのはおかしいので、CRegStringPrintableといった派生classにPrintFormated()を実装することになるわけだが、ここで一つ問題が出る。すなわち、仮想関数による動的多態が使えない。
例えば、CRegObjectへのpointerを受け取る関数foo()を考えてみる。
void foo(CRegObject* pReg) { pReg->PrintFormated(); // CReg[DWord|String|Binary]の内容を表示 }
CRegStringPrintableを使う方法ではこれができない。PrintFormated()はCRegObjectのメンバではないから。結局、CRegObjectに純粋仮想関数PrintFormated()を置いておくしかなさそうだが、そのままでは美しくないのでtemplateを使った手を考えた(長い前フリだ)。
CRegObjectに仮想関数を置くという点は譲れない。しかし、置き放しにするわけにもいかない。そこでtemplateを使った継承を考えてみる。
template <class T> class CRegObjectT : public T { // 省略 }; template <class T> class CRegStringT : public CRegObject<T> { // 省略 / DWordとBinaryについても同様 }; class CEmpty // 空のclass { }; class CPrintFormated { virtual PrintFormated() = 0; }
普段はCEmptyを継承したCRegObjectT<CEmpty>を使うが、表示が必要になったらCRegObjectT<CPrintFormated>を使って、適当にhookを掛けるわけだ。実際、これでうまくいくし、表示以外にも応用が効く。
もう一つ、CReg[DWord|String|Binary]とCPrintFormatedを多重継承したCReg[DWord|String|Binary]Printableを作って、dynamic_castを使うという手も考えたのだが、CRegObject*から継承木をたどるのが辛いので諦めた。こっちが本来やるべき実装なので、私がdynamic_castの使い方を理解していないだけかもしれないが。