Hi dev list,
Question about the syntax of creation arguments and type checking. I was working on an object yesterday, with the following setup line:
grab_class = class_new(s, (t_newmethod)grab_new, (t_method)grab_free, sizeof(t_grab), 0, A_DEFFLOAT, A_DEFSYM, 0);
I'd assumed that it would require grab_new() to have this declaration to match the order float, symbol as in class_new:
static void *grab_new(t_floatarg f, t_symbol *s);
but it only worked with the reverse:
static void *grab_new(t_symbol *s, t_floatarg f);
We ended up using A_GIMME, but for the future, is there a way to know the order of parameters passed to the creator?
Thanks, Matt
Hi Matt,
if you mix A_FLOAT / A_DEFFLOAT and A_SYM / A_DEFSYM in any Pd method definition (not just the "new" method!), the arguments are rearranged so that in the actual C function signature all the symbol arguments come first.
Here's an especially confusing example:
foo_class = class_new(s, (t_newmethod)foo_new, (t_method)foo_free, sizeof(t_foo), 0, A_DEFFLOAT, A_DEFSYM, A_DEFFLOAT, A_DEFSYM, 0);
becomes
static void *foo_new(t_symbol *arg2, t_symbol *arg4, t_floatarg arg1, t_float arg3);
We ended up using A_GIMME,
Good choice :-) My personal advice: if you need to mix different argument types, better use A_GIMME.
---
Technical explanation: Pd methods take max. 5 type checked arguments. Without the optimization, there would be 32 possible function prototypes. Pd would not only have to declare them all, but also select the correct one at runtime, which would be very inefficient. With the optimization there are only 6 prototypes and you can simply select the appropriate one based on the number of symbol resp. gpointer arguments.
If you want to learn more, have a look at pd_typedmess() in in m_class.c.
Fun fact: pd_typedmess() often calls function pointers with more arguments than the original functions - which is undefined behavior. It just happens to work because in the default calling convention ("cdecl") the caller cleans up the stack. With other calling conventions where the *callee* has to clean up the stack, e. g. "stdcall", this would lead to stack corruption and crash horribly :-)
Christof
On 05.08.2021 20:22, Matt Barber wrote:
Hi dev list,
Question about the syntax of creation arguments and type checking. I was working on an object yesterday, with the following setup line:
grab_class = class_new(s, (t_newmethod)grab_new, (t_method)grab_free, sizeof(t_grab), 0, A_DEFFLOAT, A_DEFSYM, 0);
I'd assumed that it would require grab_new() to have this declaration to match the order float, symbol as in class_new:
static void *grab_new(t_floatarg f, t_symbol *s);
but it only worked with the reverse:
static void *grab_new(t_symbol *s, t_floatarg f);
We ended up using A_GIMME, but for the future, is there a way to know the order of parameters passed to the creator?
Thanks, Matt
Pd-dev mailing list Pd-dev@lists.iem.at https://lists.puredata.info/listinfo/pd-dev
Hi,
On 05/08/2021 22:32, Christof Ressi wrote:
Fun fact: pd_typedmess() often calls function pointers with more arguments than the original functions - which is undefined behavior. It just happens to work because in the default calling convention ("cdecl") the caller cleans up the stack. With other calling conventions where the *callee* has to clean up the stack, e. g. "stdcall", this would lead to stack corruption and crash horribly :-)
I had to fix this in my patches to compile for web with Emscripten, where function pointers must be called at their exact type (or the Emscripten runtime stops hard).
https://github.com/pure-data/pure-data/pull/688
May need a little care and attention before merging, sorry I haven't been more proactive on this one.
I think something similar might have been integrated into Purr-data already?
Claude
I agree that the prototypes should be fixed. Actually, it's not that bad, just 21 instead of 6 prototypes, if I'm not mistaken: https://github.com/pure-data/pure-data/pull/688#discussion_r684245557
On 06.08.2021 13:26, Claude Heiland-Allen wrote:
Hi,
On 05/08/2021 22:32, Christof Ressi wrote:
Fun fact: pd_typedmess() often calls function pointers with more arguments than the original functions - which is undefined behavior. It just happens to work because in the default calling convention ("cdecl") the caller cleans up the stack. With other calling conventions where the *callee* has to clean up the stack, e. g. "stdcall", this would lead to stack corruption and crash horribly :-)
I had to fix this in my patches to compile for web with Emscripten, where function pointers must be called at their exact type (or the Emscripten runtime stops hard).
https://github.com/pure-data/pure-data/pull/688
May need a little care and attention before merging, sorry I haven't been more proactive on this one.
I think something similar might have been integrated into Purr-data already?
Claude
Hi,
On 06/08/2021 12:26, Claude Heiland-Allen wrote:
On 05/08/2021 22:32, Christof Ressi wrote:
Fun fact: pd_typedmess() often calls function pointers with more arguments than the original functions - which is undefined behavior. It just happens to work because in the default calling convention ("cdecl") the caller cleans up the stack. With other calling conventions where the *callee* has to clean up the stack, e. g. "stdcall", this would lead to stack corruption and crash horribly :-)
I had to fix this in my patches to compile for web with Emscripten, where function pointers must be called at their exact type (or the Emscripten runtime stops hard).
https://github.com/pure-data/pure-data/pull/688
May need a little care and attention before merging, sorry I haven't been more proactive on this one.
Should be good to go now; I force-pushed a re-do relative to current master.
I checked in some generated code because it should change very rarely (if ever), and the work required to properly run the code generator at compile time is out of all proportion to the benefit.
Claude
Em qui., 5 de ago. de 2021 às 18:33, Christof Ressi info@christofressi.com escreveu:
Hi Matt,
if you mix A_FLOAT / A_DEFFLOAT and A_SYM / A_DEFSYM in any Pd method definition (not just the "new" method!), the arguments are rearranged so that in the actual C function signature all the symbol arguments come first.
what's the difference between A_FLOAT / A_DEFFLOAT and A_SYM / A_DEFSYM? thanks
A_DEFFLOAT and A_DEFSYM arguments are optional and default to 0 resp. an empty symbol. A_FLOAT and A_SYMBOL, on the other hand, are mandatory and Pd will print an error if you omit them in the method call.
On 06.08.2021 14:53, Alexandre Torres Porres wrote:
Em qui., 5 de ago. de 2021 às 18:33, Christof Ressi <info@christofressi.com mailto:info@christofressi.com> escreveu:
Hi Matt, if you mix A_FLOAT / A_DEFFLOAT and A_SYM / A_DEFSYM in any Pd method definition (not just the "new" method!), the arguments are rearranged so that in the actual C function signature all the symbol arguments come first.
what's the difference between A_FLOAT / A_DEFFLOAT and A_SYM / A_DEFSYM? thanks