ObjectScript の詳細
大部分のメソッドおよび大部分のルーチンは ObjectScript で作成されます。この章では、それを使用しようとしている人や、他の人が作成したコードを理解する必要がある人を対象にこの言語の概要について説明します。以下の項目について説明します。
メソッドには、ルーチンの場合と同じ文、同じラベル、同じコメントを含めることができます。つまり、ルーチンのコンテンツについてここで説明する情報は、メソッドのコンテンツにも当てはまります。
ルーチンではなくクラスを作成する場合は、“変数” のセクションからお読みください。
ルーチン
以下に、ObjectScript で作成された demoroutine という名前のサンプル・ルーチンを示します。この例は、いくつかの一般的なコマンド、演算子、および関数と、ルーチン内でのコードの構成方法を示しています。
; this is demoroutine
write "Use one of the following entry points:"
write !,"random"
write !,"input"
write !,"interesting"
quit
//this procedure can be called from outside the routine
random() public {
set rand=$RANDOM(10)+1 ; rand is an integer in the range 1-10
write "Your random number: "_rand
set name=$$getnumbername(rand)
write !, "Name of this number: "_name
}
//this procedure can be called from outside the routine
input() public {
read "Enter a number from 1 to 10: ", input
set name=$$getnumbername(input)
write !, "Name of this number: "_name
}
//this procedure can be called only from within this routine
getnumbername(number) {
set name=$CASE(number,1:"one",2:"two",3:"three",
4:"four",5:"five",6:"six",7:"seven",8:"eight",
9:"nine",10:"ten",:"other")
quit name
}
/* write some interesting values
this procedure can be called from outside the routine
*/
interesting() public {
write "Today's date: "_$ZDATE($HOROLOG,3)
write !,"Your installed version: "_$ZVERSION
write !,"Your username: "_$USERNAME
write !,"Your security roles: "_$ROLES
}
以下の点に注意してください。
-
実際にキャレット (^) で始まる識別子のみが、グローバルの名前であり、これについては、この章で後述します。ただし、実行されるテキストおよびコード・コメント内では、ルーチンを呼び出すときにキャレットを使用するため、一般的に、ルーチンの名前がキャレットで始まっているかのように、ルーチンが参照されます (この章で後述します)。例えば、demoroutine というルーチンは、通常、^demoroutine と呼び出されます。
-
ルーチン名は、そのルーチン内に含める必要はありません。スタジオでルーチンを表示するときは、ルーチン名はそのルーチンが表示されているタブに表示されます。以下はその例です。
多くのプログラマは、ルーチンの最初にコメントとして、またはルーチンの最初のラベルとしてルーチン名を含めます。
-
ルーチンには、複数のラベル (random、input、getnumbername、および interesting) があります。
ラベルは、プロシージャ (この例の場合)、関数、およびサブルーチンの開始点を示すために使用されます。これらの用語については、この章の後半で説明します。これらは、特定のコマンドの宛先としても使用できます。
ラベルは、一般的にルーチン内で使用されますが、メソッド内でも使用できます。
ラベルは、エントリ・ポイントまたはタグとも呼ばれます。
-
random および input サブルーチンは、getnumbername サブルーチンを呼び出します。
-
WRITE、QUIT、SET、および READ はコマンドです。この言語には、ほかに変数を削除するコマンド、プログラム・フローを制御するコマンド、入出力デバイスを制御するコマンド、トランザクションを管理するコマンド (ネスト可能) などがあります。
コマンドの名前では大文字小文字は区別されませんが、規約によって実行されるテキストではすべて大文字で表記します。
-
このサンプルには 2 つの演算子が含まれています。プラス記号 (+) は加算を、アンダースコア (_) は文字列連結を実行します。
ObjectScript には、通常の演算子以外に他の言語にはないいくつかの特別な演算子があります。
-
$RANDOM、$CASE、および $ZDATE は関数です。
この言語は、文字列処理、多くの種類の変換、フォーマット処理、算術演算などのための関数を提供します。
-
$HOROLOG、$ZVERSION、$USERNAME、および $ROLES は、システム変数 (Caché では特殊変数と呼ぶ) です。大部分の特殊変数には、Caché 操作環境の状況、現在の処理状態などに対応した値が格納されます。
-
ObjectScript は、コメント行、ブロック・コメント、文の終わりのコメントをサポートします。
デモンストレーションとして、このルーチンの一部をターミナルで実行できます。最初に、以下はルーチン自体を実行するターミナル・セッションを示しています。これらの例では、SAMPLES> はターミナルに表示されるプロンプトです。同じ行の、プロンプトの後にあるテキストは、入力されたコマンドです。その後の行は、応答としてシステムによってターミナルに書き込まれた値を示しています。
SAMPLES>do ^demoroutine
Use one of the following entry points:
random
input
SAMPLES>
ルーチンを実行するときは、ここに示すようにヘルプ情報が表示されます。ルーチンをこのように記述することは必須ではありませんが、一般的です。ルーチンには、最初のラベルの前に QUIT が含まれており、それによって、ユーザがそのルーチンを呼び出したときに、そのラベルの前で処理が停止されます。この方法も必須ではありませんが、一般的です。
次に、以下に 1 組みのサブルーチンの動作のしかたを示します。
SAMPLES>do input^demoroutine
Enter a number from 1 to 10: -7
Name of this number: other
SAMPLES>do interesting^demoroutine
Today's date: 2010-11-30
Your installed version: Cache for Windows (x86-32) 2010.2 (Build 454U) Sun Oct 24 2010 17:14:03 EDT
Your username: UnknownUser
Your security roles: %All
SAMPLES>
プロシージャ、関数、およびサブルーチン
ObjectScript ルーチン内では、ラベルは、以下のコード・ユニットの 1 つの開始ポイントを定義します。
-
プロシージャ (オプションで値を返します)。プロシージャで定義される変数は、そのプロシージャに対してプライベートです。これは他のコードから使用できないことを意味します。これは、関数およびサブルーチンの場合は異なります。
プロシージャは、プロシージャ・ブロックと呼ばれます。
-
関数 (値を返します)。
-
サブルーチン (値を返しません)。
インターシステムズでは、プロシージャを使用することをお勧めします。それにより、変数の範囲を制御する作業がシンプルになるからです。ただし、既存のコードでは、関数およびサブルーチンも使用されているため、それらを認識できると便利です。以下のリストは、これらのすべての形式のコードがどのようなものであるかを示しています。
label(args) scopekeyword {
zero or more lines of code
QUIT returnvalue
}
または以下のようにします。
label(args) scopekeyword {
zero or more lines of code
}
labelは、プロシージャの識別子です。
args は、オプションの引数のコンマ区切りリストです。引数がない場合でも、括弧は含める必要があります。
オプションの scopekeyword は、以下のいずれか (大文字と小文字を区別しない) です。
-
Public。Public を指定すると、そのプロシージャはパブリックとなり、そのルーチン自体の外で呼び出すことができます。
-
Private (プロシージャに対する既定値)。Private を指定すると、そのプロシージャはプライベートとなり、それと同じルーチン内の他のコードのみで呼び出すことができます。別のルーチンからそのプロシージャにアクセスしようとすると、<NOLINE> エラーが発生します。
returnvalue は、オプションで返される 1 つの値です。値を返すには、QUIT コマンドを使用する必要があります。中括弧はプロシージャの終了を示すので、値を返さない場合は QUIT コマンドを省略できます。
プロシージャでは、変数をパブリック変数として宣言できます。ただし、この方法は最新の方法とは見なされていません。これを実行するには、scopekeyword の直前に、変数名をコンマで区切ったリストを角括弧で囲んで記述します。詳細は、"Caché ObjectScript の使用法" の “ユーザ定義コード” を参照してください。
label(args) scopekeyword
zero or more lines of code
QUIT optionalreturnvalue
args は、オプションの引数のコンマ区切りリストです。引数がない場合でも、括弧は含める必要があります。
オプションの scopekeyword は Public (関数に対する既定値) または Private です。
label(args) scopekeyword
zero or more lines of code
QUIT
args は、オプションの引数のコンマ区切りリストです。引数がない場合、括弧の使用はオプションです。
オプションの scopekeyword は Public (サブルーチンに対する既定値) または Private です。
以下の表は、ルーチン、サブルーチン、関数、およびプロシージャの相違点を要約したものです。
ルーチン | サブルーチン | 関数 | プロシージャ | |
---|---|---|---|---|
引数を受け入れられるか | 不可 | 可 | 可 | 可 |
値を返せるか | 不可 | 不可 | 可 | 可 |
ルーチンの外で呼び出せるか (既定の場合) | 可 | 可 | 可 | 不可 |
その中で定義された変数をそのコードの実行終了後に使用できるか | 可 | 可 | 可 | 変数の特性によって異なる |
この章の後半の “変数の可用性と範囲” で変数の範囲について詳しく説明します。
一般的な使用法では、サブルーチンという用語は、プロシージャ、関数、またはサブルーチン (ここで正式に定義したものの場合) を意味することがあります。
変数
ObjectScript には、データの保持方法で分類した場合、次の 2 種類の変数があります。
-
ローカル変数。データをメモリに保持します。
ローカル変数の範囲は、パブリックまたはプライベートです。
-
グローバル変数。データをデータベースに保持します。これらは、グローバルとも呼ばれます。グローバルとのやり取りはすべて、データベースに直接作用します。例えば、グローバルの値を設定した場合、その変更は、格納されているデータに直ちに作用し、値を格納するために別のステップは行われません。同様に、グローバルを削除すると、そのデータはデータベースから直ちに削除されます。
ここでは、説明しませんが特別な種類のグローバルもあります。付録 “Caché の様々な構文” の “キャレット (^)” を参照してください。
変数名
変数の名前は、以下のルールに従う必要があります。
-
大部分のローカル変数の場合、最初の文字は英字であり、残りの文字は英字または数字です。有効な名前には、myvar や i があります。
-
大部分のグローバル変数は、最初の文字は常にキャラット (^) です。残りの文字は、英字、数字、またはピリオドです。有効な名前には、^myvar や ^my.var があります。
Caché は、パーセント変数という特別な種類の変数もサポートしています。これは、あまり一般的ではありません。パーセント変数の名前は、パーセント文字 (%) で始まります。パーセント変数は、常にパブリックである点と、プロセス内のすべてのコードから見える点で特別です。これは、呼び出し元スタック内のすべてのメソッドとすべてのプロシージャを含みます。
パーセント変数を定義する場合は、以下のルールに従います。
-
ローカル・パーセント変数の場合は、%Z または %z で始まる名前にします。他の名前はシステムで使用するために予約されています。
-
グローバル・パーセント変数の場合は、^%Z または ^%z で始まる名前にします。他の名前はシステムで使用するために予約されています。
パーセント変数と変数の有効範囲の詳細は、この章で後述する “変数の可用性と範囲” を参照してください。また、"Caché ObjectScript の使用法" の “呼び出し可能なユーザ定義コードモジュール” も参照してください。
名前の詳細およびバリエーションについては、"Caché ObjectScript の使用法" の “構文規則” の章を参照してください。または、このドキュメントで後述する、“識別子のルールとガイドライン” を参照してください。
変数タイプ
ObjectScript の変数は、弱く動的に型指定されます。変数が動的に型指定されるのは、変数に対して型を宣言する必要がないためであり、変数は有効な値 (有効なリテラル値または有効な ObjectScript 式) であればどのような値も取ることができます。変数は、弱く型指定されます。それは、使用法によってそれらの評価方法が決まるためです。
ObjectScript の有効なリテラル値は、次のいずれかの形式です。
-
数値。例 : 100、17.89、および 1e3
-
引用符で囲まれた文字列。1 組みの引用符 (") で囲まれた一連の文字です。例 : "my string"
文字列リテラル内に二重引用符を含めるには、" (二重引用符) 文字の前にもう 1 つ " 文字を置きます。例 : "This string has ""quotes"" in it."
コンテキストに応じて、文字列が数値として扱われたり、数値が文字列として扱われることがあります。同様に、コンテキストによっては、値がブーリアン (True または False) 値として解釈され、ゼロに評価されるものはすべて False に、それ以外のものはすべて True として処理される場合があります。
クラスを作成する場合、プロパティの型、メソッドの引数などを指定できます。Caché クラスのメカニズムでは、これらの型は、指定したとおりに適用されます。このドキュメントの後のセクションで、Caché データ型クラスの概要について説明します。
可変長
変数の値には長さの制限があります。使用している環境で長い文字列を有効化している場合、上限は 3,641,144 文字です。長い文字列が有効化されていない場合、上限は 32,767 文字になります。
長い文字列演算を有効化する方法については、このドキュメント内の後のセクションで説明します。
変数の存在
変数は、通常、SET コマンドを使用して定義します。前述したように、グローバル変数を定義すると、それはデータベースに直ちに作用します。
グローバル定数は、それを削除した (KILL コマンドを使用して削除する) 場合にのみ未定義になります。これも、即座にデータベースに作用します。
ローカル変数は、以下の 3 つのいずれかの方法で未定義になります。
-
削除 (KILL) された場合。
-
それが定義されているプロセスが終了した場合。
-
そのプロセス内の範囲から抜けた場合。
変数が定義されているかどうかを判別するには、$DATA 関数を使用します。例えば、以下は、この関数を使用するターミナル・セッションを示しています。
SAMPLES>write $DATA(x)
0
SAMPLES>set x=5
SAMPLES>write $DATA(x)
1
最初のステップで、$DATA を使用して、変数が定義されているかどうかを調べます。0 が表示され、変数が定義されていないことを示します。次に、変数を 5 に設定し、再試行します。今度は関数が 1 を返します。
この例と前の例からわかるように、変数を宣言する必要はありません。必要なのは、SET コマンドのみです。
未定義の変数にアクセスしようとすると、<UNDEFINED> エラーが発生します。以下はその例です。
SAMPLES>WRITE testvar
WRITE testvar
^
<UNDEFINED> *testvar
変数の可用性と範囲
ObjectScript は、以下のプログラミング・フローをサポートしており、それは他のプログラミング言語でサポートされているフローと多くの面で類似しています。
-
ユーザがプロシージャを呼び出します (通常はユーザ・インタフェースから)。
-
そのプロシージャは、いくつかの文を実行し、別のプロシージャを呼び出します。
-
プロシージャは、ローカル変数 A、B、および C を定義します。
変数 A、B、および C は、このプロシージャ内の範囲内で使用されます。それらは、このプロシージャに対してプライベートです。
そのプロシージャは、グローバル変数 ^D も定義します。
-
2 番目のプロシージャは終了し、制御が最初のプロシージャに戻ります。
-
最初のプロシージャが実行を再開します。このプロシージャは、変数 A、B、および C を使用できません。それらは定義されていない状態になっています。^D は、直ちにデータベースに保存されたため、使用できます。
上記のプログラム・フローはとても一般的なものです。ただし、Caché では他のオプションも提供されており、それに注意する必要があります。
変数の範囲の概要
変数を定義するコード・ユニットの外でその変数を使用できるかどうかは、いくつかの要因によって決まります。それらを説明する前に、以下の環境の詳細を確認する必要があります。
-
Caché インスタンスには、複数のシステム・ネームスペースと、場合によってはユーザが定義した複数のネームスペースなど、複数のネームスペースが含まれています。
ネームスペースとは、その中でコードが実行される環境です。ネームスペースについては、後で詳細に説明します。
-
1 つのネームスペース内で複数のプロセスを同時に実行できます。一般的なアプリケーションでは、多数のプロセスが同時に実行されています。
以下の表は、変数を使用可能な場所を示しています。
変数の可用性 (種類別) | それが定義されているコード・ユニットの外 (ただし、同じプロセス内) | 同じネームスペースの他のプロセス内 | 同じ Caché インスタンス内の他のネームスペース |
---|---|---|---|
ローカル変数、プライベート範囲* | 不可 | 不可 | 不可 |
ローカル変数、パブリック範囲 | 可 | 不可 | 不可 |
ローカル・パーセント変数 | あり | 不可 | 不可 |
グローバル変数 (パーセント以外) | 可 | 可 | いいえ (グローバル・マッピングで許可されていない場合)† |
グローバル・パーセント変数 | 可 | 可 | 可 |
*既定では、プロシージャ内で定義された変数は、前述したとおり、そのプロシージャに対してプライベートです。また、プロシージャでは、変数をパブリック変数として宣言できます。ただし、この方法はお勧めできません。"Caché ObjectScript の使用法" の “ユーザ定義コード” を参照してください。
†各ネームスペースには、特定の目的のための既定のデータベースがあり、追加のデータベースへのアクセスを提供するマッピングを設定できます。その結果、グローバル変数がグローバル・パーセント変数でない場合でも、それを複数のネームスペースで使用可能にすることができます。“ネームスペースとデータベース” の章を参照してください。
NEW コマンド
Caché には、変数の範囲の制御を可能にするもう 1 つのメカニズムがあります。NEW コマンドです。このコマンドの引数は、コンマで区切られた 1 つ以上の変数名のリストです。この変数は、パブリック変数である必要があり、グローバル変数にすることはできません。
このコマンドにより、変数 (既に存在していてもいなくてもかまいません) に対して新しい、制限されたコンテキストが確立されます。例えば、以下のルーチンを考えてみます。
; demonew
; routine to demo NEW
NEW var2
set var1="abc"
set var2="def"
quit
このルーチンを実行した後は、以下のターミナル・セッションの例に示すように、変数 var1 は使用可能であり、変数 var2 は使用できません。
SAMPLES>do ^demonew
SAMPLES>write var1
abc
SAMPLES>write var2
write var2
^
<UNDEFINED> *var2
NEW を使用する前に変数が存在している場合は、NEW の範囲が終了した後もその変数は存在し、それが前に持っていた値を保持します。例えば、前に定義されたルーチンを使用する、以下のターミナル・セッションを考えてみます。
SAMPLES>set var2="hello world"
SAMPLES>do ^demonew
SAMPLES>write var2
hello world
多次元配列
ObjectScript では、どの変数も Caché 多次元配列 (配列とも呼ぶ) にすることができます。多次元配列は、通常、何らかの関連を持つ一連の値を保持することを目的としています。ObjectScript には、値への便利で高速なアクセスを可能にするコマンドと関数があります。これらについては、後のセクションで説明します。
多次元配列を直接操作するかどうかは、使用するシステム・クラスと好みによって異なります。Caché には、一連の関連する値のためのコンテナが必要な場合に使用するクラスベースの代替手段があります。このドキュメントで後述する “コレクション・クラス” を参照してください。
基本
多次元配列は、添え字で定義される、任意の数のノードで構成されます。以下の例では、配列のいくつかのノードが設定され、その配列のコンテンツが印刷されます。
set myarray(1)="value A"
set myarray(2)="value B"
set myarray(3)="value C"
zwrite myarray
この例は、一般的な例を示しています。メモ :
-
この配列には 1 つの添え字があります。この場合、添え字は整数 1、2、および 3 です。
-
事前に配列の構造を宣言する必要はありません。
-
myarray は、その配列自体の名前です。
-
ObjectScript には、配列全体または特定ノードに対して作用できるコマンドおよび関数があります。以下はその例です。
kill myarray
また、特定のノードおよびその子のノードを削除することもできます。
-
以下のバリエーションは、^myglobal という名前のグローバル配列のいくつかの添え字を設定します。つまり、これらの値がディスクに書き込まれます。
set ^myglobal(1)="value A" set ^myglobal(2)="value B" set ^myglobal(3)="value C"
-
グローバル参照には長さの制限があります。この制限は、グローバル名の長さ、および添え字の長さと数に影響します。制限を超えた場合、<SUBSCRIPT> エラーが発生します。"Caché グローバルの使用法" の “グローバル参照の最大長” セクションを参照してください。
-
ノードの値には長さの制限があります。使用している環境で長い文字列が有効化されていない場合、上限は 32,767 文字になります。長い文字列が有効化されてる場合、この制限値ははるかに大きくなります。
長い文字列演算を有効化する方法については、このドキュメント内の後のセクションで説明します。
多次元配列は、定義済みノードごとに 1 つの予約済みメモリ位置を持っており、それ以外は持っていません。グローバルの場合、それが使用するディスク領域はすべて動的に割り当てられます。
構造のバリエーション
上記の例は、配列の一般的な形を示しています。以下の使用可能なバリエーションに注意してください。
-
添え字の数に制限はありません。以下はその例です。
Set myarray(1,1,1)="grandchild of value A"
-
添え字は文字列にすることができます。以下も有効です。
set myarray("notes to self","2 Dec 2010")="hello world"
使用上の注意
ObjectScript の学習者がよく犯す誤りは、グローバルと配列を混同することです。どの変数もローカルかグローバルのいずれかであり、さらに添え字ありか添え字なしのいずれかであることを忘れないでください。以下の表は、その例を示しています。
例と注意 | ||
---|---|---|
ローカル | 添え字なし | Set MyVar=10
このような変数はきわめて一般的です。変数の大部分はこのような変数です。 |
添え字付き |
Set MyVar(1)="alpha" Set MyVar(2)="beta" Set MyVar(3)="gamma" このようなローカル配列は、一連の関連するデータを渡す場合に便利です。 |
|
グローバル | 添え字なし | Set ^MyVar="saved note"
実際、グローバルには通常添え字があります。 |
添え字付き | Set ^MyVar($USERNAME,"Preference 1")=42 |
演算子
このセクションでは、ObjectScript の演算子の概要について説明します。よく知られているものと、あまり知られていないものがあります。
ObjectScript で演算子の評価順序は、必ず左から右です。したがって、式の演算は表示された順番で実行されます。式で明示的に小括弧を使用して、特定の演算子を先に処理させることができます。
通常、括弧は、必ずしも必要でない場所にも使用します。これは、他のプログラマに (および後で作成者自身に)、コードの意図を明確にすることができるので便利です。
よく知られている演算子
ObjectScript には、一般的なアクティビティのための以下の演算子があります。
-
算術演算子 : 加算 (+)、減算 (-)、除算 (/)、乗算 (*)、整数除算 (\)、剰余 (#)、および指数 (**)
-
単項演算子 : 正 (+)、および負 (-)
-
文字列連結演算子 (_)
-
論理比較演算子 : 等しい (=)、より大きい (>)、以上 (>=)、より小さい (<)、以下 (<=)
-
論理補数演算子 (')
これは、論理値の直前および論理比較演算子の直前に使用できます。
-
論理値を組み合わせる演算子 : AND (&&)、OR (||)
ObjectScript では、これらの演算子それぞれの古くて効率的でない形式 (&& 演算子の &、|| 演算子の !) もサポートされています。これらの古い形式は、既存のコードに使用されていることがあります。
あまり知られていない演算子
ObjectScript には、いくつかの言語に同等のものがない演算子もあります。最も重要なものは以下のとおりです。
-
パターン・マッチング演算子 (?) は、左オペランドの文字パターンが、その右オペランドのパターンを使用しているかどうかを判断します。パターンが発生する回数、代替パターン、パターンの入れ子などを指定できます。
例えば、以下は、文字列 (testthis) が米国の社会保障番号の書式である場合は、値 1 (True) を、それ以外の場合は 0 を返します。
Set testthis="333-99-0000" Write testthis ?3N1"-"2N1"-"4N
これは、入力データの妥当性を確保するための価値のあるツールであり、クラス・プロパティの定義内で使用できます。
-
二項包含関係演算子 ([) は、右のオペランドの一連の文字が、左の文字の部分文字列であるかどうかによって、1 (True) または 0 (False) を返します。以下はその例です。
Set L="Steam Locomotive",S="Steam" Write L[S
-
二項後続関係演算子 (]) は、左のオペランドの文字が、ASCII 文字順で右のオペランドの文字の後に来るかどうかを判断します。
-
二項前後関係演算子 (]]) は、左のオペランドが数値添え字の照合順序で右のオペランドの後に順番に並んでいるかを判定します。
-
間接演算子 (@) により、コマンド引数、変数名、添え字リスト、またはパターンの一部またはすべてを実行時に動的に置き換えることができます。Caché は、関連するコマンドを実行する前に、置換を実行します。
コマンド
このセクションでは、これから使用する可能性が高いコマンド、および ObjectScript でよく使用されているコマンドの概要について説明します。これらには、他の言語に類似したコマンドと、他の言語には同等のものがないコマンドがあります。
コマンドの名前では大文字小文字は区別されませんが、規約によって実行されるテキストではすべて大文字で表記します。
よく知られているコマンド
ObjectScript には、以下のようなよく知られたタスクを実行するためのコマンドがあります。
-
変数を定義するには、前述のように SET を使用します。
-
変数を削除するには、前述のように KILL を使用します。
-
ロジックのフローを制御するには、以下のコマンドを使用します。
-
IF、ELSEIF、および ELSE。これらは連携して機能します。
-
FOR
-
WHILE。単独で使用できます。
-
DO および WHILE。これらは一緒に使用できます。
-
QUIT。これも値を返すことができます。
フローを制御するコマンドはほかにもありますが、それらはあまり使用されません。
-
-
エラーをトラップするには、TRY および CATCH を使用します。これらは連携して機能します。
-
値を書き込むには、WRITE を使用します。これは、現在のデバイス (例えば、ターミナルやファイル) に値を書き込みます。
このコマンドを引数なしで使用した場合、すべてのローカル変数の値を書き込みます。これは、特にターミナルで便利です。
このコマンドは、出力を配置する一連の形式制御コード文字を使用できます。既存のコードでは、新しい行を開始するために感嘆符が使用されている場合があります。以下はその例です。
write "hello world",!,"another line"
-
現在のデバイス (例えば、ターミナル) から値を読み取るには、READ を使用します。
-
主デバイス以外のデバイスを使用するには、以下のコマンドを使用してください。
-
OPEN は、デバイスを使用可能にします。
-
USE は、使用可能になったデバイスを WRITE および READ で使用するために現在のデバイスとして指定します。
-
CLOSE は、デバイスを使用不可にします。
-
-
同時処理を制御するには、LOCK を使用します。Caché のロック管理システムは、他の言語の同様のシステムとは異なる点に注意してください。この動作のしくみを再確認することが重要になります。この章で後述する、“ロックと並行処理の制御” を参照してください。
このコマンドは、複数のプロセスが同一の変数などの項目にアクセスする可能性がある場合に使用します。
-
トランザクションを管理するには、TSTART、TCOMMIT、TROLLBACK、および関連コマンドを使用します。
-
デバッグするには、ZBREAK および関連コマンドを使用します。
-
実行を中断するには、HANG を使用します。
多次元配列で使用するコマンド
ObjectScript では、以下の方法で多次元配列を操作できます。
-
ノードを定義するには、SET コマンドを使用します。
-
個別のノードまたはすべてのノードを削除するには、KILL コマンドを使用します。
例えば、以下は、多次元配列全体を削除します。
kill myarray
以下は、対照的にノード myarray("2 Dec 2010") およびその子すべてを削除します。
kill myarray("2 Dec 2010")
-
グローバルまたはグローバル・ノードを削除するが、その下位サブノードは削除しない場合は、ZKILL を使用します。
-
多次元配列のすべてのノードに繰り返し処理を行い、それらすべてを書き込むには、ZWRITE を使用します。これは、特にターミナルで便利です。以下のターミナル・セッションの例は、出力がどのようなものになるのかを示しています。
SAMPLES>ZWRITE ^myarray ^myarray(1)="value A" ^myarray(2)="value B" ^myarray(3)="value C"
この例では、ローカル変数ではなくグローバル変数を使用しますが、どちらも多次元配列にすることができることを忘れないでください。
-
一連のノードを 1 つの多次元配列から別の多次元配列に、ターゲットに既存のノードを残したままコピーするには、MERGE を使用します。例えば、以下のコマンドはメモリ内の配列 (sourcearray) 全体を新しいグローバル (^mytestglobal) にコピーします。
MERGE ^mytestglobal=sourcearray
これは、コードをデバッグしているときに、使用している配列のコンテンツを調べるのに便利です。
特殊変数
このセクションでは、Caché のいくつかの特殊変数について説明します。これらの変数の名前では、大文字と小文字は区別されません。
いくつかの特殊変数は、コードが実行されている環境に関する情報を提供します。これは、以下の項目が含まれます。
-
$HOROLOG。これには、オペレーティング・システムから提供される、現在のプロセスの日付と時刻が格納されます。この章で後述する “日付と時刻の値” を参照してください。
-
$USERNAME および $ROLES。これには、現在使用しているユーザ名と、そのユーザが属しているロールに関する情報が格納されます。
write "You are logged in as: ", $USERNAME, !, "And you belong to these roles: ",$ROLES
-
$ZVERSION。これには、現在動作している Caché のバージョンを表す文字列が格納されます。
そのほかに $JOB、$ZTIMEZONE、$IO、および $ZDEVICE があります。
他の変数は、コードの処理状態に関する情報を提供します。それらには、$STACK、$TLEVEL、$NAMESPACE、および $ZERROR があります。
$SYSTEM 特殊変数
特殊変数 $SYSTEM は、一連の多数のユーティリティ・メソッドへの、言語に依存しないアクセスを提供します。
$SYSTEM 特殊変数は、%SYSTEM パッケージのエイリアスであり、そのパッケージには、幅広いニーズに対応するクラス・メソッドを提供するクラスが含まれています。%SYSTEM のメソッドを参照する一般的な方法は、$SYSTEM 変数を使用する参照を構築することです。例えば、以下のコマンドは %SYSTEM.OBJOpens in a new tab クラスの SetFlags() メソッドを実行します。
DO $SYSTEM.OBJ.SetFlags("ck")
特殊変数の名前は、クラス名やそのメンバ名とは異なり、大文字と小文字が区別されないため、以下のコマンドはすべて等価です。
DO ##class(%SYSTEM.OBJ).SetFlags("ck")
DO $System.OBJ.SetFlags("ck")
DO $SYSTEM.OBJ.SetFlags("ck")
DO $system.OBJ.SetFlags("ck")
このクラスにはすべて、Help() メソッドがあり、これはそのクラスで使用可能なメソッドのリストを出力できます。以下はその例です。
SAMPLES>d $system.OBJ.Help()
'Do $system.OBJ.Help(method)' will display a full description of an individual method.
Methods of the class: %SYSTEM.OBJ
CloseObjects()
Deprecated function, to close objects let them go out of scope.
Compile(classes,qspec,&errorlog,recurse)
Compile a class.
CompileAll(qspec,&errorlog)
Compile all classes within this namespace
....
また、メソッドの名前を Help() の引数として使用することもできます。以下はその例です。
SAMPLES>d $system.OBJ.Help("Compile")
Description of the method:class Compile:%SYSTEM.OBJ
Compile(classes:%String="",qspec:%String="",&errorlog:%String,recurse:%Boolean=0)
Compile a class.
<p>Compiles the class <var>classes</var>, which can be a single class, a comma separated list,
a subscripted array of class names, or include wild cards. If <var>recurse</var> is true then
do not output the intial 'compiling' message or the compile report as this is being called inside
another compile loop.<br>
<var>qspec</var> is a list of flags or qualifiers which can be displayed with
'Do $system.OBJ.ShowQualifiers()'
and 'Do $system.OBJ.ShowFlags()
ロックと並行処理の制御
マルチプロセス・システムでの重要な機能の 1 つに、並行処理の制御があります。これは、異なるプロセスがデータの特定の要素を同時に変更し、破損に至ることを防止する機能です。そのために、ObjectScript にはロック管理システムが用意されています。このセクションでは、簡単な概要を説明します。
このドキュメントで後述する、“ロック、グローバル、およびネームスペース” も参照してください。
基本
基本のロック・メカニズムは、LOCK コマンドです。このコマンドの目的は、あるプロセス内のアクティビティを、別のプロセスが処理継続 OK の合図を送るまで遅延することです。
ロックは、それ自体では他のプロセスによる関連データの変更を防止しないことを理解しておくことが重要です。つまり、Caché は一方的なロックを強制実施しないということです。規約では、ロックが機能するには、互いに競合するプロセスがすべて同じロック名でロックを実装していることが要求されています。
LOCK コマンドは、ロックの作成 (プロセスが所有していた以前のすべてのロックの置換)、ロックの追加、特定のロックの削除、およびプロセスが所有するすべてのロックの削除に使用できます。
ここでの簡単な説明のために、LOCK コマンドに次の引数を使用します。
-
ロック名。ロック名は、任意の名前ですが、共通の規則として、プログラマはロックする項目の名前と同じロック名を使用します。通常、ロックする項目は、グローバルまたはグローバルのノードになります。
-
オプションのロック・タイプ (既定のタイプ以外のロックを作成する場合)。複数のロックタイプがあり、それぞれの動作が異なります。
-
オプションのタイムアウト引数。この引数では、ロック操作の試行をタイムアウトにするまでの待機時間を指定します。既定では、 Caché は永久に待機します。
次に一般的なロック・シナリオについて説明します。プロセス A が LOCK コマンドを発行し、Caché はロックの作成を試行します。プロセス B が指定されたロック名のロックを既に所有している場合、プロセス A は一時停止します。具体的には、プロセス A の LOCK コマンドは復帰しなくなり、コードの後続行が実行できなくなります。プロセス B がロックを解放すると、プロセス A の LOCK コマンドが復帰して実行を継続できるようになります。
システムは、永続オブジェクト (このドキュメントで後述) を操作するときや、特定の Caché SQL コマンドを使用するときなど、多くの場合に自動的に LOCK コマンドを使用します。
ロック・テーブル
Caché は、現在のすべてのロックと、そのロックを所有しているプロセスを記録するために、システム規模のテーブルをメモリ内に保持しています。このテーブル (ロック・テーブル) は、管理ポータルからアクセスできます。管理ポータルでは、ロックの表示と、まれに必要になるロックの削除を実行できます。特定のプロセスが、ロック名が異なる複数のロックを所有している可能性がある点に注意してください (複数のロックが同じ名前の場合もあります)。
プロセスが終了すると、システムは、そのプロセスが所有するすべてのロックを自動的に解放します。そのため、通常は、管理ポータルからロックを削除する必要はありません。ただし、アプリケーション・エラーが発生した場合を除きます。
ロック・テーブルは、固定サイズを超過することはありません (このサイズは指定できます)。詳細は、"Caché 監視ガイド" の “ロックの監視” を参照してください。そのため、ロック・テーブルが一杯になり、それ以上のロックが不可能になることがあります。この場合、Caché は、cconsole.log ファイルに以下のエラー・メッセージを書き込みます。
LOCK TABLE FULL
通常は、ロック・テーブルが一杯になっても、アプリケーション・エラーとは見なされません。Caché には、ロック・キューも用意されているため、プロセスはロック・テーブルにロックを追加する領域ができるまで待機します。
ただし、2 つのプロセスが、既に別のプロセスでロックされている変数に対して増分ロックをアサートすると、デッドロックと呼ばれる状態になり、その状態はアプリケーション・プログラミング・エラーと見なされます。詳細は、"Caché ObjectScript の使用法" の “ロック管理” の章にある “デッドロックの回避” を参照してください。
ロックと配列
配列をロックする場合は、配列全体をロックすることも、配列内の 1 つ以上のノードをロックすることもできます。配列ノードをロックすると、他のプロセスは、そのノードに従属するどのノードもロックできなくなります。また、他のプロセスは、ロックされたノードの直接の祖先もロックできなくなります。
次の図に例を示します。
ロック・タイプの概要
ロックの作成時には、ロックの特性を制御する、ロック・タイプ・コードの組み合わせを指定できます。このセクションでは、ロック・タイプの重要なコンセプトの一部について説明します。
ロック・タイプによっては、同じロック名で複数のロックを作成することも可能です。これらのロックは同一プロセスが所有することも、別々のプロセスが所有することもできます (繰り返しになりますが、これは、ロック・タイプによって異なります)。ロック・テーブルには、これらすべてについての情報が表示されます。
あらゆるロックは、排他 (既定) または共有のどちらかになります。これらのタイプは、次に示す重要な意味を持ちます。
-
あるプロセスが特定のロック名の付いた排他ロックを所有しているときに、その他のプロセスは、そのロック名の付いたロックを取得できません。
-
あるプロセスが特定のロック名の付いた共有ロックを所有しているときに、その他のプロセスは、そのロック名の付いた共有ロックを取得できます。ただし、他のプロセスはそのロック名で排他的なロックを取得できません。
一般に、排他ロックは、値を変更する予定があり、他のプロセスはその値の読み取りまたは変更を試行してはいけないことを示すために使用されます。共有ロックの目的は、値を読み取る予定があることを示し、その他のプロセスがその値の変更を試行してはいけないことを示すことです。ただし、その他のプロセスがその値を読み取ることは可能です。
さらに、あらゆるロックは、非エスカレート (既定) またはエスカレートのどちらかになります。エスカレート・ロックの目的は、メモリを消費し、ロック・テーブルが埋め尽くされる可能性が大きくなる大量のロックの管理を簡単にすることです。エスカレート・ロックは、同じ配列に含まれる複数のノードをロックする場合に使用します。エスカレート・ロックの場合、あるプロセスがある配列の兄弟ノードに特定の数 (既定では 1,000) を超えるロックを作成すると、Caché は、個別のロック名をすべて削除して、それらを親レベルで新しい 1 つのロックに置き換えます。例えば、^MyGlobal("sales","EU",salesdate) という形式で salesdate が日付を表しているロックが 1,000 個あるとします。同じプロセスが、この形式で別のロックを作成しようとすると (すべてのロックがエスカレート・ロックの場合)、Caché は、これらのロックをすべて削除してから、^MyGlobal("sales","EU") という名前のロックに置き換えます。ロック・テーブルは、この新しいロック用のロック・カウントを維持します。このロック・カウントは、現在 1,001 ですが、同じ形式の別のロック名を追加すると、ロック・テーブルでは、ロック名 ^MyGlobal("sales","EU") のロック・カウントがインクリメントされます。同様に、同じ形式のロック名を削除すると、ロック・テーブルではこのロック・カウントがデクリメントされます。
Caché には、トランザクションの範囲内で特別な方法で扱われるロックの追加のサブタイプがあります。これらのロックの詳細と、全般的なロックの説明は、"Caché ObjectScript リファレンス" の "LOCK" を参照してください。ロックしきい値 (既定値は 1000) の指定の詳細は、"Caché パラメータ・ファイル・リファレンス" の “LockThreshold” を参照してください。
システム関数
このセクションでは、ObjectScript で最もよく使用されるシステム関数のいくつかに焦点を当てます。
これらの関数の名前では、大文字と小文字は区別されません。
Caché クラス・ライブラリでは、関数を使用するのと同じように使用できる多数のユーティリティ・メソッドも提供されています。特定の用途のメソッドを見つけるには、"インターシステムズ・プログラミング・ツールの索引" を使用してください。
この章で後述する “日付と時刻の値” も参照してください。
値の選択
以下の関数を使用すると、入力に対して 1 つの値を選択できます。
-
$CASE は、指定されたテスト評価式を、一連の比較値と比較し、一致した比較値と関連付けられた返り値を返します。以下はその例です。
SAMPLES>set myvar=1 SAMPLES>write $CASE(myvar,0:"zero",1:"one",:"other") one
-
$SELECT は、一連の式を評価し、最初の True 式に関連付けられた返り値を返します。以下はその例です。
SAMPLES>set myvar=1 SAMPLES>write $SELECT(myvar=0:"branch A",1=1:"branch B") branch B
存在の関数
以下の関数を使用して、変数の存在または変数のノードの存在をテストできます。
-
特定の変数が存在するかどうかを判別するには、$DATA 関数を使用します。
複数のノードを格納する変数に対しては、この関数は、指定されたノードが存在するかどうか、および指定されたノードに値と子ノードがあるかどうかを示すことができます。
-
変数の値を取得する (変数が存在する場合) または既定値を取得する (存在しない場合) には、$GET 関数を使用します。
リスト関数
ObjectScript には、ネイティブのリスト形式が用意されています。以下の関数を使用して、これらのリストを作成および操作できます。
-
$LISTBUILD は、リストと呼ばれる特別な種類の文字列を返します。これは、他の種類のリスト (コンマ区切りリストなど) と区別するために $LIST 形式と呼ばれることもあります。
$LIST リストの操作には、ObjectScript のリスト関数の使用のみがサポートされます。この種のリストの内部構造は文書化されていません。また、予告なしに変更される場合があります。
-
$LIST は、リスト要素を返します。また、リスト要素を置換するために使用することもできます。
-
$LISTLENGTH は、リスト内の要素の数を返します。
-
$LISTFIND は、指定されたリスト内の指定された要素の位置を返します。
リスト関数は、ほかにもあります。
リストにない値を指定してリスト関数を使用すると、<LIST> エラーを受け取ります。
システム・クラス %Library.ListOpens in a new tab は、$LISTBUILD によって返されるリストと同じです。つまり、クラスに %Library.ListOpens in a new tab タイプのプロパティがある場合、ここに示す関数を使用してそのプロパティを操作します。このクラスは、その短い名前である %ListOpens in a new tab によって参照できます。
Caché には、$LISTBUILD によって返されるリストとは異なる他のリスト・クラスもあります。これらは、クラスを操作する場合に便利です。概要については、このドキュメントで後述する “コレクション・クラス” を参照してください。
文字列関数 (1)
ObjectScript には、文字列を効率的に使用するための一連の広範な関数も用意されています。
-
$EXTRACT は、文字カウントを使用して、部分文字列を返すか、置換します。
-
$FIND は、値により部分文字列を検索し、文字列の最終位置を指定する整数を返します。
-
$JUSTIFY は、左にスペースを埋め、右揃えした文字列を返します。
-
$ZCONVERT は、文字列の形式を変換します。大文字と小文字の変換 (大文字変換、小文字変換、タイトル文字変換など) とコード変換 (さまざまな形式でコード化された文字間の変換) をサポートします。
-
$TRANSLATE は、文字単位の置換を実行し、指定した文字列を変更します。
-
$REPLACE は、1 つの文字列内で文字列単位の置換を実行し、新しい文字列を返します。
-
$PIECE は、文字で区切られた文字列 (分割化された文字列 と呼ぶ) から、部分文字列を返します。多くの古いアプリケーションは、それぞれが長い文字列内の部分文字列である、関連する値を格納するために便利な形式として文字区切り文字列を使用しています。長い文字列はレコードとして、部分文字列はそのフィールドとして動作します。
多くの場合、区切り文字はキャレットです。したがって、既存のコードには、"value 1^value 2^value 3" のような分割化された文字列が含まれていることがあります。
以下は、部分文字列の抽出方法の例を示しています。
SET mystring="value 1^value 2^value 3" WRITE $PIECE(mystring,"^",1)
-
$LENGTH は使用されるパラメータによって、指定した文字列内の文字数あるいは指定した文字列内の区切られた部分文字列の数を返します。
以下はその例です。
SET mystring="value 1^value 2^value 3" WRITE !, "Number of characters in this string: " WRITE $LENGTH(mystring) WRITE !, "Number of pieces in this string: " WRITE $LENGTH(mystring,"^")
多次元配列の操作
以下の関数を使用して多次元配列全体を操作できます。
-
$ORDER を使用すると、多次元配列内の各ノードに順番にアクセスできます。
-
$QUERY を使用すると、サブノード間を移動して、配列内の各ノードと各サブノードにアクセスできます。
配列内の個別ノードを操作するには、前述した、どの関数も使用できます。特に次のことが可能です。
-
$DATA は、指定されたノードが存在するかどうか、および指定されたノードに子ノードがあるかどうかを示すことができます。
-
$GET は、指定されたノードの値を取得するか、それ以外の場合は既定値を取得します。
文字値
文字列を作成するときに、タイプできない文字を含めることが必要な場合があります。そのような場合は、$CHAR を使用します。
整数を指定すると、$CHAR は、対応する ASCII または Unicode 文字を返します。一般的な使用法は以下のとおりです。
-
$CHAR(9) はタブです。
-
$CHAR(10) は改行です。
-
$CHAR(13) はキャリッジ・リターンです。
-
$CHAR(13,10) はキャリッジ・リターンと改行のペアです。
関数 $ASCII は、指定された文字の ASCII 値を返します。
$ZU 関数
既存のコードには、$ZU(n)、$ZUTIL(n)、$ZU(n,n) など (n は整数) が含まれていることがあります。これらは、現在では廃止され、ドキュメントに記載されなくなった $ZU 関数 です。それらは、現在でも使用できますが、ユーザには、Caché クラス・ライブラリ内の同等のアクションを実行するメソッドおよびプロパティと、それらを置き換えることをお勧めします。"Caché ObjectScript リファレンス" の “ObjectScript $ZUTIL 関数の代替機能” に代替機能の表があります。
日付と時刻の値
このセクションでは、ObjectScript の日付と時刻の値の簡単な概要について説明します。
ローカル時刻
現在のプロセスの日付と時刻にアクセスするには、$HOROLOG 特殊変数を使用します。これが原因となって、多くの Caché アプリケーションでは、日付と時刻はこの変数で使用される形式で格納され、送信されます。この形式は、通常、$H 形式または $HOROLOG 形式と呼ばれます。
$HOROLOG は、オペレーティング・システムから日付と時刻を取得するため、常にローカル・タイムゾーンになります。
Caché クラス・ライブラリには、ODBC など一般的な形式で日付を表すデータ型クラスが含まれており、多くのアプリケーションは $H 形式の代わりにそれらを使用します。
UTC 時刻
Caché には、$ZTIMESTAMP 特殊変数も用意されています。これには、現在の日付と時刻が協定世界時 (UTC) 値で、$H 形式で格納されます。UTC は、時刻と日付の世界標準です。この値は、ローカル時刻 (および日付) の値と異なる場合がほとんどです。
日付・時刻の変換
ObjectScript には、日付と時刻の値を変換するための関数もあります。
-
関数 $ZDATE は、$H 形式で日付を指定された場合、指定した形式で日付を表す文字列を返します。
以下はその例です。
SAMPLES>WRITE $ZDATE($HOROLOG,3) 2010-12-03
-
関数 $ZDATETIME は、$H 形式で日付と時刻を指定された場合、指定した形式で日付と時刻を表す文字列を返します。
以下はその例です。
SAMPLES>WRITE $ZDATETIME($HOROLOG,3) 2010-12-03 14:55:48
-
他の形式の日付と時刻の文字列を指定された場合、関数 $ZDATEH および $ZDATETIMEH は、それらを $H 形式に変換します。
-
関数 $ZTIME は時刻を $H 形式から変換し、$ZTIMEH は時刻を $H 形式に変換します。
$H 形式の詳細
$H 形式は、コンマで区切られた数値のペアです。例 : 54321,12345
-
最初の数値は、1840 年 12 月 31 日からの日数です。つまり、日付の番号 1 は 1841 年 1 月 1 日です。この数値は常に整数です。
-
2 番目の数値は、指定された日付の午前 0 時からの秒数です。
$NOW() などのいくつかの関数では、小数部分が提供されます。
開始日の説明を含む詳細は、"Caché ObjectScript リファレンス" の "$HOROLOG" を参照してください。
マクロとインクルード・ファイルの使用
前述のように、ルーチンでは、マクロを定義し、後でそれらのマクロをその同じルーチン内で使用できます。一般的には、それらはインクルード・ファイルで定義します。インクルード・ファイル、スタジオでは拡張子 .inc が付いたドキュメントです。
マクロを定義するには、#define 指示文または他のプリプロセッサ指示文を使用します。以下はその例です。
#define mymacro "hello world"
インクルード・ファイルをルーチンにインクルードするには、#Include 指示文を使用します。以下はその例です。
#Include myincludefile
クラス定義では構文が若干異なります。
マクロを参照するには、以下の構文を使用します。
$$$macroname
または以下のようにします。
$$$macroname(arguments)
プリプロセッサ指示文の詳細は、"Caché ObjectScript の使用法" の “ObjectScript マクロとマクロ・プリプロセッサ” を参照してください。
スタジオと管理ポータルの両方に、ルーチンを含むインクルード・ファイルのリストが表示されます。例えば、スタジオの [ワークスペース] ウィンドウでは、[ルーチン] フォルダ内にインクルード・ファイルが表示されます。ただし、インクルード・ファイルは実行ファイルではないため、実際にはルーチンではありません。
ルーチンとサブルーチンの使用
ルーチンを実行するには、以下のように DO コマンドを使用します。
do ^routinename
プロシージャ、関数、またはサブルーチンを (その返り値にアクセスすることなく) 実行するには、以下のコマンドを使用します。
do label^routinename
または以下のようにします。
do label^routinename(arguments)
プロシージャ、関数、またはサブルーチンを実行し、その返り値を参照するには、$$label^routinename または $$label^routinename(arguments) の形式の式を使用します。以下はその例です。
set myvariable=$$label^routinename(arguments)
すべての場合において、ラベルが同じルーチン内にあれば、キャラットおよびルーチン名は省略できます。以下はその例です。
do label
do label(arguments)
set myvariable=$$label(arguments)
すべての場合において、渡す引数は、リテラル値、式、また変数の名前です。
値または参照による変数渡し
コードを呼び出す場合、値または参照によって、そのコードに変数の値を渡すことができます。多くの場合、これらの変数は添え字なしのローカル変数であるため、このセクションでは最初にそれらについて説明します。
他のプログラミング言語の場合と同様に、Caché は、各ローカル変数の値を格納するメモリ位置を持っています。変数の名前は、メモリ位置のアドレスとして機能します。
添え字なしのローカル変数を、プロシージャ、関数、またはサブルーチンに渡すときは、その変数を値によって渡します。つまり、システムによってその値のコピーが作成され、元の値が変更されることはありません。代わりに、メモリ・アドレスを渡すには、引数リストの変数の名前の直前にピリオドを配置します。以下はその例です。
do ^myroutine(.myarg)
この例を示すために、次のプロシージャを考えてみます。
square(input) public
{
set answer=input*input
set input=input + 10
quit answer
}
変数を定義し、それをこのプロシージャに値によって渡すとします。
SAMPLES>set myvariable=5
SAMPLES>write $$square^demobyref(myvariable)
25
SAMPLES>write myvariable
5
反対に、変数を参照によって渡すとします。
SAMPLES>set myvariable=5
SAMPLES>write $$square^demobyref(.myvariable)
25
SAMPLES>write myvariable
15
添え字なしのローカル変数に加えて変数の他のバリエーションもあります。以下の表は、そのすべてのバリエーションを示しています。
変数の種類 | 値渡し | 参照渡し |
---|---|---|
ローカル変数 (添え字なし) | これらの変数を渡す既定の方法 | 可能 |
ローカル変数 (添え字付き) | この方法では渡せません (最上位ノードのみが渡されます) | 必須 |
グローバル変数 (添え字付き、または添え字なし) | 必須 | この方法では渡せません (グローバルのデータがメモリ内にありません) |
潜在的な落とし穴
以下の項目は、ObjectScript を初めて使用するプログラマ (特に、他のプログラマによって記述されたコードの管理担当者) の混乱を招くことがあります。
-
ルーチンまたはメソッド内では、ラベルが含まれている行以外は、すべての行が少なくとも 1 つのスペースまたは 1 つのタブでインデントされている必要があります。つまり、最初の文字位置にテキストがある場合、コンパイラおよびスタジオではそれがラベルとして処理されます。スタジオでは、前述の例のようにラベルは赤で表示されます。
ただし、例外が 1 つあり、中括弧は最初の文字位置に配置できます。
-
コマンドとその最初の引数の間には 1 つのスペース (タブではない) を配置する必要があります。それ以外の場合は、スタジオでは構文エラーがあると表示されます。
同様に、ターミナルでは、以下のような構文エラーが表示されます。
SAMPLES>write 5 WRITE 5 ^ <SYNTAX> SAMPLES>
-
ObjectScript で演算子の評価順序は、必ず左から右です。したがって、式の演算は表示された順番で実行されます。式で明示的に小括弧を使用して、特定の演算子を先に処理させることができます。
通常、括弧は、必ずしも必要でない場所にも使用します。これは、他のプログラマに (および後で作成者自身に)、コードの意図を明確にすることができるので便利です。
-
これまでの使用法により、ObjectScript は空の文字列 ("") を ASCII の NULL 値と同等とは見なしません。ASCII の NULL 値を表現するには、$CHAR(0) を使用します。($CHAR は、ASCII 文字 (特定の 10 進数ベースのコード) を返すシステム関数です)。以下に例を示します。
write "" = $char(0)
同様に、ObjectScript 値が SQL または XML に投影されるときには、値 "" と $CHAR(0) は異なる方法で処理されます。これらの値の SQL プロジェクションの詳細は、"Caché SQL の使用法" の “言語要素” の章にある “NULL および空文字列” を参照してください。これらの値の XML プロジェクションの詳細は、"オブジェクトの XML へのプロジェクション" の “空文字列および NULL 値の処理” を参照してください。
-
ObjectScript には、大文字と小文字を区別する場合とそうでない場合があります。大文字と小文字を区別しないものには、コマンド、関数、特殊変数、ネームスペース、およびユーザの名前があります。
大文字と小文字を区別するものには、定義する要素の大部分 (ルーチン、変数、クラス、プロパティ、およびメソッド) の名前があります。詳細は、"Caché ObjectScript の使用法" の “構文規則” の章を参照してください。
-
ほとんどのコマンド名は省略形で表現できます。したがって、WRITE、Write、write、W、および w はいずれも、WRITE コマンドの有効な形式です。リストは、"Caché ObjectScript リファレンス" の “省略形テーブル” を参照してください。
-
多くのコマンドに対して、後置条件式 (単に後置条件と呼ばれることが多い) を含めることができます。
この式は、Caché がコマンドを実行するかどうかを制御します。後置条件式の評価が True (ゼロ以外の値) の場合、Caché はそのコマンドを実行します。式の評価が False (ゼロ) の場合、Caché はコマンドを無視し、次のコマンドに実行を移します。
以下はその例です。
Set count = 6 Write:count<5 "Print this if count is less than five" Write:count>5 "Print this if count is greater than five"
上記のコードは、次の出力を生成します。Print this if count is greater than five
Note:後置条件の使用経験がないと、“後置条件式”という表現を誤解してしまう可能性があります。この表現では、コマンドの後に式が実行されるという、誤った暗示を与えてしまうためです。その名前にかかわらず、後置条件はコマンドの前に実行されます。
-
1 つの行に複数のコマンドを含めることができます。以下はその例です。
set myval="hello world" write myval
これを行うには、その行に追加のコマンドがある場合は、引数を取らないコマンドの後には必ずスペースを 2 つ使用してください。そのようにしない場合は構文エラーが発生します。
-
IF、ELSE、FOR、および DO コマンドは、以下の 2 つの形式で使用できます。
-
新しいブロック形式。中括弧を使用してブロックを示します。以下はその例です。
if (testvalue=1) { write "hello world" }
インターシステムズでは、新しいコードすべてでブロック形式を使用することをお勧めします。
-
古い行ベースの形式。中括弧は使用しません。以下はその例です。
if (testvalue=1) write "hello world"
-
-
前述の項目を使用すると、ObjectScript をとてもコンパクトな形式で記述できます。以下はその例です。
s:$g(%d(3))'="" %d(3)=$$fdN3(%d(3)) q
クラス・コンパイラによって、上記のコンパクトな形式のコードが自動的に生成されます (この例のように省略された形式になるとは限りません)。場合によっては、問題の原因を追跡するため、または何かの機能のしかたを理解するために、この生成されたコードを調べると役立ちます。
多くの古いアプリケーションが、ここで示すコンパクトな形式で記述されています。
-
ObjectScript には予約語がないため、例えば、set という変数を使用することも理論的には可能です。ただし、コマンド、関数、SQL 予約語、および特定のシステム項目の名前は避けた方が無難です。"Caché ObjectScript の使用法" の “構文規則” を参照してください。
-
Caché では、文字列操作の結果を保存するために、一定容量を持つメモリが割り当てられます。割り当てられた容量を超える文字列式が発生すると、<MAXSTRING> エラーとなります。長い文字列が有効化されていない場合、上限は 32,767 文字になります。長い文字列が有効化されてる場合、この制限値ははるかに大きくなります。長い文字列演算を有効化する方法については、このドキュメント内の後のセクションで説明します。
クラス定義の場合、文字列演算の制限は文字列プロパティのサイズに影響します。Caché では、この上限を超える文字列を操作する必要がある場合に使用できるシステム・オブジェクト (ストリームと呼ばれる) があります。ストリーム・インタフェース・クラスを使用する方法については、このドキュメント内の後のセクションで説明します。
詳細
この後の章では、この章で取り上げたトピックについてより詳しく説明します。この情報は、以下のドキュメントを参考にしています。
-
"Caché ObjectScript の使用法" には、ObjectScript に関する詳しい説明が記載されています。
-
"Caché グローバルの使用法" には、多次元配列およびグローバルに関する詳しい説明が記載されています。
-
"Caché ObjectScript リファレンス" には、ObjectScript の演算子、コマンド、関数、特殊変数、およびその他の部分に関する参照情報が記載されています。
Caché ドキュメントには、このドキュメントで取り上げない Caché MVBasic および Caché Basic に関するドキュメントも含まれています。