
List Comprehensions in C - fogus
http://benlynn.blogspot.com/2011/04/list-comprehensions-in-c.html
======
skrebbel
Nice trick, but you end up selling a _LOT_ of readability and maintainability
just to get a "cool feature". When in Rome, act like the Romans: wouldn't a
nested for loop do the trick just fine, in a way any C programmer can
understand?

~~~
xyzzyz
I do not think that author considers it useful in real world programming. It
is a cool hack, therefore we should treat it like one, and not complain about
readability.

~~~
cema
I think it's more than a hack. List comprehension is a way to look at list
manipulations which comes from the functional paradigm of programming. It is
interesting and instructional to see how it can be expressed in a heavily
imperative language like C. I would say it's a teaching tool, not just a hack.

------
tedunangst
Minor point: Extensive use of GNU extensions, so not really C.

Major point: Very much easier to do this in C++ by overloading operators for
list<>:

    
    
        L2 = L1 + L3; // L2 is L1 concat L3
        L2 = L1 < 3; // L2 is L1 elements less than 3
        L2 = L1 | even; // L2 is L1 elements passed through a filter for even numbers

~~~
ot
There is a C++ library proposal to implement (lazy) range algorithms and
overload the operator| for their composition:

[http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2005/n187...](http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2005/n1871.html)

it would allow to do things like

    
    
      std::copy( ptr_vec | std::reversed | std::indirected,
                 std::ostream_iterator<int>( std::cout ) );
    

Boost.Range implements part of the proposal, a much more complete
implementation is Oven
(<http://p-stade.sourceforge.net/oven/doc/html/index.html>), which includes
the pipe operator, but I think it is unmaintained.

The result can be very readable and robust, I've seen complex production code
using extensively this syntax.

~~~
pstademb
Now Oven is fortunately maintained by awesome hackers in Japan. The latest C++
should compile against the trunk.

Regards,

------
k4st
I implemented a rather nice C++ pattern matching facility for productions of
context-free grammars in my undergraduate thesis project
(<http://www.grailplus.org>). It is able to do some really fancy stuff and I
think that is one were using C++ then one could use some similar techniques
for creating list comprehensions. Here's how I envision it working:

First, the variables used in the comprehension would be defined locally, with
the right types.

Second, we would need an overloaded template function, named something like
"constructor" to abstractly represent a constructor for some arbitrary object.
Here is how the constructor function works: for N arguments, all taken by
reference, it allocates an array of N void * pointers (or sufficiently large
slot sizes + proper alignment to hold any pointer type), and returns a pointer
to the first slot in that array as some member in an instantiated template,
where one of the parameters of the template contains all the info of the types
of the constructor parameters. It also initializes each slot of the array to
be the address of the local variable passed in to the constructor function by
reference. So, if the following is my setup:

    
    
       int foo;
       float bar;
       constructor<std::pair>(foo, bar)
    

returns an object of type Constructor<std::pair, Slot<Base<int>,float> >,
where the object contains a pointer to the first slot in the array. This type
and the array contain all the info we need to construct an
std::pair<int,float>.

The comprehensions would likely require an new iteration mechanism. This was
the case in my thesis project, as a cursor-based iterator, while being able to
represent the iteration aspect of this, is unable to fully represent the
pattern-matching/destructuring bind operations. The tricky part is to make it
so that one can advance multiple loops in sequence.

When we know that we can enter the body of the inner loop that would normally
represent the innermost loop in an imperative implementation of the same
operation being performed by the comprehension then we can use the pointer
table to bind values to local variables, and then use a compile-time created
function from the Constructor type to yank out those values all at once,
impose the proper types using a cast on the void * pointers, and then
construct the thing we want to add into our final list.

