This version does type-checking (correctly pointing to procedure definition),
and allows that simple method invocation syntax.
type
BinaryTree*[V; cmp: static[proc(a, b: auto): bool]] = object
# different ways of providing a procedure
# an `echo` is added to each of them, to distinguish
const less1 = proc(a, b: int): bool = (echo 1; a < b)
type T1 = BinaryTree[int, less1]
var tree1: T1
const less2 = proc(a, b: int): bool = (echo 2; a < b)
var tree2: BinaryTree[int, less2]
proc less3(a, b: int): bool = (echo 3; a < b)
type T3 = BinaryTree[int, less3]
var tree3: T3
proc less4(a, b: int): bool = (echo 4; a < b)
var tree4: BinaryTree[int, less4]
var tree5: BinaryTree[int, proc(a, b: int): bool = (echo 5; a < b)]
import macros
proc desymbolize(node: NimNode): NimNode =
result = node
while result.kind == nnkSym:
result = result.getImpl
# the macro can be quite short, if to restrict to just one of formats above
macro compare(v: typed): auto =
var p=v.getImpl[1]
var ty: NimNode
if p.kind == nnkSym:
p = p.getImpl
expectKind p, nnkTypeDef
expectKind p[2], nnkBracketExpr
expectKind p[2][2], nnkSym
ty = p[2][1]
p = p[2][2]
else:
ty = p[1]
p = p[2]
if p.kind == nnkSym:
p = p.getImpl
else:
p = p[0]
let prm = params(desymbolize p)
if prm.len != 2 or prm[1].len != 4 or prm[1][2] != ty:
error("Wrong comparison procedure provided, signature should be " &
"``proc(a, b: " & $ty & "): bool``.\n", p.desymbolize)
if p.kind == nnkProcDef:
p = p[0]
p
template compare*[T: BinaryTree, V](bt: T, a, b: V): bool =
compare(bt)(a,b)
# testing
var n = 20
echo tree1.compare(n, 30)
echo tree2.compare(n, 30)
echo tree3.compare(n, 30)
echo tree4.compare(n, 30)
echo tree5.compare(n, 30)
Run