Marco Cantu's
Essential Pascal Chapter 4
User-Defined Data Types
 
第4章 ユーザー定義データ型
 
Along with the notion of type, one of the great ideas introduced by the Pascal language is the ability to define new data types in a program. Programmers can define their own data types by means of type constructors, such as subrange types, array types, record types, enumerated types, pointer types, and set types. The most important user-defined data type is the class, which is part of the object-oriented extensions of Object Pascal, not covered in this book.
 
型についての考え方に加え、Pascal では「偉大」、と言ってもいいアイデアが導入された。 それは、プログラムの中で新しいデータ型が定義できる、ということだ。 プログラマは独自型定義機能を使って、サブ範囲型、配列型、レコード型、列挙型、ポインタ型、セット型など、自分のデータ型を定義できる。 一番重要なユーザー定義データ型が、クラスだ。 これは Object Pascal のオブジェクト指向への拡張の一部で、ここでは取り扱わない。
 
If you think that type constructors are common in many programming languages, you are right, but Pascal was the first language to introduce the idea in a formal and very precise way. There are still few languages with so many mechanisms to define new types.
 
どんなプログラミング言語にも、型を独自に定義する機能はあるだろう、と思うのなら、それも正解と言える。 しかし、まさしく Pascal が、このアイデアを最初に導入し、それを非常に正確に実装したんだ。 新しい型を定義するのに、これだけ豊富なやり方を提供する言語は、そう多くない。
 
Named and Unnamed Types
 
名前のある、また名前の無い型
 
These types can be given a name for later use or applied to a variable directly. When you give a name to a type, you must provide a specific section in the code, such as the following:
 
この型は、後から名前が与えられるか、変数に直接適用されるものだ。 型に名前を付ける時は、コードの特定の場所に書く。 こういう具合だ。
 
type
 // subrange definition  サブ範囲の定義
 Uppercase = 'A'..'Z';
 
 // array definition   配列の定義
 Temperatures = array [1..24] of Integer;
 
 // record definition  レコードの定義
 Date = record
  Month: Byte;
  Day: Byte;
  Year: Integer;
 end;
 
 // enumerated type definition   列挙型の定義
 Colors = (Red, Yellow, Green, Cyan, Blue, Violet);
 
 // set definition   セットの定義
 Letters = set of Char;
 
Similar type-definition constructs can be used directly to define a variable without an explicit type name, as in the following code:
 
同様の型定義構文では、明確に型名を示さずに、直接変数を定義することもできる。 こういう具合だ。
 
var
 DecemberTemperature: array [1..31] of Byte;
 ColorCode: array [Red..Violet] of Word;
 Palette: set of Colors;
 
Note: In general, you should avoid using unnamed types as in the code above, because you cannot pass them as parameters to routines or declare other variables of the same type. The type compatibility rules of Pascal, in fact, are based on type names, not on the actual definition of the types. Two variables of two identical types are still not compatible, unless their types have exactly the same name, and unnamed types are given internal names by the compiler. Get used to defining a data type each time you need a variable with a complicated structure, and you won稚 regret the time you致e spent in it.
 
注:一般的に言って、上のような名前無しの型は使うべきではない。 というのは、パラメータとしてルーチンに渡すこともできないし、同じ型の別の変数を定義することもできないからだ。 実のところ、Pascal の型互換性のルールは、型名を基盤としていて、型の定義そのものを基盤としているのではない。 同じ型のふたつの変数には、その型名がまったく同じで無い限り、互換性が無い。 それに、名前無しの型は、コンパイラが内部名をつけてしまう。 複雑になりそうなら、変数が必要な時には、まずデータ型を定義する習慣を付けよう。 その方が、後々後悔しないで済む。
 
But what do these type definitions mean? I値l provide some descriptions for those who are not familiar with Pascal type constructs. I値l also try to underline the differences from the same constructs in other programming languages, so you might be interested in reading the following sections even if you are familiar with kind of type definitions exemplified above. Finally, I値l show some Delphi examples and introduce some tools that will allow you to access type information dynamically.
 
しかし、こういう型定義とは、どんなものなんだろう? Pascal の型構造に慣れていない人達のために、少し説明してみよう。 また、他の言語の、この型構造との違いを強調してみよう。 そうすれば、型定義に慣れている人でも、これ以降が面白く読めるだろう。 最後に、Delphi での例をいくつか紹介し、また、動的に型情報にアクセスできるように、ツールを提供しよう。
 
Subrange Types
 
サブ範囲型
 
A subrange type defines a range of values within the range of another type (hence the name subrange). You can define a subrange of the Integer type, from 1 to 10 or from 100 to 1000, or you can define a subrange of the Char type, as in:
 
サブ範囲型というのは、別の型の一部の範囲にある値を定義するものだ ( だからサブ範囲という )。 整数型で言えば、1 から 10、や 100 から 1000 などをサブ範囲として定義できる。 また、Char 型なら、
 
type
 Ten = 1..10;
 OverHundred = 100..1000;
 Uppercase = 'A'..'Z';
 
In the definition of a subrange, you don稚 need to specify the name of the base type. You just need to supply two constants of that type. The original type must be an ordinal type, and the resulting type will be another ordinal type.
 
サブ範囲の定義では、元になっている型名を明示する必要は無い。 その型のふたつの定数を示せばよい。 ただし元型は、順序型でないといけないし、結果として現れる型も、別の順序型でないといけない。
 
When you have defined a subrange, you can legally assign it a value within that range. This code is valid:
 
サブ範囲を定義したら、その範囲内での値を割り当てできる。 次のコードは有効だ。
 
var
 UppLetter: UpperCase;
begin
 UppLetter := 'F';
 
But this one is not:
 
でも、次のコードは無効になる。
 
var
 UppLetter: UpperCase;
begin
 UppLetter := 'e'; // compile-time error
 
Writing the code above results in a compile-time error, "Constant expression violates subrange bounds." If you write the following code instead:
 
こう書くとに、コンパイル時のエラー「定数がサブ範囲を超えています」になる。 その時に、こう書けば、
 
var
 UppLetter: Uppercase;
 Letter: Char;
begin
 Letter :='e';
 UppLetter := Letter;
 
Delphi will compile it. At run-time, if you have enabled the Range Checking compiler option (in the Compiler page of the Project Options dialog box), you値l get a Range check error message.
 
Delphi はとにかくコンパイルしてくれる。 しかし実行時に、「範囲チェックをつけてコンパイル」 ( プロジェクト・オプション・ダイアログ・ボックスのコンパイラ・ページで ) オプションを有効にしていれば、範囲チェックのエラー・メッセージが出ることになる。
 
Note: I suggest that you turn on this compiler option while you are developing a program, so it'll be more robust and easier to debug, as in case of errors you'll get an explicit message and not an undetermined behavior. You can eventually disable the option for the final build of the program, to make it a little faster. However, the difference is really small, and for this reason I suggest you to leave all these run-time checks turned on, even in a shipping program. The same holds true for other run-time checking options, such as overflow and stack checking.
 
注:開発中は、このコンパイラ・オプションを有効にしておくこと。 そうすれば、エラーが出た場合でも、何がなんだか分からない形ではなく、原因をはっきりと示してくれるので、デバッグはとても簡単になる。 開発が終わったら、このオプションを無効にすればいい。 そうすると、コンパイルが少し早くなる。 しかし、その差は本当に僅かなので、出荷時点のプログラムでも、実行時のチェックを有効にしておくことを、薦める。 オーバーフローやスタック・チェックなどの、他の実行時のチェックについても同じことが言える。
 
Enumerated Types
 
列挙型
 
Enumerated types constitute another user-defined ordinal type. Instead of indicating a range of an existing type, in an enumeration you list all of the possible values for the type. In other words, an enumeration is a list of values. Here are some examples:
 
列挙型は、ユーザーが定義する順序型だ。 既存型の範囲を指定するのではなく、その型に適合する値を列挙する。 つまり、列挙とは、値のリストだ。 例を挙げれば、
 
type
 Colors = (Red, Yellow, Green, Cyan, Blue, Violet);
 Suit = (Club, Diamond, Heart, Spade);
 
Each value in the list has an associated ordinality, starting with zero. When you apply the Ord function to a value of an enumerated type, you get this zero-based value. For example, Ord (Diamond) returns 1.
 
リストのそれぞれの値は、ひとまとまりの順序型で、ゼロから始まる。 列挙型に Ord 関数を使えば、このゼロから始まる値が得られる。 たとえば、Ord(Diamond) は 1 になる。
 
Note: Enumerated types can have different internal representations. By default, Delphi uses an 8-bit representation, unless there are more than 256 different values, in which case it uses the 16-bit representation. There is also a 32-bit representation, which might be useful for compatibility with C or C++ libraries. You can actually change the default behavior, asking for a larger representation, by using the $Z compiler directive.
 
注:列挙型では、Delphi 内部で意味が変わることがある。 Delphi は、デフォルトでは値が256 種類を境にして、それ以下なら 8 ビット演算、以上なら 16 ビット演算する。 32 ビット演算する場合もあり、これは C や C++ との互換性を保つ役目をする。 このデフォルトの設定を変えて、上位演算をしてほしい場合は、$Z コンパイラ指令をすればいい。
 
The Delphi VCL (Visual Component Library) uses enumerated types in many places. For example, the style of the border of a form is defined as follows:
 
Delphi の VCL ( ビジュアル・コンポーネント・ライブラリ ) では、列挙型を多用している。 たとえば、フォームの境界のスタイルでは、
 
type
 TFormBorderStyle = (bsNone, bsSingle, bsSizeable,
  bsDialog, bsSizeToolWin, bsToolWindow);
 
When the value of a property is an enumeration, you usually can choose from the list of values displayed in the Object Inspector, as shown in Figure 4.1.
 
図 4.1 のように、プロパティの値が列挙型なら、オブジェクト・インスペクタで示されたリストから、値を選択することができる。
 
Figure 4.1: An enumerated type property in the Object Inspector
 
図 4.1: オブジェクト・インスペクタで列挙されたプロパティ
 
The Delphi Help file generally lists the possible values of an enumeration. As an alternative you can use the OrdType program, available on www.marcocantu.com, to see the list of the values of each Delphi enumeration, set, subrange, and any other ordinal type. You can see an example of the output of this program in Figure 4.2.
 
Delphi のヘルプ・ファイルを見れば、列挙型で値が表示されている。 www.marcocantu.com の OrdType プログラムでも、Delphi の列挙型、セット、サブ範囲、その他の順序型でどのような値があるのか、そのリストを見ることができる。 このプログラムの結果を、図 4.2 に示してある。
 
Figure 4.2: Detailed information about an enumerated type, as displayed by the OrdType program (available on my web site).
 
図 4.2: OrdType プログラムで表示される、列挙型についての詳細
 
Set Types
 
セット型
 
Set types indicate a group of values, where the list of available values is indicated by the ordinal type the set is based onto. These ordinal types are usually limited, and quite often represented by an enumeration or a subrange. If we take the subrange 1..3, the possible values of the set based on it include only 1, only 2, only 3, both 1 and 2, both 1 and 3, both 2 and 3, all the three values, or none of them.
 
セット型というのは、値をグループにしたもので、扱うことのできる値は、そのセットの元型になっている、順序型で示される。 普通、この順序型の値は有限で、列挙型やサブ範囲になっていることが多い。 たとえば、サブ範囲で 1..3 を取れば、このサブ範囲に基づくセットというのは、1 のみ、2 のみ、3 のみ、1 と 2、1 と 3、2 と 3、この3つの値全部、またはどれでも無い、ということになる。
 
A variable usually holds one of the possible values of the range of its type. A set-type variable, instead, can contain none, one, two, three, or more values of the range. It can even include all of the values. Here is an example of a set:
 
変数というのは、該当する型の範囲の内の、どれかの値を取るものだ。 これに対して、セット型変数は、どれも取らないこともあれば、ひとつ、ふたつ、みっつ、またはそれ以上の値を取っても構わない。 値全部を取ることもある。 例を挙げよう。
 
type
 Letters = set of Uppercase;
 
Now I can define a variable of this type and assign to it some values of the original type. To indicate some values in a set, you write a comma-separated list, enclosed within square brackets. The following code shows the assignment to a variable of several values, a single value, and an empty value:
 
これで、この型の変数を定義でき、その型に合致する値を割り当てることができる。 セットに属している値を表すときは、カンマで区切ったリストを角括弧に入れる。 どのように割り当てるのか、複数の値、ひとつだけ、それに空白を割り当てる例を示す。
 
var
 Letters1, Letters2, Letters3: Letters;
begin
 Letters1 := ['A', 'B', 'C'];
 Letters2 := ['K'];
 Letters3 := [];
 
In Delphi, a set is generally used to indicate nonexclusive flags. For example, the following two lines of code (which are part of the Delphi library) declare an enumeration of possible icons for the border of a window and the corresponding set type:
 
Delphi では、一般にセットは非排他フラグを表すのに使われる。 たとえば次のコードでは ( Delphi ライブラリに入っている)、ウィンドウ境界のアイコンと、それに合致したセット型に対応するアイコンを列挙している。
 
type
 TBorderIcon = (biSystemMenu, biMinimize, biMaximize, biHelp);
 TBorderIcons = set of TBorderIcon;
 
In fact, a given window might have none of these icons, one of them, or more than one. When working with the Object Inspector (see Figure 4.3), you can provide the values of a set by expanding the selection (double-click on the property name or click on the plus sign on its left) and toggling on and off the presence of each value.
 
実際には、このどのアイコンにも合致しないこともあるし、どれかの時もあるし、またはひとつ以上に合致することもある。 オブジェクト・インスペクタ ( 図 4.3 参照 ) を使えば、リストを広げてセットの値を選んだり ( プロパティ名をダブルクリックするか、プラス記号をクリックする ) 、値をトグルすることもできる。
 
Figure 4.3: A set-type property in the Object Inspector
 
図 4.3 : オブジェクト・インスペクタでのセット型プロパティ
 
Another property based on a set type is the style of a font. Possible values indicate a bold, italic, underline, and strikethrough font. Of course the same font can be both italic and bold, have no attributes, or have them all. For this reason it is declared as a set. You can assign values to this set in the code of a program as follows:
 
セット型で他の例を挙げるなら、フォント・スタイルがある。 値としては、太字、イタリック、下線付き、横棒付きがある。 もちろん、太字でかつまたイタリックの時もあり、どれでも無いときもあり、またすべての時もある。 だから、セットとして宣言している。 セットをプログラムのコードで扱うときは、このようにする。
 
Font.Style := []; // no style
Font.Style := [fsBold]; // bold style only
Font.Style := [fsBold, fsItalic]; // two styles
 
You can also operate on a set in many different ways, including adding two variables of the same set type (or, to be more precise, computing the union of the two set variables):
 
セットは様々な方法で扱え、同じセット型のふたつの値を加えることもできる( 正確には、二つのセット型変数のユニオンを取る )。
 
Font.Style := OldStyle + [fsUnderline]; // two sets
 
Again, you can use the OrdType examples included in the TOOLS directory of the book source code to see the list of possible values of many sets defined by the Delphi component library.
 
上に示した、僕のソースコードの TOOLS ディレクトリにある、OrdType サンプルを使えば、Delphi のコンポーネント・ライブラリに定義してある、様々なセットの値を見ることができる。
 
Array Types
 
配列型
 
Array types define lists of a fixed number of elements of a specific type. You generally use an index within square brackets to access to one of the elements of the array. The square brackets are used also to specify the possible values of the index when the array is defined. For example, you can define a group of 24 integers with this code:
 
配列型は、数の決まった、ある型の要素のリストだ。 普通は、角括弧の中にインデックスを入れ、配列の要素のひとつにアクセスする。 角括弧は、配列が定義された時に、インデックスとして取り得る値を明示するのにも使われる。 たとえば、24 個の整数のグループを定義するには、
 
type
 DayTemperatures = array [1..24] of Integer;
 
In the array definition, you need to pass a subrange type within square brackets, or define a new specific subrange type using two constants of an ordinal type. This subrange specifies the valid indexes of the array. Since you specify both the upper and the lower index of the array, the indexes don稚 need to be zero-based, as is necessary in C, C++, Java, and other programming languages.
 
配列の定義では、角括弧にサブ範囲型を収めるか、順序型のふたつの定数を使い、新たに特定のサブ範囲型を定義する。 このサブ範囲型が、配列の有効なインデックス、と言う訳だ。 配列の最大、最小値を定義する、ということは、インデックスがゼロから始まらなくて良い、ということだ。 C、C++、Java、その他、ゼロ・ベースが必須になっている言語とは違うね。
 
Since the array indexes are based on subranges, Delphi can check for their range as we致e already seen. An invalid constant subrange results in a compile-time error; and an out-of-range index used at run-time results in a run-time error if the corresponding compiler option is enabled.
 
配列インデックスが、サブ範囲を基にしているので、今まで見てきたように Delphi は、その範囲をチェックすることができる。 無効なサブ範囲であれば、コンパイル・エラーになる。 また、コンパイル・オプションでコンパイル時に回避しても、実行時に実行時エラーになる。
 
Using the array definition above, you can set the value of a DayTemp1 variable of the DayTemperatures type as follows:
 
配列を使い、DatTemperature 型の DayTemp1 変数に値をセットするには、
 
type
 DayTemperatures = array [1..24] of Integer;
 
var 
 DayTemp1: DayTemperatures;
 
procedure AssignTemp; 
begin 
 DayTemp1 [1] := 54;
 DayTemp1 [2] := 52;
 ...
 DayTemp1 [24] := 66;
 DayTemp1 [25] := 67; // compile-time error コンパイル・エラー
 
An array can have more than one dimension, as in the following examples:
 
配列には、多次元が使える。
 
type
 MonthTemps = array [1..24, 1..31] of Integer;
 YearTemps = array [1..24, 1..31, Jan..Dec] of Integer;
 
These two array types are built on the same core types. So you can declare them using the preceding data types, as in the following code:
 
上記の両方とも、コアの部分は同じ型を使っている。 そこで、前の型を利用して、こういう具合に書ける。
 
type
 MonthTemps = array [1..31] of DayTemperatures;
 YearTemps = array [Jan..Dec] of MonthTemps;
 
This declaration inverts the order of the indexes as presented above, but it also allows assignment of whole blocks between variables. For example, the following statement copies January痴 temperatures to February:
 
この宣言は、その前に定義してあるインデックス順を逆転するが、変数間でのすべてのブロックがコピーできる。 たとえば、下記のようにすると、1月の気温を2月にコピーできる。
 
var
 ThisYear: YearTemps;
begin
 ...
 ThisYear[Feb] := ThisYear[Jan];
 
You can also define a zero-based array, an array type with the lower bound set to zero. Generally, the use of more logical bounds is an advantage, since you don稚 need to use the index 2 to access the third item, and so on. Windows, however, uses invariably zero-based arrays (because it is based on the C language), and the Delphi component library tends to do the same.
 
もちろん、最小値をゼロに設定する、ゼロ・ベースの配列も定義できる。 一般的に言えば、ゼロ・ベースが必須で無いのは有利だ。 2 番目のインデックスが、実は 3 番目の項目だ、と覚えておく必要は無いからね。 ただし、Windows は、絶対的にゼロ・ベースを要求する ( C で書いているからね ) ので、Delphi のコンポーネント・ライブラリも、普通はこれに従っている。
 
If you need to work on an array, you can always test its bounds by using the standard Low and High functions, which return the lower and upper bounds. Using Low and High when operating on an array is highly recommended, especially in loops, since it makes the code independent of the range of the array. Later, you can change the declared range of the array indices, and the code that uses Low and High will still work. If you write a loop hard-coding the range of an array you値l have to update the code of the loop when the array size changes. Low and High make your code easier to maintain and more reliable.
 
配列を使うのなら、標準の Low と High 関数を使って最小、最大値の確認ができる。 この関数は、その値の範囲の最大、最小値を示すものだ。 配列を使うときに、この Low と High 関数を使うことを薦めるが、ループを使うときには特にお薦めだ。 というのも、ループでは、配列の範囲のみを見ている。 後から配列の範囲を書き換えても、Low と High 関数を使っているコードは、問題なく動く。 ところが、配列をハード・コードしてしまうと、配列の範囲を変更した時には、ループのコードも変えなくてはならなくなる。 Low と High 関数は、君のコードの保守性を高め、もっと信頼の置けるものにするんだ。
 
Note: Incidentally, there is no run-time overhead for using Low and High with arrays. They are resolved at compile-time into constant expressions, not actual function calls. This compile-time resolution of expressions and function calls happens also for many other simple system functions.
 
注:それに、配列で Low と High を使っても、実行時のオーバーヘッドは無い。 この二つは、コンパイル時に定数に置き換えられ、関数ではなくなる。 このコンパイル時に式や関数を定数に変えてしまう機能は、他のシンプルなシステム関数でも、よく見られる。
 
Delphi uses arrays mainly in the form of array properties. We have already seen an example of such a property in the TimeNow example, to access the Items property of a ListBox component. I値l show you some more examples of array properties in the next chapter, when discussing Delphi loops.
 
Delphi では、配列は主に配列プロパティで使っている。 既に TimeNow の例で見たように、ListBox コンポーネントの項目プロパティにアクセスする時に使っている。 次の章で、Delphi のループについて紹介するときに、配列プロパティについて詳しく話そう。
 
Note: Delphi 4 introduced dynamic arrays into Object Pascal , that is arrays that can be resized at runtime allocating the proper amount of memory. Using dynamic arrays is easy, but in this discussion of Pascal I felt they were not an proper topic to cover. You can find a description of Delphi's dynamic arrays in Chapter 8.
 
注:Delphi4 では、Object Pascal に動的配列を導入した。 これは、実行時に、必要なメモリ量だけ割り当てて、メモリ・サイズを小さくするものだ。 動的配列を使うのは簡単だが、今は Pascal について話しているので、深くは取り扱わない。 これについては、第8章で話そう。 
 
Record Types
 
レコード型
 
Record types define fixed collections of items of different types. Each element, or field, has its own type. The definition of a record type lists all these fields, giving each a name you値l use later to access it.
 
レコード型というのは、型の違った項目の集まりを定義したものだ。 それぞれの要素とか、フィールドは、それぞれ自分の型を持っている。 レコード型の定義では、後から君がアクセスする、すべてのフィールドのリストを示す。
 
Here is a small listing with the definition of a record type, the declaration of a variable of that type, and few statements using this variable:
 
例を示そう。 その型の変数についての宣言と、その変数についての文のリストを定義している。
 
type
 Date = record
  Year: Integer;
  Month: Byte;
  Day: Byte;
 end;
 
var
 BirthDay: Date;
 
begin
 BirthDay.Year := 1997;
 BirthDay.Month := 2;
 BirthDay.Day := 14;
 
Classes and objects can be considered an extension of the record type. Delphi libraries tend to use class types instead of record types, but there are many record types defined by the Windows API.
 
クラスとオブジェクトというのは、レコード型を拡張したもの、と考えてもいい。 Delphi のライブラリでは、レコード型の代わりにクラス型を使っているが、Windows API では、レコード型が多い。
 
Record types can also have a variant part; that is, multiple fields can be mapped to the same memory area, even if they have a different data type. (This corresponds to a union in the C language.) Alternatively, you can use these variant fields or groups of fields to access the same memory location within a record, but considering those values from different perspectives. The main uses of this type were to store similar but different data and to obtain an effect similar to that of typecasting (something less useful now that typecasting has been introduced also in Pascal). The use of variant record types has been largely replaced by object-oriented and other modern techniques, although Delphi uses them in some peculiar cases.
 
レコード型は、バリアントも扱える。 これは、データ型が異なっても、複数のフィールドが同じメモリ領域を使える、ということだ。 (これは、 C 言語での union に合致する) ある値を別の観点から見ていると考えて、レコードの同じメモリ領域を、バリアントなフィールドでアクセスしてもいいし、フィールドのグループでアクセスしてもいい。
この型は、同じような、しかし違ったデータを格納し、型キャストに似た効果を得たい時によく使われたものだった。 (現在では Pascal にも型キャストが導入されたので、値打ちは下がった) バリアント・レコード型は、殆どがオブジェクト指向やその他の技術で置き換わったが、Delphi では特定の場合で、まだ利用している。
 
The use of a variant record type is not type-safe and is not a recommended programming practice, particularly for beginners. Expert programmers can indeed use variant record types, and the core of the Delphi libraries makes use of them. You won稚 need to tackle them until you are really a Delphi expert, anyway.
 
バリアント・レコード型を使うのは、型の制御を受けず、特に初心者に薦められるプログラミング技法ではない。 エキスパートなら、もちろんバリアント・レコード型も使えるし、Delphi ライブラリの核心部では、この型を有効に使っている。 どちらにしても、Delphi のエキスパートにならない限り、この型を使おうとしない方がいい。
 
Pointers
 
ポインタ
 
A pointer type defines a variable that holds the memory address of another variable of a given data type (or an undefined type). So a pointer variable indirectly refers to a value. The definition of a pointer type is not based on a specific keyword, but uses a special character instead. This special symbol is the caret (^):
 
ポインタ型というのは、それとは別の与えられたデータ型(または定義されていない型)の変数が収められている、メモリ・アドレスを保持している変数のことだ。 だから、ポインタ変数というのは、間接的に値を参照している。 ポインタ型の宣言には特別のキーワードは必要ではなく、代わりに特別な文字を使う。 この文字がキャレット(^)だ。
 
type
 PointerToInt = ^Integer;
 
Once you have defined a pointer variable, you can assign to it the address of another variable of the same type, using the @ operator:
 
ポインタ変数を定義したら、@オペレータを使って、同じ型の別の変数のアドレスを割り当てることができる。
 
var
 P: ^Integer;
 X: Integer;
begin
 P := @X;
 // change the value in two different ways
 // 2種類のやり方で、値を変える
 X := 10;
 P^ := 20; 
 
When you have a pointer P, with the expression P you refer to the address of the memory location the pointer is referring to, and with the expression P^ you refer to the actual content of that memory location. For this reason in the code fragment above ^P corresponds to X.
 
ポインタを P とすると、この P で、そのポインタが参照しているメモリ・アドレスを参照していることになる。 また、P^ とすると、そのメモリ・アドレスの実際の中身を参照していることになる。 だから、上記のコードでは、^P と X は同じものだ。
 
Instead of referring to an existing memory location, a pointer can refer to a new memory block dynamically allocated (on the heap memory area) with the New procedure. In this case, when you don't need the pointer any more, you値l also have to to get rid of the memory you致e dynamically allocated, by calling the Dispose procedure.
 
現在のメモリ・アドレスを参照する替わりに、New プロシージャを使うことで、(ヒープ・メモリ領域に)動的に割り当てられた、まったく新しいメモリ・アドレスを参照するようにもできる。 こうして、ポインタがいらなくなったら、動的に割り当てたメモリ領域を、Dispose プロシージャで解放できる。
 
var
 P: ^Integer;
begin
 // initialization
 // 初期化
 New (P);
 // operations
 // 操作
 P^ := 20;
 ShowMessage (IntToStr (P^));
 // termination
 // 後始末
 Dispose (P);
end;
 
If a pointer has no value, you can assign the nil value to it. Then you can test whether a pointer is nil to see if it currently refers to a value. This is often used, because dereferencing an invalid pointer causes an access violation (also known as a general protection fault, GPF):
 
ポインタが値を持たない場合、nil を割り当てることもできる。 こうすると、現在、何か値を参照しているかどうか、nil を判別してやればいい。 無効なポインタを参照すると、アクセス違反(有名なGPF、一般保護違反だ)になるので、この技法は良く使われている。
 
procedure TFormGPF.BtnGpfClick(Sender: TObject);
var
 P: ^Integer;
begin
 P := nil;
 ShowMessage (IntToStr (P^));
end;
 
You can see an example of the effect of this code by running the GPF example (or looking at the corresponding Figure 4.4). The example contains also the code fragments shown above.
 
このコードがどう働くか、GPF (図4.4 参照) の例で見てみればいい。 この GPF では、上記のコードも含まれている。
 
Figure 4.4: The system error resulting from the access to a nil pointer, from the GPF example.
 
図4.4 : nil ポインタにアクセスして、システム・エラーになった。
 
In the same program you can find an example of safe data access. In this second case the pointer is assigned to an existing local variable, and can be safely used, but I致e added a safe-check anyway:
 
このプログラムでは、安全にアクセスする方法も示している。 この2番目の例では、ポインタは既存のローカル変数に割り当てられており、安全に使うことができるが、安全チェックの機能を付け加えてある。
 
procedure TFormGPF.BtnSafeClick(Sender: TObject);
var
 P: ^Integer;
 X: Integer;
begin
 P := @X;
 X := 100;
 if P <> nil then
  ShowMessage (IntToStr (P^));
end;
 
Delphi also defines a Pointer data type, which indicates untyped pointers (such as void* in the C language). If you use an untyped pointer you should use GetMem instead of New. The GetMem procedure is required each time the size of the memory variable to allocate is not defined.
 
Delphi にはポインタ・データ型というのもある。 これは、型無しのポインタ( C 言語の void* のような)を指す。 この型を使うときには、New ではなく、GetMem を使うこと。 使われるメモリ変数のサイズが定義されていない時には、必ず GetMem プロシージャが必要になる。
 
The fact that pointers are seldom necessary in Delphi is an interesting advantage of this environment. Nonetheless, understanding pointers is important for advanced programming and for a full understanding of the Delphi object model, which uses pointers "behind the scenes."
 
実のところ、Delphi を使う限りポインタは殆ど必要無い、というのは Delphi の強みだ。 しかし、上級プログラミングをしたり、Delphi のオブジェクト・モデルを完全に理解するには、このポインタを理解する必要がある。 というのも、Delphi オブジェクト・モデルでは、ユーザーの見えない「裏側」でポインタを使っているからだ。
 
Note: Although you don稚 use pointers often in Delphi, you do frequently use a very similar construct溶amely, references. Every object instance is really an implicit pointer or reference to its actual data. However, this is completely transparent to the programmer, who uses object variables just like any other data type.
 
注:確かに Delphi ではポインタを使うことは少ないが、これと似たものはよく使っているはずだ、これが参照だ。 すべてのオブジェクト実体は、実際のところ、実データへのポインタか参照だ。 しかしこれは、オブジェクト変数を他のデータ型と同様に扱うプログラマには、見えないようになっている。
 
File Types
 
ファイル型
 
Another Pascal-specific type constructor is the file type. File types represent physical disk files, certainly a peculiarity of the Pascal language. You can define a new file data type as follows:
 
もうひとつの、Pascal 独特の型がファイル型だ。 ファイル型は物理的ディスク・ファイルを扱う。 これは Pascal の特異な点だ。 新しいファイル・データ型は、こういう具合に定義する。
 
type
 IntFile = file of Integer;
 
Then you can open a physical file associated with this structure and write integer values to it or read the current values from the file.
 
こうすると、この構造に結びついている物理ファイルを開くことができ、整数値をファイルに書き込んだり、現在の値をファイルから読み出したりできる。
 
Author's Note: Files-based examples were part of older editions of Mastering Delphi and I plan adding them here as well)
 
著者注:ファイルを扱ったプログラム例は、僕の著書 Mastering Delphi の以前のバージョンで取り扱っているので、将来、ここに付け加えるつもりだ。
 
The use of files in Pascal is quite straightforward, but in Delphi there are also some components that are capable of storing or loading their contents to or from a file. There is some serialization support, in the form of streams, and there is also database support.
 
Pascal でファイルを扱うのは、ずいぶんと簡単だが、Delphi でもファイルとのデータの出し入れを扱うコンポーネントが用意されている。 ストリームなどの連続したデータや、データベースもサポートされている。
 
Conclusion
 
結論
 
This chapter discussing user-defined data types complete our coverage of Pascal type system. Now we are ready to look into the statements the language provides to operate on the variables we've defined.
 
この章では、Pascal の型すべてを理解するために、ユーザー定義型について考えてみた。 さてこれで、自分で定義した変数を扱う「文」について、検討する準備は整ったね。
 
Next Chapter: Statements
 
次章:文
 
c Copyright Marco Cantu, Wintech Italia Srl 1995-2000
 
 
Marco Cantu's
Essential Pascal Chapter 5
 
Essential Pascal 第5章
 
Statements
 
 
If the data types are one of the foundations of Pascal programming the other are statements. Statements of the programming language are based on keywords and other elements which allow you to indicate to a program a sequence of operations to perform. Statements are often enclosed in procedures or functions, as we'll see in the next chapter. Now we'll just focus on the basic types of commands you can use to create a program.
 
Pascal のプログラミングでは、基本のひとつがデータ型で、もうひとつが文になる。 プログラム言語の文はキーワードと、プログラムに対して、実行してほしい一連の操作を指示する、その他の要素で成り立っている。 文は、これから説明するように、主に手続きや関数の中に見かけられる。 まずは、プログラムを作るときに使う、基本的コマンドについて見ていこう。
 
Simple and Compound Statements
 
単純文、複合文
 
A Pascal statement is simple when it doesn't contain any other statements. Examples of simple statements are assignment statements and procedure calls. Simple statements are separated by a semicolon:
 
Pascal の文というのは、別の文を含まない、単純文ではシンプルだ。 単純文を例に挙げれば、代入文や手続きの呼び出しということになる。 単純文はセミコロンで終わる。
 
X := Y + Z; // assignment 代入文
Randomize;  // procedure call 手続き呼び出し
 
Usually, statements are part of a compound statement, marked by begin and end brackets. A compound statement can appear in place of a generic Pascal statement. Here is an example:
 
一般的には、文は、begin と end で囲まれる複合文の一部になっている。 純粋な Pascal 文では、複合文がよく使われる。 例として;
 
begin
 A := B;
 C := A * 2;
end;
 
The semicolon after the last statement before the end isn't required, as in the following:
 
end の前の最後の文に付いているセミコロンは、本来は必要がない。 こうしても良い;
 
begin
 A := B;
 C := A * 2
end;
 
Both versions are correct. The first version has a useless (but harmless) semicolon. This semicolon is, in fact, a null statement; that is, a statement with no code. Notice that, at times, null statements can be used inside loops or in other particular cases.
 
両方とも正しい。 最初のものには、無用(実害なし)なセミコロンが付いている。 実のところ、このセミコロンはヌル文、コードの無い文だ。 ループの中や、特定の場合には、ヌル文も使えることを覚えておくといい。
 
Note: Although these final semicolons serve no purpose, I tend to use them and suggest you do the same. Sometimes after you've written a couple of lines you might want to add one more statement. If the last semicolon is missing you should remember to add it, so it might be better to add it in the first place.
 
注:この最後のセミコロンは意味の無いものだが、私はなるべく使うようにしているし、君達にも薦める。 コードを書き終えた後に、文を追加することもよくある。 セミコロンを付けたかどうか、神経質になるより、最初から付けておく方がいいね。
 
Assignment Statements
 
代入文
 
Assignments in Pascal use the colon-equal operator, an odd notation for programmers who are used to other languages. The = operator, which is used for assignments in some other languages, in Pascal is used to test for equality.
 
Pascal では、代入はコロンとイコール記号を使う。 これは、他の言語に詳しいプログラマには奇妙に思えるだろう。 = オペレータは、他の言語では代入文に使われているけれど、Pascal では等しいかどうかをテストするために使われる。
 
Note: By using different symbols for an assignment and an equality test, the Pascal compiler (like the C compiler) can translate source code faster, because it doesn't need to examine the context in which the operator is used to determine its meaning. The use of different operators also makes the code easier for people to read.
 
注:代入と等号を分けているため、Pascal のコンパイラ(C コンパイラと同様)は、高速でソースコードを変換できる。 これは、等号の意味をいちいち判別する必要が無いからだ。 また、別のオペレータを使うことで、人間にも判読が簡単になるね。
 
Conditional Statements
 
条件文
 
A conditional statement is used to execute either one of the statements it contains or none of them, depending on some test. There are two basic flavors of conditional statements: if statements and case statements.
 
条件文というのは、いくつか文が指定してあって、条件に応じて、どれかの文を実行したり、場合によってはどれも実行しないようにするものだ。 条件文には2種類ある。 if と case 文だ。
 
If Statements
 
If 文
 
The if statement can be used to execute a statement only if a certain condition is met (if-then), or to choose between two different alternatives (if-then-else). The condition is described with a Boolean expression. A simple Delphi example will demonstrate how to write conditional statements. First create a new application, and put two check boxes and four buttons in the form. Do not change the names of buttons or check boxes, but double-click on each button to add a handler for its OnClick event. Here is a simple if statement for the first button:
 
if 文は、条件が合致するとき (if-then)、または二者択一でどちらかを選ぶ (if-then-else) ときに使う。 条件には、ブール式を用いる。 簡単な例で、条件式の書き方を示してみよう。 まずアプリケーションを新規作成し、チェックボックスを2個、ボタンを4個、フォームに配置する。  チェックボックスとボタンの名前を変えないこと。 ボタンを順にダブルクリックし、OnClick イベントのハンドラを書く。 最初のボタンには、
 
procedure TForm1.Button1Click(Sender: TObject);
begin
 // simple if statement 単純な if 文
 if CheckBox1.Checked then
  ShowMessage ('CheckBox1 is checked') チェックボックス1をチェックした!
end;
 
When you click on the button, if the first check box has a check mark in it, the program will show a simple message (see Figure 5.1). I've used the ShowMessage function because it is the simplest Delphi function you can use to display a short message to the user.
 
ボタンを押した時に、最初のチェックボックスにチェックが付いていると、プログラムが上記のメッセージを表示してくれる (図 5.1 参照)。 ユーザーに短いメッセージを表示するには、ShowMessage が一番単純な Delphi 関数なので、この関数を使っている。
 
Figure 5.1: The message displayed by the IfTest example when you press the first button and the first check box is checked.
 
図 5.1 : IfTest プログラムで、最初のボタンを押した時に、最初のチェックボックスにチェックが付いていた場合のメッセージ表示
 
If you click the button and nothing happens, it means the check box was not checked. In a case like this, it would probably be better to make this more explicit, as with the code for the second button, which uses an if-then-else statement:
 
ボタンを押しても、何も起こらなかったら、チェックボックスにチェックが入っていない、ということだ。 こういう時には、もっとはっきりさせるためにも、2番目のボタンのコードのように、if - then - else 構文を使う方がいいだろう。
 
procedure TForm1.Button2Click(Sender: TObject);
begin
 // if-then-else statement if - then - else 分
 if CheckBox2.Checked then
  ShowMessage ('CheckBox2 is checked')  CheckBox2 にチェック
 else
  ShowMessage ('CheckBox2 is NOT checked'); CheckBox2 にはチェック無し
end;
 
Notice that you cannot have a semicolon after the first statement and before the else keyword, or the compiler will issue a syntax error. The if-then-else statement, in fact, is a single statement, so you cannot place a semicolon in the middle of it.
 
始めの方の文の後ろに、セミコロンを付けられない事に注意。 これは else キーワードの前でも同じだ。 そうしないと、コンパイラが構文エラーの警告を出す。 事実、if - then - else というのは、これ全部でひとつの文なので、途中でセミコロンは付けられない。
 
An if statement can be quite complex. The condition can be turned into a series of conditions (using the and, or and not Boolean operators), or the if statement can nest a second if statement. The last two buttons of the IfTest example demonstrate these cases:
 
if 文というのは、いくらでも複雑にできる。 and や or、and not オペレータを使えば、組み合わさった条件が作れるし、if 文を次の if 文にネストすることもできる。 これをサンプルの、IfTest の残りのボタンふたつで見てみよう。
 
procedure TForm1.Button3Click(Sender: TObject);
begin
 // statement with a double condition 二重条件文
 if CheckBox1.Checked and CheckBox2.Checked then
  ShowMessage ('Both check boxes are checked') 両方の CheckBox にチェック有り
end;
 
procedure TForm1.Button4Click(Sender: TObject);
begin
 // compound if statement 複合文
 if CheckBox1.Checked then
  if CheckBox2.Checked then
   ShowMessage ('CheckBox1 and 2 are checked') CheckBox1、2 共にチェック
  else
   ShowMessage ('Only CheckBox1 is checked') CheckBox1 のみチェック
 else
  ShowMessage (
   'Checkbox1 is not checked, who cares for Checkbox2?')
   CheckBox1 にチェック無し、それで CheckBox2 はどうする?
end;
 
Look at the code carefully and run the program to see if you understand everything. When you have doubts about a programming construct, writing a very simple program such as this can help you learn a lot. You can add more check boxes and increase the complexity of this small example, making any test you like.
 
コードをよく呼んで、プログラムを走らせ、完全にマスターすること。 プログラム構造に疑問がある時は、こういう、ごく簡単なコードを書いてみると、より理解しやすくなる。 もっとチェックボックスを増やし、このサンプルをもっと複雑にして勉強してみるといい。
 
Case Statements
 
Case 文
 
If your if statements become very complex, at times you can replace them with case statements. A case statement consists in an expression used to select a value, a list of possible values, or a range of values. These values are constants, and they must be unique and of an ordinal type. Eventually, there can be an else statement that is executed if none of the labels correspond to the value of the selector. Here are two simple examples:
 
if 文がずっと複雑になってしまったら、case 文を使ってみるといい。 case 文というのは、どれを選択するか、という文と、値のリストか、範囲が示されているものだ。 この値は定数で、他のものと判別できる順序型でないといけない。 最後に else をつけて、選択肢に該当しないときには、この文を実行するようにもできる。 例をふたつ挙げる。
 
case Number of
 1: Text := 'One';
 2: Text := 'Two';
 3: Text := 'Three';
end;
 
case MyChar of
 '+' : Text := 'Plus sign';
 '-' : Text := 'Minus sign';
 '*', '/': Text := 'Multiplication or division';
 '0'..'9': Text := 'Number';
 'a'..'z': Text := 'Lowercase character';
 'A'..'Z': Text := 'Uppercase character';
else
 Text := 'Unknown character';
end;
 
Loops in Pascal
 
Pascal でのループ
 
The Pascal language has the typical repetitive statements of most programming languages, including for, while, and repeat statements. Most of what these loops do will be familiar if you've used other programming languages, so I'll cover them only briefly.
 
一般的に使われている繰り返し文も、Pascal にある。 これが for、while、repeat だ。 他の言語をやったことのある人なら、繰り返し文についてはよく知っているだろうから、説明はごく簡単にしておこう。
 
The For Loop
 
For ループ
 
The for loop in Pascal is strictly based on a counter, which can be either increased or decreased each time the loop is executed. Here is a simple example of a for loop used to add the first ten numbers.
 
Pascal での for ループは、ループが実行されるときに増減するカウンタ、を基準にしている。 1 から 10 までの数を加算するループを示そう。
 
var
 K, I: Integer;
begin
 K := 0;
 for I := 1 to 10 do
  K := K + I;
 
This same for statement could have been written using a reverse counter:
 
逆カウンタを使っても、同様に書ける。
 
var
 K, I: Integer;
begin
 K := 0;
 for I := 10 downto 1 do
  K := K + I;
 
The for loop in Pascal is less flexible than in other languages (it is not possible to specify an increment different than one), but it is simple and easy to understand. If you want to test for a more complex condition, or to provide a customized counter, you need to use a while or repeat statement, instead of a for loop.
 
Pascal の for ループは( 他の言語ではできるが )、1 以外の増減は指定できないが、単純で理解しやすい。 条件をもっと複雑にしたり、カウンタを自由に設定したいのなら、while か repeat 文を使う。
 
Note: The counter of a for loop doesn't need to be a number. It can be a value of any ordinal type, such as a character or an enumerated type.
 
注 : for ループのカウンタは、数字以外でもいい。 順序型ならなんでもよく、文字でも列挙型でもいい。
 
While and Repeat Statements
 
While と Repeat 文
 
The difference between the while-do loop and the repeat-until loop is that the code of the repeat statement is always executed at least once. You can easily understand why by looking at a simple example:
 
while-do と repeat-until の違いは、repeat ではコードは最低一回は必ず実行される、ということだ。 例を挙げよう。
 
while (I <= 100) and (J <= 100) do
begin
 // use I and J to compute something...
 // I と J で何かを計算する...
 I := I + 1;
 J := J + 1;
end;
 
repeat
 // use I and J to compute something...
 // I と J で何かを計算する...
 I := I + 1;
 J := J + 1;
until (I > 100) or (J > 100);
 
If the initial value of I or J is greater than 100, the statements inside the repeat-until loop are executed once anyway.
 
I と J の最初の値が 100 より大きくても、repeat-until ループでは、この計算は必ず行われる。
 
The other key difference between these two loops is that the repeat-until loop has a reversed condition. The loop is executed as long as the condition is not met. When the condition is met, the loop terminates. This is the opposite from a while-do loop, which is executed while the condition is true. For this reason I had to reverse the condition in the code above to obtain a similar statement.
 
もうひとつの大きな違いは、repeat-until では、逆条件が働くということだ。 repeat-until では、条件に合致しない限り、ループは実行される。 条件に合致すれば、ループは終了する、ということだ。 これが while-do では逆になる。 条件に合致している限り、ループは繰り返される。 だから、上のサンプルでは、同じ結果をえるために、条件を逆にしている。
 
An Example of Loops
 
ループを使った例
 
To explore the details of loops, let's look at a small Delphi example. The Loops program highlights the difference between a loop with a fixed counter and a loop with an almost random counter. Start with a new blank project, place a list box and two buttons on the main form, and give the buttons a proper name (BtnFor and BtnWhile) by setting their Name property in the Object Inspector. You can also remove the word Btn from the Caption property (and eventually even add the & character to it to activate the following letter as a shortcut key). Here is a summary of the textual description of this form:
 
ループをもう少し勉強するために、サンプルを挙げよう。 このプログラムでは、定められたカウンタを使うものと、ランダム・カウンタを使う例を挙げている。 新しくプロジェクトを開始し、メイン・フォームにリストボックスと、ボタンを2個配置して、オブジェクト・インスペクタで、ボタンの Name プロパティに BtnFor、BtnWhile 位の名前を付ける。 続いて、Caption プロパティにある、Btn を消して、ショートカット・キーが働くように、&For、&While とし、Ctrl + F か Ctrl + W で、このボタンが働くようにする。
コードで書けば、こうなる。
 
object Form1: TForm1
 Caption = 'Loops'
 object ListBox1: TListBox ...
 object BtnFor: TButton
  Caption = '&For'
  OnClick = BtnForClick
 end
 object BtnWhile: TButton
  Caption = '&While'
  OnClick = BtnWhileClick
 end
end
 
Figure 5.2: Each time you press the For button of the Loops example, the list box is filled with consecutive numbers.
 
図 5.2 : For ボタンを押せば、リストボックスに順に数字が入る。
 
Now we can add some code to the OnClick events of the two buttons. The first button has a simple for loop to display a list of numbers, as you can see in Figure 5.2. Before executing this loop, which adds a number of strings to the Items property of the list box, you need to clear the contents of the list box itself:
 
さて、このふたつのボタンに OnClick イベントを加えよう。 図 5.2 でわかるように、最初のボタンでは for ループが働く。 ただ、前の数字が表示されている場合があるので、このループが実行される前に、リストボックスの内容を初期化 (clear) する必要がある。
 
procedure TForm1.BtnForClick(Sender: TObject);
var
 I: Integer;
begin
 ListBox1.Items.Clear;
 for I := 1 to 20 do
  Listbox1.Items.Add ('String ' + IntToStr (I));
end;
 
The code associated with the second button is slightly more complex. In this case, there is a while loop based on a counter, which is increased randomly. To accomplish this, I've called the Randomize procedure, which resets the random number generator, and the Random function with a range value of 100. The result of this function is a number between 0 and 99, chosen randomly. The series of random numbers control how many times the while loop is executed.
 
二番目のボタンに付いているコードは、もう少し複雑になっている。 カウンタをベースにした while ループで、加算される値が、ランダムになっている。 このために、Randomize 手続きを使ってランダム数を初期化し、100 を範囲とするRandom 関数を使っている。 この関数は、0 から 99 までの値を、ランダムに選び出す。 このランダムな値が、何度 while ループを繰り返せばいいのか、決定する。
 
procedure TForm1.BtnWhileClick(Sender: TObject);
var
 I: Integer;
begin
 ListBox1.Items.Clear;
 Randomize;
 I := 0;
 while I < 1000 do
 begin
  I := I + Random (100);
  Listbox1.Items.Add ('Random Number: ' + IntToStr (I));
 end;
end;
 
Each time you click the While button, the numbers are different, because they depend on the random-number generator. Figure 5.3 shows the results from two separate button-clicks. Notice that not only are the generated numbers different each time, but so is the number of items. That is, this while loop is executed a random numbers of times. If you press the While button several times in a row, you'll see that the list box has a different number of lines.
 
While ボタンを押すたびに、値は変わる。 というのも、ランダムに値が生成されるからだ。 図 5.3 では、別々にボタンを押した場合を示している。 毎回別の値が生成されるばかりでなく、項目数も変わることに注意。 これは、この while ループの繰り返し回数がランダムだからだ。 何度も While ボタンを押し続けると、そのたびに、リストボックスの行数が変わるね。
 
Figure 5.3: The contents of the list box of the Loops example change each time you press the While button. Because the loop counter is incremented by a random value, every time you press the button the loop may execute a different number of times.
 
図 5.3 : While ボタンを押すたびに、リストボックスの内容が変わる。 ループのカウンタは、ランダムに変わるので、ボタンをおすたびに、ループの回数も変わる。
 
Note: You can alter the standard flow of a loop's execution using the Break and Continue system procedures. The first interrupts the loop; the second is used to jump directly to the loop test or counter increment, continuing with the next iteration of the loop (unless the condition is zero or the counter has reached its highest value). Two more system procedures, Exit and Halt, let you immediately return from the current function or procedure or terminate the program.
 
注 : ループの実行経過は、Break と Continue システム手続きの使用で変えられる。 Break はループを停止させ、Continue は、条件がゼロになったり、カウンタが上限に達していない限り、ループの続行を始める。 Exit と Halt というシステム手続きもあり、これは現在の関数や手続きから直ちに抜け出したり、プログラムを停止させたりする。
 
The With Statement
 
With 文
 
The last kind of Pascal statement I'll focus on is the with statement, which used to be peculiar to this programming language (although it has been recentrly introduced also in JavaScript and Visual Basic) and can be very useful in Delphi programming.
 
最後に with 文について見ていこう。 これは Pascal に特有のものでDelphi プログラミングには無くてはならないものだが、最近、JavaScript や Visual Basic にも採用されている。
 
The with statement is nothing but shorthand. When you need to refer to a record type variable (or an object), instead of repeating its name every time, you can use a with statement. For example, while presenting the record type, I wrote this code:
 
with 文というのは、コードを省略して書けるということだ。 レコード型の変数や、オブジェクトを扱うときに、その名称をなんども繰り返し書く代わりに、with 文を使う。 たとえば、レコード型とすると、
 
type
 Date = record
  Year: Integer;
  Month: Byte;
  Day: Byte;
 end;
 
var
 BirthDay: Date;
 
begin
 BirthDay.Year := 1997;
 BirthDay.Month := 2;
 BirthDay.Day := 14;
 
Using a with statement, I can improve the final part of this code, as follows:
 
上記を with 文で書けば、このコードの後半部はこうなる。
 
begin
 with BirthDay do
 begin
  Year := 1995;
  Month := 2;
  Day := 14;
 end;
 
This approach can be used in Delphi programs to refer to components and other class types. For example, we can rewrite the final part of the last example, Loops, using a with statement to access the items of the list box:
 
これは Delphi では、コンポーネントや他の型にも使える。 たとえば、この前のループのサンプルならば、with 文を使えば、リストボックスの項目には、こうアクセスできる。
 
procedure TForm1.WhileButtonClick(Sender: TObject);
var
 I: Integer;
begin
 with ListBox1.Items do
 begin
  Clear; // shortcut 記述を短くできる。
  Randomize;
  I := 0;
  while I < 1000 do
  begin
   I := I + Random (100);
   // shortcut:  中略
   Add ('Random Number: ' + IntToStr (I));
  end;
 end;
end;
 
When you work with components or classes in general, the with statement allows you to skip writing some code, particularly for nested fields. For example, suppose that you need to change the Width and the Color of the drawing pen for a form. You can write the following code:
 
コンポーネントや他のクラスを使っているときには、ネストしているような時には、特にコード記述の手間を省ける。 たとえば、フォームで使用するペンの幅と色を変えるとする。 こういう時には、
 
Form1.Canvas.Pen.Width := 2;
Form1.Canvas.Pen.Color := clRed;
 
But it is certainly easier to write this code:
 
こうするより、次のように書く方が簡単だ。
 
with Form1.Canvas.Pen do
begin
 Width := 2;
 Color := clRed;
end;
 
When you are writing complex code, the with statement can be effective and spares you the declaration of some temporary variables, but it has a drawback. It can make the code less readable, particularly when you are working with different objects that have similar or corresponding properties.
 
コードが複雑な時には、with 文を使えば、その時に使用している変数の宣言を省略でき、実に有効だが、問題が無い訳ではない。 他のオブジェクトもともに使い、似たようなプロパティを扱っているときには、コードが読みづらくなる。
 
A further drawback is that using the with statement can allow subtle logical errors in the code that the compiler will not detect. For example:
 
もっと深刻なのが、with 文を使うことで、コンパイラも気づかないような微妙な論理的間違いが起こりうる、ということだ。 たとえば、
 
with Button1 do
begin
 Width := 200;
 Caption := 'New Caption';
 Color := clRed;
end;
 
This code changes the Caption and the Width of the button, but it affects the Color property of the form, not that of the button! The reason is that the TButton components don't have the Color property, and since the code is executed for a form object (we are writing a method of the form) this object is accessed by default. If we had instead written:
 
これはボタンの Caption と Width を変えるものだが、フォームの色までも変えてしまう。 原因は、TButton コンポーネントには、色のプロパティは無いので、このコードの色の部分は、フォームを目標に書いていると解釈されてしまう。 というのも、ユニットでは明示しない限り、デフォルト・オブジェクトは、フォームになっているからだ。 本来はこのように書いているので、
 
Button1.Width := 200;
Button1.Caption := 'New Caption';
Button1.Color := clRed; // error! エラー!
 
the compiler would have issued an error. In general, we can say that since the with statement introduces new identifiers in the current scope, we might hide existing identifiers, or wrongfully access another identifier in the same scope (as in the first version of this code fragment). Even considering this kind of drawback, I suggest you get used to with statements, because they can be really very handy, and at times even make the code more readable.
 
コンパイラはエラー・メッセージを出してくるはずなのだ。 このように with 文では、現在のスコープの中で、意図しない識別子を出してくる場合があり、既に見たように、他の識別子に誤ってアクセスする場合もある。 ただ、こういう欠点はあるが、非常に便利で、時にはコードをずっと読みやすくするので、with 文を使いこなすことを薦める。 
 
You should, however, avoid using multiple with statements, such as:
 
ただし、このように with 文を重ねて使うことは避けた方がいい。
 
with ListBox1, Button1 do...
 
The code following this would probably be highly unreadable, because for each property defined in this block you would need to think about which component it refers to, depending on the respective properties and the order of the components in the with statement.
 
このコードの後のコードは、間違いなく読みづらいだろう。 というのも、そのプロパティがどのコンポーネントに属しているのか、ひとつひとつ with 文のブロックの中で対応させなくてはならないからだ。
 
Note: Speaking of readability, Pascal has no endif or endcase statement. If an if statement has a begin-end block, then the end of the block marks the end of the statement. The case statement, instead, is always terminated by an end. All these end statements, often found one after the other, can make the code difficult to follow. Only by tracing the indentations can you see which statement a particular end refers to. A common way to solve this problem and make the code more readable is to add a comment after the end statement indicating its role, as in:
 
注 : 可読性ということから言えば、Pascal には endif や endcase 文が無い。 if が begin-end でくくられていれば、そのブロックの end が、文の終了点になる。 case 文では、常に end が終了点だ。 この複数の end 文が、ずっと続いていたりすると、追っかけるのが難しくなる。 字下げのインデントだけが頼り、ということになる。 一般的な解決策として、end 文の後に、コメントを入れて可読性を上げる、ということがよくやられている。 たとえば、
 
if ... then
...
end; // if  if の終了
 
Conclusion
 
結論
 
This chapter has described how to code conditional statements and loops. Instead of writing long lists of such statements, programs are usually split in routines, procedures or functions. This is the topic of the next chapter, which introduces also some advanced elements of Pascal.
 
この章では、条件文とループについて検討した。 ただ、こうした条件文やループを使って長いコードを書く代わりに、手続きや関数というルーチンに分けることが多い。 次章ではこの手続きや関数を取り上げ、また Pascal の高度な機能についても見ていこう。
 
Next Chapter: Procedures
 
次章 : 手続き
 
c Copyright Marco Cantu, Wintech Italia Srl 1995-2000
 
 
戻る