That function is hard for automatic bindings generation.


Current Nim bindings are obviously wrong:

$ grep -A24 "newGFileTmp" ~/.nimble/pkgs/gintro-#head/gintro/gio.nim 
proc newGFileTmp*(tmpl: cstring = ""; iostream: var FileIOStream): GFile =
  var gerror: ptr glib.Error
  let gobj = g_file_new_tmp(safeStringToCString(tmpl), cast[var ptr FileIOStream00](addr iostream.impl), addr gerror)
  if gerror != nil:
    let msg = $gerror.message
    raise newException(GException, msg)
  let qdata = g_object_get_qdata(gobj, Quark)
  if qdata != nil:
    result = cast[type(result)](qdata)
    assert(result.impl == gobj)
    fnew(result, gio.finalizeGObject)
    result.impl = gobj
    if g_object_is_floating(result.impl).int != 0:
      discard g_object_ref_sink(result.impl)
    g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
    assert(g_object_get_qdata(result.impl, Quark) == nil)
    g_object_set_qdata(result.impl, Quark, addr(result[]))

Access to iostream.impl is wrong, as FileIOStream is a Nim proxy object which we had to allocate before use. I think I have to fix it manually, teaching the bindings generator to handle it fully correct seems to be difficult.

Before I try to fix that: What is the iostream instance in the g_file_new_tmp() call, for what is it needed and do we have to free it? I think for writing to the tmp file we do need only the returned GFile, but not the iostream instance?

The GIOStream is a second return value together with the proper GFile return value. It’s an (out) parameter, and it can be used for writing/reading that temporary file that was created here while the GFile is basically its “path”. When calling the function you’d pass in a pointer to a pointer to where that stream should be stored, and it’s stored there (transfer full).

In Python and Rust such function works by returning a tuple with the GFile and the stream in the successful, non-error case.

This has to be handled the same as all other (out) parameters, it’s not really special so if this is confusing the bindings generator then you’ll probably also end up generating wrong bindings for other similar functions too.

I have this fear indeed. How do you manage to send such fine and fast replies all the time? :slight_smile:

I still have not fully understand if we have to call something like g_object_unref() on the iostream object.

I am reading



From https://developer.gnome.org/gio/stable/GFile.html#g-file-new-for-path

a new GFile for the given path . Free the returned object with g_object_unref().

Are we assumed to call g_object_unref() on the iostream?

iostream on return, a GFileIOStream for the created file. [out]

Check the gobject-introspection data:

      <function name="new_tmp"
          <parameter name="iostream"

This tells you that it’s an (out) parameter (i.e. yet another return value), and that it’s (transfer full) (you own the reference that was returned and have to unref it at some point).

In addition because this function has a GError parameter there are further semantics: if NULL is returned for the proper return value (or FALSE for functions returning bools) then it’s considered an error and the GError out parameter will be set instead (and the stream will not be set).

I’m waiting for some C++ code to compile right now :wink:

1 Like

Ah yes indeed. I was a bit lazy this morning, and maybe a bit confused about the fact that
transfer-ownership=“full” for iostream is not mentioned in the API docs.

But as this info is available in the gobject-introspection data, my generator script has this info and often uses it. I guess the current problem is that my bindings generator script handles Constructors and plain functions very differently, for constructors I seem to expect always that there are no other out parameters involved. I think we had a similar issue with one more function some months ago. I have to fix that.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.