After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 794920 - Anonymous Delegates
Anonymous Delegates
Status: RESOLVED FIXED
Product: vala
Classification: Core
Component: Delegates
unspecified
Other All
: Normal major
: 0.42
Assigned To: Vala maintainers
Vala maintainers
: 664284 (view as bug list)
Depends on:
Blocks: 794409
 
 
Reported: 2018-04-03 06:49 UTC by Jakub Kaszycki
Modified: 2018-05-19 21:14 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
vala: Support anonymous definitions of delegates in bindings (2.93 KB, patch)
2018-04-12 07:38 UTC, Rico Tzschichholz
none Details | Review
vala: Support anonymous definitions of delegates in bindings (3.65 KB, patch)
2018-04-12 08:50 UTC, Rico Tzschichholz
committed Details | Review

Description Jakub Kaszycki 2018-04-03 06:49:32 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)
Comment 1 Al Thomas 2018-04-09 10:43:20 UTC
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?
Comment 2 Al Thomas 2018-04-12 07:29:20 UTC
@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?
Comment 3 Rico Tzschichholz 2018-04-12 07:38:01 UTC
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 ();
Comment 4 Rico Tzschichholz 2018-04-12 07:47:30 UTC
@al I am not certain about the terminology either. I guess lambda expressions are already "anonymous functions".
Comment 5 Al Thomas 2018-04-12 08:01:42 UTC
(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")]
Comment 6 Rico Tzschichholz 2018-04-12 08:32:04 UTC
I agree that [CCode (has_typedef = false)] is a more understandable naming. I going to update the patch.
Comment 7 Rico Tzschichholz 2018-04-12 08:50:21 UTC
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 ();
Comment 8 Rico Tzschichholz 2018-04-15 17:44:05 UTC
Attachment 370834 [details] pushed as e9214a7 - vala: Support anonymous definitions of delegates in bindings
Comment 9 Rico Tzschichholz 2018-05-19 21:14:09 UTC
*** Bug 664284 has been marked as a duplicate of this bug. ***