"良いプログラムを作成する"ための決定的な方法を説明するのは難しいことですが、良い構造を持つプログラムの利点を再度ここで強調します。4Dは構造化プログラミングが可能であり、この能力はプログラミングの大きな助けになります。
構造化されたデータベースのコンパイルは、そうでないデータベースのコンパイルと比べ、同じ労力で得られる結果が大きく異なります。例えば、n個のオブジェクトに対する共通メソッドは、同じステートメントで書かれたn個のオブジェクトメソッドより、インタプリタモードでもコンパイルモードでも、はるかに良い結果をもたらすことでしょう。
つまり、プログラミングの質がコンパイルされたコードの品質にも影響を与えるのです。
経験を積むことで、4Dコードを段階的に改善できます。コンパイラを頻繁に使用して間違いを訂正するフィードバックを得、最も効果的な解決方法に到達できます。
この節では、単純な繰り返しの作業にかかる時間を短縮するためのアドバイスや秘訣を紹介します。
プログラミングテクニックによっては、コードが他の人や自分自身にとって理解しづらいものもあります。このため、詳細にわたるコメントをメソッドに入れることをお勧めします。コメントが多すぎるとインタプリタデータベースでは実行が遅くなりますが、コンパイルされたデータベースにはまったく影響しません。
コンパイラコマンドを使用すると、コードの実行速度がかなり速くなります。記述のされ方から変数のタイプを決定する場合、一番広い範囲をカバーできるタイプを設定します。例えば、変数のタイプをVar:=5というステートメントで定義する場合、整数のみ使用されているのにもかかわらず、コンパイラはタイプを実数に設定します。
変数がコンパイラー指示子で型宣言されていない場合、(データベース設定でコンパイル時のデフォルト数値型が設定されていないと) デフォルトで数値変数には実数が割り当てられます。実数は倍長整数よりも計算が遅いので、数値変数が常に整数だと分かっている場合は、コンパイラ指示子C_LONGINTで変数を定義すると効果的です。
例えば、ループのカウンタは常に整数として定義しておくとよいでしょう。
4D関数の中には整数を返すものがあります(Character code, Int関数等)。コンパイラは、このような関数の結果を未定義の変数に代入する場合も、変数のタイプを整数ではなく実数にします。変数が別のタイプの値に使用されないことが明らかな場合は、必ずコンパイラ指示子で変数を宣言してください。
ここで簡単な例を示します。指定された範囲内のランダムな数を返す関数です。
$0:=Mod(Random;($2-$1+1))+$1
このように記述されていると、コンパイラは$0のタイプを倍長整数ではなく実数に設定してしまうので、メソッドにコンパイラ指示子を使用してください。
C_LONGINT($0)
$0:=Mod(Random;($2-$1+1))+$1
メソッドの戻り値に使用するメモリスペースも少なく、メソッドの実行速度も速くなります。
もう1つの例を紹介します。2つの変数を倍長整数として定義します。
C_LONGINT($var1;$var2)
そして、他の2つの変数の合計が3つ目のタイプの定義されていない変数に返されます。
$var3:=$var1+$var2.
コンパイラは、3つ目の変数$var3を実数とします。結果を倍長整数としたい場合は、倍長整数として明示的に定義しなければなりません。
注:コンパイルモードでの計算結果は、計算結果を受け取る変数のタイプではなく、計算に使用される数値のデータタイプであることに注意してください。
下記の例では、変数が倍長整数として計算されています。
C_REAL($var3)
C_LONGINT($var1;$var2)
$var1:=2147483647
$var2:=1
$var3:=$var1+$var2
コンパイルモードおよびインタプリタモードの両方で、$var3は-2147483648となります。
しかし、下記の例では、最適化のためにコンパイラは、1の値を整数と見なします。
C_REAL($var3)
C_LONGINT($var1)
$var1:=2147483647
$var3:=$var1+1
コンパイルモードでは、倍長整数として計算されるため、$var3は-2147483648となります。インタプリタモードでは、実数として計算されるため、$var3は2147483648となります。
ボタンは倍長整数として定義できる具体的なケースです。
文字の値をテストしたい場合、文字そのものではなくて文字のCharacter code値で比較をしてください。通常の文字として比較した場合、英大文字、小文字の区別はされず同一のものとして比較されます。
二次元配列は、2番目の次元が1番目の次元より大きい方が実行効率が上がります。
例えば、次のように定義された配列は、
ARRAY INTEGER(Array;5;1000)
次のような配列より効率が高くなります。
ARRAY INTEGER(Array;1000;5)
フィールドを使用して複数の演算を行う場合、変数にフィールドの値を代入して計算をしたほうが、直接フィールドで計算するより効率が良くなります。以下のメソッドをご覧ください
Case of
:([Client]Dest="New York City")
Transport:="Messenger"
:([Client]Dest="Puerto Rico")
Transport:="Air mail"
:([Client]Dest="Overseas")
Transport:="Express mail service"
Else
Transport:="Regular mail service"
End case
このメソッドは以下のように記述すると実行速度が速くなります。
$Dest:=[Client]Dest
Case of
:($Dest="New York City")
Transport:="Messenger"
:($Dest="Puerto Rico")
Transport:="Air mail"
:($Dest="Overseas")
Transport:="Express mail service"
Else
Transport:="Regular mail service"
End case
フィールドの場合と同じように、ポインタ参照よりも変数を使用する方が速くなります。
ポインタ参照される変数で何回も計算する場合、値を変数に格納すると時間を節約できます。
例えば、ポインタMyPtrがフィールドや変数を指しており、その値を使用して一連のテストをする場合は以下のように記述することができます。
Case of
:(MyPtr->=1)
Sequence 1
:(MyPtr->=2)
Sequence 2
End case
このテストは、以下のように記述することで実行速度が上がります。
Temp:=MyPtr->
Case of
:(Temp=1)
Sequence 1
:(Temp=2)
Sequence 2
End case
コードを作成する場合は、できるだけローカル変数を使用してください。ローカル変数には、次の利点があります。
- ローカル変数は、データベースのスペースを多く必要としません。ローカル変数は、メソッド中で使用されると作成され、メソッドの実行が終わると破棄されます。
- 生成されるコードは、ローカル変数(特に倍長整数)のために最適化されます。これはループカウンタに有効です。