Hey all. As usual, my question isn't a simple "malloc kilz prg w/segfault".
I needed a generic list type in C, so I hacked up a simple library that does that.
I parameterized it like is done in C++ templates:
| 12
 
 | #include "list.h"
list_t (int) numbers;
 | 
However, I quickly realized that I'd have to use the GCC 
typeof() operator to avoid having to name the element type when using things like
| 12
 
 | /* Pretty GCC stuff */
int x = *list_first( numbers );
 | /* But I know the type anyway... */
int x = *list_first( int, numbers ); | 
(This code has to be extremely portable -- so GCC extensions are out, especially for just a couple small things like that pretty stuff.)
Next it became apparent that the actual type of the elements in the list are not needed. I could just as easily have coded the above as:
| 12
 3
 4
 
 | #include "list.h"
list_t numbers;
...
int x = *list_first( int, numbers );
 | 
However, I 
liked having the element type in the typename of the list. I like the explicit typing, and it makes it easier for the programmer to remember to avoid abuses like adding differently typed data to the same list.
| 12
 3
 
 | list_t numbers;
list_append( numbers, 12 );
list_append( numbers, "Hello" );
 | 
Of course, without the typeof() operator, or true generics (which I'll mention below) it is impossible to guarantee against such behavior...
Also, I still need to 
typedef stuff, since you can't use anonymous 
structs in argument lists and the like (at least not without complaints).
| 12
 3
 4
 5
 6
 
 | void print_list( list_t (point_t) ls );
...
list_t (point_t) points = {0};
...
print_list( points );
 | test-list.c:39: warning: anonymous struct declared inside parameter list
test-list.c:39: warning: its scope is only this definition or declaration, which
 is probably not what you want
test-list.c: In function 'main':
test-list.c:63: error: incompatible type for argument 1 of 'print_list'
... | 
In this case, it probably 
is what I want, but I don't want my library code generating error messages, so I have to eschew using the generic type directly in lieu of the aforementioned typedef:
| 12
 3
 4
 5
 6
 7
 
 | typedef list_t (point_t) point_list_t;
...
void print_list( point_list_t ls );
...
point_list_t points = {0};
...
print_list( points );
 | 
That's a bit disappointing. So ultimately, there doesn't seem to be much point in parameterizing over a type at all. Except, of course, for the same pretty factor that was dismissed earlier.
True generics 
can be achieved in C. For example:
   generic_list.h
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | #ifndef DATATYPE 
#error You must #define DATATYPE before #including this file!
#endif
/* The structure definition */
typedef struct DATATYPE ## _node_tag
  {
  struct DATATYPE ## _node_tag* next;
  struct DATATYPE ## _node_tag* prev;
  DATATYPE                      data;
  }
  DATATYPE ## _node_t;
typedef struct
  {
  DATATYPE ## _node_t** first;
  DATATYPE ## _node_t** last;
  unsigned long         length;
  }
  DATATYPE ## _list_t;
/* Prototypes */
DATATYPE* DATATYPE ## _list_first( DATATYPE ## _list_t list );
unsigned long DATATYPE ## _list_append( DATATYPE ## _list_t list, DATATYPE data );
etc
#undef DATATYPE 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | #include "generic_list.h"
#define DATATYPE int
#include "generic_list.h"
typedef struct { int x, y; } point_t;
#define DATATYPE point_t
#include "generic_list.h"
...
int_list_t     primes;
point_t_list_t points;
...
 | 
This, of course, includes all the overhead of regular C++ templates, plus it requires some careful compilation... (And this is all simplified considerably, of course. If I go this route I'll make the #including and the like much less gory for the user 
which is likely just myself anyway...)
So here's the question.
What do you gurus think? Should I stick with my simple untyped-generic above? Should I get rid of the "pretty template jazz" which has no apparent point?
Or should I just give in and use true generics?
Remember, I'm using ANSI C89 here. Thanks for reading. :-@