> 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.

Reply via email to