> I don't see why that would cause any problems for the Nim wrappers.
The core problem is, what we can pass objects to the external lib, and later
want to get them back or delete a sub-collection of them all.
A very basic gtk3 app has this well known shape:
# nim c button.nim
import gintro/[gtk, glib, gobject, gio]
proc buttonClicked (button: Button) =
button.label = utf8Strreverse(button.label, -1)
proc appActivate (app: Application) =
let window = newApplicationWindow(app)
window.title = "GNOME Button"
window.defaultSize = (250, 50)
let button = newButton("Click Me")
window.add(button)
button.connect("clicked", buttonClicked)
window.showAll
proc main =
let app = newApplication("org.gtk.example")
connect(app, "activate", appActivate)
discard app.run
main()
Run
Here we create a single window and a button, add window and button to the app
and wait for events like button-clicked, while gtk main loop is running.
So there is no obvious owner of button widget.
Generally, our app has much more widgets, put in various containers like grids
to arrange them.
And, and here starts the trouble: We can get back widgets from GTK, for example
we can get back a button from a cell of a grid. We may need the button to
modify it, or we may put it into a different container.
Or we may want to delete a row or a column of our grid, which is deleting
multiple widgets at one.
It may be not used too often, but this activity is offered by GTK and is
generally used.
Currently gintro solves this with GC and proxy objects, that is gtk widgets are
wrapped in Nim ref object: For a widget gc_ref is applied when it is passed to
a gtk container. GTK may increase a gtk-internal ref counter when the widgets
is referenced gtk-intern multiple times, and gtk decreases the internal ref
count when widgets are removed. When gtk-intenal ref count is zero then gtk
calls Nims gc_unref() with associated finalizer, so the widget can be fully
destroyed. I an not sure if this description is really accurate, but that is
the basic principle, supported by gtk's toggle_ref concept, which was built to
support foreign GC languages. From my observaitons it seems to work well, only
drawback is delayed destruction. Delayed destruction can be a serious issue for
special cases, for example for drawing operations (cairo) where cairo drawing
context and temporary surfaces are allocated in loops called 60 times per sec.
(see bottom most example in
[https://github.com/StefanSalewski/gintro)](https://github.com/StefanSalewski/gintro\)).
With this approach sub-classing of widgets works well, as we get back from GTK
exactly our Nim object. So when we get for example a subclassed button of Nim
type MyButton, then we may get from gtk calls like grid.getFirstChild() (or
from a callback function) a Widget as basic type, but we can use Nim's 'of'
operator to test for exact subclassed type.
I think the core problem is, that without GC, gc_ref and finalizer, the Nim
world and the external lib like GTK do not really know from each other -- it is
unclear who owns an object and who may have dangling references. Similar
problems may occur with other C/C++ libs like CGAL. For example when we use a
geometric data structure from GGAL with vertices and edges, is it obvious who
owns the vertices and edges? Maybe similar problems also can occur when we
create a pure Nim GUI app using a shape like in GTK. But for a pure Nim app we
may base all Widgets on a basic container, which can guarantee a clear
ownership.
I think for GTK all that will be difficult with owned refs and without
available GC_ref. Maybe, when we restrict ourself to never deleting widgets,
then we can collect all used widgets in a Nim container, which owns them. But
that is a restriction, even a seriously one when we allocate widgets in loops,
for example cairo objects in drawing loops.