DEV Community

ringabout
ringabout

Posted on

Wrap const char* in the Nim language

Nim language has a great FFI with C/C++ which makes it easy to use C/C++ libraries. This article introduces
how to wrap const char* in C/C++ backend.

In the Nim world, we often play with string which handles the dirty works for us such as resizing the buffer, creating/deleting the memory which can satisfy the most of our needs. However, if we want to interact with other languages, we need the power of cstring. Note that cstring doesn't mean "string in C", it means compatible string(char * in C/C++ backend, JS string in JavaScript backend and so on).

Nim doesn't provide const char * for us. But it is easy to make our own one.

You need to import const char* types from C/C++ backend using importc pragmas. Then make a distinct type for it.

type
  cstringConstImpl {.importc:"const char*".} = cstring
  constChar* = distinct cstringConstImpl
Enter fullscreen mode Exit fullscreen mode

Now, let's look at a simple example using it.

First emit the c function, then write the function declaration(nodecl pragmas means that we
do not generate the function declaration in the output codes). Finally we construct a constChar object and
pass it to the fn proc.

{.emit: """
int fn(const char* a, char b) {
  return 1;
}
"""
.}

proc fn(a: constChar, b: char): int {.importc: "fn", nodecl.}

var x = constChar("abc")
doAssert fn(x, 'c') == 1
doAssert not compiles(fn("abc", 'b'))
doAssert not compiles(fn("abc".cstring, 'b'))
Enter fullscreen mode Exit fullscreen mode

We could see that the fn proc doesn't accept string and cstring types and only the constChar type is allowed. After looking at the generated C codes using nim c -r --nimcache:nimcache app.nim or nim cpp -r --nimcache:nimcache app.nim, it does generate const char* x = "abc";.

Lastly let's look at an example with C++ backend, it has the same story as above.

Now we need to create a new .h file and overload the fn functions.

fun.h

int fn(const char* a, char b) {
  return 1;
}

int fn(char* a, char b) {
  return 2;
}
Enter fullscreen mode Exit fullscreen mode

fun.nim

proc fn(a: constChar, b: char): int {.importcpp: "$1(@)", header: "fun.h".} = discard
proc fn(a: cstring, b: char): int {.importcpp: "$1(@)", header: "fun.h".} = discard


var a = constChar("abs")
doAssert fn(a, 'b') == 1
var b = cstring("abc")
doAssert fn(b, 'b') == 2
Enter fullscreen mode Exit fullscreen mode

Run the codes above using nim cpp -r fun.nim and it works!

Reference:
https://github.com/nim-lang/Nim/issues/3720

Nim is a great language. Let's port and wrap more libraries for it.

https://github.com/nim-lang/needed-libraries/issues

https://github.com/nothings/single_file_libs

Top comments (2)

Collapse
 
kaushalmodi profile image
Kaushal Modi

Hello, thanks for sharing this! I was led to this post from this recent question post on const char by me on Nim Forums.

As a follow up, I am some basic questions ..

  1. How can we make this constChar type main stream so that every C wrapper library does not need to define this. Those libraries would also need to export this type and then we will end up with type clashes if a user imports multiple of such libraries.
  2. As the type is a distinct type, we cannot use this type until we define $, [] and may be more low level ops.
  • Do you have a full-fledged library for these const types?
  • Is there a plan to bake this into a nim stdlib?
Collapse
 
apollodevs profile image
Ahmed Muhammed Galadima

im still a noob to nim just started learning this week but i just wanna say .. you are a really amazing person and i hope you keep up with this content! thanks hopefully one day nim becomes as popular as it should be