So i have a game engine core written in c99 and i would love to use nim to make it full-blown game engine. I have a struct which contains const fields, and it works fine with pure c.
// Don't mind the type names, those are configured in somewhere else in the project
typedef struct kira_renderer_batcher {
const u32 max_objects;
const u32 max_index, max_vertex;
u32 vertex_array, vertex_buffers[2]; // vao, vbo, ebo
u32 submission_counter;
kira_renderer_vertex* vertex_list;
u32* index_list;
} kira_renderer_batcher;
int main() {
static kira_renderer_batcher batch = (kira_renderer_batcher) {
1024, 6, 4, 0, {0, 0}, 0, (kira_renderer_vertex*)null, (u32*)null
};
}
I tried to use this struct in nim, but i could not find solution for assign data into constant fields. I am not sure this is going to work the way i am doing this
type batcher* {.header: "KIRA/renderer/batcher.h", importc: "kira_renderer_batcher", bycopy.}
= object
max_objects*, max_index*, max_vertex*: uint32
vertex_array*: uint32
vertex_buffers*: array[2, uint32]
submission_counter*: uint32
vertex_list*: ptr vertex
index_list*: ptr uint32
# This does not work
var batch: batcher = batcher(max_objects: 1024, max_index: 6, max_vertex: 4)
The compile error(From what i understanding it tries assign values one by one instead of just do the all in once like i did):
/home/kira/.cache/nim/main_d/@mmain.nim.c: In function ‘main__QR2FCf1rO4331t6VVp9auAA’:
/home/kira/.cache/nim/main_d/@mmain.nim.c:321:24: error: assignment of read-only member ‘max_objects’
321 | batch.max_objects = ((NU32) 1024);
| ^
/home/kira/.cache/nim/main_d/@mmain.nim.c:322:22: error: assignment of read-only member ‘max_index’
322 | batch.max_index = ((NU32) 6);
| ^
/home/kira/.cache/nim/main_d/@mmain.nim.c:323:23: error: assignment of read-only member ‘max_vertex’
323 | batch.max_vertex = ((NU32) 4);
| ^
How am i going to do this without having to remove the constant signature from the struct?? (Well i actually in theory i just need to remove macro from the nim object and it should do the job but i want to have the safety of constants)
Have you tried to define an object constant and then assign that const as init value to your object var?
Something like
type
O = object
i: int
const
OI = O(i: 7)
var o = OI
echo o.i
I've got maybe the beginnings of a workaround.
type
constint {.importc: "const int".} = int
Foo = object
a: constint
b: int
let bar = Foo(a:5,b:7)
#this worked for me, annoyingly. So I'm not reproducing properly
echo bar
var baz:Foo
#baz = bar #c error: assignment of readonly variable
copyMem(baz.unsafeaddr,bar.unsafeaddr,sizeof(Foo))
echo baz
var qux = Foo(a:6,b:8)
echo qux
baz.b=9
echo baz
This much works on play.nim-lang.org However, as soon as I tried overloading =
to hide that ugly copyMem, everything immediately broke, unable to compile for the same reasons as you describeYou're right, it doesn't, once those assignments are wrapped in a main()
You're gonna like this one even less but here you go:
.emit:"""
typedef struct Foo{
const int a;
int b;
}Foo;
typedef struct Foo2{
int a;
int b;
}Foo2;
""".}
type
constint {.importc: "const int".} = int
Foo {.importc:"Foo".}= object
a: constint
b:int
Foo2 {.importc:"Foo2".}= object
a: int
b: int
proc makeit(c:var Foo,a,b:int)=
var x = Foo2(a:a,b:b)
copyMem(c.unsafeAddr,x.unsafeAddr,sizeof(Foo))
proc main()=
var bar:Foo
makeit(bar,5,7)
echo bar.a,',',bar.b
var baz:Foo
#baz = bar #c error: assignment of readonly variable
copyMem(baz.unsafeaddr,bar.unsafeaddr,sizeof(Foo))
echo baz.a,',',baz.b
baz.b=9
echo baz.a,',',baz.b
#baz.a=11#error assignment read-only member a
main()
Foo2 has to be declared in the C source cuz otherwise the fields won't be in the right places.