> I am not sure what is going on with RED though, that seems very different 
> than the original code, but I'm sure it makes sense, if I look at what 
> Futhark outputted.

In the C code it's a union between a uint32 and a struct with four uint8 fields 
as you say. Nim doesn't have anonymous structs so it gets turned into a union 
between a uint32 and an object with a auto-generated name. It's compatible with 
the C code, and you can still assign to the uint32 as you would expect from C. 
It's just that it looks a bit strange since Nim and C differs a bit with how 
unions and anonymous structs are done.

> I dunno if they really are "hard to understand", but I have a hard time 
> telling what is nim, and what is Futhark, and what any of those chunks of 
> code are doing doesn't totally make sense to me. I am learning nim at the 
> same time, so it's a lot of new stuff.

I can see that it would be a bit overwhelming. But everything is Nim, Futhark 
is just a library that you import in Nim like any other, and it reads its 
settings from the `importc` block (which still just takes normal Nim code. I'm 
writing an article on wrapping libraries with Futhark at the moment, which 
should take people all the way from just getting things from C into Nim to have 
fully GC managed data structures and async-capable libraries.

> When I look at things like this raylib binding it makes a lot of sense right 
> away, because I already know how raylib bindings will work, and maybe 
> incorrectly encourages me to not use any kind of wrapper (because it covers a 
> huge API without Futhark.) That might be a bad example, though, since like we 
> do on node-raylib, they auto-generate the binding-code from raylib's 
> definitions, and it's very tailored to that.

Well that is still a wrapper, just a manually maintained one. The goal of 
Futhark is to auto-generate the C <-> C-like Nim part so that library 
maintainers can focus on the C-like Nim <-> Idiomatic Nim part. It basically 
just gives Nim the ability to read C headers so that you don't have to manually 
write Nim "headers" for your C files.

> There are lots of things I have no idea how to translate, for example a 
> byte-array as a C pointer. I don't know what that should be, in nim. I 
> started with a fixed-length array, but that would only support a single 
> screen-resolution. I used seq because the size of the array depends on the 
> dimensions of the screen, but doesn't change again, after you initially 
> allocate it.

Well you just need to keep in mind what a byte-array as a C pointer really 
means. C just gets a pointer to the first element of contiguous bytes in 
memory, along with a count to read as a separate argument (or possibly a width 
and a height in the case of a screen resolution). So to replicate passing such 
a buffer in Nim you just need to supply a pointer to an element. Which kind of 
data structure is actually used to hold the data isn't really that important, 
as long as the data is contiguous. So if you want to pass a `seq[byte]` from 
Nim to C you will have to do something like `my_c_func(myNimSeq[0].addr, 
myNimSeq.len)`. This passes a pointer to the first element in the sequence, and 
the amount of bytes it can safely access at that address. The code would look 
exactly the same for an array, but as you pointed out these are static in size, 
so for a dynamically adapted screen size it probably isn't the right choice of 
data structure. Just keep in mind that Nims GC isn't able to see if C holds on 
to a copy of the pointer you pass in. So if you don't use the data in Nim 
afterwards the GC will free it at some point, and C might access the pointer 
and crash your program. There are ways around this though, like `GC_ref` to 
manually increase the refcount, or just using manually allocated memory if C 
intends to free the buffer once it's done with it. For things which returns 
such a pointer you can use the `ptr UncheckedArray[byte]` type, this will tell 
Nim that this is a pointer to an array of bytes, but we don't know how many so 
we can't do range checks on it. Essentially what this means is that you will be 
able to use array semantics on it, but you will have to manually make sure you 
don't read past the end (but you've probably also got a count somehow).

> The seq doesn't seem to grow, if I don't add, and I had it running for a 
> while to test, without crashing, but you are probly right, I haven't tested 
> much more than that. In standard libretro there is no GC to clean it up, in 
> C, and it seems ok (it's very popular, with lots of great cores that don't 
> crash or eat up memory all the time.)

The seq by itself won't grow without you adding stuff to it. But for every time 
you create a GC managed resource without the GC running your memory will just 
increase and never go back down. Might not be a problem with a single sequence, 
but if you start importing other Nim libraries or actually write a game with 
your wrapper then you'll quickly run into issues. The reason standard libretro 
and cores written for it doesn't crash or have memory leaks is because the 
authors of those cores have done the memory management manually, so they 
allocate and free all the memory they use. What you're doing here is 
essentially the same as manually allocating a bunch of memory, but never 
freeing it.

> I dunno, I am getting a bit frustrated with the C/nim interop scenerio. I am 
> fairly quick with writing nim already, even as a new person, which I really 
> appreciate, and I enjoy the language, but I think I am ignoring the massive 
> time-suck that it has been to get it to work with C.

And this is why I use Futhark. With it I don't have to really care much about 
the C/Nim interop part. I just give it the C headers, and I get a complete 
wrapper with all the types correctly generated for me. Then I write my Nim 
code, with the Nim compiler alerting me to any type mismatches I might've made 
(e.g. I wouldn't be allowed to pass a `seq[int]` to something which expected a 
`int *` because those aren't compatible). I just look at the C examples and 
copy them almost verbatim into Nim, and I can use normal Nim for the rest of my 
program.

> As a sidenote, if you have a better way to make a more idiomatic libretro 
> core, you should improve this PR, if you are interested. I think they will 
> probably want it to not use a wrapping library (since it is meant to be a 
> repo of simple standalone core examples) but I am sure it could still use 
> lots of improvements.

My PR to your repo is the way I would've done it, wrap using Futhark, then just 
use it like you would in C. If they don't want the samples to require a library 
then it can use the method described under shipping wrappers to copy the 
generated wrapper into the project itself so people don't need to have libclang 
or Futhark installed to run it.

Not entirely sure how Mac and Clang handles libraries like this, it might seem 
like `LD_LIBRARY_PATH` isn't respected. But since I don't have a Mac I can't 
test this myself, I can only point you to how other Mac users have been able to 
install and use Futhark: <https://github.com/PMunch/futhark/issues/46>. I've 
using Futhark on 14.0.0, and currently on 15.0.7, so that shouldn't matter.

Reply via email to