On Wed, 2013-10-16 at 09:48 +0200, Donn Ingle wrote:
On 15 October 2013 23:30, Evan Nemerson <evan coeus-group com> wrote:You're close. valac doesn't handle this very well because of the anonymous structs in the C API. It wants to assign to temporary variables even when all you're doing is accessing fields, and since they're structs the temporary variables aren't pointers, which will cause the CC to complain (even though the types are compatible). You can use pointers to assign temporary variables in vala to work around this:It would be useless to say I understand that, but I get the start of a fuzzy idea :) Heuristic: if the C library uses structs and unions and arrays thereof, fear for my sanity!
Indeed. Please don't take this as an example of good code. It's a hack to get around some problems Vala has with the API. Anonymous structs and unions are pretty rare in C APIs. Furthermore, the fact that the C example abuses the relationship between arrays and pointers is probably a bit confusing for someone without a lot of experience with C.
I will use your code as an edit/run/redo lesson.while ( i < path.num_data ) { unowned Cairo.PathData? data = path.data[i];I'm not sure why the data var was declared, it's not used.
Yeah, you can get rid of it.
Cairo.PathDataHeader* header = &(path.data[i].header);This I kind of get from a little reading of docs. (header is a pointer, it's being given the address of some other thing.) Do I have to perform a "delete header;" within the loop? At end of loop? At all?
No. You only use delete if you own the value the pointer points to. It's extremely impolite to delete other people's data, and will usually result in a segfault.
switch (header->type) { case Cairo.PathDataType.MOVE_TO: Cairo.PathDataPoint* point = &(path.data[i + 1].point);Same delete questions on "point".do_move_to_things (point.x, point.y); break; } i += header.length; }Sundry questions if you're in the mood: unowned Cairo.PathData? data = path.data[i]; According to 'pointers' section in the Vala tut, this could be written as: Cairo.PathData* data = path.data[i]; Is that so? (i.e. dropping the 'unowned', which is still a mystery to me.)
Yes, but in general you shouldn't use pointers in Vala unless you have a very good reason. "unowned" is pretty easy to understand, see https://wiki.gnome.org/Vala/ReferenceHandling The reason I used a pointer for the point variable is to avoid some problematic C code which valac will generate due to the fact that Cairo.PathDataPoint is really an anonymous struct. If I could have used an unowned reference I would have.
How about that nullable character ... Cairo.PathData*? = :-O
Pointers can be null already, so that doesn't really make sense. And it's a syntax error. Theoretically I suppose Cairo.PathData?* could make sense, but it's also a syntax error.
Can one declare vars before the loop, like: Cairo.PathDataPoint* point; And then within the loop: point = &(path.data...);
You could, but unless you actually need to use the last point for something else later on it's probably not a good idea. In general you should declare variables in the smallest scope you can without incurring an unacceptable performance penalty in order to minimize memory usage. If I had declared them outside of the loop they would still be accessible outside the loop, and still taking up memory. This isn't really a big deal for a pointer or an unowned reference to a class, but imagine something like reading data from files: GLib.FileStream stream; foreach ( unowned string filename in filenames ) { stream = GLib.FileStream.open (filename, "r"); do_stuff (); } Now you have a file stream sitting around which will not be closed until it goes out of scope, which could be a while (depending on how much other stuff you have in the function). If you put stream inside the loop then it will automatically be closed immediately after you're done. Of course, there are situations where you want to keep something around between loop iterations because creating/destroying it is expensive. For example, reading or writing chunks of a file: while ( !stream.eof () ) { uint8[] buf = new uint8[1024 * 1024]; size_t bytes_read = stream.read (buf); do_stuff (); } Allocating and freeing a 1MB buffer for each iteration isn't a good idea, but you also don't want to naively keep it outside the loop and wait to free it much longer than needed. What you can do here is create a new scope to surround both your variables and the loop: { uint8[] buf = new uint8[1024 * 1024]; while ( !stream.eof () ) { size_t bytes_read = stream.read (buf); do_stuff (); } } If creating/destroying a variable is basically free (like simpletype structs such as size_t, as well as pointers and unowned references), keep the variable inside the loop. If it's expensive but reusable, but it outside the loop but inside another small scope. Only put stuff completely outside if you need to use the last value for something outside the loop. -Evan
Attachment:
signature.asc
Description: This is a digitally signed message part