【IRIS/Cache】コーディングを減らす!マクロの料理法(基本編)

本記事は、鮪の料理方法を解説・・・ではなく、マクロ(基本編)について解説致します。

※この記事は下記の方向けになります。
  • コーディングを楽にしたい方
  • チームで共通のコーディング方法を目指したい方
  • マクロ初心者の方

はじめに

プログラミングにおいて効率化は欠かせないテーマです。

IRIS/Cacheでは「マクロ」を活用することで、コードの簡素化や保守性の向上、さらにはチーム全体で統一感のあるコーディングが実現できます。

一方で、「マクロとは何か?」「どのように設定すればよいのか?」と疑問を感じる方も少なくないでしょう。

この記事では、IRIS/Cacheにおけるマクロの基本、活用方法、そしてその利点について分かりやすく解説します。
マクロの基礎を押さえ、実際の開発に活かすことで、日々の業務をより効率的に進められるようになります。

それではさっそく、マクロについて詳しくみていきましょう。

マクロとは

マクロとは、コード内で繰り返し使用する定義や記述を効率的に管理するための仕組みです。

サンプルを元に、簡単に確認していきましょう。

マクロの定義

インクルードファイルの作成

汎用的に使用したいのであれば、インクルード・ファイル(.inc)を作成します。
 → 本記事では、「Sample.inc」を作成しました。

ファイルが作成できたら、ついでにマクロを1つ作成してみましょう。

マクロの記述方法は、後述します。
※今回はサンプルとして、「#define」、マクロ名「GetMacroData」、式「$g(^macro.test(%arg))」を記載します。

#define GetMacroData(%arg) $g(^macro.test(%arg))

関数内でのマクロ

関数内でもマクロを設定する事が可能です。

【サンプル】

ClassMethod testMacro()
{
	#define Name  "サンプル出力"
	#define TEST w !,$$$Name
	$$$TEST
}

ターミナルで実行してみます。

【実行結果】
サンプル出力

特定の定数や処理を、何度も繰り返し使用する場合に便利ですね。
修正も1か所で済みます。

では次に、作成したマクロを使用してみましょう。

インクルードファイルの設定とマクロの使用方法

先ほど作成したインクルードファイル「Sample.inc」を読み込みます。

実行クラス「developer.macro.Sample.cls」を作成し、先ほど作成した「Sample.inc」ファイルを読み込むコマンド「Include」を記述します(※1行目)。
 ※複数読み込む場合は、Include (xxx, yyy, zzz)と記述

後は、「$$$ + マクロ名」で作成したマクロを使用する事が出来ます。

Include Sample

Class developer.macro.Sample
{
ClassMethod start()
{
	k ^macro.test
	s ^macro.test("start")="マクロ生活の開始"
	
	w $$$GetMacroData("start"),!
	w $g(^macro.tset("start"))
}
}

下記コマンドをターミナルで実行すると、「マクロ生活の開始」が2行表示されます。

d ##class(developer.macro.Sample).start()
// > マクロ生活の開始
// > マクロ生活の開始

マクロの動作確認

ご存じの通り、クラス「developer.macro.Sample.cls」をコンパイルすると、中間ソースファイル(.intファイル)が生成されます。

この.intファイルが、最終的に実行されるコマンドの形になっているので、確認してみましょう。

start() methodimpl {
	k ^macro.test
	s ^macro.test("start")="マクロ生活の開始"
	w $g(^macro.test("start")),!
	w $g(^macro.tset("start")) }

4行目と5行目が同じコマンドになっているのが分かります。

いかがでしょうか。
マクロの良い点は下記3点だと考えます。

マクロのメリット3点
  1. コーディング量の減少:長いコードを短縮できる
  2. 一貫したロジック  :コーディングルールが統一化される
  3. メンテナンス性の向上:変更箇所が集約されているのでメンテナンスが容易

また、%ZLANGルーチンとは異なり、余計なオーバーヘッドが無いのも魅力ですね。

マクロの定義方法

本記事では、一番オーソドックスな形をご紹介致します。

書き方

マクロの記述方法は下記になります。

マクロ名

  • スペース、アンダースコア、ハイフン等の記号が使えません
  • 大文字、小文字を区別する必要があり
  • max500文字だそうですが、試したことはありません(汗)
  • 日本語OKです。
  • ISCで始まるマクロ名はNG

値・関数・式

記述した内容が、そのまま.intファイルに展開されます。
式の場合、「()括弧」で括った方が良いです。

引数について

引数には、必ず「%」で始まる必要があります。

下記サンプルは、$horologの値を引数「%val」として設定しています。

#; 日付変換
#define CnvSDate(%val) ($tr($zd(%val,3),"-", "/"))
ClassMethod test()
{
	w $$$CnvSDate($h)
}

【実行結果】
2025/01/29

マクロのサンプル

文字列や数値を展開したり、式やコマンド等も展開可能です。

【マクロ】

#; サンプル
#define GetMacroData(%arg) $g(^macro.test(%arg))

#; 値
#define Cmnt1 "飲み会は%1日に決定しました。"
#define Cmnt2 2
#define Cmnt3(%val) ##expression(%val * 180)


#; 日付変換
#define CnvSDate(%val) ($tr($zd(%val,3),"-", "/"))

#; クラスメソッド実行
#define WriteCmnt ##class(developer.macro.Sample).WriteCmnt()

#; コメントも展開される
#define TestCmnt w "test",! // このコメントも展開される!

【使用例】

ClassMethod test()
{
	w $$$FormatText($$$Cmnt1, $$$CnvSDate($h)),!
	w $$$FormatText("	※日本酒は%1合(%2ml)までです。", $$$Cmnt2, $$$Cmnt3($$$Cmnt2)),!
	
	$$$TestCmnt // コマンド実行
	d $$$WriteCmnt
}

ClassMethod WriteCmnt()
{
	w "クラスメソッド実行",!
}

【実行結果】
飲み会は2025-01-29日に決定しました。
    ※日本酒は2合(360ml)までです。
test
クラスメソッド実行

赤い文字がマクロで定義した値になります。

.intファイルの状態です。
マクロの「値・関数・式」にコメントを記載すると、そのまま展開されているのが分かります。

WriteCmnt() methodimpl {
	w "クラスメソッド実行",! }
test() methodimpl {
	w $$FormatText^%occMessages("飲み会は%1日に決定しました。", ($tr($zd($h,3),"-", "/"))),!
	w $$FormatText^%occMessages("	※日本酒は%1合(%2ml)までです。", 2, 360),!
	w "test",! // このコメントも展開される! // コマンド実行
	d ##class(developer.macro.Sample).WriteCmnt() }

複数行

マクロの定義で「##continue」を末尾に付与すると、改行が行え複雑な処理を記述する事ができます。

サンプルでは、SQLの実行をマクロにしてみました。

【マクロ】

/// sqlの実行を楽にする
#define SQLGO(%rset, %query, %param) ##continue
	s stmt = ##class(%SQL.Statement).%New(1) ##continue
	s %rset = stmt.%ExecDirect(, %query, data...) ##continue

【使用例】

ClassMethod sql()
{
	k data
	s data(1)="%埼玉%"
	, data(2)=3
	, data=2
	$$$SQLGO(rset,"select ID,カナ氏名,性別,漢字氏名,生年月日 from developer_data.Patient2 where 漢字氏名 like ? & 性別=?", data)
	while( rset.%Next()){
		w !,rset.ID,",",rset.カナ氏名,",",rset.性別,",",rset.漢字氏名,",",rset.生年月日
	}
}

【.intファイル展開】

sql() methodimpl {
	k data
	s data(1)="%埼玉%"
	, data(2)=3
	, data=2
	s stmt = ##class(%SQL.Statement).%New(1) 
	s rset = stmt.%ExecDirect(, "select ID,カナ氏名,性別,漢字氏名,生年月日 from developer_data.Patient2 where 漢字氏名 like ? & 性別=?", data...) 
	while( rset.%Next()){
		w !,rset.ID,",",rset.カナ氏名,",",rset.性別,",",rset.漢字氏名,",",rset.生年月日
	} }

ダイナミックSQLのように、クエリの実行時に「お約束事」がある場合は、それらをマクロ化する事でコーディングが楽になります。

ただ、これに慣れてしまうと、マクロの無いプロジェクトに配属された時に、SQLが書けなる弊害があったります。
 ※個人差あり

一長一短ですかねー。

あると便利なマクロ

マクロを使って、手軽に色々な処理が書けるようになりました。

次に紹介するのは、マクロとして設定しておくと、コーディングが捗るマクロになります。(マクロ名は任意)。

【クラス名と関数名の取得】

/// クラス名
#define className ##Expression($$$quote(%classname))
/// 関数名
#define methodName ##Expression($$$quote(%methodname))
/// 合成情報
#define info(%line) $$$methodName_"+"_%line_"^"_$$$className

【文字操作系】

/// 改行
#define CRLF $c(13,10)
#define CR $c(13)
#define LF $c(10)
/// TAB
#define TAB $c(9)

【時刻関連】

#define timeH $p($h,",",2)
#define aTimeH(%h) $p(%h,",",2)
#define time $zt($$$timeH,1)
#define nowNum $tr($zdt($h,3,1),"-: ")

他にも業務において、あると便利な処理をマクロ化していくと色々と捗ります。

おわりに

いかがだったでしょうか。

マクロは、ObjectScriptでの効率的なコーディングをサポートする便利な仕組みです。

コードを簡潔にし、一貫性を保ちながらメンテナンスもしやすくなります。
特に、繰り返し使う定数の管理に役立つと思います。

うまく活用すれば開発効率が向上し、コーディングがスムーズになりソースの可読性も上がります。
 →バグの抑制にも一役買いそうですね。

まずはシンプルなマクロの定義から試していき、少しずつ慣れていくと良いでしょう。