概要 objectbaseライブラリは、Swarmオブジェクトモデルの様々な基本的外観をカプセル化し、Swarmオブジェクトからデータを取得するのに使用されるプロービング装置を定義します。ここで定義されるクラスの基礎となる関数は、ほとんどがdefobjとactivityライブラリに含まれます。 Probe. Probeは、オブジェクトの内部機構の監視や修正ができる理想化されたエンティティです。コンパイル時にそれらの機能性を明示的に与えないため、オブジェクトインスタンス変数やメソッドを使った動的な相互作用が可能になります。probeの機能性は大部分がこのライブラリに実装されていますが、現在のところ、それらはsimtoolsguiライブラリに密接にリンクしています。simtoolsguiはGUIからprobeを使用するのに必要なウィジトリを含んだライブラリです。このような緊密性はありますが、probeはSwarmオブジェクトと動的に相互作用するあらゆるエージェントやデバイスに対する汎用メカニズムであるようにデザインされています。probeの背景にある目的や論理については、付録のSwarmObjectコンテンツのプローブと表示で詳しく説明します。 |
以下は<objectbase.h>がインポートする他のヘッダファイルです。
#import <defobj.h> #import <activity.h> |
1.0.4 => 1.0.5. 変更点はありません。
1.0.3 => 1.0.4. このライブラリの名前が、swarmobjectからobjectbaseに変わりました。ライブラリのより総称的な性質を反映するために変更したものですが、SwarmのWindows NTへの移殖が急務であったこともその理由にあります(ファイル名がSwarmObjectクラスと混同されないように)。ユーザには、ほとんど、あるいはまったく影響ありません。唯一の目に見える変更箇所は、実際のライブラリである(.a)や(.so)ファイルの名前が変わり、ヘッダファイル名が修正されたことです。下位互換を確保するためにobjectbase.hからswarmobject.hへのシンボリックリンクが提供されますが、これに頼り続けてはいけません。コードにあるswarmobject.hへのリファレンスを、objectbase.hへ移行してください。このシンボリックリンクは将来のリリースで削除されます。
注意: これは先のリリースで同じように残っているSwarmObjectクラスにはまったく影響しません。
1.0.0 => 1.0.1. インターフェイスが再度変更されました!EmptyProbeMapがProbeMapからサブクラス化されたCustomProbeMapのサブクラスになり、ショートカットするcreate:メソッドがその枝に加えられました。
また、isProbeMapDefinedForメソッドがProbeLibraryに新しく加えられました。isProbeMapDefinedForは、あるクラスのProbeMapの存在を非侵襲的にテストするときに役立ちます。
Beta => 1.0.0. Swarmのベータリリースで稼動するアプリケーションにとって、swarmobjectライブラリへの新しいインターフェイスはいくつか問題を招く可能性があります。全体的な情報については、ライブラリインターフェイス規則を参照してください。
objectbaseライブラリは、エージェントやswarmをデザインするのに必要とされる最も基本的なオブジェクトを含んでいます。また現在のところ、各SwarmObjectに提供されるプロービング装置のリポジトリとしても役立ちます。objectbaseライブラリのクラスの利用方法は変化しますが、基本的にこのライブラリはユーザ自身のオブジェクトやSwarmからサブクラス化するときに利用されることを目的としています。
ライブラリの使用方法を説明するには例を示すのが一番です。そこで、objectbaseが使用される方法をHeatbugを使って紹介しましょう。細かい説明があった方が良いので、まずObjective Cに慣れていない人でも理解できるように低いレベルで説明します。すでにあなたがObjective Cに詳しければ、この部分は飛ばしてください。
Heatbugシミュレーションの基本エレメントは、heatbug、model swarm、observer swarmです。model swarmはheatbug群を束ねたもの、observer swarmはmodel Swarmやheatbugをつつくprobeのディスプレイを束ねたものです。それぞれのインターフェイスファイルは、何をインポートしなければならないかを示し、SwarmObjectからサブクラス化するのに必要な宣言構文を示します。
この説明にはHeatbug.hを使います。このファイルの最初の部分は、必要なC-プリプロセッサのインポートです。
#import <objectbase/SwarmObject.h> #import <space.h> #import "HeatSpace.h" #import <tkobjc/Raster.h> |
#import <objectbase/SwarmObject.h>;は、SwarmObjectからサブクラス化するための記述です。しかし、このインポートはライブラリインターフェイスファイルobjectbase.hにも下位互換のために置かれています。つまり、objectbase.hファイルをインポートすれば、SwarmObjectからのサブクラス化は可能なわけで、できるだけ標準的にライブラリインターフェイスを作成しようと思えばこの記述は邪魔です。
次にobjectbaseに関連するコードは、
@interface Heatbug: SwarmObject { double unhappiness; int x, y; HeatValue idealTemperature; HeatValue outputHeat; float randomMoveProbability; Grid2d * world; int worldXSize, worldYSize; HeatSpace * heat; Color bugColor; } |
@interfaceキーワードは、他のオブジェクトに可視となるオブジェクト(この場合はHeatbug)の部分を定義し始めることを示します。Heatbug: SwarmObjectは、あなたがHeatbugオブジェクトを呼び出していることを表し、またそれがSwarmObjectのサブクラスであることを表します。中括弧({})の間は、SwarmObjectクラスから継承されるインスタンスに加えてHeatbugクラスに定義するインスタンス変数です。
この"エージェント"の中では、エージェントそのもの、あるいはそれが存在する空間に関連するパラメータをいくつか定義します。エージェントのあらゆる振る舞いや存続期間に関するデータも、すべて宣言しなければなりません。また、ここで宣言されたものはどれもプロービング装置にアクセスできるので、エージェントの外側から眺めたり処理したりできるようになります。
次に、このエージェントが反応するメッセージのプロトタイプに進みましょう。SwarmObjectのスーパークラスで宣言されているものに加えて記述しても意味はありません。言い換えれば、他のオブジェクトはここで宣言されたこのエージェントへのメッセージだけでなく、先ほどインポートしたobjectbase/SwarmObject.hで宣言されたすべてのメッセージを送ることができます。ここでプロトタイプ化されたメッセージは、コンパイラがこのオブジェクトは何に反応できるかを判定するのに使用されます。したがって、もしどれかのプロトタイプのある部分がHeatbug.mの対応する関数定義と違っていれば、コンパイラはObject: aHeatbug does not respond to xyz(ここでxyzはHeatbugに送られているメッセージ名。つまり"aHeatbugは送られたメッセージに反応しない")というような警告を出力するでしょう。ヘッダファイルのプロトタイプを対応する".m"ファイルのメッセージ宣言に適合するように固定するスクリプトは、Swarmの配布と一緒に提供されています。このスクリプトはm2hという名前で、$SWARMHOME/binディレクトリにあります。
これらのプロトタイプに関してもう1つ注意すべきことは、そのいくつかがobjectbase/SwarmObject.hに現れるものの複製だということです。つまり、Heatbugオブジェクト上にメッセージが呼び出されたとき、それはここで定義されたメソッドを実行するのであり、SwarmObjectクラスのそれを実行するのではありません。objectbaseライブラリでは、create:, createBegin:, createEnd, customizeBegin:, customizeEnd, customizeCopy:, describe:, getInstanceNameの各メッセージは、必要に応じてオーバーライドされるべきです。これらのメッセージは、それぞれSwarmObjectのサブクラスからサブクラスへ変化する可能性を持った特定の事柄をなすものです。しかしこの場合、我々はcreateEndをオーバーライドしているだけです。Heatbugsにそれを実装することとデフォルトとの違いはそれほど顕著ではありませんが、createBegin:やcreateEndのような特定のメッセージをオーバーライドするときは、新しいメソッドはそのメッセージのスーパークラスのバージョンも同様に呼び出さなければなりません。superと明示するスーパークラスへのデフォルトのポインタを使います。Heatbugsでは、以下の構文になります。
[super createEnd]; |
これをする理由は、defobjが使用するオブジェクトフェーズプロトコルに関係があります。この詳細については、付録の"Objective CとSwarm"にあるSwarm流Objective Cの原則としてのCreateフェーズを参照してください。
最後にインターフェイス定義を締めくくるのは@endキーワードです。GNU Objective Cではこれを記述しなくても構いませんが、良い方法とは言えません。
説明はこれで終わりです。もちろん、ここでは言及しなかったobjectbaseライブラリのトリッキーな利用法もいくらかはあります。そのうちいくつかは、上級利用ガイドや実装に関する注意で解説しますが、最良の学習方法はデモアプリケーションでの利用方法を研究し、あなた自身がいくつかの変更を試してみることです。
Swarmクラスからのサブクラス化は、SwarmObjectからのサブクラス化とよく似ています。
シミュレーション実行を対話的にコントロールしたいときは、ActivityControlオブジェクトが役に立ちます。任意のアクティビティの任意のポイントでシミュレーションをストップしたいというような問題も、ActivityControlによって解決されます。ActivityControlオブジェクトは、Swarmデバッガの最初の一歩となります。
Swarmカーネルだけが使用する目的で作成されたアクティビティも含み、Swarmシミュレーションで作成されるどのアクティビティにも、アクティビティコントローラを置くことができます。コントローラはrun, stop, next, step, stepUntil, terminateといった基本的なアクティビティの操作メッセージを、そのアクティビティに提供します。
ActivityControlオブジェクトを、ControlPanelと混同するかもしれません。ControlPanelは様々なスケジュールの実行をコントロールするもので、(ユーザがいつでもボタンをクリックできるGUISwarmのように)ランダムな干渉が予測されるコンテキストで実行しているシミュレーションの、トップレベルの制御を行うために利用されます。つまり、ControlPanelはトップレベルのSwarmの実行を永続させる無限ループに、擬似的な割り込みを送ります(現時点のGUISwarmには、goメッセージしかありません)。この種のコントロールは将来変更されるかもしれませんが、今のところはシミュレーションのコントロール状態を監視する方法となっています。
シミュレーションの実行には、もうControlPanelは利用すべきでありません。ControlPanelはコントロールのコンテキストを示し、シミュレーション全体を終了させるためだけに使用してください。つまり、いつかはControlPanelディスプレイからGoとStopボタンが削除されるということです。これらはActivityControlを使っていないアプリケーションでもそれらの操作(不便ですが)ができるように、下位互換の目的で残されています。また、現在のTime Stepボタンは、その新しい目的に見合うようにStartと改名されるでしょう。
新しいコントロールメカニズムを使用するには、あなたは以下のようなコードをトップレベルのSwarmに置かなければなりません。このコードは、修正されたmousetrapデモアプリケーションから取り出しました。
observerActCont = [ActivityControl createBegin: [self getZone]]; observerActCont = [observerActCont createEnd]; [observerActCont attachToActivity: [self getSwarmActivity]]; [probeDisplayManager createProbeDisplayFor: observerActCont]; |
ActivityControlを作成し、それをトップレベルのアクティビティ(この例ではobserverSwarm)にアタッチしています。次に、コントローラのディスプレイを作成します(ActivityControlクラスのprobemapは、ActivityControl自身の中に設計されます。これは、これらのオブジェクトすべてがどのオブジェクトの外側にも等しく見えるようにしたいためです)。このアクティビティコントローラを使うと、アクティビティをrun、stop、next、step、stepUntil、terminateできるようになります。
ActivityControlオブジェクトをうまく利用するトリッキーな手法もいくつかありますが、それは上級利用ガイドで説明します。
あるSwarmObject(のサブクラス)にProbeMapを設計するときは、スーパークラスに定義されたインスタンス変数やメッセージを包含することが望まれます。ProbeMapを設計する通常のコードは以下のようなものです。このコードは"hello-world"と呼ばれるチュートリアルアプリケーションから抜粋しました。
probeMap = [CustomProbeMap createBegin: [self getZone]]; [probeMap setProbedClass: [person class]]; probeMap = [probeMap createEnd]; [probeMap addProbe: [probeLibrary getProbeForVariable: "room" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "party" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "name" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "stillhere" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "listOfFriends" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "myColor" inClass: [person class]]]; [probeLibrary setProbeMap: probeMap For: [person class]]; [probeDisplayManager createProbeDisplayFor: person]; |
room、party、name、stillhere、listOfFriends、myColorは、Personサブクラスへのインターフェイスで宣言されたインスタンス変数で、Personは、SwarmObjectのサブクラスであるAgent2dのサブクラスです。
さて、Personからの変数以外に、このカスタムprobeに置きたいAgent2dに宣言された2つの変数xとyがあるとしましょう。probeMapにそれを加えるには、上述のコードに以下の2行を付け加えます。
[probeMap addProbe: [probeLibrary getProbeForVariable: "x" inClass: [Agent2d class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "y" inClass: [Agent2d class]]]; |
これで、2つのスーパークラス宣言の変数(実際にはサブクラスのインスタンスのインスタンス変数)がprobeに含まれました!
さらに、上記の入り乱れたメカニズムを1つのメッセージに圧縮する便利なメッセージがCustomProbeMapインターフェイスに加えられています。同じクラスからの変数とメッセージでProbeMapが構成されることがよくありますが、その場合はこの便利なメッセージを使用することができます。たとえば上記のカスタムprobe作成の最初の部分は、以下のように短くできます。
[probeLibrary create: [self getZone] forClass: [person class] withIdentifiers: "room", "party", "name", "stillhere", "listOfFriends", "myColor", NULL]; |
probeMap = [CustomProbeMap create: [self getZone] forClass: [person class] withIdentifiers: "room", "party", "name", "stillhere", "listOfFriends", "myColor", ":", "setWorld:Room:Party:", "setPerson:Topic_array:ShowSpeech:", NULL]; |
現在のところ、このメッセージはここにリストされるメッセージ名に対するスーパークラスは探索しません。しかし、まもなく修正されるでしょう。
シミュレーションのすべてのアクティビティに渡る明示的なコントロールが可能になれば実に合理的なのですが、現時点ではアクティビティが走るコンテキストがその振る舞いを決定するため、このコントロールは制限されます。ActivityControlがどのように利用されるべきかを理解するには、コンテキストのアクティビティの振る舞いを探索しなければなりません(アクティビティの振る舞いに関する詳細はactivityライブラリのドキュメンテーションを参照してください)。
スタートしたアクティビティを取得する方法は2つあります。まず、nilのアクティビティ、あるいは他のアクティビティ内のアクティビティをアクティベートできます。"トップレベル"アクティビティはnilでアクティベートされ、シミュレーションの他のあらゆるコンテキスト内でアクションの実行を指示するアクティビティのスケジューリングからは独立していることとされます。すなわち、nilでアクティベートされるべき唯一のアクティビティは、たとえシミュレーションの他の部分でそれが起こっても同じ振る舞いを保つことが期待されるイベントの集合です。
他の種類のアクティビティ、つまりある他のアクティビティでアクティベートされたアクティビティには、そのオーナーアクティビティの不可欠な一部であるように意図されるものです。しかし、それがオーナーアクティビティに起こるアクションの結果に依存しなければならないということではありません。実際、以下のようなコードを使えば、ActionPlanは並行に処理され得るアクションを含むように指示できます。
[anActionPlan setDefaultOrder: Concurrent]; |
アクティビティをnilでアクティブ化することの操作上の影響は、それがSwarmの残りのアクティビティ構造に適合しないことにあります。そのアクティビティの実行上の完全なコントロールはユーザ(あるいはプロセス)に与えられます。そのアクティビティ上のrunは、そのアクティビティに対して完全に内的なイベントシーケンスがストップフラグをセットするか、あるいは完了するまで走ります。ActivityControlなどからのメッセージを使い、外側からストップさせることもできます。
つまり、ActivityControlはどのアクティビティにもアタッチできますが、一方、"トップレベル"のアクティビティ(nilでアクティベートされたもの)だけがそれによく反応することになります。サブアクティビティはどれもしぶしぶ反応します。たとえばSwarmと一緒に配布されるMousetrapのデモでは、ObserverSwarmとModelSwarmアクティビティの両方にActivityControlが置かれています。observerSwarmのアクティビティにアタッチされているActivityControlにrunメッセージを送ると、モデル全体はユーザがstopメッセージを送るまで完了に向けて走り続けます。しかし、もし何かのポイントでシミュレーションがストップしたら、modelSwarmのアクティビティへのrunメッセージはまったく効果を持ちません(注意:アクティビティコントローラを使ってこれを行うと、currentTime変数は更新されていくことに注意してください。しかし、そのアクティビティへの実際のrunメッセージは何の効果も持っていません)。
したがって、ObserverSwarmのような"トップレベル"のアクティビティに対してのみActivityControlオブジェクトをアタッチすることが、当分の実践ルールです。
ここでは、主にSwarmとSwarmObjectがユーザにサブクラス化されるべきクラスだと定義されます。提供されるプロービング機能は、主としてSwarmカーネル内での使用に向けたものですが、Swarmと他のエージェントやデバイス間にインターフェイスを設計するときは、このプロービング装置を使用しなければなりません。
SwarmObject. SwarmObjectは、Swarmのすべての対話型エージェントに対する基底クラスです。作成、プロービング、ゾーンメモリ割り当て、破棄を含み、すべてのSwarmスタイルエージェントへの標準的な振る舞いを定義します。
Swarm. Swarmクラスはactivityライブラリの抽象実行装置だけでなく、関連オブジェクトのグループの概念をすべてカプセル化します。隠喩的には、"Swarm"はオブジェクトのコレクションと、それらのオブジェクト上のアクティビティのスケジュールを組み合わせたものです。したがって、Swarmクラスはそのようなオブジェクトやスケジュールのスタートアップに必要な振る舞いを提供します。
サブクラス化の詳細は、 利用ガイドでも説明されています。
残念ながら、このインターフェイスは厳密な設計リビューを経験していません。将来的に変更が予定されているからですが、そもそもこのライブラリはdefobjライブラリに統合されるといううわさもあります。このインターフェイスの設計についてはほとんど配慮されませんが(この時期に頑健なインターフェイスの設計に労力を費やすことはおそらくありません)、defobjによる標準的なセットに調和した様々なライブラリをすべて揃えるための、最初のステップを提供する目的で実装されています。
これに伴って関連する注意事項を以下に挙げます。
Probeは、任意のオブジェクトの生来の一部分になるかもしれません。
ActivityControlは、Swarmモデルのデバッグに使用されるより大きなツールセットの一部になるでしょう。
目下、Probeは、どのプロービング可能なオブジェクトにも実装しなければならない特別なメソッドgetInstanceNameに頼っています。これによりProbeは、オブジェクトの指示ウィジットの中に、そのオブジェクトのクラス名以外の何ものでも置くことができるようになります。しかし、さらに一般的な機能がdefobjに加えられ、どのオブジェクトにも意味を持った名前を与えるようになりました。Probeもこの新しい機能の利点を享受できるように変更されるでしょう。
ActivityControlでは、updateStateVarメッセージの頻度が極めて高くなります。このメッセージはどのサイクルにも少なくとも1回送られ、そのたびにActivityControlにメッセージが送られます。これには満足できません。これらのメッセージのいくつかはオブジェクトから削ることができます。
ActivityControlと一緒に利用するように設計されたprobeMapがかなり独断的に選択されました。今は、それがそのクラスのデフォルトとして役に立ちます。ユーザがそれをオーバーライドするには、新しいものを設計してprobeLibraryに挿入します。
objectbaseライブラリのオブジェクトに特有のエラーは、defobjライブラリのそれと同様に収集して初期化する必要があります。
ドキュメンテーションと実装の現状