Functions
A function is defined in either a namespace or a named type (class, interface, record, union, enum or bitfield). (Although a callback is a named type, it does not define any functions.) No function is defined at the top level, outside a namespace.
A function may be marked as a method or a constructor:
A function in a class or interface may be a method if its first argument is an instance of the class or interface.
A function in a class or interface may be a constructor if it returns a new instance.
SML has no concept of classes so this distinction is not particularly significant except that the instance argument of a method is treated differently in the SML interface, as described below.
Referring to functions
For a function some_function_name in a namespace Namespace, the hierarchical SML name is Namespace.someFunctionName.
For example, the function shell_parse_argv in the namespace GLib is GLib.shellParseArgv.
For a function some_function_name in a named type Type in a namespace Namespace, the hierarchical SML name is Namespace.Type.someFunctionName.
For example, the function grab_focus in the class Widget in the namespace Gtk is Gtk.Widget.grabFocus.
The arguments of an introspected function are classified as ‘in’, ‘out’ or ‘inout’, indicating the direction in which the argument data flows. To enable a function to write to ‘out’ and ‘inout’ arguments with the C calling convention, such arguments are references. In the SML interface, a function does not use references for ‘out’ and ‘inout’ arguments because its arguments contain only initial values and the final values of are part of the returned value.
The specification of someFunctionName in the signature NAMESPACE or NAMESPACE_TYPE has the form:
-
val someFunctionName : inTypes -> retOutTypes
if someFunctionName is not a method;
-
val someFunctionName : instanceType -> inTypes -> retOutTypes
if someFunctionName is a method of a class or interface.
where
- instanceType
-
is:
'a class for a class, which allows an instance of the class or any subclass of the class;
t for an interface;
- inTypes
contains the types of the ‘in’ and ‘inout’ arguments, as a tuple if there are two or more and as unit if there are none;
- retOutTypes
-
contains the following types as a tuple if there are two or more and as unit if there are none:
the types of the ‘out’ and ‘inout’ arguments, if the return type is void or there is an error ‘out’ argument;
-
the return type followed by the types of the ‘out’ and ‘inout’ arguments, if:
the return type is not void, and
the return type is not gboolean or there are no ‘out’ arguments, and
there is no error ‘out’ argument
the types of the ‘inout’ arguments followed by an optional type containing the types of the ‘out’ arguments as a tuple if there are two or more, if the return type is gboolean and there are ‘out’ arguments but none is an error ‘out’ argument.
The section Calling functions, below, provides examples showing instantiations of these types.
Correspondence with C function names
In C libraries that support GObject Introspection, function names have a hierarchical form that corresponds to the hierarchical SML name as follows:
C identifier |
SML identifier |
|
⌜c_prefix⌝_⌜type_name⌝_⌜method_name⌝ |
↔ |
⌜NamespaceName⌝.⌜TypeName⌝.⌜methodName⌝ |
⌜c_prefix⌝_⌜type_name⌝_⌜constructor_name⌝ |
↔ |
⌜NamespaceName⌝.⌜TypeName⌝.⌜constructorName⌝ |
⌜c_prefix⌝_⌜type_name⌝_⌜function_name⌝ |
↔ |
⌜NamespaceName⌝.⌜TypeName⌝.⌜functionName⌝ |
⌜c_prefix⌝_⌜function_name⌝ |
↔ |
⌜NamespaceName⌝.⌜functionName⌝ |
The relationship between c_prefix and NamespaceName is, in principle, arbitrary but standard libraries use a standard mapping as follows:
c_prefix |
NamespaceName |
g, glib |
GLib |
g |
GObject |
g |
Gio |
g |
GModule |
atk |
Atk |
pango |
Pango |
gdk |
Gdk, GdkX11 |
gtk |
Gtk |
gtk_source |
GtkSource |
The relationship between other placeholders is simply the difference in character case and separator convention as indicated by the placeholder names. For instance, type_name and TypeName represent identifiers containing the same words where
type_name indicates that all words are lowercase and separated by underscore characters;
TypeName indicates that all words have an uppercase initial character and lowercase subsequent characters and are not separated by any character.
For example, to convert a C identifier to an SML identifier, first split the name into its hierarchical components and then convert each field:
C identifier |
SML identifier |
|||
g_io_add_watch |
↔ |
g.io_add_watch |
↔ |
GLib.ioAddWatch |
gtk_text_buffer_insert_at_cursor |
↔ |
gtk.text_buffer.insert_at_cursor |
↔ |
Gtk.TextBuffer.insertAtCursor |
Calling functions
Non-method functions
For a non-method introspected function, the corresponding SML function takes a tuple for the inputs containing the (before) value of the ‘in’ and ‘inout’ arguments and returns a tuple for the outputs containing the return value, if the return type is neither void nor gboolean, followed by the (after) values of the non-error ‘out’ and ‘inout’ arguments.
For example, given a call to a non-method C function f as follows:
ret = f (in1, &inout2, &out3, &out4, in5, &error);
the corresponding SML function could be called as follows:
val (ret, inout2', out3, out4) = f (in1, inout2, in5)
Note that the argument error is not treated like a normal ‘out’ argument in SML as described in the section Errors, below.
If the return type is void, no return value is included in the returned tuple.
For example, if the return type of f is void, the corresponding SML function could be called as follows:
val (inout2', out3, out4) = f (in1, inout2, in5)
A tuple must have two or more elements. Therefore, if the input or output tuple would have:
no elements, it is replaced by the unit value ();
one element, it is replaced by that element.
For example, if an introspected function get_x has no arguments and has a non-void return type, the corresponding SML function could be called as follows:
val x = getX ()
and if an introspected function set_x has one ‘in’ argument and has return type void, the corresponding SML function could be called as follows:
val () = setX x
Method functions
For a method function, the corresponding SML function takes the instance object as an initial curried argument and returns an SML function that takes the remaining arguments as described above for a non-method function.
For example, given a call to a method m on an object obj in C as follows:
ret = m (obj, in1, &inout2, &out3, &out4, in5, &error);
the corresponding SML function could be called as follows:
val (ret, inout2', out3, out4) = m obj (in1, inout2, in5)
There is no partial evaluation after applying the SML function to just the instance argument.
If the method function is defined in an interface but the instance argument has the type of a class that implements the interface, the instance argument must be converted explicitly as described by the section Implemented interfaces.
For example, if the method function m is from an interface Iface in a namespace IfaceNamespace and obj has the type of a class Class in a namespace ClassNamespace that implements the interface, the SML function m could be called as follows:
val (ret, inout2', out3, out4) = m (ClassNamespace.Class.asIface obj) (in1, inout2, in5)
Argument types
The SML type of an argument or the return value is based on the corresponding C type as described in Types.
If an argument or return value has an introspection annotation that marks it as optional, its SML type is t option where t is the SML type corresponding to the C type of the argument.
Object types
An object value that is an instance of any subclass of C is guaranteed to be an instance of a class C. To avoid the need to explicitly upcast object values, the object type for a class C or any subclass of C is used where an instance of class C occurs in
the argument of a constructor, method or function and
the result of a callback function
Conversely, an object value that is guaranteed to be an instance of a class C is not guaranteed to be an instance of any subclass of C. Therefore the object type for a class C but not a subclass of C is used where an instance of class C occurs in
the result of a constructor, method or function and
the argument of a callback function
Unsupported arguments
An introspected function may allow ‘out’ (and, possibly, ‘inout’) arguments to be omitted when called by passing a null reference. The corresponding SML function does not omit any argument so the introspected function is called with all arguments.
Introspected functions that use varargs have no SML equivalent. Alternative functions should be available that provide the same capablity.
Conditional ‘out’ arguments
An introspected function may write to ‘out’ arguments conditionally. To avoid uninitialized values in SML, the value of an ‘out’ argument is not returned by the corresponding SML funtion when it is not written.
At present, a heuristic must be used to determine which ‘out’ arguments are written conditionally because GObject introspection annotations do not specify this information.
For an introspected function without an error argument that does not have return type gboolean, all ‘out’ arguments are considered to be written unconditionally.
For an introspected function without an error argument that has return type gboolean, all ‘out’ arguments are considered to be written conditionally, being written if and only if the function returns true.
For an introspected function with an error argument, it is assumed that if no error is raised, all (non-error) ‘out’ (and ‘inout’) arguments are written, as described in the section Errors, below.
(A proposal to introduce GObject Introspection annotations that specify the condition under which an ‘out’ argument is written is given in the comment https://bugzilla.gnome.org/show_bug.cgi?id=626721#c3.)
An introspected function without an error argument whose return type is gboolean returns a tuple for the outputs containing an optional tuple containing the (after) values of the ‘out’ arguments conditional on the return value, which is non-nil if and only if the return value is true, followed by the (after) values of ‘inout’ arguments.
For example, given a call to a C function h whose return type is gboolean as follows:
if (h (in1, &inout2, &out3, &out4, in5))
{
/* can use inout2, out3, out4 */
…
}
else
{
/* can use only inout2 */
…
}
the corresponding SML function could be called as follows:
let
val (inout2', condOuts) = h (in1, inout2, in5)
in
case condOuts of
SOME (out3, out4) => …
| NONE => …
end
A tuple must have two or more elements. Therefore, if the tuple for the conditional outputs would have one element, it is replaced by that element.
Errors
A C function reports an error by including an ‘out’ argument of type GError * as the last argument. (The extra level of indirection for an ‘out’ argument means that the C type will actually be GError **.)
For example, the declaration of the non-method C function f mentioned in an earlier example, which case raise an error, is as follows:
ty
f (ty1 in1,
ty2 *inout2,
ty3 *out3,
ty4 *out4,
ty5 in5,
GError **error);
An error is raised by a C function if the (after) value of the error ‘out’ argument is a reference to a GError. Otherwise no error is raised.
For example, the C function f could be called as follows, assuming the return type ty is not void:
GError *error = NULL;
ret = f (in1, &inout2, &out3, &out4, in5, &error);
if (error != NULL)
{
/* handle error, cannot use ret, inout2, out3 and out4 */
…
}
else
{
/* no error, can use ret, inout2, out3 and out4 */
…
}
If an error is raised, the corresponding SML function raises the exception GLib.Error (ex, error) where
ex of type exn is the error exception, which allows the domain and code to be pattern matched
error of type GLib.Error.t is the (after) value of the error ‘out’ argument.
Therefore, the SML function provides neither the return value nor the (after) values of non-error ‘out’ and ‘inout’ arguments of the corresponding introspected function if an error is raised: it is assumed that these provide no information further to the error.
The SML function returns a tuple for the outputs containing the return value, if the return type is neither void nor gboolean, followed by the (after) values of the non-error ‘out’ and ‘inout’ arguments.
For example, the SML function corresponding to C function f could be called as follows:
let
val (ret, inout2', out3, out4) = f (in1, inout2, in5)
in
…
end
handle
GLib.Error (_, error) => …
As the tuple of outputs is returned by the SML function only if no exception is raised, it does not include the (after) value of the error ‘out’ argument because it would never contain an error. Also, the return value in the output tuple never has an error-specific value so it is not included in the output tuple if the return type is gboolean because it is assumed that a boolean return value indicates success, i.e. no error, so would always return true. The non-error ‘out’ arguments are assumed to be written unconditionally so the section Conditional ‘out’ arguments does not apply if there is an error ‘out’ argument.
For example, the C function f could be called as follows if the return type ty is gboolean (i.e. the return value indicates success):
GError *error = NULL;
if (!f (in1, &inout2, &out3, &out4, in5, &error))
{
/* handle error, cannot use inout2, out3 and out4 */
…
}
else
{
/* no error, can use inout2, out3 and out4 */
…
}
and the corresponding SML function could be called as follows:
let
val (inout2', out3, out4) = f (in1, inout2, in5)
in
…
end
handle
GLib.Error (_, error) => …