GNOME Bugzilla – Bug 794920
Anonymous Delegates
Last modified: 2018-05-19 21:14:09 UTC
Brief: Support declaring delegates in VAPIs that don't have corresponding C type. Possible solutions: 1. Have CCode add a parameter "defined" with a default of true. If it is false, the Vala compiler would generate required typedefs in each generated source file that uses the symbol. 2. Have Vala add syntax for "delegate types on the fly" - like i showed in my C example below 3. Possibly more of them. Long story: Some C libraries have their headers define: typedef struct { void (* something) (); } Sample; Now, when I try to create a VAPI by hand: [CCode (has_target = false)] public delegate void SomethingFunc (); [CCode (has_type_id = false)] public struct Sample { public SomethingFunc something; } But this obviously fails, because SomethingFunc is not declared in C. So I try further: [CCode (cname = "void(*)(void*,void*)", has_target = false)] public delegate void SomethingFunc (); //... This fails with a cryptic error message like this: /home/jakub/Programy/x/bzlib-demo-allo/demo-memcnt.vala.c:24:31: error: expected declaration specifiers or ‘...’ before ‘*’ token static void* ___lambda4__void(*)(void*,int,int) (void* target, ^ /home/jakub/Programy/x/bzlib-demo-allo/demo-memcnt.vala.c:29:30: error: expected declaration specifiers or ‘...’ before ‘*’ token static void ___lambda5__void(*)(void*,void*) (void* target, ^ /home/jakub/Programy/x/bzlib-demo-allo/demo-memcnt.vala.c:52:18: error: expected declaration specifiers or ‘...’ before ‘*’ token ___lambda4__void(*)(void*,int,int) (void* target, ^ /home/jakub/Programy/x/bzlib-demo-allo/demo-memcnt.vala.c:71:18: error: expected declaration specifiers or ‘...’ before ‘*’ token ___lambda5__void(*)(void*,void*) (void* target, ^ /home/jakub/Programy/x/bzlib-demo-allo/demo-memcnt.vala.c: In function ‘_vala_main’: /home/jakub/Programy/x/bzlib-demo-allo/demo-memcnt.vala.c:87:19: warning: implicit declaration of function ‘___lambda4__void’; did you mean ‘__lambda4_’? [-Wimplicit-function-declaration] stream.bzalloc = ___lambda4__void(*)(void*,int,int); ^~~~~~~~~~~~~~~~ __lambda4_ /home/jakub/Programy/x/bzlib-demo-allo/demo-memcnt.vala.c:87:37: error: expected expression before ‘)’ token stream.bzalloc = ___lambda4__void(*)(void*,int,int); ^ /home/jakub/Programy/x/bzlib-demo-allo/demo-memcnt.vala.c:88:18: warning: implicit declaration of function ‘___lambda5__void’; did you mean ‘__lambda5_’? [-Wimplicit-function-declaration] stream.bzfree = ___lambda5__void(*)(void*,void*); ^~~~~~~~~~~~~~~~ __lambda5_ /home/jakub/Programy/x/bzlib-demo-allo/demo-memcnt.vala.c:88:36: error: expected expression before ‘)’ token stream.bzfree = ___lambda5__void(*)(void*,void*); (playing with BZLib and my bug #794409)
From the Vala "LegacyBindings" document (https://wiki.gnome.org/Projects/Vala/LegacyBindings#Delegates): "It is common for C programmers not to create a typedef for a function pointer, instead opting to include it directly. Create a delegate and do not set the cname. If possible, contribute a patch to the library to create a typedef" It looks like the cname you are using is causing the C errors. For a moment I had thought a workaround would be to add a space after the double quotes and before the C name, so cname = " void(*)(void*,void*)". This is a work around that separates the ___lambda5__ identifier from the type, but looking at the code it won't get you very much further. There are other C code attribute details that could be tried: ctype, type_cname and type. These appear in https://git.gnome.org/browse/vala/tree/vala/valausedattr.vala#n33 , but only type_cname and type are listed in http://www.vala-project.org/doc/vala/Attributes.html#CCode_Attribute . On the face of it they could be synonyms. To my mind this part of the binding seems fine: [CCode (has_type_id = false)] public struct Sample { public SomethingFunc something; } Following the rule that if there is no typedef there is no cname then delegate would be: [CCode (has_target = false)] public delegate void SomethingFunc (); I'm not following where the function signature void(*)(void*,void*) comes from. From the C struct it would be void(*)(void) I think. The void (* something) (); in the struct identifies the field name as 'something' and that it is a pointer. I've not got as far as writing some sample code to understand where this is failing in the code generation. Is it the struct declaration/initialization, referencing the field 'something' or the way Vala creates the function in C to be pointed to in the struct?
@ricotz I understood delegates to be a Vala/C# construct. You've changed the title back to "Anonymous Delegates". Are you saying that there should be anonymous delegates, like anonymous functions, in Vala? I don't understand how the delegate type can then be referred to though. I was intending to update the legacy bindings document to make the distinction between delegates in Vala and function pointers in C clearer. Have I missed something in my understanding?
Created attachment 370832 [details] [review] vala: Support anonymous definitions of delegates in bindings If a library header does not include a defintion for a delegate then bindings can annotate the symbol with "Anonymous" which will force creation of typedef in generated source-file. [Anonymous] public delegate void Func ();
@al I am not certain about the terminology either. I guess lambda expressions are already "anonymous functions".
(In reply to Rico Tzschichholz from comment #4) > @al I am not certain about the terminology either. I guess lambda > expressions are already "anonymous functions". Yep, I agree. Lambda expressions are anonymous functions. The patch is a nice idea, but I think a Vala concept should be kept separate from C terminology. The error message in your patch "Anonymous delegates must be external" says this attribute shouldn't be used for Vala code. So is a CCode attribute detail not possible? There is [CCode (has_target = false)] why not [CCode (has_typedef = false)]? Or more explicitly that this only applies to delegates at present: [CCode (delegate_has_typedef = false)] similar to [CCode (delegate_target_cname = "xyz")]
I agree that [CCode (has_typedef = false)] is a more understandable naming. I going to update the patch.
Created attachment 370834 [details] [review] vala: Support anonymous definitions of delegates in bindings If a library header does not include a defintion for a delegate then bindings can use the CCode annotation "has_typedef = false" which will force creation of typedef in generated source-file. [CCode (has_typedef = false)] public delegate void Func ();
Attachment 370834 [details] pushed as e9214a7 - vala: Support anonymous definitions of delegates in bindings
*** Bug 664284 has been marked as a duplicate of this bug. ***