目次
関連する機能(メソッド)やデータ(プロパティ)をひとつのグループとしてまとめたものをモジュールと言います。モジュール化することでプログラムの構造化、利用性や保守性を高めることができます。
- 構文
- MODULE モジュール名
CONST 変数
PUBLIC 変数
DIM 変数
PROCEDURE モジュール名
PROCEDURE 関数名( )
FUNCTION 関数名( )
ENDMODULE
CLASS クラス名
CONST 変数
PUBLIC 変数
DIM 変数
PROCEDURE クラス名
PROCEDURE 関数名( )
FUNCTION 関数名( )
ENDCLASS
- 引数
- 戻り値
モジュールとは
モジュールとはプログラムにおいて特定の機能を持ったひとまとまりの構成要素(部品)のことを指します。
モジュールは関数をMODULE-ENDMODULEもしくはCLASS-ENDCLASSで囲むことで定義することができます。MODULEとCLASSで2種類の書き方がありますが、どちらも動作としては全く同じものとなります。
クラスというと他の言語ではインスタンス生成をしたりできますが、UWSCでのクラスはあくまで名前空間を管理するためのものです。CLASS-ENDCLASSで定義するとクラス化と紛らわしいので当サイトでは基本的にMODULE-ENDMODULEでモジュールを定義します。
モジュール内に関数を作る方法については関数の定義を参考にしてください。
名前空間
名前空間とは、識別子(変数名や関数名)の衝突(重複)を防ぎ、コードやデータを整理・管理するための仕組みのことです。
具体的な例を出すと、当サイトでは数値を負の方向に丸める関数としてfloor関数 (自作関数)を定義しています。これとは別にDecimalモジュール (自作関数)にもfloor関数を定義していますが、関数が重複しているというエラーは発生しません。
これは名前空間を分けていることでそれぞれの関数を区別できるためで、PROCEDURE-FEND、FUNCTION-FENDで定義した関数とMODULE化で定義したモジュール内の関数では呼び出し方が異なります。
モジュールで定義した関数の呼び出し方法は関数を呼び出す方法で記述しますが、通常の関数とモジュール内で定義した関数は簡潔に書くと以下のように呼び出し方に違いがあります。
PRINT floor(arg) // 関数名
PRINT Decimal.floor(args) // モジュール.関数名
モジュール定義のメリット
- データと処理のカプセル化
- 状態(プロパティ)と機能(メソッド)を一つのまとまりとして管理することができます。
- 状態の保持
- 前回の処理結果や設定を保持することができます。
- 名前空間の整理
- 宣言された変数や関数が参照できるスコープがモジュール内に収まるのでモジュール内外で重複する変数名・関数名をつけることができ、名前の衝突が防げます。
- 保守性の向上
- 関連するコードがモジュール内にまとめられているので、機能を修正する際変更の影響を受ける範囲をモジュール内単位で局所化できます。バグ修正や機能拡張が容易となります。
例えばPythonでは、数学計算用の関数を集めたmathモジュール、日付や時間を扱うdatetimeモジュールなどがあります。
モジュールは入れ子(ネスト)することはできませんが、関数名に.(ピリオド)をつけることで階層化したように見せる書き方はできます。
MODULE Cipher
MODULE Caesar
FUNCTION encode()
RESULT = ""
FEND
FUNCTION decode()
RESULT = ""
FEND
ENDMODULE
ENDMODULE
Cipherモジュール (自作関数)では、モジュール名がCipher、関数名にCaesar.encodeとCaesar.decodeで入れ子したような書き方をしています。
このような書き方をすることでCipher.Caesar.encode()、Cipher.Caesar.decode()というメソッドが使えるようになります。
MODULE Cipher
FUNCTION Caesar.encode()
RESULT = ""
FEND
FUNCTION Caesar.decode()
RESULT = ""
FEND
ENDMODULE
ただ注意が必要なのはあくまでCaesar.encode、Caesar.decodeというひとかたまりで関数名で.がモジュール名とメソッドの区切りを表しているわけではないので、このピリオドで区切りWITH文で書くということはできません。
WITH Cipher.Caesar
PRINT .encode()
PRINT .decode()
ENDWITH
モジュール名と関数名を分けることはできます。
WITH Cipher
PRINT .Caesar.encode()
PRINT .Caesar.decode()
ENDWITH
関数を呼び出す方法
関数を呼び出す例として以下のプログラムを使います。モジュールの内部と外部にalert関数が定義されていて、それぞれを内部・外部から呼び出す方法について解説します。
MODULE myClass
PROCEDURE alert()
MSGBOX("モジュール内の関数")
FEND
ENDMODULE
PROCEDURE alert()
MSGBOX("モジュール外の関数")
FEND
モジュール内部から関数を呼び出す方法
モジュール内部から呼び出すのでmyClassモジュールにtest関数を定義し、そのtest関数から呼び出す例を記述します。
内部から内部の関数
モジュール内部から内部に定義した関数を呼び出すには、呼び出す関数名をそのまま記述します。
以下は、myClassモジュールのtest関数からモジュール内のalert関数を呼び出す例です。
myClass.test()
MODULE myClass
PROCEDURE test()
alert()
FEND
PROCEDURE alert()
MSGBOX("モジュール内の関数")
FEND
ENDMODULE
PROCEDURE alert()
MSGBOX("モジュール外の関数")
FEND
- 結果
モジュール内の関数
THIS.関数名と記述することでモジュール内部の関数と明示することもできます。
myClass.test()
MODULE myClass
PROCEDURE test()
THIS.alert()
FEND
PROCEDURE alert()
MSGBOX("モジュール内の関数")
FEND
ENDMODULE
PROCEDURE alert()
MSGBOX("モジュール外の関数")
FEND
- 結果
モジュール内の関数
モジュール内部に標準関数と同じ関数を定義している場合も同様に、THIS.関数名と記述することでモジュール内部の関数を呼び出すことができます。
以下はmyClassモジュールに2000年1月1日からの秒数(ミリ秒を含む)を返すGETTIME関数を定義し、それを呼び出しています。
MSGBOX(myClass.test())
MODULE myClass
FUNCTION test()
RESULT = THIS.GETTIME()
FEND
FUNCTION GETTIME()
RESULT = GLOBAL.GETTIME() + G_TIME_ZZ / 1000
FEND
ENDMODULE
- 結果
811631575.18
内部から外部の関数
モジュール内部から外部に定義した関数を呼び出すには、GLOBAL.関数名と記述します。
myClass.test()
MODULE myClass
PROCEDURE test()
GLOBAL.alert()
FEND
PROCEDURE alert()
MSGBOX("モジュール内の関数")
FEND
ENDMODULE
PROCEDURE alert()
MSGBOX("モジュール外の関数")
FEND
- 結果
モジュール外の関数
モジュール内部に標準関数と同じ関数を定義している場合も同様に、GLOBAL.標準関数名と記述することで標準関数を呼び出すことができます。
以下はmyClassモジュール内からUWSCの標準関数であるGETTIMEを呼び出しています。
MSGBOX(myClass.test())
MODULE myClass
FUNCTION test()
RESULT = GLOBAL.GETTIME()
FEND
FUNCTION GETTIME()
RESULT = GLOBAL.GETTIME() + G_TIME_ZZ / 1000
FEND
ENDMODULE
- 結果
811631575
モジュール外部から関数を呼び出す方法
外部から内部の関数
モジュール外部から内部に定義した関数を呼び出すには、モジュール名.関数名と記述します。
myClass.alert()
MODULE myClass
PROCEDURE alert()
MSGBOX("モジュール内の関数")
FEND
ENDMODULE
PROCEDURE alert()
MSGBOX("モジュール外の関数")
FEND
- 結果
モジュール内の関数
外部から外部の関数
モジュール外部から外部の関数を呼び出すことは通常の関数を呼び出すのと同じなので、呼び出す関数名のみを記述します。
alert()
MODULE myClass
PROCEDURE test()
GLOBAL.alert()
FEND
PROCEDURE alert()
MSGBOX("モジュール内の関数")
FEND
ENDMODULE
PROCEDURE alert()
MSGBOX("モジュール外の関数")
FEND
- 結果
モジュール外の関数
使い方
モジュール内にある変数・関数・モジュール名を呼び出すには以下のように書きます。
モジュール名.変数
モジュール名.モジュール名
モジュール名.関数名([引数], ...)
CONSTまたはPUBLICで宣言されたものは、モジュール名.変数で外部からも呼び出すことができます。
自モジュール内の変数、関数には自モジュールを示すTHIS.を付けてのアクセス可。
モジュール内からモジュール外関数を使う場合にGLOBAL.関数名にて明示可。
DIMで宣言されたものは、外部からアクセスすることはできません。
モジュール内の関数から同一モジュール内の関数を呼び出すときモジュール名は省略できます。
コンストラクタ
モジュール名と同じ関数は コンストラクタ として機能します。コンストラクタはインスタンス生成時に自動的に呼び出されるメソッドで、メンバを初期化するときによく使われます。モジュール内のすべての関数で共通する初期処理を記述する使い方もできます。
以下はclassNameというモジュール名で、同一のメソッドが実行されコンストラクタという文字列が出力されます。関数1と関数2はコンストラクタではないので出力されません。
MODULE className
PROCEDURE className
PRINT "コンストラクタ"
FEND
PROCEDURE func1()
PRINT "関数1"
FEND
PROCEDURE func2()
PRINT "関数2"
FEND
ENDMODULE
- 結果
コンストラクタ
モジュールの書き方
以下のプログラムは、Pythonのmathモジュールの一部をUWSCで書いてみた例です。
PRINT math.pi
PRINT math.e
PRINT math.tau
PRINT math.fabs(-4)
PRINT math.factorial(5)
MODULE math
// 円周率π
CONST pi = 3.14159265358979323846
// 自然対数e
CONST e = 2.71828182845904523536
// τ(τ=2π)
CONST tau = THIS.pi * 2
// 引数の絶対値を返す
FUNCTION fabs(x)
RESULT = ABS(x)
FEND
// 引数の階乗を返す
FUNCTION factorial(x)
IF x <> ABS(INT(x)) THEN RESULT = ERR_VALUE
IFB x = 0 OR x = 1 THEN
RESULT = 1
ELSE
RESULT = x * factorial(x - 1)
ENDIF
FEND
ENDMODULE
関連記事
- QuotedPrintableモジュール (自作関数)
- 文字列をQuoted-Pintableにエンコード・デコードします。Quoted-Printableとは、電子メールの送受信の際に用いられるデータの変換方式のひとつで、本文に用いられる8ビット文字を7ビットのデータであるASCIIコードに変換する方式のことです。
- Base64モジュール (自作関数)
- 文字列をBASE64にエンコード・デコードします。BASE64とは、バイナリデータを一定の規則に基づいてテキスト(文字)データに置き換える変換方式の一つで、64種類の英数字のみを用いてデータを表現する方式。 電子メールの添付ファイル(MIME)などでよく用いられます。
- Cipherモジュール (自作関数)
- 引数に指定した文字列をシーザー暗号・ROT13・ヴィジュネル暗号・XOR暗号の4種類に暗号化または復号します。
- Morseモジュール (自作関数)
- 引数に指定した文字列をモールス信号、またはモールス信号を文字列に変換します。