Yes indeed.
But the fact that an object is a boxed type in first line determines how it is freed/deallocated. It makes not really a difference how we access the fields of structs. In early versions of the Nim bindings we generated all the fields of the structs, so generally we could access the fields directly. But as gobject-introspection supports getter and setter functions for all public fields in GTK3 and GTK 4, we have decided around one year ago that it makes not really sense to generate the fields. Exceptions are the stack allocated primitive types like TextIter, Rectangle, RGB-Color, graphene types and some more. We have already a lot of Nim GTK examples and some user applications, and we have never needed direct field access elsewhere. Of course there may be exceptions that we have not yet discovered.
The GstMessage is an exception, we will generate the fields for that struct and provide manually created accessor functions in the next release.
Note that Nim uses Garbage Collectors, and that we use proxy objects for the heap allocated Gobjects in combination with the GTK toggle references for true GObjects. For GstMessage we do not use toggle references as GstMessage is not a true GObject, but we use gBoxedFree for releasing memory.
So it is all fine really. The question was only if we have in opposition to most other GTK related structs to generate the fields to access the type field, and the answer seems to be that we have to do so, as Gst authors have on some way forgotten to provide a introspectable function.
If you want to know how our bindings code looks, here is a snippet of the Gst Message related code:
type
Message00* {.pure.} = object
Message* = ref object
impl*: ptr Message00
ignoreFinalizer*: bool
proc gst_message_get_type*(): GType {.importc, libprag.}
proc gBoxedFreeGstMessage*(self: Message) =
if not self.ignoreFinalizer:
boxedFree(gst_message_get_type(), cast[ptr Message00](self.impl))
when defined(gcDestructors):
proc `=destroy`*(self: var typeof(Message()[])) =
if not self.ignoreFinalizer and self.impl != nil:
boxedFree(gst_message_get_type(), cast[ptr Message00](self.impl))
self.impl = nil
proc gst_message_new_application(src: ptr Object00; structure: ptr Structure00): ptr Message00 {.
importc, libprag.}
proc newMessageApplication*(src: Object = nil; structure: Structure): Message =
fnew(result, gBoxedFreeGstMessage)
result.impl = gst_message_new_application(if src.isNil: nil else: cast[ptr Object00](src.impl), cast[ptr Structure00](structure.impl))
if result.impl.isNil:
return nil
Message00 stands for the C struct of the GstMessage, as you can see we have not created fields. But we could, gobject-introspection provides all the fields. The Message without the 00 ending is our Nim Proxy object, that is handled by the Nim GarbageCollector. And the GC uses finalizers or destructors to deallocate the C struct when the NimProxy object is released, for deallocating the C struct the gboxed types functions are used.
But I wonder why you want to know all these details. Are you writing bindings yourself? Are you the author of the JavaScript bindings?