今回はモジュールとオブジェクト指向的な構文の勉強になります。
Nimには Java や .Net における namespace 的なものは存在せず、モジュールの分割はファイル単位での分割のみになります。
他のモジュール(ファイル)を読み込むには、import 文を使用します。
モジュール内のプロシージャ、変数、宣言で、import された際に公開したいものについては、* を付けておくことで、import した先で参照もできるようになります。
いわゆる、Javaで言うところの public指定のようなものになりますが、Javaの用語で置き換えると、Nimには public と private しか存在しないことになります。
ika = 10
複数のモジュールを読み込み名前が被った場合、先頭にモジュール名+[.] を付けてやることで、どちらのモジュールを使用しているかを判別できます。
モジュール名には別名を付けることもできます。
from を用いれば、モジュールから特定のプロシージャや変数のみをインポートして使用することが出来ます。
逆に、except は、モジュールから特定のプロシージャや変数を除外してインポートすることが出来ます。
import と似たような機能に、include というものがあります。
これは指定されたファイルの内容をそのまま取り込む機能になります。
他ファイルの内容をコピペしているようなものなので、import文のようにアクセス制御など細かい指定はできません。
Nimのオブジェクトは継承することができます。 継承については、オブジェクト型 のところで説明しているので、ここでは割愛します。
Nimでは、互いに参照し合うような型(相互再帰的な型)を定義する場合、同一の type ブロック内で定義する必要があるようです。
(ika: ...)
echo で出力したらどうなってしまうのかちょっと気になったのですが、こう出力されるのですね。
Nimにおける型変換は以下のうようにして行います。
TAKO(ebi) : (uni: 10, kani: 5) D:\Projects\nim\nimtest01\test01.nim(15) test01 D:\Projects\nim\nimtest01\test01.nim(9) TAKO D:\devtools\nim\lib\system\fatal.nim(49) sysFatal Error: unhandled exception: invalid object conversion [ObjectConversionError]
オブジェクトは同一オブジェクトの中で複数のバリエーションを持つ型のグループを定義する事ができます。
(objtype: 2, uni: "雲丹") D:\Projects\nim\nimtest01\test01.nim(11) test01 D:\devtools\nim\lib\system\fatal.nim(49) sysFatal Error: unhandled exception: 'ebi' is not accessible using discriminant 'objtype' of type 'IKA' [FieldError]
この例では、objtype にセットされる値によって、使用出来るメンバ変数が切り替わります。
objtype の値とアクセスしようとした変数がアンマッチの場合、ランタイムエラーが発生します。
Nimでのメゾットはプロシージャまたは、(この後説明する)メゾットの糖衣構文による実装となります。
マグロ5
Nimでポリモフィズムを実装しようとした際、以下のコードでは期待通りの出力は得られません。
IKA IKA
これは、プロシージャは通常コンパイル時に静的に実行先が決められてしまうため、引数の型が親オブジェクトのものである限り、親オブジェクトのメゾットしか呼ばれないことになります。
呼び出し時にインスタンスの型をチェックして適切な実行先を動的に決定するためには、プロシージャの定義に、proc ではなく、method を使用します。
EBI1 EBI2
ベースとなるメゾットには、base プラグマを付けないとワーニングとなるので、付けています。
method は、第一引数に判定元となるオブジェクトを指定しなくてはならない制約がありますが、他はproc と同様に使用出来ます。
マルチメゾットを使用すると、引数に複数のオブジェクトが存在する場合、その全てが判定の対象となります。
(マルチメゾットを使用するためには、コンパイルのオプションに --multimethods:on を指定する必要があります)
IKA-IKA EBI1-EBI2
Nimでのプロパティの実装について、getterに関しては通常のプロシージャ構文を用いて実現できます。
setter に関しては少し特殊で、以下のように記載します。
(uni: 300)
Nimでの例外は次のように記載します。
OverflowError over- or underflow finally!!!
例外を発生させるには、raise を使用します。
Error: unhandled exception: ERROR!!!!! [Exception]
引数は省略可です。
その場合、前回発生した例外をそのまま渡します。
対処すべき例外を明確にしたい場合、{.raises.} プラグマを用いると、記載されていない例外が発生し得る場合にコンパイルエラーとなります。
これによって、プログラムの改変等により新たな例外が発生する状況となった場合にコンパイルエラーとなり、対応漏れを防げます(という役割だと思う)
{.effects.} プラグマを使用することで、その時点で発生しうる例外の一覧をヒントとして出してくれます。
D:\Projects\nim\nimtest01\test01.nim(8, 6) Hint: ref IOError [User] D:\Projects\nim\nimtest01\test01.nim(9, 6) Hint: ref OSError [User]
ただ何故か上の例で書いた OverflowError とかは検知してくれないんですよね。
明示的な raise 由来のものしかダメということ? 役に立つのか疑問。。。
Nimでもジェネリックスは普通に使えます。
iKani:5 iTako:6 iIka:4 sKani:蛸 sTako:烏賊 sIka:蟹
テンプレートはNimの抽象構文ツリー上で動作する置換処理らしい。
何か分かったような、分からないような。
コンパイル時に展開される処理であるが、C言語の define のような単なる文字の置換えではなくて、Nimの構文の流れに沿った定義がされるという解釈でよろしいかな?
使い方自体はそれほど難しくなく、プロシージャの proc 部分を template に置換えるイメージ
TAKO10
テンプレートは引数としてブロックも渡すことがですます。 その場合、最後の引数の型を untyped として渡すそうです。
NOT KANI!! EBI SABA
う〜ん、やってる事は分かるけど、typed とか untyped とか、正直自分の中で理解したとは言い難いですね。 この後 macro とかも調べなくてはいけないし、分かるのか?
と思いつつ、今回はこの程度で。。
以上になります。