Functional programming in C with macro "Higher Order Function" generators
Asked Answered
O

3

32

Pay attention carefully because this is a hell of a question ;-)

I want to use template functions for generic collection actions (like search, foreach, etc.) in C while maintaining compiler static type checking. It is fairly straightforward while you're using simple callbacks like in this example:

#define MAKE_FOREACH(TYPE)\
void foreach_##TYPE (TYPE[n] array, int n, void(*f)(TYPE)) {\
  for(int i = 0; i < n; i++) {\
    f(array[i]);\
  }\
}

so you can do things like:

MAKE_FOREACH(int)
MAKE_FOREACH(float)

void intcallback(int x){
  printf("got %d\n", x);
}

void floatcallback(float x){
  printf("got %f\n", x);
}

int main(){
  int[5] iarray = {1,2,3,4,5};
  float[5] farray = {1.0,2.0,3.0,4.0,5.0};
  foreach_int(iarray, 5, intcallback);
  foreach_float(farray, 5, floatcallback);
}

If I'd like to implement callbacks with return types, for example to make a "map" function, I could do:

#define MAKE_MAP(TYPE, RTYPE)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE)) {\
  RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
  for(int i = 0; i < n; i++) {\
    result[i]=f(array[i]);\
  }\
}

So far, so good. The problem comes now, when I want my callback functions to accept any number of typed arguments.

The idea is something like:

#define MAKE_MAP(TYPE, RTYPE, ...)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE, __VA_ARGS__), __VA_ARGS__)
/*this would work for the declaration (because just the types would be enough)
but the  parameter names are missing :-s*/ \
{\
  RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
  for(int i = 0; i < n; i++) {\
    result[i]=f(array[i], /*here the names of the parameters, in order*/);\
  }\
}

so, as you can see, I could declare a map function as:

MAKE_MAP(int, float, char)

giving:

float* map_int(int[n] array, int n, float(*f)(int, char), char);

but I cannot figure how to implement the parameter passing with the preprocessor. Here is where I ask for your help, ideas and suggestions.

(By the way, don't tell me to use a variadic function as template and passing a va_list argument to the callback, because all this stuff was because of the type checking :-p)

Obliquity answered 21/5, 2009 at 17:43 Comment(4)
MAYBE IF I JUST PUSH A LITTTTLE HARDER THIS SQUARE PEG WILL FIT IN MY ROUND HOLE!!!!Pharyngo
Kudos for tagging this "preprocessor-abuse". I'm thinking right now of how I would write a MAKE_PROGRAM() macro.Vassaux
This certainly is preprocessor abuse, but isn't the oh-so-fashionable template meta-programming really just C++ template system abuse too? Sometimes the only sensible answer is to push the tool to the edge of its usability.Gautama
+1 for interesting preprocessor abuse.Gautama
I
12

If you are on Linux/BSD Unix, take a look at queue(3) and check into /usr/include/sys/queue.h - it's been done before :)

Ishmael answered 21/5, 2009 at 18:4 Comment(0)
H
1

A recent question raised quite a few shameless preprocessor abusing libraries.

Helainehelali answered 22/5, 2009 at 4:13 Comment(0)
W
1

For information, the source code of GCC 4.6 implements similar tricks for vectors. Look into its file gcc/vec.h

Walsingham answered 27/10, 2011 at 14:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.