メソッド
メソッドとは、1つ以上の動作を実行するコードのことです。 メソッドは、1つ以上のステートメントで構成されます。
ステートメントは 1つの命令を実行し、単純な場合もあれば複雑な場合もあります。 ステートメントとは通常、メソッドの 1行のことを指します (必要に応じて \
文字を使って行を分割 することができます。
メソッドは最大 2GBのテキストまたは、32000行まで記述できます。
メソッドタイプ
4D ランゲージにおいて、数種類のメソッドが存在します。 その呼び出し方によって、メソッドは区別されます:
型 | 自動呼び出しのコンテキスト | 引数の受け取り | 説明 |
---|---|---|---|
プロジェクトメソッド | 呼び出しに応じて (プロジェクトメソッドの呼び出し 参照) | ◯ | 任意のアクションを実行するためのコードです。 作成されたプロジェクトメソッドは、そのプロジェクトのランゲージの一部となります。 |
オブジェクト (ウィジェット) メソッド | メソッドが設定されたフォームオブジェクトに関連したイベント発生時に | × | フォームオブジェクト (ウィジェットとも呼びます) のプロパティです。 |
フォームメソッド | メソッドが設定されたフォームに関連したイベント発生時に | × | フォームのプロパティです。 フォームメソッドを使用してデータとオブジェクトを管理することができます。ただし、これら目的には、オブジェクトメソッドを使用する方が通常は簡単であり、より効果的です。 |
トリガー (別名 テーブルメソッド) | テーブルのレコード操作 (追加・削除・修正) の度に | × | テーブルのプロパティです。 トリガーは、データベースのレコードに対して「不正な」操作がおこなわれることを防ぎます。 |
データベースメソッド | 作業セッションのイベント発生時に | ○ (既定) | 4D には 16のデータベースメソッドがあります。 |
クラス | クラス関数 は、オブジェクトインスタンスのコンテキストにおいて呼び出されます。 | ◯ | クラス関数にはビルトインのものと (例: collection.orderBy() や entity.save() )、開発者によって作成されるものがあります。 クラス 参照。 |
プロジェクトメソッドの呼び出し
その実行方法や使用方法に応じて、プロジェクトメソッドは次のような役割を果たします:
- サブルーチン
- オブジェクトフォーミュラ
- メニューメソッド
- プロセスメソッド
- イベントまたはエラー処理メソッド
また、テスト目的などで、プロジェクトメソッドを手動で実行することもできます。
サブルーチン
サブルーチンは、処理の下請け的なプロジェクトメソッドです。 他のメソッドから呼ばれて、要求された処理を実行します。 関数は、呼び出し元のメソッドに値を返すサブルーチンのことです。
プロジェクトメソッドを作成すると、それは同データベースのランゲージの一部となります。 プロジェクトメソッドは、4Dのビルトインコマンドと同様に、ほかのメソッド (プロジェクトメソッドやオブジェクトメソッド) から呼び出すことができます。 このように使用されるプロジェクトメソッドをサブルーチンと呼びます。
サブルーチンは、以下のような目的で使います:
- 重複コードの削減
- メソッドの役割の明確化
- メソッド改変の容易化
- コードのモジュール化
たとえば、顧客データベースがあるとします。 プロジェクトをカスタマイズしていくうちに、顧客を検索してレコードを修正するという一連の作業を繰り返しおこなっていることに気づいたとします。 そのコーディングは以下のようになっています:
// 顧客を検索します
QUERY BY EXAMPLE([Customers])
// 入力フォームを選択します
FORM SET INPUT([Customers];"Data Entry")
// 顧客レコードを修正します
MODIFY RECORD([Customers])
サブルーチンを使用しなければ、顧客レコード修正のたびにコードを作成しなければなりません。 プロジェクトの 10箇所で同じ処理が必要であれば、同じコーディングを 10回も書かねばなりません。 サブルーチンを使用すれば 1回コーディングするだけですみます。 これがコーディングの重複を減らすというサブルーチンの第一の利点です。
先ほど説明したコードが MODIFY_CUSTOMER
と呼ばれるメソッドであるとすれば、他のメソッド内でそのメソッド名を使うことで実行できます。 たとえば、顧客のレコードを修正し、それからレコードをプリントするために、以下のようなメソッドを書くことができます:
MODIFY_CUSTOMER
PRINT SELECTION([Customers])
この機能はメソッドを劇的にに簡素化します。 さきほどの例で言えば、MODIFY_CUSTOMER
メソッドがどのように動作するかは知る必要がなく、何をおこなうかだけ知っていればよいのです。 これはメソッドをサブルーチン化することの2番目の理由、役割の明確化です。 このように、作成されたメソッドは 4Dランゲージを拡張します。
このプロジェクトの例で顧客の検索方法を変える場合、10箇所ではなく、たった1つのメソッドを変更するだけですみます。 これがサブルーチンを使うもう一つの理由、改変の容易化です。
また、サブルーチンの利用はコードをモジュール化します。 これはコードをモジュール (サブルーチン) に分割することを意味し、それぞれは論理的な処理を実行します。 小切手振り出し口座のプロジェクトから、以下のコードを見てみましょう:
FIND_CLEARED_CHECKS // 決済された小切手の検索
RECONCILE_ACCOUNT // 口座の照合
PRINT_CHECK_BOOK_REPORT // レポートの印刷
プロジェクトの詳細を知らない人でも、このプログラムが何をしているかはわかります。 各サブルーチンの処理手順を知る必要はありません。 各サブルーチンは長く、複雑な処理で構成されていることもありますが、それらが何を実行するのかだけを知っていれば十分なのです。 プログラムを論理的な処理単位やモジュールにできるだけ分割することをお勧めします。
オブジェクトフォーミュラ
プロジェクトメソッドは、フォーミュラ オブジェクトにカプセル化して、オブジェクトから呼び出すことができます。
Formula
または Formula from string
コマンドを使用すると、オブジェクトプロパティに格納可能な、ネイティブなフォーミュラオブジェクトを作成することができます: つまり、カスタムなオブジェクトメソッドを実装することが可能です。
オブジェクトプロパティに保存されているメソッドを実行するには、プロパティ名のあとに () をつけます。 例:
// myAlert プロジェクトメソッド
ALERT("Hello world!")
この myAlert
プロジェクトメソッドを任意のオブジェクトに格納し、呼び出すことができます:
var $o : Object
$o:=New object("custom_Alert";Formula(myAlert))
$o.custom_Alert() // "Hello world!" と表示します
大カッコを使用したシンタックスもサポートされます:
$o["custom_Alert"]() // "Hello world!" と表示します
$1, $2, .... を使用して呼び出すことで、フォーミュラに 引数を渡す こともできます (4D プロジェクトメソッドと同様):
//fullName メソッド
C_TEXT($0;$1;$2)
$0:=$1+" "+$2
fullName
メソッドをオブジェクトに格納し、呼び出します:
var $o : Object
$o:=New object("full_name";Formula(fullName))
$result:=$o.full_name("John";"Smith")
//$result = "John Smith"
// $result:=fullName("param1";"param2") と同義です
This
関数と組み合わせることで、オブジェクトメソッドを利用した汎用的なコードを書くことができます。 例:
//fullName2 メソッド
C_TEXT($0)
$0:=This.firstName+" "+This.lastName
このメソッドをオブジェクトに格納すると、オブジェクトの新しい計算属性のように使えます:
var $o : Object
$o:=New object("firstName";"Jim";"lastName";"Wesson")
$o.fullName:=Formula(fullName2) // メソッドをオブジェクトに追加します
$result:=$o.fullName()
// $result = "Jim Wesson"
たとえ引数を受け取らなかったとしても、オブジェクトメソッドを実行するためにはカッコ ()
をつけて呼び出す必要があるという点に注意してください。 オブジェクトプロパティのみを呼び出した場合、フォーミュラへの新しい参照が返されます (そしてフォーミュラは実行はされません):
$o:=$f.message // $o にはフォーミュラオブジェクトが返されます
メニューメソッド
メニューメソッドは、カスタムメニューから呼び出されるプロジェクトメソッドです。 メニューエディターまたは "メニュー" テーマのコマンドを使用して、メニューにメソッドを割り当てます。 メニューが選択されると、それに対応するメニューメソッドが実行されます。 特定の処理を実行するメニューメソッドを割り当てたカスタムメニューを作成することで、デスクトップアプリケーションのユーザーインターフェースをカスタマイズすることができます。
メニューメソッドにより、単一または複数の処理を実行することができます。 たとえば、データ入力のメニューに、以下の2つの処理を実行するメソッドを割り当てられます。まず適切な入力フォームを表示し、次にユーザーがキャンセルするまでの間 ADD RECORD
コマンドによるデータ入力を繰り返します。
連続した処理の自動化は、プログラミング言語の強力な機能の 1つです。 カスタムメニューを使用することで処理を自動化することができ、アプリケーションのユーザーにより多くのガイダンスを提供することができます。
プロセスメソッド
プロセスメソッド とは、プロセスの開始時に呼び出されるプロジェクトメソッドのことです。 ワーカープロセスの場合を除いて、プロセスはプロセスメソッドが実行されている間だけ存続します。 メニューに属するメニューメソッドのプロパティとして 新規プロセス開始 をチェックしている場合、そのメニューメソッドは新規プロセスのプロセスメソッドでもあります。
イベント・エラー処理メソッド
イベント処理メソッド は、イベントを処理するプロセスメソッドとして、分離されたプロセス内で実行されます。 通常、開発者はイベント管理の大部分を 4Dに任せます。 たとえば、データ入力中にキーストロークやクリックを検出した 4Dは、正しいオブジェクトとフォームメソッドを呼び出します。このため開発者は、これらのメソッド内でイベントに対し適切に応答できるのです。 詳細については ON EVENT CALL
コマンドの説明を参照してください。
エラー処理メソッド は、割り込みを実行するプロジェクトメソッドです。 エラーや例外が発生するたびに呼び出されます。 詳細については、エラー処理 を参照ください。
手動での実行
アプリケーションに定義されたプロジェクトメソッドは通常、アプリケーションの使用中にボタンやメニュー、他のメソッドなどから自動的に呼び出されます。 データベースメソッドについては、アプリケーションで発生する特定のイベントに反応して実行されます。
しかし、テストやデバッグの目的で、プロジェクトメソッドや特定のデータベースメソッドをデザインモードで実行することができます。 この場合、メソッドを新規プロセスで実行するか、または直接デバッグモードで一行ごと実行できます。
メソッド実行は 2つの方法でおこなえます:
- コードエディターウィンドウからメソッド実行
- メソッド実行ダイアログボックスから実行 (プロジェクトメソッドのみ)
コードエディターからメソッド実行
コードエディター ウィンドウには、そのエディターで開かれているメソッドを実行するためのボタンがあります。 このボタンに関連付けられているメニューから実行オプションを選択できます。
このボタンは、プロジェクトメソッドと以下のデータベースメソッドでのみ利用できます:
- On Startup
- On Exit
- On Server Startup
- On Server Shutdown
詳細は ツールバー を参照ください。
メソッド実行ダイアログボックスから実行
実行 メニューから メソッド... コマンドを選択すると、メソッド実行 ダイアログボックスが表示されます。
このダイアログボックスには、データベースのプロジェクトメソッド (コンポーネントの共有メソッドを含む) が表示されます。 一方、非表示属性が設定されたプロジェクトメソッドは表示されません。
プロジェクトメソッドを実行するには、リストからメソッドを選択し、実行 をクリックします。 デバッグモードでメソッドを実行するには デバッグ をクリックします。 デバッガーに関する詳細は、デバッガー の章を参照ください。
新規プロセス チェックボックスを選択すると、選択したメソッドは新規に作成されたプロセス内で実行されます。 大量の印刷など時間のかかる処理をメソッドがおこなう場合でもこのオプションを使用すれば、レコードの追加、グラフの作成などの処理をアプリケーションプロセスで継続できます。 プロセスに関する詳細は 4D ランゲージリファレンス マニュアルの プロセス を参照ください。
4D Serverに関する注記:
- クライアントではなくサーバー上でメソッドを実行したい場合、実行モードメニューで 4D Server を選択します。 この場合 ストアドプロシージャー と呼ばれるプロセスが新規にサーバー上で作成され、メソッドが実行されます。 このオプションを使用して、ネットワークトラフィックを減らしたり、4D Serverの動作を最適化したりできます (特にディスクに格納されたデータにアクセスする場合など)。 すべてのタイプのメソッドをサーバー上や他のクライアント上で実行できますが、ユーザーインターフェースを変更するものは例外です。 この場合、ストアドプロシージャーは効果がありません。
- 他のクライアントマシン上でメソッドを実行するよう選択することもできます。 他のクライアントマシンは、事前に登録されていなければメニューに表示されません (詳細は REGISTER CLIENT の説明を参照ください)。
デフォルトでは、ローカル オプションが選択されています。 4D シングルユーザーの場合、このオプションしか選択できません。
プロジェクトメソッドの再帰呼び出し
プロジェクトメソッドは、自分自身を呼び出すことができます。 例:
- メソッドAがメソッドBを呼び出し、メソッドBはメソッドAを呼び出します。
- メソッドAは自身を呼び出すことができます。
これは再帰呼び出しと呼ばれています。 4D ランゲージは再帰呼び出しを完全にサポートしています。
次に例を示します。 以下のフィールドから成る [Friends and Relatives]
テーブルがあります:
[Friends and Relatives]Name
[Friends and Relatives]ChildrensName
この例題では、フィールドの値は重複しない、つまり同じ名前の人間はいないとします。 名前を指定することで、以下のような文を作成します: “A friend of mine, John who is the child of Paul who is the child of Jane who is the child of Robert who is the child of Eleanor, does this for a living!”:
- この文を以下のように作成できます:
$vsName:=Request("Enter the name:";"John")
If(OK=1)
QUERY([Friends and Relatives];[Friends and Relatives]Name=$vsName)
If(Records in selection([Friends and Relatives])>0)
$vtTheWholeStory:="A friend of mine, "+$vsName
Repeat
QUERY([Friends and Relatives];[Friends and Relatives]ChildrensName=$vsName)
$vlQueryResult:=Records in selection([Friends and Relatives])
If($vlQueryResult>0)
$vtTheWholeStory:=$vtTheWholeStory+" who is the child of "+[Friends and Relatives]Name
$vsName:=[Friends and Relatives]Name
End if
Until($vlQueryResult=0)
$vtTheWholeStory:=$vtTheWholeStory+", does this for a living!"
ALERT($vtTheWholeStory)
End if
End if
- 以下の方法でも作成できます:
$vsName:=Request("Enter the name:";"John")
If(OK=1)
QUERY([Friends and Relatives];[Friends and Relatives]Name=$vsName)
If(Records in selection([Friends and Relatives])>0)
ALERT("A friend of mine, "+Genealogy of($vsName)+", does this for a living!")
End if
End if
再帰関数 Genealogy of
は以下の通りです:
` Genealogy of project method
` Genealogy of ( String ) -> Text
` Genealogy of ( Name ) -> Part of sentence
$0:=$1
QUERY([Friends and Relatives];[Friends and Relatives]ChildrensName=$1)
If(Records in selection([Friends and Relatives])>0)
$0:=$0+" who is the child of "+Genealogy of([Friends and Relatives]Name)
End if
Genealogy of
メソッドが自分自身を呼び出していることに注目してください。
最初に挙げた方法は 反復性のアルゴリズム です。 2番目に挙げた方法は 再帰呼び出しのアルゴリズム です。
前述の例題のようなコードを実装する場合、反復性や再帰呼び出しを使用してメソッドを書くことができるということに留意してください。 再帰呼び出しは一般的に、より明瞭で読みやすく、維持しやすいコードを提供します。ただし、この使用は必須ではありません。
4D内での再帰呼び出しの代表的な使用方法は以下のとおりです:
- 例題と同じく、互いに関連するテーブル内でのレコードの取り扱い。
FOLDER LIST
とDOCUMENT LIST
コマンドを使用して、ディスク上にあるドキュメントとフォルダーをブラウズする。 フォルダーにはフォルダーとドキュメントが含まれており、サブフォルダーはまたフォルダーとドキュメントを含むことができます。
重要: 再帰呼び出しは、必ずある時点で終了する必要があります。 たとえば、Genealogy of
メソッドが自身の呼び出しを止めるのは、クエリがレコードを返さないときです。 この条件のテストをしないと、メソッドは際限なく自身を呼び出します。 (メソッド内で使用される引数やローカル変数の蓄積を含む) 再帰呼び出しによって容量が一杯になると、最終的に 4Dは “スタックがいっぱいです” エラーを返します 。