Maxは、あなたのオブジェクト宛てのメッセージに対し、アーギュメントの型チェックを行うサービスを提供することができます。setup と addmess という2つの関数はこのタスクを実行するために、アーギュメントの型を指定するリストを使用します。
オブジェクト生成関数は、特別な新規のオブジェクトへ送られるメッセージに対する応答として呼び出されます。setup には、あなたがメッセージへのアーギュメントを定義する場合と同様なアーギュメントの型指定リストを渡します。新規のオブジェクトにメッセージが送られた場合、クラス名が "メッセージセレクタ”自身になり、アーギュメントはクラス名の後に続きます。(例えば、20 in + 20)
関数 addmess は、setupと同様、アーギュメント型指定リストを受け取ります。例えば、2つの long 整数をアーギュメントとして必要とするメッセージ searce を定義したいと考えましょう。ユーザは、私たちのオブジェクトへ連結されているMaxメッセージボックスにこのようにタイプするでしょう。この場合、searchはメッセージで、304 と228はアーギュメントです。アーギュメントの型リストはこのようになります。
A_LONG, A_LONG, 0
アーギュメントの型リストは常に0で終わります。(A_NOTHING で定義されています)。関数でアーギュメントを宣言しようとする場合、(searchメッセージへの応答であれば)次のように書きます。
void myobject_search (myObject *x, long arg1, long arg2);
浮動小数はA_FLOAT で、シンボル(テキストによる語)は A_SYM で指定することができます。
アーギュメントをオプションにしたい場合、A_DEFLONG、A_DEFFLOAT、A_DEFSYM を使うことができます。これらのアーギュメントがない場合のデフォルトはそれぞれ、0,0.0,そして空シンボル("")になります。
明確にアーギュメントを宣言した場合には、Maxは指定された型のアーギュメントを直接メソッドに送ります。アーギュメントの型が違っていると、Maxはユーザにエラーメッセージを表示します。
ここで、基本的な型リストの指定を見てみましょう。
A_NOTHING | 型リストの最後 |
A_LONG | 型チェックされる整数(int)アーギュメント |
A_FLOAT | 型チェックされる浮動小数(float)アーギュメント |
A_SYM | 型チェックされるシンボル(symbol)アーギュメント |
A_OBJ | ポインタアーギュメント(旧式な形) |
A_DEFLONG | 型チェックされる整数(int)アーギュメント、デフォルトは0 |
A_DEFFLOAT | 型チェックされる浮動小数(float)アーギュメント、デフォルトは0 |
A_DEFSYM | 型チェックされるシンボル(symbol)アーギュメント、デフォルトは0 |
A_GIMME | リストとして指定できるアーギュメントは7つまでです。しかし、次のような型リストを使用すると、Maxに対し、アーギュメントを t_atoms(後で述べるような構造体定義)の配列として渡すよう指定することができます。 |
A_GIMME, 0
このような方法を用いた場合、アーギュメントの型チェックを自分自身で行うことができます。このメッセージに含まれるアーギュメントの数には制限がありません。
Atomは次のような形式になります。
union word /* どのようなデータでもパックできる共用体 */{ long w_long; float w_float; t_symbol *w_sym; t_object *w_obj; }; typedef struct atom /* 典型的なデータ型であるAtom */{ short a_type; /* from the definitions above*/ union word a_w; } t_atom;
メソッドがA_GIMME でアーギュメントを受け取るように宣言すると、アーギュメントはargc、argv によるリスト(UNIXのCプログラマには何となく親しみのある形)として渡されます。argcはアーギュメントの数、argvは配列の最初の argc である t_atomへのポインタになります。また、t_symbol をメッセージ自身に含めて受け取ります。生成関数がアーギュメントを A_GIMME で受け取ると、この t_symbol はあなたのクラス名になります。これは A_GIMME 型のリストに対応する関数宣言です。
void myMethod (myObject *x, t_symbol *s, short argc, t_atom *argv); | |
x | あなたのオブジェクト |
s | t_symbol.としてのメッセージセレクタ |
argc | argv の t_atom の数 |
argv | アーギュメントの配列 |
アーギュメントの型チェックを自分で行うためには、t_atom の a_typeフィールドを見ます。可能な値は、A_LONG、A_SYM、A_FLOAT です(A_DEFLONG、A_DEFSYM、 A_DEFFLOAT は使えません)。次は、型チェックとアーギュメントの処理のモデルとして使用できるアーギュメントを表示するメソッドの例です。
void myMethod(myObject *x, t_symbol *s, short argc, t_atom *argv) { short i; for (i=0; i < argc; i++) { switch (argv[i].a_type) { case A_LONG: post("argument %ld is a long: %ld", (long)i, argv[i].a_w.w_long); break; case A_SYM: post("argument %ld is a symbol: name %s", (long)i, argv[i].a_w.w_sym->s_name); break; case A_FLOAT: post("argument %ld is a float: %lf", (long)i, argv[i].a_w.w_float); break; } } }
メソッドへの文字列(t_symbol) アーギュメントは呼び出されるメッセージの名前です。いくつかのメッセージ名を同じメソッドに結び付ける(バインドする)こともできます。例えば、
addmess(myObject_doit,"doit", A_GIMME, 0); /*doit にバインドする*/
addmess(myObject_doit,"finger", A_GIMME, 0); /* finger にバインドする*/
メソッドが、いつ doit メッセージにバインドされたかを知りたい場合には、次のようなテクニックを使って、t_symbol が シンボル doit と同じかどうかをチェックします。
void myobject_doit(myObject *x, t_symbol *s, short argc, t_atom *argv) { if (s == gensym("doit")) { post("Called as a result of receiving the message doit"); } }
注:gensym は文字列に関連づけられた t_symbol を返す関数です。Chapter7で説明します。