10月2006

昨日に引き続き

昨日のArrayの続きの話ですが、いい方法を思いつきました。というよりは、昨日はテンションを上げ過ぎたので見落としていたといった感じです。
問題は、複数のオブジェクトが同じインスタンスを保持している場合、両方のデストラクタでインスタンスが破棄されてしまうというものです。
これの対処法は、やはりデストラクタでインスタンスを破棄しないような仕様にするのが一番いいと思いました。ガベージコレクションもあるので、破棄をする必要もありませんし、もし破棄したいのなら、DeleteObject()で任意に破棄することができます。また、RemoveObject()で、破棄をせずにオブジェクトからインスタンスを取り除くこともできます。そして、RemoveObject()の戻り値は取り除いたオブジェクトになります。他のインスタンスにオブジェクトを渡すとき、これを使用することにより、両方のオブジェクトにDeleteObject()が使われても、インスタンスが両方で破棄されない仕組みです。
ある程度整った仕様にはなりましたが、まだ抜け穴がいくつかあるのが気になるところです。

ところで、今日はArrayのソートを実装してみようと思いました。幸い、手元にある日経ソフトウェア2006.04にアルゴリズムの特集が組まれているので、そこに大抵のソートが載っています。さらに、以前フォーラムの方でもソート大会があったので、資料は豊富に揃ってますね。まあ、無駄に自己流でソートしようかと考えもしましたが…
とりあえず、クイックソートを実装中です。ソートは、暫定的にToString()の値でソートする仕様にするつもりです。

さて、今回作っているArrayは結構自己流な仕様なので、ライブラリ搭載の際には、再考の余地が十分ありそうです。というか、IObjectなど、結構ディープな領域でもあるので、慎重にならなければならないでしょう。
ともあれ、せっかく作成したので、今日までのコードをアップしておきます。
array.abp.zip
.abpファイルはアップできないようなので、とりあえずzipにしときました。
ちなみに、デバッグはそんなにやっていません。Stringクラスの時のデバッグは、3段階やりました。次のような感じです。
Lv1. 任意の値を与えて、正しく出力されるか確認
Lv2. 端っこの値を与えて、正しく出力されるか確認
端っこの値というのは、例えば、StringのInsertで、インデックスに0を指定するとかです。
Lv.3 機械的に引数を入れて実行する。ランダムな引数を与えて、何回も試行します。基本的にはどんな値が引数に設定されても大丈夫なように設計する。

と、Stringの私が実装したところには、この3段階目までデバッグをやっています。今回のArrayは手抜きで最初の段階しかやってませんので、どこかでエラーが出るかもしれません。

最後に、もしそのArrayについて質問があれば、このコメント欄へ書いてください。基本的には、昨日書いた仕様と同様です。

思わぬ落とし穴

今日は、ライブラリに搭載するような意気込みで(あくまで意気込みなんで、搭載するとなれば、もっと仕様を議論してからです。)、Arrayクラスを実装していましたが、思わぬところで設計ミスが生まれてしまいました。

まず、私が実装していたArrayクラスはどんなものかといえば、オブジェクトを格納するものです。といっても、インスタンスのポインタを配列に記録させていくだけですが、ここに格納されたオブジェクトは、Arrayの破棄時に、同時に格納されているオブジェクトも解放するような仕様にしました。とりあえず、下に簡単にまとめてみます。

'格納するオブジェクトはこれを継承する
Interface IObject
Function Equals(ByRef obj As IObject) As BOOL
Function GetTypeName() As *Byte
Function ToString() As String
End Interface

Class Array
Sub Resize(capacity)
'格納できる最大数を指定します。

Function Capacity() As Long
'最大数を返します。

Function Size() As Long
'現在格納されてるオブジェクトの数を返します。

Sub AddObject(object As *IObject)
'オブジェクトを配列の末尾に追加します。

Sub AddObjects(object As Array, startIndex As Long, count As Long)
'配列に格納されているオブジェクトを、指定した範囲だけ、追加します。
Sub InsertObject(object As *IObject, InsertPos As Long)
'オブジェクトを指定した位置に挿入します。

Sub InsertObjects(object As Array, startIndex As Long, count As Long, InsertPos As Long)
'配列に格納されている指定した範囲のオブジェクトを、指定した位置から挿入します。

Sub DeleteObject(index As Long)
'指定したオブジェクトを消去します。格納されていたインスタンスも破棄され、後のオブジェクトがそこに入ります。

Sub DeleteObjects(startIndex As Long, count As Long)
'指定した範囲のオブジェクトがDeleteObject()されます。

Function RemoveObject(index As Long) As *IObject
'指定したオブジェクトをこの配列から取り除きます。インスタンスは破棄されません。戻り値は、取り除いたインスタンスです.
DeleteObject()同様、取り除いた位置に、後ろのオブジェクトが入ります。
Function DeleteObjects(startIndex As Long, count As Long) As Array
'指定した範囲をRemoveObject()しますが、戻り値は、取り除いた範囲のオブジェクト配列です。
End Class

ここに載せてないのもありますが、ソートはまだ実装していません。また、Allocatorはあまり必要性がないと思ったので、設定できるようにしていません。
AddObject()やInsertObject()で既にオブジェクトの最大数が限界の場合は、勝手に拡張されるように作っています。

ここからが本題なんですが、この配列クラスはオブジェクトの破棄も管理してくれるように作った訳です。ですから、DeleteObject()とRemoveObject()2種類作り、破棄しないでも配列クラスから取り除くことが可能なものにしてみました。
しかし、実際に実装してみると、この仕様に問題があることに気がつきました。RemoveObject()は問題ないのですが、RemoveObjects()に問題があるのです。RemoveObjects()は指定した範囲のオブジェクトを配列から外すことができるのですが、その外したオブジェクトは、戻り値のArray配列に入ります。
実は、ここに欠陥があったのです。例えば、下のコード。

Dim array1 As Array
Dim array2 As Array
array1 = 'いろいろインスタンスを格納する
array2 = array1.RemoveObjects('適当)

もともとRemoveを作ったのは、上のように、格納しているオブジェクトを、他の配列に移動させたりする場合とかで使えるからです。二つの配列が同じポインタのインスタンスを保持していると、Array破棄時に、両方のデストラクタでインスタンスが破棄されることになってしまいますからね。
ここで、落とし穴です。RemoveObjects()の戻り値がArrayになっているということは、RemoveObjects()内部では、一時的なArrayオブジェクトに入れて、それを戻り値にし、それからArray2に渡されます。その一時的なArrayオブジェクトにもインスタンスが格納されるわけですから、この一時的なArrayオブジェクトが破棄時にもデストラクタで格納されているインスタンスが破棄されてしまうのです。戻り値のArray配列なので、Returnしたときにはインスタンスを保持させてなくてはなりませんし、関数から抜けてすぐに破棄されますので、Removeを使う暇がないのです!

対処法は、いくつかあります。
1. 格納しているインスタンスを破棄しないように設定できるようにする。
2. RemoveObjects()の戻り値でArrayを指定するのではなく、引数にByRef objects As Arrayとしてしまう。

これら、いずれの方法もあまり気に入りません。そして、やっぱり行き着く先は、格納するオブジェクトに保持カウントを持たせてしまうことです。つまり、IObjectに保持カウントのインターフェースを追加するわけです。保持カウントというのは、たとえば、Arrayに格納したときに、その格納したインスタンスの保持カウントを+1します。Arrayのデストラクタが来たときに、その保持カウントを-1します。そして、その時のもし、カウントが0であるならば、そこでそのインスタンスも破棄するわけです。
こうすることにより、二つのArrayに同じインスタンスが格納されていたとしても、保持カウントが0になるまでは、デストラクタでインスタンスが破棄されない訳です。

とりあえず、今回のは、Arrayでオブジェクトの破棄までする場合の話です。これらの問題は、ActiveBasicが既にガベージコレクションを実装していますので、別にこのようなArrayで破棄するような仕様でなくてもいいんですよね。

さて、もう時間がないので書きなぐってしまいましたが、いったいどれだけの人が理解できるような文章になってしまったどうろうか…

WillcomとMac

昨日のモバイル接続といえば…に引き続き、今回は携帯端末とPCの繋ぎ方について紹介しましょう。

はじめに、接続する端末と、PCの紹介です。私の現在使用している携帯端末は京セラのWX310Kです。フルブラウザやFlashPlayer、メールクライアントなどがついていますが、どれもあと一歩ですばらしいと言えるレベルです。例えば、フルブラウザは表示はPCと同じですが、重いですし、メールクライアントはGmailはSMTP承認がうまくいかなかったりします。次の端末に期待ですね。
そして、PCの方ですが、これはiBook G4を使用します。

さて、PCと端末の接続方法は、USBかと思っているかもしれませんが、実はWX310KはBluetoothのDUNのプロファイルを持っていますので、Buletoothで接続することができます。PCのほうは、最近のMacであれば、ほとんどBluetoothは搭載されていたはずです。

まずは、接続する準備です。WX310Kに付属していたCD-ROMで、WX310Kのドライバをインストールします。次に、Bluetooth機器登録です。あとは、ネットワークの設定で、ダイヤルアップの番号やアカウント、パスワードなどを設定していきます。これで設定は終了します。

いよいよ接続です。普段接続したいときには、ここからの操作だけで接続することになります。これが予想以上に簡単で、以下の2つの操作をするだけでOKなんです。
1. まず、携帯端末をBluetooth待ち受け状態にします。WX310Kでは、ショートカットキーでBluetoothがありますので、端末を開いて、”*”キーを長押しするだけで、Bluetooth待機状態になります。つまり、”*”キーを押すだけです。
2. OS Xのステータスメニュー(Windowsのタスクアイコンみたいなもの)から、接続を選択します
接続

わずか2ステップで接続完了です。

接続中
これが接続している状態です。表示されているのは、接続している時間です。

このように、予想以上の簡単に接続することができ驚きです。
他のWillcomのAIR-EDGEの接続装置もIntel Macに早々対応しているようですし、意外とWillcomとMacって相性がいいのかもしれませんね。
というわけで、噂されているAppleの携帯端末、iPhoneはSoftbankではなくて、Willcomで出してほしいものです。え?WillcomはPHSだって?そこはW-SIM使ってなんとか…

履修問題

この問題、どう収束させるつもりでしょうか。
現状の学校での措置は、とりあえず卒業前に履修させるよな対応が多いようです。そして、文部省の対応は、やらせろと。一方首相は、何か特例措置を出しましょう。だ、そうです。

まあ、どう対応しても、悪化しますよね。履修させたとしても、既に卒業した人はどうなのか、って話になりますからね。なんで今年からなんだって、生徒に不満が出るでしょう。そして、特例措置を取る。これはこれで問題になりますよね。学習指導要領ってのは法的にやってるらしいので、大変でしょう。例えば、一時的に今年度だけ特例を認めたとしても、来年から履修となるでしょう。これには学校側も対応する余裕はあるでしょうが、昨年まで良かったのになんで、って人も出てくるでしょうね。

どちらにしろ、これだけ問題になってしまったのですから、どうにかしなければならないでしょう。さて、どうなることやら。

モバイル接続といえば…

さて、最近Softbankが携帯業界に加わり、予想外割りとか言ってやっていますが、あの料金プランを見てみますと、また別の意味で予想外です。

ところで、私は携帯電話ではなく、PHSを使っています。ご存知の通り、Willcomです。一時期、いくら電話してもWillcom同士なら無料というのが話題になっていましたので、通話が安いというイメージがあるかもしれませんが、実は本命はデータ定額の方です。

現在私が契約してるプランは、ウィルコム定額プラン+リアルインターネットプラスというものです。前者は基本料金、後者はオプションとなります。

簡単に説明しますと、ウィルコム定額プランは、月額2900円で、Willcomへの通話料金は無料、それ以外は並々の値段、メールはウィルコムのメールサービスを使っていれば無料、そして1パケット0.02円です。普通な使い方をする人は、これだけで十分ですね。
そして、オプションで付けているリアルインターネットプラスですが、月額2100円で、パケット使い放題になります。ウィルコムのパケット定額には、もう一つ、データ定額というオプションもありますが、そちらは値段が高めですが、回線速度が4xの128kbpsです。リアルインターネットプラスは2xの64kbpsとなります。
そして、ここがウィルコムのパケット使い放題系プランのいいところ。なんと、PCで接続するのもこれに含まれるのです。つまり、リアルインターネットプラスやデータ定額に入っていれば、PC接続も定額になります。

まとめてみますと、私の契約しているプランは、ウィルコム定額プラン (2900円)+リアルインターネットプラス(2100円)です。合計5000円で、すべてのデータ通信が無料になる環境が手に入るのです!
気になる点といえば、通信速度でしょうか。他と比べると、64kbpsというのは、遅いと思われるかもしれません。しかし、想像するより結構早いもので、WEBを閲覧することについては、ポータルサイトなど、重いところは多少待ち時間(数秒)が必要な程度で、ストレスはそんなにありません。

ここで注意点が2つあります。
1つは、PC接続の場合、PHSでの接続料金の他に、別途でプロバイダとの契約が必要になることです。どんな仕組みか知りませんが、携帯端末から接続する時も、プロバイダは必要らしいです。もし、適当なプロバイダがなければ、Willcomが提供している、Prinという接続サービスがありますが、これは最大1500円と高めですので、今自分の契約しているプロバイダの、モバイル接続サービスを使うといいでしょう。私の契約しているプロバイダは、YAHOO!BBで、追加料金200円で、モバイル接続ができるようになります。ですから、実質5200円で使い放題です。
そしてもう1つ、これが一番重要です。PHSは電波があまりよろしくありません。地方に住んでいる方は結構辛いかもしれません。が、契約する前に、電波状況を調べることができます。
エリア確認ツール
ここに載っていない補足情報として、PHSの電波は壁を突き抜けにくいので、近くにアンテナが1つしかく、大きな建物のすぐ後ろで使ったりする場合は、電波が届かないこともあります。また、田舎で何もないところでは、アンテナが周囲2km以内に一本もなくても、使えたりしました。(実家で試しました)
どうしても不安ならば、端末のレンタルサービスをやっていたはずなので、それに申し込んでみましょう。

このように、かなり安価な値段でどこでもインターネットができるようになります。実を言いますと、私がこれを契約したときには、PC接続料金も定額になることを知りませんでしたので、意外なオプションとなりました。
最後に、もっと料金を安くする方法があります。ADSLのプロバイダをWillcomにすることで、PHS料金+ADSLの割引が使えて、確か合計7000円くらいで使うことができます(ADSLの回線速度は3MB,うちの場合はADSLは3Mbpsも出ないので十分)。PHS料金+ADSLが7000円とは、本当に安いです。
ただ、残念なことに、WillcomのADSLがうちまで通っていないため、無理なんですよね。
PCとPHSの接続については、また後日書こうと思います。これが予想以上に簡単なんです!

more active ?

私は性格上、自分で納得した出来になったものしか人に見せようとしないんですよ。ですから今運営していたHPも、書いたのは公開約3ヶ月前ですし、フォーラムへの投稿も、何度も自分の文を確認してしまいます。このブログはそこまで神経質にはなっていませんが、少なくとも、他人から見れば、いつ投稿するんだろうって感じで見られているでしょうね。実際見えませんけどね。
それはそれでいいのですが、バランスというものはあるわけです。リポジトリの編集ならいいですが、まだ決定という段階でもなく、まして、議論を展開するような、フォーラムでの発言は、そこまで完璧にしなくてもいいと思うんですよね。

円滑に開発を進めるためには、もう少しActiveなった方がいいでしょうね。きっと。
そういえば、ab.comのTOPにリンクが張ってあるってことは、結構このページは見られている可能性が高いんですよね。それがどうこうってわけではありませんけど、一度ネットに流した情報は、収集がつかないので、発言には注意すべきですよね。関係ない話題になりそうなので、この辺りで終わりにしときます。

昨日に引き続き

初めて作ったにしては、なかなかの出来の線形リスト、今回は双方向タイプのものですが、循環していないタイプのものを作っていました。しかし、いろいろ実装していくうちに、やはり、循環タイプのが綺麗なコードが書けそうなので、時間の取れる今週末あたりには、普通の配列と一緒に循環リストももう一度書き直そうと思っています。うまくできたら、ライブラリの候補として取っておきましょうか。

それはそうと、Static修飾子。ActiveBasicに実装されるようなので、どんなものか調べてみると、クラスメソッドのことらしいですね。クラスメソッドは、Objective-Cにもあったので、どんなものかは容易に想像が付きます。ちなみに、Objective-Cでのクラスメソッドの定義は、メソッドの前に「+」と書きます。ちなみに普通のインスタンスメソッドは「-」を使用します。省略はすることができませんので、すべてに「+」 か「-」が付くことになります。

+ (id)function //クラスメソッド
- (id)function //インスタンスメソッド

一応注釈しときますが、クラスメソッドという点に着目して言っているだけですので、静的か動的かということに関しては、Objective-Cでは異なっています。

しかし、クラスメソッドってどんな使い方ができるんでしょうか。複数のインスタンスを生成するオブジェクトで、共通の処理をしたいもの…なんでしょうね。
あと、静的ローカル変数はどうするんだろうか。高速化?値を保持して何かするのか?どちらにしろ、Staticって案外奥が深そうです。

とりあえず、線形リスト

昨日に引き続き、データ構造関係の、線形リストを暫定的にコーディングしてみました。
とりあえず、データ構造のクラスって便利ですよね。Insertとか、かなりいい感じです。いろいろデータ構造をコーディングしていくうちに、インターフェースも決まっていきそうな気がするので、線形リストがある程度できたら、また他のデータ構造もコーディングしてみるつもりです。

それで、今日コーディングして悩んだのが、要素の指定方法。ActiveBasicの配列は、Dim array[N] As Longで、array[0]-array[N]まで使用できる訳ですから、N+1個確保されるわけです。
そこで、配列クラスとかも、コンストラクタでサイズを指定してから配列クラスを作る場合、それと同じにしようと思った訳です。しかし、この仕様だと、配列クラスの要素数を返すメソッドを実装した場合、要素数を返すべきなのか、それとも最大のインデックスの値を返すべきなのか、迷ってしまいます。
とりあえずは前者の実装をしてしまいましたが、どうでしょうね。

とりあえず

ライブラリ開発の方が、久々に活発になりそうなので、本当は次のβ版が出てからやろうと思ってましたが、これに便乗して配列、リストあたりのクラスを構築してしまおうと考えています。
とりあえず、基底クラスの仕様や、イテレータはどうするかなど、まだ議論の余地がありそうではあるので、実装してから話を持ちかけることにしましょう。

今日は、家族にWindowsを占領されていましたが、なんとか隙を見て、 Arrayクラスをある程度構築してみました。
ところで、ソートは何を元にやりましょうか。ToString()は使い回しな気がするし、 基底クラスに比較するためのものを入れるのは、あまり汎用的ではないし、新たな比較用インターフェースっても、多重継承はできなそうだし…

スクリーンセーバー

今日、あるソフトを探していると、面白そうなスクリーンセーバーを発見しました。
LotsaWater(日本語版)
このスクリーンセーバーは、現在のスクリーンを元に、そこに波紋を発生させてくれます。波紋エフェクトは結構好きなので、私も波紋を使ったちょっとしたソフトを考えています。
スクリーンセーバー
ところで、この波紋。Mac OS Xのいつかのバージョンから追加されたCore Imageというものを使って、簡単にプログラムから呼び出せるようになっています。他にも、Core Imageにはいろいろエフェクトがあって見ているだけで面白いです。
それで、このCore ImageのAPIを使おうと思っている訳ですが、ドキュメントが英語なので、少々苦戦しています。というのも、Core Imageは基本的にはC言語ですので、CocoaのObjective-CでAPIを使うにはちょっとした細工が必要になるのです。

ここで面白いのが、Core Imageなどのコードは、C言語であるにもかかわらず、Objective-Cとまったく同等の、インスタンスの構造を持っているのです。構造体からキャストして、そのままオブジェクト型(インスタンスへのポインタ)の変数に入れても問題ないのです。当然、それからオブジェクトのメソッド呼び出しも、問題なく行えます。
Objective-Cは、それほどC言語を拡張したものではないのです。