Wednesday, May 29, 2013

A nice-looking with statement in C

I should prefix this with a warning: this only works with C99-or-later compliant compilers. So, if your compiler doesn't support a 14-year-old-standard, read no further, or do it the sane way and get modern one (I'm looking at you, MSVC, pushing us aside in favor of the C++ nerds).

Anyways, with statements.

I like with statements. They make things look so nice - your scope doesn't get cluttered up with useless variables or variables you only need once. They're lovely. Take, as an example, the following Common Lisp:

; look, ma, no cluttered namespace!
(let ((x 3) (y 4))
  (* x y)) ; => 12

Which is neat.

And there are serious benefits to this. It's common knowledge in programming circles that you can only have on average 7 variables in your head with ease (at least, according to Documentation/CodingStyle in the Linux kernel source tree). Using with statements allows you to avoid the problem of keeping track of 15 variables all declared and initialized at the beginning of a function, something I have seen all too frequently in production C (though, to be fair, it's going away now; check out block/blk-core.c in the Linux kernel source tree for an excellent example of declaring many variables at the beginning of a function).

Long story short, we should get in the habit of declaring variables only when we need them and use them for only as long as we have to to keep our heads clear 
of useless junk. One way we can solve this is with with statements.

But how do we implement a with statement in C?

Simple. We look to our old friend, the C99 standard.



6.8.5.3 The for statement

for ( clause-1 ; expression-2 ; expression-3 )

behaves as follows: The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body. The expression expression-3 is evaluated as a void expression after each execution of the loop body. If clause-1 is a declaration, the scope of any variables it declares is the remainder of the declaration and the entire loop, including the other two expressions; it is reached in the order of execution before the first evaluation of the controlling expression. If clause-1 is an expression, it is evaluated as a void expression before the first evaluation of the controlling expression.)

Oh, neat. So we can make arbitrary lexical scopes with for loops. Not only that, but we can force our condition to be true or false whenever we want it to be, because the lexical scope of the variables also includes the other statements in the for loop.

But how do we break out of them?

Simple - we just need another variable.

Now that we have this down, let's write a macro.

Before we get into this, there's a caveat - although you can declare multiple variables, you can't have multiple declarations. Everything in the with statement has to be of the same type. This isn't actually too much of a problem, because the control structure is nestable, so if you need variables of different types, stack the withs on top of each other.


#define with(...) for (__VA_ARGS__, *_wth=(void*)1; _wth; _wth = NULL) 


Here, it's what you'd expect. On top of the declarations passed by the user, we define our own statement which we know is going to evaluate to true at first, then false on the second run-through. Note that this is nestable - we only care about the value of _wth in the clauses of the for-statement; if we have a for-statement which defines the same variable in clause 1, the value will supersede the _wth in the outer for, but won't change its value or rebind it. This is perfectly safe.

We also use a variadic macro because we don't know how many assignments are being passed. Pretty straightforward.

The last thing that's important in understanding this macro is why _wth is declared the way it is. The thing is, the way this'll expand is as follows:

with (int i=3,j=4)
    => for (int i=3,j=4,*wth=(void*)1; /* ... */)

So _wth is actually just a pointer to whatever type the temporary variables are. We need to use a pointer because we're not guaranteed to get an integral type - we could just as easily get a struct or a union as an int or a pointer. This is a consistent and type-safe way of doing it, and it makes sure it always works.

So, now we have a very nice with statement. Now, we can write

with (FILE *stream = fopen("/etc/passwd", "r")
    printf("%s\n", file_to_string(stream));

A multiple-statement flavor looks like this:

with (FILE *stream = fopen("/etc/passwd", "r") {
    do_stuff_with_stream(stream);
    printf("%s\n", file_to_string(stream));
}

We can also bind multiple temporary variables like so:

with (int i = 2, j = 3)
    printf("i=%d\nj=%d\n", i, j);

And, of course, we can nest with statements, if you're using a variety of types:

with (int i = 2)
    with (float j = 3.0f)
        printf("i=%d\nj=%f\n", i, j);

I recommend, if multiple types are needed, stacking the withs on top of each other like this (this can be done just like this after if-statements without brackets, but it may be more readable to put them anyways):

with (int j = 3)
with (float d = 4.0f)
with (struct foo bar = baz()) {
    /* do things with j, d, and bar */
}

Of course, you could also put them all on the same line.

I should add that this is functionally the same as just making a new block, e.g.

{
   struct foo *bar = baz();
   use_bar(bar);
   destroy_foo(bar);
}

The reason I like with versus this is because firstly, this syntax is a lot more consistent with normal C control structures, a la if and while. Also, using with emphasizes the variables and separates the variables from the code, allowing the reader to more quickly understand the purpose of the block. For example, it takes a lot less time to understand

with (FILE *file = fopen(...))
  ...

than it does to understand

{
    FILE *file = fopen(...);
    ...
}

So, now we have a nice syntax. Cool.

Monday, May 13, 2013

Curried Functions in C

A curried function is a function which takes only one parameter and returns a function defined according to that parameter. This is a more powerful idea than is implied by that last sentence. And curried functions are everywhere.

Take Haskell, for example. In Haskell, *every* function is curried. Not just ones you specify. Everything. So, in Haskell, if you have

foo :: (Integral a) => a -> a -> a
foo a b = a + b

Writing

foo a b

Is equivalent to

(foo a) b

The reason for this is that foo isn't invoked with two parameters passed. Instead, foo is invoked with one parameter passed, which results in an expression in terms of another variable. This expression is returned as a function and then applied to the next argument.

The equivalent of a curried function in math would be something like this:

f(x) = x / y

If one were to invoke f, with x=5, the resulting expression would be

f(5) = 5 / y

Which is an expression in terms of y. (Of course, this wouldn't really happen in math, but this is just an example to attempt to make currying more clear to those unfamiliar with the idea.)

This concept of returning expressions is nice, and it can be used in a whole lot of neat ways, but how do we apply it to C? And that's the important part.

Let's examine C's concept of a function.

In C, functions are not first-class objects. In Python, you can write

def foo(a, b):
        a(b)
def bar(b):
        return b + 1
foo(bar, 5) # => 6

However, of course, in C, you can't pass functions directly. You can, however, use pointers to functions. And pointers, of course, are just variables. And, as it turns out, every function name is actually just a pointer to that function.

So, if in the statement

foo(a, b, c);

foo is just a pointer to something, why does this result in the function being called?

Simple.

The parentheses are actually C's call operator. That's right. It's an operator, just like + or * or sizeof or &.

This leads us to an interesting question. Because we know

foo(a, b, c) * 2 + 1;

Is a valid C expression, in which whatever the return value of foo is will be operated on with the rest of the expression, can we also use the call operator on expressions which evaluate to function pointers?

The answer is yes.

For example, in C, you can write:

typedef int (*fun_t)(int);

int bar(int a)
{
        return a * 5;
}

fun_t foo(void)
{
        return bar;
}

void some_fun(void)
{
        foo()(5); // => 25
}

Now, this is seriously cool, in a lot of ways. And, we can use it to write curried functions.

But, of course, typing is painful, and we don't want to do a lot of typing and thinking about what-should-return-what. So, we should write a macro.

Let's do that.

Here's the macro I came up with:

#define DECLARE_CURRIED_FUNCTION(name, type, op) \
    typedef type (*_curry_##name##_t)(type); \
    type _curried_a_##name; \
    type _curried_ret_##name(type b) { \
        type a = _curried_a_##name; \
        op;\
        return b; /* stifle warnings */ \
    } \
    _curry_##name##_t name(type a) { \
        _curried_a_##name = a; \
        return _curried_ret_##name; \
    }

This is a macro which will define a curried version of a function which takes two arguments. Those arguments are referenced in op as a and b. This macro will have to be tweaked to support functions with a different amount of arguments - multiple flavors may have to be created, though the creation of different flavors is trivial. As well, as the value of a is passed in a global variable, nasty bugs may occur if, in a multithreaded application, a is not serialized or thread-local. Also, for best results, use this macro in the global scope, and not within functions.

With those caveats out of the way, we have a neat little macro. Now, we can define curried functions neatly:

DECLARE_CURRIED_FUNCTION(add, int, return a+b);

Then, if we wish to fully evaluate add:

add(5)(3); // => 8

Which is neat. We can also use partial application to expand the power of map macros:

#define map_array(fun, array, len) \
        for (int _map = 0; _map < len; map++)
                fun(array[_map]);

DECLARE_CURRIED_FUNCTION(foo, int, printf("%d\n", a+b));

/* ... */

int array[] = { 1, 2, 3, 4, 5 };
map_array(foo(5), array, 5); //prints 6\n7\n8\n9\n10\n

This is extraordinarily useful - we may now write with a nice syntax otherwise complicated expressions.

We can also use this technique to write otherwise annoying statements in a rather nice syntax.

Consider a function which takes the dot product of 3d vectors from two sets of 3 integers.

Ordinarily, we'd write it like this:

result = dot_product(1, 2, 3, 4, 5, 6);

Using this technique, though, we can separate the two vectors, resulting in a somewhat prettier function call:

result = dot_product(1, 2, 3)(4, 5, 6);

This technique is extremely powerful. I refer to this as the "curry-by-pointer-return" technique, as we are returning pointers to functions.

Currying is an extraordinarily useful tool, and now, we have a pretty syntax to do it with.

Monday, May 6, 2013

Abuses of the C Preprocessor

As a mental exercise, let's abuse the C preprocessor. It's powerful, it's useful, and it's fun.

Let's write some loops. Because we can.

Let's start simple. We'll define a family of REPEAT() macros. Those'll look like this:

#define REPEAT(x) { x; }
#define REPEAT2(x) { x; x; }
#define REPEAT3(x) { x; x; x; }
#define REPEAT4(x) { x; x; x; x; }
#define REPEAT5(x) { x; x; x; x; x; }

Then, we can chain these together:

#define REPEAT10(x) { REPEAT5(x); REPEAT5(x); }

This can get out of hand quickly:

#define REPEAT1000(x) { REPEAT10(REPEAT10(REPEAT10(x))); }

Now, if we write an innocuous-looking statement like

REPEAT1000(printf("Hello, world!\n"));

The compiler will, without complaint, emit the functional equivalent of

for (int i = 0; i < 1000; i++)
        printf("Hello, world!\n");

unrolled. 

But this isn't complicated enough. We must go deeper.

We can use recursive inclusion to emit the functional equivalent of the above. The basic plan is, we include a file from within that file, each time defining a loop counter to a different value. Here's the first attempt, in a file thisfile.h:

#ifndef MACRO
#define MACRO printf("Hello, world!");
#endif
#ifndef I
#define I 0
#endif

#if I == 0
MACRO
#undef I
#define I 1
#include "thisfile.h"
#endif

#if I == 1
MACRO
#undef I
#define I 2
#include "thisfile.h"
#endif

#if I == 2
MACRO
#undef I
#define I 3
#include "thisfile.h"
#endif

Ad nauseam. We can put brakes on this kind of iteration by testing I against another preprocessor constant, say, USER_CONSTANT, and writing our loops like this:

#if I == 1
MACRO
#if I != USER_CONSTANT
#undef I
#define I 2
#include "thisfile.h"
#endif
#endif

We can use it like this:

int main()
{
#define USER_CONSTANT 3
#include "thisfile.h"
}

There are two problems with this - firstly, we have to manually write out every stage in the loop (which can be circumvented by even more clever macros or scripts), and, secondly, we soon hit a wall with the compiler - the compiler will only go to a depth of 200 includes or so before it craps out. So, let's abandon this technique in favor of something else.

Here's where it gets really fun.

Let's write a recursive macro using some techniques pioneered by a very intelligent man known as Pfultz2 on Github.

Before we get into recursion, there's something important to understand about the way macros are expanded. When a macro is expanded, a disabling context is created, in which the macro being expanded is tagged. Any macros tagged this way can't be expanded this expansion cycle. That's why we can't write recursive macros - if we wrote something like this

#define FACTORIAL(n) ((n) == 1? 1 : FACTORIAL((n)-1))

int x = FACTORIAL(10);

We'd get an error - FACTORIAL is the tagged token in this disabling context. So, we'll have to hack around it.

But, before we go deeper, we have to get some background on control structures in the C preprocessor.

First, we need a macro to splice two names together. This is trivial:

#define CAT(x, ...) CAT_(x, __VA_ARGS__)
#define CAT_(x, ...) x ## __VA_ARGS__

Straightforward so far, right?

Now, we can implement high-level functionality by expanding macros to other macros and forcing other scans. We can do this by writing an eval macro:

#define EVAL(...) __VA_ARGS__

We need to force another scan because otherwise the compiler will say, "Well, we've expanded this macro. I guess we're done here."

And then implementing something trivial. For example, let's implement a COMPLEMENT macro. If a one is passed, it'll evaluate to 0. If a 0 is passed, it'll evaluate to 1.

#define COMPLEMENT(x) EVAL(CAT_(COMPLEMENT_, x))
#define COMPLEMENT_0 1
#define COMPLEMENT_1 0

Now, if we write

COMPLEMENT(1)

It will expand like so:

COMPLEMENT(1) -> EVAL(CAT_(COMPLEMENT_, 1)) ->
EVAL(COMPLEMENT_1) -> COMPLEMENT_1 -> 0

Now, let's implement an if-statement in the preprocessor. First, we'll need a facility to cast predicates to a boolean type we can use. We can do this with the classic NOT-NOT operator, written in the preprocessor.

Pfultz2 has already implemented for us a NOT operator, using a macro called CHECK. It works like this:

First, we define a macro, CHECK.

#define CHECK_N(a, b, ...) b
#define CHECK(...) CHECK_N(__VA_ARGS__, 0)

Then, a NOT operator:

#define NOT(x) CHECK(CAT_(NOT_, x))
#define NOT_0 _foo_, 1

This works, because for CHECK() to expand to anything but 0, it needs two arguments. If anything is passed to NOT() that will not expand to NOT_0 by CAT_()ing the argument with NOT_(), only the result will be passed - only one argument. This means the default second argument, 0, will be passed. Because neither _foo_ nor anything else passed in the first argument will expand, we get no syntax errors.

Neat-o, now we can write a cast to bool:

#define BOOL(x) COMPL(NOT(x))

And now we have something which can expand arbitrary values to 0 or 1.

We're getting close here to an IF statement. The last thing we need is a block. What we need to  do is expand a macro to another macro which takes arguments - then we can put the body in the parens. This is trivial, considering what we know already:

#define IF_(c) CAT_(IF_, c)
#define IF_0(t, ...) __VA_ARGS__
#define IF_1(t, ...) t
#define IF(c) IF_(BOOL(c))

And, blam-o, now we have an IF statement. We write IF statements like this:

EVAL(IF(1) ( true(); , false(); ))

So, what's the point of all this?

Now, we can stop a macro from expanding by forcing it to expand to something that won't expand further.

We're almost to recursive macros. We need one last thing - a way of getting around the disabling context.

As it turns out, that's rather trivial. What we need to do is provide a way of accessing the macro from within the disabling context. We can use this by a technique called deferred evaluation.

The technique is simple. First, define a macro, DEFER(), which causes a macro to not be expanded until later.

#define EMPTY()
#define DEFER(x) x EMPTY()

Then, we write a macro to force another scan, so that whatever is deferred can be expanded later:

#define EXPAND(...) __VA_ARGS__

And now we have a system for controlling how macros expand.

We run into one limitation - we can't actually do any arithmetic without complex workarounds, but we can do much simpler stuff. Consider this WHILE macro by Pfultz2:

#define WHILE(pred, op, ...) \
        IF (pred(__VA_ARGS__)) ( \
                DEFER(WHILE_INDIRECT)() ( \
                        pred, op, op(__VA_ARGS__) \
                ),\
                __VA_ARGS__ \
        )
#define WHILE_INDIRECT WHILE

This macro works by recursively invoking itself whenever pred(__VA_ARGS__) results in a positive integer.

We can invoke this by writing helper macros.

First, the predicate:

#define PREDICATE(x) CAT_(PREDICATE_, x)
#define PREDICATE_3 2
#define PREDICATE_2 1
#define PREDICATE_1 0

Then, a better EVAL macro:

#define EVAL(x) EVAL1(EVAL1(EVAL1(EVAL1(EVAL1(x)))))
#define EVAL1(x) x

Then, the operation:

#define OP(x) printf(x)

Now, we invoke the WHILE macro:

EVAL(WHILE(PREDICATE(3), OP, "Hello, world!\n")))

Which will evaluate to an expression which prints "Hello, world!" 3 times.

Recursive macros are a bit harder to write than recursive includes, but they sure are fun.

Now, let's get the takeaway - these are fun to think about, but not really useful.

But they can be.

Let's examine a real-world application.

Say you wanted to do some loop unrolling for fetching nodes in a linked list. Say you knew at compile-time what node you wanted.

You could write a set of macros as follows, assuming the REPEATx macros from above have been implemented:

#define EVAL(...) __VA_ARGS__
#define CAT(a,b) a ## b
#define LIST_GET_NTH_NODE(list, parser, node) { parser = list; EVAL(CAT(REPEAT, node)(parser = parser->next))}

Where list is the first node in the list,  parser is a pointer to a node, and node is a constant number referring to the position of the node in the list.

And just like that, we have a real-world application.