How to wrap object fields
Not everything needs to be wrapped, for example math objects are ok. Fields with naming like xCount need to be write protected. However object like Mesh hold collections that need to be wrapped in order to implement range checks for example.
First one is easy, remove export marker and write procs, as explained in the manual:
proc glyphCount*(x: Front): int32 = x.glyphCount
My solution for the last one is to return hidden pointers (this has the cost of introducing temporaries) and define array access operators on distinct types, one for each field:
type
MaterialMaps* = distinct Material
template maps*(x: Material): MaterialMaps = MaterialMaps(x)
proc `[]`*(x: MaterialMaps, i: MaterialMapIndex): MaterialMap =
# implement range checks here
result = Material(x).maps[i]
proc `[]`*(x: var MaterialMaps, i: MaterialMapIndex): var MaterialMap =
result = Material(x).maps[i]
proc `[]=`*(x: var MaterialMaps, i: MaterialMapIndex, val: MaterialMap) =
Material(x).maps[i] = val
Tested and it works. Pros: Accidentally creating a copy: let x = x.maps is prevented by the compiler (no =copy defined for distincts), also the syntax remains the same. Cons: temporary pointer variables are introduced by the C back end.
Also worth exploring dot operators: https://nim-lang.github.io/Nim/manual_experimental.html#special-operators-dot-operators
Needs to support .[] and .[]= in order to work properly.
I even changed the parser to accept .![] but the solution is simple. Just use templates! Updated the issue.
I'm not sure I completely understand the problem. Even with range checks - usually you just pass a model to a function and this function parses it into a suitable C struct so we rarely have to interact with the internals unless we want something very specific. And at this point we might as well risk a little bit since these cases should be rare and it will be relatively simple to isolate the bug should it happen.
I don't know the main use case for this so the above can be wrong. Could you clarify the need for this? This change looks a bit involved so I wouldn't include it unless it drastically improves the ease of using the library. And there's always a reason that C works fine with it, do we really want to put more safeguards by sacrificing the familiarity with C.
In lots of examples there is:
let mapTexture = loadTexture("resources/cubicmap_atlas.png")
model.materials[0].maps[int(Albedo)].texture = mapTexture
So they are accessing raw pointers directly. With this proposal the syntax remains exactly the same but .materials and .maps is actually a template call and there is no need for returning auxiliary wrapper objects like this.
Could you provide the resulting syntax after your suggested change? It looks like model.materials[0][Albedo] where I would expect model.materials[0].maps[Albedo] as in C
The second one! Actually for ModelAnimation.framePoses I used m.framePoses[i, j] because it's ptr UncheckedArray[ptr UncheckedArray[Transform]]
It totally went over my head that `[]`, `[]=` both suffer from https://github.com/nim-lang/Nim/issues/19351 We need .copy pragma for procs as araq suggested.
It totally went over my head that
`[]`, `[]=`both suffer from nim-lang/Nim#19351 We need.copypragma for procs as araq suggested.
Does .copy pragma imply that there will be an allocation and copy somewhere? I didn't see a comment from Araq on this topic
.copy means the parameter type can't be a hidden pointer, there is a heuristic like sizeof(param) > 3*sizeof(float) that changes parameter types for non var proc parameter.