c-union.md 1.8 KB

Here's the answer to your question, then I'll continue with the GNOME widgets. C unions in GNU Modula-2 (as done in this project) Modula-2 has no C union type, so the bindings use one of three idioms depending on how C uses the type:

  1. Opaque handle (ADDRESS) — when C only ever passes it by address. This is what almost all GTK/GObject types use: TYPE AdwViewSwitcher = ADDRESS;
  2. Fixed-size opaque blob (the union/struct carrier) — when Modula-2 must allocate the value on its own stack and pass it by address. GtkTextIter is the worked example (src/GtkTextIter.def): TYPE GtkTextIter = RECORD opaque: ARRAY [0..9] OF ADDRESS; (* 10 * 8 = 80 bytes, 8-byte aligned *) END; The ARRAY OF ADDRESS gives both the exact byte size and the pointer alignment C expects. You call it via VAR: VAR start, stop: GtkTextIter; gtk_text_buffer_get_bounds(buffer, start, stop); A union nested in a struct is simply part of that opaque block — we never name its members.
  3. Variant record (the real M2 equivalent of a C union) — when you actually need to read/write overlapping members: TYPE Payload = RECORD CASE tag: CARDINAL OF 0: i: INTEGER | 1: d: REAL | 2: p: ADDRESS END END; The tag + CASE maps to a tagged union. In the GTK/GIR world we haven't needed this, because GObject-Introspection exposes unions through accessor functions, so the union stays opaque (idiom 1 or 2). The generator documents the same policy (tools/gir2def.py): "All instance/opaque/unknown/pointer types map to ADDRESS; scalars map to the closest Modula-2 type. Value structs are therefore treated as opaque." If you want, I can add a real GValue binding using idiom 2/3 as a demonstration — it's the classic C union case. Now, continuing with the GNOME widgets. Let me pull the remaining signatures and enums.