Seemingly this last issue may be bypassed with a macro.
type
BinaryTree[V; compare: static[untyped]] = 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
# the macro can be just one line, if to restrict to just one of formats
above
macro compare(v: typed): auto =
var p=v.getImpl[1]
if p.kind == nnkSym:
p = p.getImpl
expectKind p, nnkTypeDef
expectKind p[2], nnkBracketExpr
expectKind p[2][2], nnkSym
p = p[2][2]
else:
p = p[2]
if p.kind == nnkSym:
p = p.getImpl
else:
p = p[0]
if p.kind == nnkProcDef:
p = p[0]
p
# testing
var n = 20
echo compare(tree1)(n, 30)
echo compare(tree2)(n, 30)
echo compare(tree3)(n, 30)
echo compare(tree4)(n, 30)
Run
(Another issue, only for the first kind (`const` \+ `type`), if n in the
example is a constant or is replaced with a literal, that is the procedure may
be evaluated at compile-time, then it is (the side-effect will occur at
compile-time, for pure functions there's no difference).)