Chapter 3:
データ型とアーギュメントリスト

Maxは、あなたのオブジェクト宛てのメッセージに対し、アーギュメントの型チェックを行うサービスを提供することができます。setupaddmess という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_DEFLONGA_DEFFLOATA_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 でアーギュメントを受け取るように宣言すると、アーギュメントはargcargv によるリスト(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_atoma_typeフィールドを見ます。可能な値は、A_LONGA_SYMA_FLOAT です(A_DEFLONGA_DEFSYMA_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で説明します。