Nimのtuple interfaceで多重実装できるマクロをつくってみた
こんにちは、この記事では、複数のtuple interfaceを1つの型に実装するマクロを紹介します。
紹介するマクロは全て、oolibというライブラリに含まれていますので、内部の実装は割愛します。
tuple interfaceとは
NimにはJavaやKotlinのようなinterfaceが存在しませんが、tupleを使い擬似的に再現する手法があり、それをtuple interfaceと呼びます。
interfaces In Nim
NimでインターフェースとDIコンテナを使う
type
IA = tuple
a: int
IB = tuple
b: string
ClassA = ref object
a: int
ClassA = ref object
b: string
proc toInterface(self: ClassA): IA =
result = (
a: self.a
)
proc toInterface(self: ClassB): IB =
result = (
b: self.b
)
多重実装
しかし、この手法では複数のinterfaceを1つの型に実装することはできません。複数のtupleを合成して1つのtupleにしたようなものを書くことはできますが、冗長になります。
type
ClassAB = ref object
a: int
b: string
type
# 2つのtupleを合成する
IAB = tuple
a: int
b: string
proc toInterface(self: ClassAB): IAB =
result = (
a: self.a,
b: self.b
)
そこで、tuple interfaceの記述やtoInterface
、tupleの合成などのコードを自動生成するマクロをつくりました。
実装!
まずはtuple interfaceを定義するマクロをつくります。これは単に、受け取った名前とブロック内のnnkIdentDefs
を整形してtupleの定義に放り込んでいるだけです。
また、interfaceというワード自体が予約語だったため、protocol[1]という名前にしました。
protocol IA:
var a: int
protocol IB:
var b: string
複数のtuple interfaceの実装
次に、複数のtupleを受け取り、実装した型を定義するマクロをつくります。このマクロは、クラス定義とそのクラスがtupleのメンバを満たしているかを検証する処理を同時に行うので、interfaceを持つ多くの言語に倣って、以下のようなclass-likeな文法をとるようにします。
class ClassA impl IA:
...
class ClassAB impl (IA, IB):
...
しかし、このマクロで受け取れるtupleの情報は名前のみで、メンバのシグネチャなどは一切参照できません。そこで、標準ライブラリの1つであるstd/macrocacheを使います。
このライブラリは、ざっくり言うとコンパイル時におけるマクロ間でのデータのやり取りを可能にする[2]ことができます。従って、protocolで受け取ったtupleの名前をキーにしてtupleの構文木を保存すれば、classで受け取ったtupleの名前からtupleの構文木にアクセスできます。
試行錯誤の末、こんな感じになりました。
protocol Readable:
var text: string
protocol Writable:
var text: string
proc `text=`(value: string)
protocol Product:
var price: int
class Textbook impl (Readable, Product):
var
text: string = ""
price: int
class Notebook impl (Readable, Writable, Product):
var text = ""
var price: int
proc `text=`(value: string) =
self.text = value
classに渡された名前とメンバ、プロシージャから型定義のノードを組み立てつつ、それらを各tupleのノードと比較しています。実装していないプロシージャなどがある場合には該当のtupleのメンバにエラーが出るようになっています。また、class内のプロシージャには自動でその型のインスタンス自体を表すself
が挿入されています。
終わりに
今回紹介したprotocol, classは、oolibに収録されています。興味があったら覗いてみてください🙇♂️
Discussion