A type system for high-level interfaces
- From: Marius Vollmer <mvo zagadka ping de>
- To: gtk-list redhat com
- Subject: A type system for high-level interfaces
- Date: 24 Aug 1997 14:58:39 +0200
I'd like to propose the following type system for Gtk. It will be
used at runtime to construct argument lists for signal handlers and
for setting object slots (with gtk_type_set_arg). It will also be
used to statically describe most of the functions that should be
exported to an interpreter. Basically, it should reflect the needs
and capabilities of the typical high-level language that wants to
interface to Gtk.
The primary issue here is robustness. Ideally, it should not be
possible to crash your program from the high-level language. The
second issue is to allow mostly automatic stub generation for the
interpreter glue.
I have evolved it from the current system by unifying the GTK_ARG_*
types with the GtkObject types and then adding support for the new
things.
Here is my first shot at it. Some of it has already been implemented,
but the major work will probably be to go thru all of Gtk and Gdk to
make it conform to the conventions outlined below.
The Type System
---------------
Only a few types are allowed to travel between Gtk land and
interpreter land. Some of them can be converted (each in its own
special way) and some need to be wrapped. There exist some strict
conventions to ensure proper memory handling.
At runtime, a type is identified by its numerical id. These ids are
essentially determined dynamically, so you can't count on a certain
type to always be represented by the same id. The fundamental types
(see below), however, are assigned constant ids to blend well with the
established usage of the GTK_ARG_* types.
For the static function descriptions, a type is identified by its
name. That name is also available at runtime.
Types can be arranged in a hierachy to express (single) inheritance
relationships. Types without a base class are called `fundamental'
types in this text. The set of fundamental types is fixed, because
each fundamental type has its own very special semantics and they
probably need to be handled individually by the interpreter glue.
Adding a new fundamental type generally means writing new glue code
for each interpreter.
Each fundamental type has a precise description of its semantics.
Every types that (ultimately) inherits from a certain fundamental type
must exactly adhere to this semantics. The description of the
semantics include:
- How to pass it to a function.
This includes stating the types and order of all `primitive' C types
that carry the information as well as detailing the things that the
called function is allowed to do with the values and how the
associated memory is managed.
This is expressed below as a line that looks like:
pass: ctype1, ctype2, ...
followed by the description. When it is not allowed to pass this type
to functions, the line looks like this:
pass: n.a.
- How to get it back from a function as the return value.
This means stating the C type of the return value, if it is at all
possible to return the type from a function. Etc.
Expressed as
return: ctype
- How to pass it by reference as an lvalue.
Some functions might prefer to return a value by modifying some
object that has been passed by reference. We have to specify how
this should work.
Expressed as
ref: ctype1, ctype2, ...
Note that functions are generally only allowed to either have a
normal return value, or exactly one of these lvalue parameters, but
this is of no concern to the type system. We come back to it later
when describing the function descriptions.
- How to store it in a GtkArg structure.
This involves listing the names and types of the union members that
are used to store all relevant information.
Expressed as
store: ctype1 name1, ctype2 name2, ...
This will probably always be the same information as the `pass:'
line.
- How to store a reference in a GtkArg structure that allows for
returning it from a function call constructed at runtime.
Expressed as
refstore: ctype1 name1, ctype2 name2, ...
- How to copy a value of this type.
This includes reference counting issues, etc. When nothing is
mentioned about copying, this means that you can freely copy.
- Whether this type can be inherited.
Some types can not be inherited, like "int"s, other must be inherited,
like "int_enum"s to become meaningful, some can but don't have to,
like "GtkObjects".
Expressed as
inherit: no
inherit: must
inherit: yes
These descriptions are only written down in English and must be
enforced by carefully implementing both the interpreter glue and the
Gtk functions.
Because of this, the number of fundamental types should be kept to a
minimum. There is no way to add new fundamental types to the system
short of hacking the Gtk sources (and the table below).
If a prototype of a function can not be described with the fundamental
types, it can still be exported to the interpreter, but requires more
attention by the glue writers. Therefore, try to design your
functions so that they follow these conventions.
The following are all fundamental types. You can't add new
fundamental types at runtime.
- GTK_ARG_INVALID
pass: n.a.
return: n.a.
ref: n.a.
store: n.a.
refstore: n.a.
inherit: no
No valid type has this id. Use this only as the `base type' for
new fundamental types. Note that it is not recommended to
introduce new fundamental types lightly.
- GTK_ARG_NONE
pass: n.a.
return: void
ref: n.a.
store: n.a.
refstore: n.a.
inherit: no
The "void" type. There is no data associated with, so there is
nothing to store in a GtkArg. It is illegal to use it for a
function paramter. If it is used as a return type, it means that
the function does not return any useful value. It is not
meaningful to copy a GTK_ARG_NONE value.
- GTK_ARG_CHAR
pass: gchar
return: gchar
ref: n.a.
store: gchar c
refstore: gchar *p
inherit: no
A character. In good C tradition, this is represented as a
"gchar". [Maybe we can come up with something more
international?]
- GTK_ARG_BOOL
pass: gint [gbool?]
return: gint
ref: n.a.
store: gint i [gbool b?]
refstore: gint* p
inherit: no
An boolean value, zero is false, non-zero is true. The canonical
true value is 1.
- GTK_ARG_INTEGER
pass: glong
return: glong
ref: n.a.
store: glong l
refstore: glong *p
inherit: no
- GTK_ARG_UNSIGNED_INTEGER
pass: gulong
return: gulong
ref: n.a.
store: gulong ul
refstore: gulong *p
inherit: no
- GTK_ARG_FLOAT
pass: gfloat
return: gfloat
ref: n.a.
store: gfloat f
refstore: gfloat *p
inherit: no
- GTK_ARG_STRING
pass: gchar*
return: gchar*
ref: n.a.
store: gchar *s
refstore: gchar **p
inherit: no
Read only nul-terminated string of "gchar"s.
When passed to a function, the string is only valid for the
duration of the call. The callee is not allowed to retain the
pointer or to modify the string. It has to copy the whole string
to new storage.
When returned from a function, the string sits in malloced memory
that must eventually be freed by the caller (with free(3)).
When stored in a GtkArg, the pointer is only as long valid as the
GtkArg itself.
When storing a return value in a GtkArg, the pointer points to
malloced memory that falls into the responsiblity of the creator
of the GtkArg structure.
- GTK_ARG_STATIC_STRING
pass: n.a. (use GTK_ARG_STRING instead)
return: gchar*
ref: n.a.
store: n.a.
refstore: gchar **p
inherit: no
For returning a read-only string, that should not be freed by the
caller.
The caller is not responsible for freeing the memory of a static
string that it gets from some function. However the returned
pointer is only valid until the next Gtk or Gdk function is
called, so the whole string should be immediately copied into new
storage.
- GTK_ARG_OBJECT
pass: GtkObject*
return: GtkObject*
ref: n.a.
store: GtkObject *o
refstore: GtkObject **p
inherit: yes
A pointer to a GtkObject or some derived type.
There are two possible mechanism to manage the lifetime of
GtkObjects. First, they maintain a reference count that can be
controlled with gtk_object_ref and gtk_object_unref. The
GtkObject is not deleted as long as the reference count is greater
than 0.
The second possibility is to recieve a notification when a
GtkObject is about to be deleted. Install a signal handler for
the "destroy" signal. Upon recieving the notification, you must
invalidate all references you have stored to the GtkObject.
The second method is preferable because it does not run the risk
of creating cyclic references which would completely prevent the
GtkObject from being destroyed.
When a GtkObject is returned from a function -- either directly or
inside a GtkArg -- the returned pointer is reflected in the
reference count. When you want to use the notification method
from above, you should first install your handler and then unref
the GtkObject.
[A cyclic refererence is very easy to produce from Scheme. Just
register a callback that has the object in its closure. Happens
all the time.]
- GTK_ARG_INT_ENUM
pass: gint
return: gint
ref: n.a.
store: gint i
refstore: gint *p
inherit: must
An enumeration that represents separate cases, like GtkArgType
itself.
You can get information about a particular enumeration with
`gtk_type_get_enum_info'. It contains a list of all enumeration
literals, each with its name and value.
- GTK_ARG_BIT_ENUM
pass: gint
return: gint
ref: n.a.
store: gint i
refstore: gint *p
inherit: no
An enumeration that represent options that can be combined by
oring them together. The values of such an enumeration are not
required to be single bits, but can also contain common
combinations with their own names. Such combinations are required
to be listed after all the single bit `fundamental' values in the
enumeration info.
The enumeration info is obtained as for GTK_ARG_INT_ENUM.
- GTK_ARG_STRUCT_REF
pass: gpointer
return: gpointer
ref: n.a.
store: gpointer p
refstore: gpointer *p
inherit: must
A pointer to some structure. The structure maintains a reference
count that needs to be updated appropriately.
When a struct ref is returned from a function -- either directly or
inside a GtkArg -- the returned pointer is reflected in the
reference count.
To maintain the reference count, you have to find the appropriate
GtkStructInfo with gtk_type_get_struct_info. It contains two
functions, ref_func and unref_func.
- GTK_ARG_POINT
pass: GdkPoint*
return: n.a.
ref: GdkPoint*
store: GdkPoint point
refstore: GdkPoint *p
inherit: no
The caller is responsible for allocating the memory for returned
values. Always copy the whole structure.
- GTK_ARG_COLOR
pass: GdkColor*
return: n.a.
ref: GdkColor*
store: GdkColor color
refstore: GdkColor *p
inherit: no
Like GTK_ARG_POINT.
- GTK_ARG_RECTANGLE
pass: GdkRectangle*
return: n.a.
ref: GdkRectangle
store: GdkRectangle rectangle
refstore: GdkRectangle *p
inherit: no
Like GTK_ARG_POINT.
- GTK_ARG_SEGMENT
pass: GdkSegment*
return: n.a.
ref: GdkSegment*
store: GdkSegment segment
refstore: GdkSegment *p
inherit: no
Like GTK_ARG_POINT.
- GTK_ARG_EVENT
pass: GdkEvent*
return: GdkEvent*
ref: n.a.
store: GdkEvent *event
refstore: GdkEvent **event
inherit: no
[Still need to sort this out. Probably too big to store inline
and needs special treatment for copying because it contains
pointers.]
- GTK_ARG_FOREIGN
pass: gpointer, void (*destroy_notify)(gpointer)
return: n.a.
ref: n.a.
store: gpointer foreign.data,
void (*foreign.destroy_notify)(gpointer data)
refstore: n.a.
inherit: no
An arbitrary value that fits into a "gpointer" plus a function
that has to be called when the value is no longer needed. This
allows the interpreter to protect the value from its garbage
collector.
- GTK_ARG_FOREIGN_CALLBACK
pass: GtkSignalMarshal, gpointer, void (*dnotify)(gpointer)
return: n.a.
ref: n.a.
store: GtkSignalMarshal callback.marshal, gpointer callback.data,
void (*callback.destroy_notify)(gpointer data)
refstore: n.a.
inherit: no
An arbitrary value from the interpreter that can be somehow
invoked plus a destroy notification function.
- GTK_ARG_ARGS
pass: gint, GtkArg*
return: n.a.
ref: n.a.
store: gint args.n_args, GtkArg *args.args
refstore: n.a.
inherit: no
An array of GtkArgs structures plus its size.
Memory is managed just like for a GTK_ARG_STRING.
Describing Exported Functions
-----------------------------
[under construction...]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]