List Processing in C
dekorte.com
dekorte.com
Perhaps more interesting and newsworthy in this context are Apple's blocks, which are closures:
GLib offers closures in C; I've never used them, though, and they don't look very convenient.
Sure, C has function pointers. But it doesn't have closures: the things you can do with just a function pointer are fairly limited.
The callback syntax in the post should really be:
typedef void *(ListMapCallback)(void *item, void *state);
...which gets ugly quickly (passing your closure state around as a void*) and doesn't compose well (passing your closure state into your implementations of List_map_, List_fold_, etc.)All hooks, callbacks, etc. use this approach because that's what a closure is on a low enough level. And in C it looks like void()(void userdata).
typedef BOOL (* WNDENUMPROC) (HWND, LPARAM);
BOOL WINAPI EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam); (mapcar #'(lambda (x) (* x x)) some-list)
which squares all the elements of the list. To do that in C you need some abomination like /* Somewhere outside the function where you actually need this */
int square(x) { return x*x; }
/* ... */
List *r = List_new();
LIST_FOREACH(self, i, v, List_append_(r, square(v)););
Not to mention that this sort of thing tends to get ugly without automatic memory management. #define LIST_FOREACH(var, head) \
for ((var) = (head); (var) != NULL; (var) = (var)->next);
LIST_FOREACH(list_p, list_head) {
...
}
You may also occasionally want to use (C99) variadic macros (gcc seems to need -std=c99): #define LIST_MAP(my_list, f, ...) \
for (struct list *n = my_list; n != NULL; n = n->next) \
f(__VA_ARGS__, n)
void list_print(const char *format, struct list *n) {
printf(format, n->data);
}
int main(void) {
struct list n3 = {NULL, 3},
n2 = {&n3, 2},
n1 = {&n2, 1};
LIST_MAP(&n1, list_print, "%d\n");
} for (pItem = List_First(pList); pItem; pItem = List_Next(pList))
{
//do stuff to pItem
}
It really isn't that much wordier than the ruby (or lisp, or python etc, they all have similar styles for this): list.each do |item|
#do stuff to item
end
and as you do it all of the time, you don't even have a high cognitive load, your fingers can pretty much type it without having to engage the brain.OK, so it's implemented using control structures rather than closures. Is that really such a terrible thing? Am I missing some big advantage here?
Then again, I'm biased. I really like Ruby for its higher-order Lispiness, and not for its webbiness.
It has FOREACH, HEAD, TAIL, INSERT_*, the works.
http://freebsd.active-venture.com/FreeBSD-srctree/newsrc/sys...
queue.h - just say no.
1) The list contains only items of one type - in this case you already know what the type of all objects in the list is - it's a list of widgets, so all items are of type Widget. Whilst queue.h will give you a compiler warning if ever you try to put a File into your widget list, is that every really likely to happen in real life???
2) You have a list of mixed-type objects. In that case you need code to identify at runtime what the type of the object was anyhow, so type safety gets you nothing in that case either.
So, considering how little you get back for the decidely annoying problems of macros and polluted data structures, I really have no hesitation in counselling the avoidance of queue.h.
In answer to your question, no, I don't have a nice typesafe library. But I do have a nice non-typesafe library.
ccan has a much nicer list-for-each: http://ccan.ozlabs.org/info/list.html
#define LIST_FOREACH(list, index, value, code)
I'd prefer #define LIST_FOREACH(list, index, value) \
for(index = 0, value = list->items[0]; \
index < list->size; \
index++, value=list->items[index])
It lets you treat a LIST_FOREACH(...) as a normal for(...) in terms of the other syntax.edit: I did some looking around and determined that the following is probably BS
[1] If you're wondering why I didn't do
index++, value = list->items[index]
it's because expressions separated by a comma can be evaluated in any order (I believe). My friend ran up against it with a bug in jscore.Expressions separated by the comma operator are always evaluated left to right. On the other hand function arguments (which are separated by comma) can be evaluated in any order.
That's correct (for C), but I feel the need to add that in function calls the parameters are separated by commas, and they can be evaluated in any order.
(e.g. http://isis.poly.edu/kulesh/stuff/src/klist/).
Requiring idiosyncratic setup of your list struct though.
Of course, I'm talking only about C, as I love to overuse lambda in Python like it's my job
index++, value=list->items[index]
with value=list->items[++index]
?You were not sure whether the increment would always happen before the assignment. In the combined expression you can simply use the pre-increment operator, which will always increment before the rest of the expression.
It's shorter, unambiguous and leaves less questions. How can something be any "cleaner" than that?
Also, the statements "array[index++]" and "array[++index]" are pretty well-understood idioms in C.
You'll notice that there's a footnote that isn't actually related to anything in the body of the comment. It's because the footnote was wrong; I just felt like it would be dishonest to hide it in the edit. (this is also the reason the edit: I did some looking around...) portion exists.
Interestingly, the edit happened prior to any child posts on the comment, and so was not really a reaction to being corrected. I'd actually googled and found [1], and realized (as someone else said) that function calls don't use the comma as an operator.
tl;dr; never, EVER expect left-to-right evaluation of arguments to a function :)
For example, LISP, Python, and Ruby all offer beautiful and concise constructs for operating on lists of things.
This might be a matter of taste, but macros, void pointers, lack of closures, etc. don't really spell "beautiful and concise" to me. And I think that's what the original quotation is about - you can get similar things done in Java using anonymous classes, and C using function pointers, and probably more or less any language if you try hard enough, but it's just neither beautiful nor concise.
There's probably a rule in those Joint Strike Fighter C++ guidelines that says function pointers shall not be used.
This is why we often give novices rules of thumb like "don't use macros" or "don't use goto." I've seen some people criticize this practice, but I think it's actually a good thing; when you're just starting out, you don't know when these things are really called for. Working under some constraints simplifies things.
With experience, you learn the pain points well enough to outgrow those rules and use macros/goto/whatever when called for.
A nice macro which implements foreach() for C++ is in boost, (BOOST_FOREACH), in foreach.hpp. It's documentation page has an overview of the design considerations that went into making this a 'safe' macro. It's quite informative for learning what to look out for when writing macros.
Tagging posts with dates like that IMHO encourages the view that anything technology related is instantly obsolete. Since the industry seems to keep rediscovering old ideas every couple years and then rejecting them as "old", this probably does far more harm than good.
"You want to make your way in the CS field? Simple. Calculate rough time of amnesia (hell, 10 years is plenty, probably 10 months is plenty), go to the dusty archives, dig out something fun, and go for it. It's worked for many people, and it can work for you." - Ron Minnich