File: Design.txt

package info (click to toggle)
go-gir-generator 2.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,364 kB
  • sloc: ansic: 186; makefile: 47
file content (159 lines) | stat: -rw-r--r-- 5,694 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
       --==* GObject-introspection based bindings generator for Go *==--

What's implemented and how.


1. OBJECTS


In Go GObject is represented as a pointer to a pointer which points to the real
GObject owned by C. See the code:

	type Object struct { ptr *C.GObject }
	var obj *Object

Or a picture:

 +-----------------+   \ +----------------+   \ +------------------+
 |   Go pointer   -|-----|   C pointer   -|-----|    C GObject     |
 | (stack memory)  |   / | (GCed memory)  |   / | (gobject memory) |
 +-----------------+	 +----------------+     +------------------+

It's done that way, because that struct, which basically holds a chunk of
garbage collected memory represents a reference owner of the particular
GObject. When it is allocated, the reference count of GObject is incremented and
when GC is about to collect that memory, reference count is decremented. That
concludes the idea of memory management behind Go GObject representation.


Also there is a need to mimic GObject type hierarchy and support things such as
downcasting (casting from derived class to base class) and upcasting (casting
from base class to derived class). It is implemented using combined approach:
generated functions for explicit casting (up and down), interfaces and type
embedding for implicit downcasting.

1.1. Implicit downcasting.

In order to achieve that, only base GObject struct has a pointer to the C
GObject. Every derived struct embeds that base GObject struct.

Every GObject struct X has a method of that form:

	InheritedFromX() *C.X

And when derived structs embed that struct, they also receive that method.
Therefore it is possible to specify an interface for each of the base structs:

	type ObjectLike interface {
		InheritedFromGObject() *C.GObject
	}

Each base struct itself implements that interface and every derived struct
implements that interface as well (because it embeds the whole chain of base
structs). And that system is used to do implicit downcasting, every generated
function or a method instead of taking a pointer to a GObject struct, uses a
corresponding Like interface. See the code:

	func (x *Container) Add(w WidgetLike)
	// ...
	var x *gtk.Container
	var a *gtk.Button
	var b *gtk.Entry
	x.Add(a)
	x.Add(b)

1.2. Explicit casting.

Explicit casting in both directions is implemented as a generated ToX (where X
is the name of a concrete type) function for each of the GObject structs. See
the code:

	func ToWindow(o gobject.ObjectLike) *Window

1.3. Status

Implemented:
 - GObject memory management (not optimal)
 - Object hierarchy, upcasting, downcasting
 - Methods
 - Signals/Slots (gobject.Object.Connect and closure marshaling)
 - Properties

TODO:
 - Overriding virtual methods by defining a derived type (for custom widgets)
 - ...


2. INTERFACES


The major problem with interfaces, that it's not possible to use Go interfaces
to implement GObject interfaces, because GObject interfaces may have non-virtual
methods and in Go interfaces you can only mimic that with functions that take
interface as a parameter, which is not very helpful. Therefore I use a hack:
empty struct which implements all the non-virtual interface methods. Any GObject
derived struct may embed that interface implementation without increasing the
size of the GCed struct placeholder, but still adding necessary methods to
it. The hacky part here is that I use a pointer to an empty struct and assuming
that it points to some meaningful location. That kind of behaviour is not
specified by the Go specification. But so far it works.

Here is the description of a mess generated for interfaces (let's assume our
interface is called Foo):

 FooLike - Analogous to object interface for generated functions and methods.
 Foo     - Object derived struct which represents an object which implements
           that interface, at this point the real type of the object is unknown.
 FooImpl - Empty struct that implements all non-virtual methods of our
           interface.
 ToFoo   - Function for upcasting/downcasting.

Also FooImpl has a special method of that form:

	ImplementsFoo() *C.Foo

it serves the same purpose as similar object method - implicit downcasting.

2.1. Status

Implemented:
 - Objects implementing interfaces
 - Non-virtual methods

TODO:
 - Providing custom interfaces implementations from Go


3. STRUCTURES


Structures are implemented simply as byte blobs. The size should match the real
C struct size, but gobject-introspection at the moment provides wrong size in
some cases (no support for C bit fields). Also it is possible to override C
structures definitions if it's necessary.

Fields for struct are generated as well. If it's required to wrap the field
before using it, the wrapper method is generated instead. Name matches. For
example gdk.EventMotion has method `Window() *Window` for accessing its `window`
fields. But for simple things like float64 it has fields: `X` and `Y` as an
example.

Structs memory management problem is complicated. At the moment no memory
management is being done and in most cases structs are allocated on the stack as
values (Go supports that, it makes sense). For many structs like TreeIter or
TextIter it's a perfect variant, but it is possible that there are other structs
which are dynamically allocated by gobject-based library and are in a form of
boxed value. It is uncertain how it is possible to make a line here, between
structs which require dynamic memory management and structs which are ok with
stack storage.

3.1. Status

Implemented:
 - Structs as byte blobs
 - Struct methods
 - Struct fields
 - Struct fields accessors

TODO:
 - Make a final decision about structs memory management