Hello,
I'm currently creating a bridge between Julia & Nim (using Julia C-API) in order to use Julia as a scripting language for Nim. The idea is to improve Nim usability for scientific computing application.
It is currently a WIP but it is slowly taking shape, feel free to take a look : https://github.com/Clonkk/nimjl
So, I have of C-API that look like this:
uint8_t jl_unbox_uint8(value);
uint16_t jl_unbox_uint16(value);
uint32_t jl_unbox_uint32(value);
uint64_t jl_unbox_uint64(value);
int8_t jl_unbox_int8(value);
int16_t jl_unbox_int16(value);
int32_t jl_unbox_int32(value);
int64_t jl_unbox_int64(value);
float jl_unbox_float32(value);
double jl_unbox_float64(value);
This in Nim convert to the same list of functions but it would be ideal to have a generic function :
#Converting this
proc nimjl_unbox_float64*(value: ptr nimjl_value): float64 {.importc.}
proc nimjl_unbox_float32*(value: ptr nimjl_value): float32 {.importc.}
proc nimjl_unbox_int64*(value: ptr nimjl_value): int64 {.importc.}
proc nimjl_unbox_int32*(value: ptr nimjl_value): int32 {.importc.}
proc nimjl_unbox_int16*(value: ptr nimjl_value): int16 {.importc.}
proc nimjl_unbox_int8*(value: ptr nimjl_value): int8 {.importc.}
proc nimjl_unbox_uint64*(value: ptr nimjl_value): uint64 {.importc.}
proc nimjl_unbox_uint32*(value: ptr nimjl_value): uint32 {.importc.}
proc nimjl_unbox_uint16*(value: ptr nimjl_value): uint16 {.importc.}
proc nimjl_unbox_uint8*(value: ptr nimjl_value): uint8 {.importc.}
# To this :
proc nimjl_unbox[T](value:pre nimjl_value): T= ...
What would be the easiest way to achieve this (I have some ideas but I'd like to external opinion on this) ?I think that you need to have different parameters type for Nim's compiler to resolve overloading.
Yes, using when / elif is a possibility but it's a bit tedious.
What I did with nimler was essentially as Yardanico suggested.
Given your example:
proc nimjl_unbox_uint64*(value: ptr nimjl_value): uint64 {.importc.}
proc nimjl_unbox_uint32*(value: ptr nimjl_value): uint32 {.importc.}
proc nimjl_unbox_uint16*(value: ptr nimjl_value): uint16 {.importc.}
proc nimjl_unbox_uint8*(value: ptr nimjl_value): uint8 {.importc.}
you can add overloaded functions with a typedesc[target] param
proc nimjl_unbox*(value: ptr nimjl_value, T: typedesc[uint64]): T {.inline.} =
nimjl_unbox_uint64(value)
proc nimjl_unbox*(value: ptr nimjl_value, T: typedesc[uint32]): T {.inline.} =
nimjl_unbox_uint32(value)
proc nimjl_unbox*(value: ptr nimjl_value, T: typedesc[uint16]): T {.inline.} =
nimjl_unbox_uint16(value)
proc nimjl_unbox*(value: ptr nimjl_value, T: typedesc[uint8]): T {.inline.} =
nimjl_unbox_uint8(value)
To be called like:
let x = nimjl_unbox(val, uint8)
I think this is less cognitive load to the user. Still not absolutely convinced it's the right approach, just FYI.
You can of course use macros to get rid of the boiler plate
import macros
macro makeProc(T:type):untyped =
let name = "nimjl_unbox_" & $`T`
let id = ident name
quote do:
proc `id`(value: int):`T` = value.`T`
macro nimjl_unbox(value:int,type:T): untyped =
let name = "nimjl_unbox_" & $`T`
let id = ident name
try:
discard parseStmt(name & "(5)")
echo "parsed"
except ValueError:
echo "failed"
quote do:
`id`(`value`)
makeproc(uint64)
let a = nimjl_unbox(5,uint64)
echo a,',', typeof(a)
I can't figure out how to get generic foo[type](args) syntax
But with this way you at least have nimjl_value.unbox(uint64)
I had something similar in mind I was hoping there was some hidden magic I didn't know about to make my life simpler :D !
Thanks though !
Working on the Julia integration is the end goal but It'll probably be hard to have more than Arrays / Tuples / Plain Old Data types (also not all the C API of Julia is well documented).
Using Julia from Nim would be awesome! Julia has lots of Math and ML related stuff.
Sorry to point this out but Nim can already function as a scripting language and yes nimscript does not support all of Nim functionalities and some of the modules in the stdlib but wouldn't it just be better and less stressful to develop more on nimscript
It would take many years for a new language to reach maturity of ML stuff present in Python or Julia. It's not only about the language and tools, but also about documentations, examples etc.
Bridge to Julia (or Python) ML would allow to use all those tools from Nim right NOW.
Also, you don't need to use nimscript, because nim compilation is quite fast (at least for small projects) and actually could be even faster than the time required for Julia interpreter to start up (could be more than 20-40 seconds, if you use some packages like julia plot package).
You can just use compiled nim as if it's a script, recompile it every time you run it.
It would take many years for a new language to reach maturity of ML stuff present in Python or Julia.
Nitpick, Julia (and R) ML stuff is far far behind Python and actually reachable from Nim. The key value of Julia is the Physics, Fluids, Simulations ecosystem.
I tried nimterop and c2nim but wasn't able to produce usable result.
The Julia header has a lot of preprocessing name mangling and macro function while the overall documented API isn't that big, so creating the wrapper by hand was easier (also probably because I've never really used nimterop or c2nim).