手続きと関数
Object Pascalにおいて、手続き(プロシージャ)とは戻り値のないサブプログラム、つまりVBでいうSubプロシージャ、C/C++のvoid型関数のことを言い、関数とは戻り値のあるサブプログラム、つまりVBでいうFunctionプロシージャのことを言います。
まず、全てのサブプログラムはメインプログラムの前に記述されている必要があります。 それ以外の部分、戻り値の型指定、パラメータの指定方法などは問題ないと思います。 ただ、関数で戻り値を返す場合は、暗黙の変数resultに戻り値を代入するため、returnなどは使用しません。 また、VBと同じように関数名に値を代入することで関数の戻り値とする事もできます。
このプログラムでは、メインプログラムからOutputMessageプロシージャを呼び出し、さらにそのOutputMessage プロシージャはCreateMessage関数を呼び出しています。 プロシージャ・関数と名称こそ異なれど、その概念は他の言語と変わりないと言えます。
ローカル変数とスコープ
サブプログラムの中でローカル変数を宣言、使用できます。 サブプログラム宣言の直後にvar文で変数を宣言します。 使用の際は他の変数と全く同じです。 また、スコープの概念も他の言語と同じで、サブプログラム内で宣言された変数はそのサブプログラムの中においてのみ有効です。
このように、ローカル変数と同じ名前の変数がメインプログラムで宣言されていても、明確に区別されます。
参照渡し、値渡し、定数パラメータ
Object Pascalのサブプログラムの引数は、VB.NET、C#、C/C++などと同様に既定で値渡しです。 参照渡しにする場合は var キーワードを付加します。 また、パラメータを定数としてサブプログラム内での変更を許可しない場合はconstをつけます。
実行結果のとおり、値渡しで渡されたパラメータの値は、サブプログラム内で変更することができます。 また、定数パラメータに対して値を代入しようとするコードは、コンパイル時にエラーとなります。
定数
定数はconst文で宣言します。 Delphiでは他の言語同様、定数の名前は全て大文字にすることが多いようです。
また、当然ですが、定数への値の代入は許可されません。
列挙型
列挙型の概念も他の言語と変わりませんが、その動作は多少異なります。
この結果の通り、他の言語とは異なり列挙型はその他の数値型と互換性がないというのが最大の特徴といえます。 その他の宣言、使用法などはほとんど同じです。 ただ、直接数値型として扱うことができないので、インクリメント・ディクリメントなどを行うサポート関数がいくつか存在します。
文字列型配列の宣言時、添え字の部分に直接列挙型を指定していますが、こうすることにより、配列の上限と下限が自動的に列挙型の上限と下限に指定されます。 しかし、こうするとIntegerなどの整数値で添え字を指定することができなくなります。 また、整数値で添え字の範囲を指定して配列を宣言すると、添え字に列挙型を直接指定する事はできなくなります。
文字列操作
Object Pascalでの文字列の動作は、.NET Frameworkの文字列型と非常に似た動作をします。
このようにかなり柔軟な文字列操作を行うことができます。 Delete、Insert、Lengthなどがインスタンスメソッドではなくサポート関数として存在することを除いては、先程述べたようにほとんど.NET Frameworkの文字列型と同じといっていいと思います。 しかし、一つだけ違う点を上げるとすれば、文字列型に対する添え字の下限は0ではなく1ということです。 0番目の要素にアクセス使用とするとエラーになります。 これには深い意味があるようですが、それはこの次で考察します。
ShortString, AnsiString, WideString
stringとはAnsiStringのエイリアスです。 Object Pascalの文字列型にはShortString, AnsiString, WideStringの三種類があります。 また、先程述べたインデックス0の意味も調べてみます。 この例ではインデックス0を参照するために変数の値をインデックスに指定しますが、直接0を指定しようとするとエラーになります。
まず、三種類の文字列型の意味を説明すると、ShortStringは以前のPascalで用いられていた文字列型との互換性のために残された短い文字列型と呼ばれるもので、静的に256バイトが割り当てられ0バイト目(Object Pascalの用語では第一バイト)に文字列全体の長さが格納され、残りの255バイトに実際の文字列が格納されます。 これはC/C++などのnull で終わるchar型配列とは異なる文字列型の実装方法です。 しかし、実際に文字列を用いる場合は255バイトでは不足するおそれがあります。
そこで新たに用意されたのが、長い文字列と呼ばれるもので、これにはANSI文字を格納するAnsiStringとUnicode文字を扱うWideStringがあり、それぞれ2ギガ・バイトまでの文字列を扱うことができます。 これらの型は4バイトのメモリを占有するポインタ型で、文字列の終端にはヌルが付加されます。 先頭の4バイトには文字列の長さを保持するための2バイトと、残り2バイト分には参照カウンタが含まれます。
また、どの文字列型もインデックスは1から始まり、互換性の問題からShortStringのインデックス0が長さを表すのに対して、 AnsiStringとWideStringではインデックス0は意味を成しません。 また、これらの文字列型の一文字を表す型にChar, AnsiChar, WideCharがあります。 CharはAnsiCharと同義です。 実行結果から分かるとおり、WideString型の一つのインデックスの表す文字は2バイト(実際にはWideChar型)となります。 また、長さもバイト数ではなく文字数で返されます。
集合型 その1
集合型はC/C++, VBなどの言語にはない、Object Pascalの特徴的な型です。 その名の通り、ある要素の集合を扱います。
まず、集合型を宣言する際の注意点として、集合の要素は256個を越えてはいけないと言うことです。 例えば、Integer型の値全てを扱うような集合は要素数が256を越えるので宣言できませんが、Byte型であれば0から255までの256個の値しか持ち得ないので、集合型として利用できます。 これは型から直接集合型を宣言する場合ですが、特定の値の範囲を用いて集合型を宣言することができます。 ただ、いずれの場合も「set of」で何の集合であるかを指定します。
また、宣言した集合型は、変数として宣言・使用されます。 宣言された集合型の変数に集合に含まれる値を指定します。 空集合を作る際には[]を代入します。 そして、ある集合の中に特定の要素が含まれているかを調べるには in 演算子を用います。 この演算子の結果はBoolean型ですが、一般的に考えて in 演算子はif文で用いることが多いでしょう。
この例では集合型の機能のうち、ほんの一部しか使っていません。 これ以外の機能はこれ以降で引き続き説明していきます。
集合型 その2
集合型ではその包括関係を調べることもできます。
この例にあるように、>=, <=, =, <> などの各演算子を用いて集合同士の包括関係などを知ることができます。 この例では補集合を求めるために全集合からある集合を「減算」していますが、これについては次の説で説明します。
集合型 その3
先ほど少し触れたように、集合型では集合同士の和・積・差を求めることもできます。
このようにいとも簡単に集合の和・差・積を求めることができます。 当然のことですが、これらの演算は同じ型の集合型同士でしか演算できません。
最後におまけのサンプルを載せておきます。
レコード型
レコード型は他の言語で言う構造体に相当するデータ構造です。 宣言方法は列挙型や集合型のようにtype文で「識別子 = record ... end;」として、record と end; の間でメンバの宣言を行います。
レコード型変数の使い方は、C/C++やVBの構造体の使い方と全く同じです。 さらに、Object Pascalではwith文がサポートされています。 ただ、これはVBと違って各メンバにアクセスする際には「.(ドット)」をつけてはいけません。
また、本題とは関係ないのですが、TDateTime型は日付を扱うためのデータ型です(実際にはDouble型のエイリアス)。 EncodeDate, DecodeDateプロシージャは年月日の各数値からTDateTimeの値を設定・取得するためのプロシージャです。 また、Now関数は現在の時刻を取得するための関数です。
あと、全く問題ないと思いますが、一応参考までに述べておくとレコード型は値型です。
ポインタ型
Object Pascalにはポインタ型が存在します。 機能や動作はC/C++のポインタと同様です。
ありきたりな例ですが、ポインタ型を使用した例です。 まず、ポインタ型変数を宣言する場合には ^ 演算子を用いて「^型」とします。 そして、そのポインタ型変数に代入するための変数のアドレスを取得するには、「@変数」とします。 さらに、ポインタ型変数の指し示すアドレスにある値を取得するには「ポインタ変数^」とします。 宣言時と値の取得時に ^ 演算子をつける位置が異なることに注意して下さい。
また、文字型のポインタであるPCharは、ポインタ値の加減算や等価・非等価の評価も行えます。 しかし、これ以外のポインタ型ではC/C++のようにポインタ値の加減算を行うことはできません。 次の例はPChar型を利用したものです。