proc userDefinedFunction(value:int)
proc mylibFunction() =
...
userDefinedFunction(value)
...
import mylib
proc userDefinedFunction(value:int) =
...implementation...
mylibFunction()
What I am trying to do is to simplify this file. The functions setStartValues, calculateValues, eventUpdate are used by modelexchange.nim. That's the reason why I include it here. I'd like the user to just import something on the top of its file, instead of having to add a number of includes at the bottom.
Why not just take the procedure as a parameter?
proc myLibFunction(userDefinedFunction: proc(value: int)) =
# …
You also may use inheritance as a replacement of interface.
Define base class in lib with all the methods throwing errors
And inherit it in the app, and define the behaviours for those methods.
Or, similar to xigoy suggested, you can define in library proc as generic fn[ObjWithFunctions] and pass the actual object with actual functions in your app.
The thing is that I need to fulfill a C API and it complains when trying to export non final procs (or something like that, I don't remember well the error).
At the moment, I am using a template like this in order to hide those lines:
template myCode*(body:untyped) {.dirty.} =
## organize the code, keeping the required includes at the end
{.push exportc, dynlib.}
body
{.pop.}
include lib/functions/modelexchange
include lib/functions/cosimulation
include lib/functions/common
include lib/functions/setters
include lib/functions/others
include lib/functions/getters
You can do this:
#mylib.nim
proc userDefinedFunction(value:int) {.importc, nimcall.}
proc mylibFunction*() =
userDefinedFunction(1)
#myapp.nim
import mylib
proc userDefinedFunction(value:int) {.exportc, nimcall.} =
echo value
mylibFunction()
It works because it's possible to defer the symbol resolution to link-time by using the FFI.
No need for fancy function pragmas or using exportc, you could just use function references:
#mylib.nim
var userDefinedFunction*: proc(value:int)
proc mylibFunction*() =
userDefinedFunction(1)
#myapp.nim
import mylib
userDefinedFunction = proc (value:int)=
echo value
mylibFunction()
well with treeform's example it actually does that, but that's only because once mylibFunction is inlined the proc call with appear.
If you add anything more complex inbetween (like a echo in my case) it doesn't work anymore, because C compilers don't seem to reason at such grand scheme about the usage of variables.
This is how the decompilation looks in Ghidra:
userDefinedFunction__mylib_u3 = colonanonymous___myapp_u2;
echoBinSafe.constprop.0((longlong *)&TM__wfpdBMSRfuTGK9aKTtj9beBg_2,uVar7,_Env,in_R9);
(*userDefinedFunction__mylib_u3)(1);
Nim does have a mechanism to achieve this cross module forward declaration and it is as always generics or template. A generic based implementation is as follows:
type ImplIt = distinct void
proc doThing(t: typedesc[ImplIt]) =
mixin doOtherThing
doOtherThing()
proc doOtherThing() =
echo "this is other thing"
echo "yep"
doThing(ImplIt)