Hi Gustavo,

2017-08-28 0:18 GMT+09:00 Gustavo Sverzut Barbieri <[email protected]>:

> Hi all,
>
> q66 did a nice work to implement function pointers in Eolian, when you
> write this:
>

(Wasn't it Lauro Maura?)

   function Function_Name {
>        params {
>           a: int;
>        }
>        return: bool;
>    }
>
> you can then use your method as:
>
>    method_name {
>       params {
>          cb: Function_Name
>       }
>    }
>
> Which results in:
>
>    my_class_method(o, func_data, func, free_func);
>
> Basically enforces the pattern we always use, which is good. But
> keeping them explicitly as 3 pointers is a bit cumbersome.
>
> So my suggestion is to pack them in a structure, so it will become a
> single parameter (as would be exposed in higher level languages):
>
>    typedef struct _Function_Name_Desc {
>       Function_Name func;
>       const void *data;
>       Eina_Free_Cb free;
>    } Function_Name_Desc;
>
>    my_class_method(o, func_desc);
>
> A simple macro can make it more usable:
>
>     #define FUNCTION_NAME(...) (Function_Name_Desc){__VA_ARGS}
>
>    my_class_method(o, FUNCTION_NAME(func));
>    my_class_method(o, FUNCTION_NAME(func, func_data));
>    my_class_method(o, FUNCTION_NAME(func, func_data, free));
>
> and also named parameters:
>
>    my_class_method(o, FUNCTION_NAME(.func = cb, .free = data_free));
>
> For method implementors it will be also simple, since we always have
> to do something like:
>
>    struct _My_Class_Data {
>       ...
>       Function_Name func;
>       const void *func_data;
>       Eina_Free_Cb func_free;
>       ...
>    };
>
>    pd->func = func;
>    pd->func_data = func_data;
>    pd->func_free = func_free;
>
> would become a simple entry:
>
>    struct _My_Class_Data {
>       ...
>       Function_Name_Desc cb;
>       ...
>    };
>
>    pd->cb = func_desc;
>
>
> And we could generate a caller macro:
>
>    #define FUNCTION_NAME_CALL(desc, ...) \
>       do { \
>          if ((desc)->func) (desc)->func((void *)(desc)->data, ##
> __VA_ARGS); \
>       } while (0)
>
>    #define FUNCTION_NAME_CALL_RET(desc, ret_storage ...) \
>       do { \
>          if ((desc)->func) ret_storage = (desc)->func((void
> *)(desc)->data, ## __VA_ARGS); \
>       } while (0)
>
>    #define FUNCTION_NAME_FREE(desc) \
>       do { \
>          if ((desc)->free) (desc)->free((void *)(desc)->data); \
>          (desc)->func = NULL; \
>          (desc)->data = NULL; \
>          (desc)->free = NULL; \
>       } while (0)
>
> Then I could use in my object code:
>
>
>      _my_class_func_caller(Eo *o, _My_Class_Data *pd, int a) {
>          Eina_Bool r;
>
>          FUNCTION_NAME_CALL_RET(&pd->cb, r, a);
>          FUNCTION_NAME_FREE(&pd->cb); // won't be used anymore
>      }
>
> What do you think?
>
>
As I've introduced the first usage of function pointers in EO I kept
thinking this needs to be standardized in a structure with proper macros.
Otherwise I'm sure we will end up with too many places that forget to free
the user data.

In fact we need a macro like stringshare_replace, which frees the previous
data.

I am not a fan of the call macros though, very ugly (their only value is
the NULL check).

-- 
Jean-Philippe André
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to