Would it be possible to automate writing the implementation ...
Yes, it would be possible to automate implementation of just about anything using nim macros that take typed
argument (and then getTypeImpl
)
import std/macros
macro dumpImpl(arg: typed): untyped =
echo arg.getTypeImpl().treeRepr()
proc rcall*[A, B, R](fn: string, a: A, b: B, _: type[R]): R =
echo (fn, a, b)
proc multiply(a, b: int): int
proc multiply(a, b: int): int =
rcall("multiply", a, b, int)
dumpImpl multiply
Shows that multiply
type (function signature) has the following structure:
ProcTy
FormalParams
Sym "int"
IdentDefs
Sym "a"
Sym "int"
Empty
IdentDefs
Sym "b"
Sym "int"
Empty
Empty
Although it is important to keep in mind that overloaded procedures cannot be easily resolved based only on name (because, well, there are many implementations). The most obvious choice would be to still use typed
argument, but pass some parameter to disambiguate the function call
import std/macros
macro dumpImpl(arg: typed): untyped =
echo arg.treeRepr()
proc overload(a: string) = discard
proc overload(a: int) = discard
dumpImpl overload
# ClosedSymChoice - lists all possible overloads with their respective symbols
# Sym "overload"
# Sym "overload"
dumpImpl overload("123")
#Call
# Sym "overload"
# StrLit "123"
dumpImpl overload(123)
#Call
# Sym "overload"
# IntLit 123
As a small (personal) side note - when you are talking about nim macros the question should mostly be not "if this is even possible?" but rather "what is the most optimal way to do this?". It might require some knowledge of macro tricks, but it is possible to implement almost anything.
EDIT1 (add implementation code example, reply to question in comments):
import std/[macros]
proc rcall*[A, B, R](fn: string, a: A, b: B, _: type[R]): R =
echo (fn, a, b)
macro remotefn(fn: typed) =
let fname = fn.str_val()
# `quote do` generates hygienic identifiers - i.e. all new
# variables/functions introduced by it are unique and not visible in
# global. To fix this you need to explicitly create identifier for your
# procedure using `ident`
let
multId = ident("multiply") # < Function name identifier
# Same goes for variables - nim does have a name-based overloading, so
# you need to make sure function arguments use the same identifiers as
# the original one
aId = ident("a")
bId = ident("b")
result = quote do:
proc `multId`(`aId`, `bId`: int): int =
rcall(`fname`, 1, 1, int)
echo result.toStrLit()
proc multiply(a, b: int): int
remotefn multiply