Vala bindings for an unusual C ownership function signature

Nautilus extension modules are required to have a function with the following signature:

 * nautilus_module_list_types:
 * @types: (out) (array length=num_types): array of GType *
 * @num_types: the number of types in the array
 * Called after the extension has been initialized and has registered all the
 * types it exports, to load them into Nautilus.
void nautilus_module_list_types (const GType **types,
                                 int          *num_types);

that is, types is an output, despite being const. I haven’t been able to come up with an appropriate Vala function signature to match this. The best I have is:

public void _nautilus_module_list_types([CCode (array_length_type = "int")] out Type[] types)

But this does not generate the const modifier and compilation fails.

I’m wondering: is there some kind of annotation I can add here to generate the correct C function signature? The Vala bindings tutorial seems to suggest that it is possible to change the const status, but I’m not sure exactly how.

If it’s helpful, the relevant part of the Gir file is the following:

        <parameter name="types"
          <doc xml:space="preserve"
               line="53">array of GType *</doc>
          <array length="1" zero-terminated="0" c:type="const GType**">
            <type name="GType" c:type="GType*"/>
        <parameter name="num_types"
          <doc xml:space="preserve"
               line="54">the number of types in the array</doc>
          <type name="gint" c:type="int*"/>

After some discussion on Matrix, it seems that there is no way to control the C type of an array as of yet in Vala. See this issue:

The workaround I’m currently using is to use some shim C code to drop the const modifier.

At the minimum, the annotations need to be fixed: the array cannot be const and transfer full. If the array is const it should be transfer none.

The C API doesn’t really make much sense either, though. Instead of using an out argument, it should return the GType C array, and either terminate it with G_TYPE_INVALID, or take num_types as the out argument for the length of the array.

1 Like

I think what the const modifier is expressing (granted, poorly) that the returned array must have a static lifetime, which is how all of the C-based extensions I’ve looked at behave. Looking at the source of Nautilus/Files, it seems to (1) iterate over the returned list of types and (2) create a new object for each – does that constitute transfer full in your view?

I’m not familiar enough with GLib to know what would happen if the underlying type was GC’d in this case.

Nautilus’s extension API is very old and established at this point, so while it’s arguable this is a mistake, it’s not a mistake that can be fixed without breaking every existing extension.

The transfer full annotation means that the ownership of the “out” argument is transferred from the callee (the function) to the caller—i.e. the caller is now responsible for freeing the array. This is entirely incorrect, as the module owns the list of types, and it’s merely returning a pointer to it. The correct transfer annotation is, thus, transfer none. What the caller does or does not do with the returned array is inconsequential: the ownership stays with the callee.

Nevertheless, this is pointless to begin with, because this function does not exist in the ABI; it’s defined by the extension, and the extension is not going to call it. The whole function should be annotated with (skip).

1 Like

That makes sense to me, thanks.

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