[PATCH 4/4] Update NEWS for user.other_name
[notmuch-archives.git] / cc / e135535f0cbbe4bf66bc0bd3e501114f070787
1 Return-Path: <amdragon@mit.edu>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id 30B1C431FB6\r
6         for <notmuch@notmuchmail.org>; Thu, 19 Jul 2012 20:24:02 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id 361fwEsHskcC for <notmuch@notmuchmail.org>;\r
16         Thu, 19 Jul 2012 20:24:01 -0700 (PDT)\r
17 Received: from dmz-mailsec-scanner-6.mit.edu (DMZ-MAILSEC-SCANNER-6.MIT.EDU\r
18         [18.7.68.35])\r
19         by olra.theworths.org (Postfix) with ESMTP id C5B70431FAE\r
20         for <notmuch@notmuchmail.org>; Thu, 19 Jul 2012 20:24:00 -0700 (PDT)\r
21 X-AuditID: 12074423-b7f396d0000008f4-10-5008cf4ff7a1\r
22 Received: from mailhub-auth-3.mit.edu ( [18.9.21.43])\r
23         by dmz-mailsec-scanner-6.mit.edu (Symantec Messaging Gateway) with SMTP\r
24         id 1F.EE.02292.F4FC8005; Thu, 19 Jul 2012 23:23:59 -0400 (EDT)\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
26         by mailhub-auth-3.mit.edu (8.13.8/8.9.2) with ESMTP id q6K3Nwe1027864; \r
27         Thu, 19 Jul 2012 23:23:58 -0400\r
28 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91])\r
29         (authenticated bits=0)\r
30         (User authenticated as amdragon@ATHENA.MIT.EDU)\r
31         by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q6K3Nrli023977\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Thu, 19 Jul 2012 23:23:54 -0400 (EDT)\r
34 Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.77)\r
35         (envelope-from <amdragon@MIT.EDU>)\r
36         id 1Ss3om-0005qn-Kc; Thu, 19 Jul 2012 23:23:52 -0400\r
37 Date: Thu, 19 Jul 2012 23:23:52 -0400\r
38 From: Austin Clements <amdragon@MIT.EDU>\r
39 To: Adrien Bustany <adrien@bustany.org>\r
40 Subject: Re: [PATCH 3/7] go: Allow notmuch objects to be garbage collected\r
41 Message-ID: <20120720032352.GX31670@mit.edu>\r
42 References: <1342636475-16057-1-git-send-email-adrien@bustany.org>\r
43         <1342636475-16057-4-git-send-email-adrien@bustany.org>\r
44         <20120718204001.GT31670@mit.edu> <50085106.8040804@bustany.org>\r
45 MIME-Version: 1.0\r
46 Content-Type: text/plain; charset=iso-8859-1\r
47 Content-Disposition: inline\r
48 Content-Transfer-Encoding: 8bit\r
49 In-Reply-To: <50085106.8040804@bustany.org>\r
50 User-Agent: Mutt/1.5.21 (2010-09-15)\r
51 X-Brightmail-Tracker:\r
52  H4sIAAAAAAAAA+NgFprNKsWRmVeSWpSXmKPExsUixCmqret/niPA4E2LuMX6O2vZLK7fnMns\r
53         wOTx8cA9Jo9nq24xBzBFcdmkpOZklqUW6dslcGUsadrEVNCSU9HXvJG5gXFiaBcjJ4eEgInE\r
54         2u+/WCBsMYkL99azdTFycQgJ7GOUePpmLyOEs4FRYsWDHawQzkkmiYXPN0I5Sxgl/v+8zArS\r
55         zyKgKvHy+luwWWwCGhLb9i9nBLFFBNQldnS2g9nMAtIS3343M4HYwgJeErc39zB3MXJw8Aro\r
56         SExosAQJCwnsZ5T4cCIIxOYVEJQ4OfMJC0SrjsTOrXfYQMpBxiz/xwERlpdo3jqbGcTmFNCW\r
57         2PFrL1i5qICKxJST29gmMArPQjJpFpJJsxAmzUIyaQEjyypG2ZTcKt3cxMyc4tRk3eLkxLy8\r
58         1CJdM73czBK91JTSTYygOGB3Ud7B+Oeg0iFGAQ5GJR7eSUkcAUKsiWXFlbmHGCU5mJREeZtP\r
59         A4X4kvJTKjMSizPii0pzUosPMUpwMCuJ8H4/BZTjTUmsrEotyodJSXOwKInzXku56S8kkJ5Y\r
60         kpqdmlqQWgSTleHgUJLgvXcOqFGwKDU9tSItM6cEIc3EwQkynAdoeDZIDW9xQWJucWY6RP4U\r
61         o6KUOK8NSEIAJJFRmgfXC0tTrxjFgV4R5l0FUsUDTHFw3a+ABjMBDeYuZgMZXJKIkJJqYGxm\r
62         4IzjW3+kt/V639ndtz4yKPC8YnvNquG8zF9L08s9r8pxGZN60NUX4dOyHgXKF6nFal5Uspp6\r
63         9650aFDXu9lfKsuVTnXdiJnSZOCZu433fFTun5mWHcevGi+Xk3RR2Xrk6Y/sKd8uP5yyexOL\r
64         vo2eX7FTo8S5d2orU+7KWjH4+C6o/1B5VImlOCPRUIu5qDgRALJAgyYuAwAA\r
65 Cc: notmuch@notmuchmail.org\r
66 X-BeenThere: notmuch@notmuchmail.org\r
67 X-Mailman-Version: 2.1.13\r
68 Precedence: list\r
69 List-Id: "Use and development of the notmuch mail system."\r
70         <notmuch.notmuchmail.org>\r
71 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
72         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
73 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
74 List-Post: <mailto:notmuch@notmuchmail.org>\r
75 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
76 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
77         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
78 X-List-Received-Date: Fri, 20 Jul 2012 03:24:02 -0000\r
79 \r
80 Quoth Adrien Bustany on Jul 19 at  9:25 pm:\r
81 > Le 18/07/2012 23:40, Austin Clements a écrit :\r
82 > >This is subtle enough that I think it deserves a comment in the source\r
83 > >code explaining that tracking the talloc owner reference, combined\r
84 > >with the fact that Go finalizers are run in dependency order, ensures\r
85 > >that the C objects will always be destroyed from the talloc leaves up.\r
86\r
87 > Definitely, I tend to comment in the commit message and forget about\r
88 > the code...\r
89\r
90 > >\r
91 > >Just one inline comment below.  Otherwise, I think this is all\r
92 > >correct.\r
93\r
94 > Agree with the comment, the Database should be the parent. I guess I\r
95 > wasn't sure of the talloc parenting.\r
96\r
97 > >\r
98 > >Is reproducing the talloc hierarchy in all of the bindings really the\r
99 > >right approach?  I feel like there has to be a better way (or that the\r
100 > >way we use talloc in the library is slightly broken).  What if the\r
101 > >bindings created an additional talloc reference to each managed\r
102 > >object, just to keep the object alive, and used talloc_unlink instead\r
103 > >of the destroy functions?\r
104\r
105 > Reproducing the hierarchy is probably error prone, and not that\r
106 > simple indeed :/\r
107 > I haven't checked at all the way you suggest, but if we use\r
108 > talloc_reference/unlink, we get the same issue no?\r
109 > - If we do for each new wrapped object talloc_reference(NULL,\r
110 > wrapped_object), the the object will be kept alive until we\r
111 > talloc_unlink(NULL, wrapped_object), but what about its parents? For\r
112 > example will doing that on a notmuch_message_t keep the\r
113 > notmuch_messages_t alive?\r
114 \r
115 Hmm.  This is what I was thinking.  You have an interesting point; I\r
116 think it's slightly wrong, but it exposes something deeper.  I believe\r
117 there are two different things going on here: some of the talloc\r
118 relationships are for convenience, while some are structural.  In the\r
119 former case, I'm pretty sure my suggestion will work, but in the\r
120 latter case the objects should *never* be freed by the finalizer!\r
121 \r
122 For example, notmuch_query_search_messages returns a new\r
123 notmuch_messages_t with the query as the talloc parent, but that\r
124 notmuch_messages_t doesn't depend on the query object; this is just so\r
125 you can conveniently delete everything retrieved from the query by\r
126 deleting the query.  In this case, you can either use parent\r
127 references like you did---which will prevent a double-free by forcing\r
128 destruction to happen from the leaves up but at the cost of having to\r
129 encode these relationships and of extending the parent object\r
130 lifetimes beyond what's strictly necessary---or you can use my\r
131 suggestion of creating an additional talloc reference.\r
132 \r
133 However, in your example, the notmuch_message_t's are structurally\r
134 related to the notmuch_messages_t from whence they came.  They're all\r
135 part of one data structure and hence it *never* makes sense for a\r
136 caller to delete the notmuch_message_t's.  For example, even with the\r
137 code in this patch, I think the following could lead to a crash:\r
138 \r
139 1. Obtain a Messages object, say ms.\r
140 2. m1 := ms.Get()\r
141 3. m1 = nil\r
142 4. m2 := ms.Get()\r
143 5. m2.whatever()\r
144 \r
145 If a garbage collection happens between steps 3 and 4, the Message in\r
146 m1 will get finalized and destroyed.  But step 4 will return the same,\r
147 now dangling, pointer, leading to a potential crash in step 5.\r
148 \r
149 Maybe the answer in the structural case is to include the parent\r
150 pointer in the Go struct and not set a finalizer on the child?  That\r
151 way, if there's a Go reference to the parent wrapper, it won't go away\r
152 and the children won't get destroyed (collecting wrappers of children\r
153 is fine) and if there's a Go reference to the child wrapper, it will\r
154 keep the parent alive so it won't get destroyed and neither will the\r
155 child.\r
156 \r
157 > - If we do talloc_reference(parent, wrapped), then we reproduce the\r
158 > hierarchy again?\r
159\r
160 > Note that I have 0 experience with talloc, so I might as well be\r
161 > getting things wrong here.\r
162\r
163 > >\r
164 > >Quoth Adrien Bustany on Jul 18 at  9:34 pm:\r
165 > >>This makes notmuch appropriately free the underlying notmuch C objects\r
166 > >>when garbage collecting their Go wrappers. To make sure we don't break\r
167 > >>the underlying links between objects (for example, a notmuch_messages_t\r
168 > >>being GC'ed before a notmuch_message_t belonging to it), we add for each\r
169 > >>wraper struct a pointer to the owner object (Go objects with a reference\r
170 > >>pointing to them don't get garbage collected).\r
171 > >>---\r
172 > >>  bindings/go/src/notmuch/notmuch.go |  153 +++++++++++++++++++++++++++++++-----\r
173 > >>  1 files changed, 134 insertions(+), 19 deletions(-)\r
174 > >>\r
175 > >>diff --git a/bindings/go/src/notmuch/notmuch.go b/bindings/go/src/notmuch/notmuch.go\r
176 > >>index 1d77fd2..3f436a0 100644\r
177 > >>--- a/bindings/go/src/notmuch/notmuch.go\r
178 > >>+++ b/bindings/go/src/notmuch/notmuch.go\r
179 > >>@@ -11,6 +11,7 @@ package notmuch\r
180 > >>  #include "notmuch.h"\r
181 > >>  */\r
182 > >>  import "C"\r
183 > >>+import "runtime"\r
184 > >>  import "unsafe"\r
185 > >>\r
186 > >>  // Status codes used for the return values of most functions\r
187 > >>@@ -47,40 +48,152 @@ func (self Status) String() string {\r
188 > >>  /* Various opaque data types. For each notmuch_<foo>_t see the various\r
189 > >>   * notmuch_<foo> functions below. */\r
190 > >>\r
191 > >>+type Object interface {}\r
192 > >>+\r
193 > >>  type Database struct {\r
194 > >>    db *C.notmuch_database_t\r
195 > >>  }\r
196 > >>\r
197 > >>+func createDatabase(db *C.notmuch_database_t) *Database {\r
198 > >>+   self := &Database{db: db}\r
199 > >>+\r
200 > >>+   runtime.SetFinalizer(self, func(x *Database) {\r
201 > >>+           if (x.db != nil) {\r
202 > >>+                   C.notmuch_database_destroy(x.db)\r
203 > >>+           }\r
204 > >>+   })\r
205 > >>+\r
206 > >>+   return self\r
207 > >>+}\r
208 > >>+\r
209 > >>  type Query struct {\r
210 > >>    query *C.notmuch_query_t\r
211 > >>+   owner Object\r
212 > >>+}\r
213 > >>+\r
214 > >>+func createQuery(query *C.notmuch_query_t, owner Object) *Query {\r
215 > >>+   self := &Query{query: query, owner: owner}\r
216 > >>+\r
217 > >>+   runtime.SetFinalizer(self, func(x *Query) {\r
218 > >>+           if (x.query != nil) {\r
219 > >>+                   C.notmuch_query_destroy(x.query)\r
220 > >>+           }\r
221 > >>+   })\r
222 > >>+\r
223 > >>+   return self\r
224 > >>  }\r
225 > >>\r
226 > >>  type Threads struct {\r
227 > >>    threads *C.notmuch_threads_t\r
228 > >>+   owner Object\r
229 > >>+}\r
230 > >>+\r
231 > >>+func createThreads(threads *C.notmuch_threads_t, owner Object) *Threads {\r
232 > >>+   self := &Threads{threads: threads, owner: owner}\r
233 > >>+\r
234 > >>+   runtime.SetFinalizer(self, func(x *Threads) {\r
235 > >>+           if (x.threads != nil) {\r
236 > >>+                   C.notmuch_threads_destroy(x.threads)\r
237 > >>+           }\r
238 > >>+   })\r
239 > >>+\r
240 > >>+   return self\r
241 > >>  }\r
242 > >>\r
243 > >>  type Thread struct {\r
244 > >>    thread *C.notmuch_thread_t\r
245 > >>+   owner Object\r
246 > >>+}\r
247 > >>+\r
248 > >>+func createThread(thread *C.notmuch_thread_t, owner Object) *Thread {\r
249 > >>+   self := &Thread{thread: thread, owner: owner}\r
250 > >>+\r
251 > >>+   runtime.SetFinalizer(self, func(x *Thread) {\r
252 > >>+           if (x.thread != nil) {\r
253 > >>+                   C.notmuch_thread_destroy(x.thread)\r
254 > >>+           }\r
255 > >>+   })\r
256 > >>+\r
257 > >>+   return self\r
258 > >>  }\r
259 > >>\r
260 > >>  type Messages struct {\r
261 > >>    messages *C.notmuch_messages_t\r
262 > >>+   owner Object\r
263 > >>+}\r
264 > >>+\r
265 > >>+func createMessages(messages *C.notmuch_messages_t, owner Object) *Messages {\r
266 > >>+   self := &Messages{messages: messages, owner: owner}\r
267 > >>+\r
268 > >>+   return self\r
269 > >>  }\r
270 > >>\r
271 > >>  type Message struct {\r
272 > >>    message *C.notmuch_message_t\r
273 > >>+   owner Object\r
274 > >>+}\r
275 > >>+\r
276 > >>+func createMessage(message *C.notmuch_message_t, owner Object) *Message {\r
277 > >>+   self := &Message{message: message, owner: owner}\r
278 > >>+\r
279 > >>+   runtime.SetFinalizer(self, func(x *Message) {\r
280 > >>+           if (x.message != nil) {\r
281 > >>+                   C.notmuch_message_destroy(x.message)\r
282 > >>+           }\r
283 > >>+   })\r
284 > >>+\r
285 > >>+   return self\r
286 > >>  }\r
287 > >>\r
288 > >>  type Tags struct {\r
289 > >>    tags *C.notmuch_tags_t\r
290 > >>+   owner Object\r
291 > >>+}\r
292 > >>+\r
293 > >>+func createTags(tags *C.notmuch_tags_t, owner Object) *Tags {\r
294 > >>+   self := &Tags{tags: tags, owner: owner}\r
295 > >>+\r
296 > >>+   runtime.SetFinalizer(self, func(x *Tags) {\r
297 > >>+           if (x.tags != nil) {\r
298 > >>+                   C.notmuch_tags_destroy(x.tags)\r
299 > >>+           }\r
300 > >>+   })\r
301 > >>+\r
302 > >>+   return self\r
303 > >>  }\r
304 > >>\r
305 > >>  type Directory struct {\r
306 > >>    dir *C.notmuch_directory_t\r
307 > >>+   owner Object\r
308 > >>+}\r
309 > >>+\r
310 > >>+func createDirectory(directory *C.notmuch_directory_t, owner Object) *Directory {\r
311 > >>+   self := &Directory{dir: directory, owner: owner}\r
312 > >>+\r
313 > >>+   runtime.SetFinalizer(self, func(x *Directory) {\r
314 > >>+           if (x.dir != nil) {\r
315 > >>+                   C.notmuch_directory_destroy(x.dir)\r
316 > >>+           }\r
317 > >>+   })\r
318 > >>+\r
319 > >>+   return self\r
320 > >>  }\r
321 > >>\r
322 > >>  type Filenames struct {\r
323 > >>    fnames *C.notmuch_filenames_t\r
324 > >>+   owner Object\r
325 > >>+}\r
326 > >>+\r
327 > >>+func createFilenames(filenames *C.notmuch_filenames_t, owner Object) *Filenames {\r
328 > >>+   self := &Filenames{fnames: filenames, owner: owner}\r
329 > >>+\r
330 > >>+   runtime.SetFinalizer(self, func(x *Filenames) {\r
331 > >>+           if (x.fnames != nil) {\r
332 > >>+                   C.notmuch_filenames_destroy(x.fnames)\r
333 > >>+           }\r
334 > >>+   })\r
335 > >>+\r
336 > >>+   return self\r
337 > >>  }\r
338 > >>\r
339 > >>  type DatabaseMode C.notmuch_database_mode_t\r
340 > >>@@ -100,12 +213,13 @@ func NewDatabase(path string) (*Database, Status) {\r
341 > >>            return nil, STATUS_OUT_OF_MEMORY\r
342 > >>    }\r
343 > >>\r
344 > >>-   self := &Database{db: nil}\r
345 > >>-   st := Status(C.notmuch_database_create(c_path, &self.db))\r
346 > >>+   var db *C.notmuch_database_t;\r
347 > >>+   st := Status(C.notmuch_database_create(c_path, &db))\r
348 > >>    if st != STATUS_SUCCESS {\r
349 > >>            return nil, st\r
350 > >>    }\r
351 > >>-   return self, st\r
352 > >>+\r
353 > >>+   return createDatabase(db), st\r
354 > >>  }\r
355 > >>\r
356 > >>  /* Open an existing notmuch database located at 'path'.\r
357 > >>@@ -134,12 +248,13 @@ func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) {\r
358 > >>            return nil, STATUS_OUT_OF_MEMORY\r
359 > >>    }\r
360 > >>\r
361 > >>-   self := &Database{db: nil}\r
362 > >>-   st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db))\r
363 > >>+   var db *C.notmuch_database_t;\r
364 > >>+   st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &db))\r
365 > >>    if st != STATUS_SUCCESS {\r
366 > >>            return nil, st\r
367 > >>    }\r
368 > >>-   return self, st\r
369 > >>+\r
370 > >>+   return createDatabase(db), st\r
371 > >>  }\r
372 > >>\r
373 > >>  /* Close the given notmuch database, freeing all associated\r
374 > >>@@ -204,7 +319,7 @@ func (self *Database) GetDirectory(path string) (*Directory, Status) {\r
375 > >>    if st != STATUS_SUCCESS || c_dir == nil {\r
376 > >>            return nil, st\r
377 > >>    }\r
378 > >>-   return &Directory{dir: c_dir}, st\r
379 > >>+   return createDirectory(c_dir, nil), st\r
380 > >\r
381 > >It looks like you have a nil owner for anything whose talloc parent is\r
382 > >the database.  Is this intentional?  Shouldn't the owner be self in\r
383 > >these cases, too?\r
384 > >\r
385 > >>  }\r
386 > >>\r
387 > >>  /* Add a new message to the given notmuch database.\r
388 > >>@@ -258,7 +373,7 @@ func (self *Database) AddMessage(fname string) (*Message, Status) {\r
389 > >>    var c_msg *C.notmuch_message_t = new(C.notmuch_message_t)\r
390 > >>    st := Status(C.notmuch_database_add_message(self.db, c_fname, &c_msg))\r
391 > >>\r
392 > >>-   return &Message{message: c_msg}, st\r
393 > >>+   return createMessage(c_msg, nil), st\r
394 > >>  }\r
395 > >>\r
396 > >>  /* Remove a message from the given notmuch database.\r
397 > >>@@ -319,12 +434,12 @@ func (self *Database) FindMessage(message_id string) (*Message, Status) {\r
398 > >>            return nil, STATUS_OUT_OF_MEMORY\r
399 > >>    }\r
400 > >>\r
401 > >>-   msg := &Message{message: nil}\r
402 > >>-   st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg.message))\r
403 > >>+   var msg *C.notmuch_message_t\r
404 > >>+   st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg))\r
405 > >>    if st != STATUS_SUCCESS {\r
406 > >>            return nil, st\r
407 > >>    }\r
408 > >>-   return msg, st\r
409 > >>+   return createMessage(msg, nil), st\r
410 > >>  }\r
411 > >>\r
412 > >>  /* Return a list of all tags found in the database.\r
413 > >>@@ -339,7 +454,7 @@ func (self *Database) GetAllTags() *Tags {\r
414 > >>    if tags == nil {\r
415 > >>            return nil\r
416 > >>    }\r
417 > >>-   return &Tags{tags: tags}\r
418 > >>+   return createTags(tags, nil)\r
419 > >>  }\r
420 > >>\r
421 > >>  /* Create a new query for 'database'.\r
422 > >>@@ -379,7 +494,7 @@ func (self *Database) CreateQuery(query string) *Query {\r
423 > >>    if q == nil {\r
424 > >>            return nil\r
425 > >>    }\r
426 > >>-   return &Query{query: q}\r
427 > >>+   return createQuery(q, nil)\r
428 > >>  }\r
429 > >>\r
430 > >>  /* Sort values for notmuch_query_set_sort */\r
431 > >>@@ -459,7 +574,7 @@ func (self *Query) SearchThreads() *Threads {\r
432 > >>    if threads == nil {\r
433 > >>            return nil\r
434 > >>    }\r
435 > >>-   return &Threads{threads: threads}\r
436 > >>+   return createThreads(threads, self)\r
437 > >>  }\r
438 > >>\r
439 > >>  /* Execute a query for messages, returning a notmuch_messages_t object\r
440 > >>@@ -505,7 +620,7 @@ func (self *Query) SearchMessages() *Messages {\r
441 > >>    if msgs == nil {\r
442 > >>            return nil\r
443 > >>    }\r
444 > >>-   return &Messages{messages: msgs}\r
445 > >>+   return createMessages(msgs, self)\r
446 > >>  }\r
447 > >>\r
448 > >>  /* Destroy a notmuch_query_t along with any associated resources.\r
449 > >>@@ -607,7 +722,7 @@ func (self *Messages) Get() *Message {\r
450 > >>    if msg == nil {\r
451 > >>            return nil\r
452 > >>    }\r
453 > >>-   return &Message{message: msg}\r
454 > >>+   return createMessage(msg, self)\r
455 > >>  }\r
456 > >>\r
457 > >>  /* Move the 'messages' iterator to the next message.\r
458 > >>@@ -659,7 +774,7 @@ func (self *Messages) CollectTags() *Tags {\r
459 > >>    if tags == nil {\r
460 > >>            return nil\r
461 > >>    }\r
462 > >>-   return &Tags{tags: tags}\r
463 > >>+   return createTags(tags, self)\r
464 > >>  }\r
465 > >>\r
466 > >>  /* Get the message ID of 'message'.\r
467 > >>@@ -739,7 +854,7 @@ func (self *Message) GetReplies() *Messages {\r
468 > >>    if msgs == nil {\r
469 > >>            return nil\r
470 > >>    }\r
471 > >>-   return &Messages{messages: msgs}\r
472 > >>+   return createMessages(msgs, self)\r
473 > >>  }\r
474 > >>\r
475 > >>  /* Get a filename for the email corresponding to 'message'.\r
476 > >>@@ -871,7 +986,7 @@ func (self *Message) GetTags() *Tags {\r
477 > >>    if tags == nil {\r
478 > >>            return nil\r
479 > >>    }\r
480 > >>-   return &Tags{tags: tags}\r
481 > >>+   return createTags(tags, self)\r
482 > >>  }\r
483 > >>\r
484 > >>  /* The longest possible tag value. */\r