On Sat, 2015-11-21 at 20:48 -0600, Aaron Paden wrote: > On Sat, Nov 21, 2015 at 6:33 AM, Al Thomas <astavale at yahoo.co.uk> > wrote: > > > > > > This looks complex so I can only give a few pointers. > > > > Does the code actually compile or are you getting an error about an > > unresolved symbol? > > Right, the code compiles, but the linker fails because of the > unresolved symbols. I didn't think of this before, but the minimal > example is pretty simple: > > void main() { > Â PulseAudio.SourceInfo info; > } > > You can solve this by declaring info unowned. Clearly the issue is > that vala is managing SourceInfo when it shouldn't be managed, but I > wasn't sure how to actually fix this given how the API is actually > used. Ideally, the vapi itself should indicate that the struct is > unmanaged, but I'm not sure how to do that as of yet. That's not quite right; the VAPI shouldn't indicate that a *type* is "unmanaged"â?¦ Â it's up to your code to indicate whether an instance is unowned. Â However, the question is really what the proper way to destroy an instance is. In order to determine how to destroy a struct which doesn't specify a destroy_function CCode attribute, Vala will look at the members. Â If none of the members require destroy or free functions, then Vala can assume that simply releasing the memory associated with the struct itself (i.e., calling g_free on heap-allocated instances, or simply allowing stack-allocated instances to go out of scope) is sufficient. For example, consider the following two structs: public struct Foo { public int foo_value; } public struct Bar { public string bar_value; } In this case, in order to destroy Foo nothing special is required. However, to destroy Bar g_free must be called on the bar_value field. That is where "unowned" comes into play. Â If the bar_value field had been marked as "unowned" then Vala would know that nothing special is required to free it. If you don't provide a destroy_function CCode annotation but Vala determines that it is necessary to call one, it will default to lower_case_cprefix_destroy, which is why it is generating a call to pulse_audio_source_info_destroy. The idea is recursive; if Foo had an owned Bar member then foo would require a destroy function (which would call Bar's destroy function on the appropriate field). Â On the other hand, if Foo had an owned field that contained another struct which didn't require a destroy function then that wouldn't cause Foo to require one, either. So, the right thing to do is probably to make any fields which require a destroy or free function unowned. Â However, this does have some implications; if you transfer ownership of an instance to Pulse Audio, and there is code in the library which calls a free function (such as g_free) on one of the fields, you'll likely end up with a double free. That behavior would be pretty unlikely; at that point I would argue that it is really a bug in the API (unless there is actually a destroy function but nobody told Vala about it). -Evan