Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the lambda macro create a lambda?

I found this piece of code on GitHub but didn't quite understand it:

#define lambda(ret_type, _body) ({ ret_type _ _body _; })

Then:

int (*max)(int, int) = lambda(int,
                             (int x, int y) {
                                 return x > y ? x : y;
                             });

int max_value = max(1, 2);
// max_value is 2

What are the underscores doing inside the #define and how does it return a function pointer?

like image 401
Kish Avatar asked Jan 30 '20 16:01

Kish


2 Answers

Using this macro,

int (*max)(int, int) = lambda(int,
                              (int x, int y) {
                                  return x > y ? x : y;
                              });

expands to:

int (*max)(int, int) = ({
    int _ (int x, int y) { return x > y ? x : y; }
    _;
});

In the curly braces, this uses GCC's Nested Functions to create a function that performs the desired operation. Within the inner scope, it has the name _.

Then, as noted by interjay, GCC's Statement Expressions are used. Effectively, the function _ is assigned to the pointer max.

If such a macro isn't being used, this could be written differently and used as:

int val1 = 4;
int val2 = -30;

int perform_operation(int (*op)(int, int)) {
    int new_val = op(val1, val2);
    val1 = val2;
    val2 = new_val;
    return new_val;
}

int enclosing_function (void) {
    // Create max "lambda"
    int (*max)(int, int);
    {
        // Curly braces limit the scope of _
        int _ (int x, int y) { return x > y ? x : y; }
        max = _;
    }

    return perform_operation(max);
}

The three methods can be compared in this code example.

like image 129
Thomas Jager Avatar answered Nov 15 '22 00:11

Thomas Jager


This is called a statement expression and creates a "lambda" (or nested function) and returns a pointer to it. It is GNU C-specific.

The macro expands to:

int (*max)(int, int) = ({ int _ (int x, int y) { return x > y ? x : y; } _; })

The _ at the end is like a return.

The underscore is actually the name of the function that is created and "returned". It's used because it's an uncommonly-used identifier (for good reason; _ is quite possibly the least descriptive identifier possible).

The reason the statement expression is used is so _ won't be defined after the scope of the statement expression exits.

So, going through the macro:

#define lambda(ret_type, _body) ({ ret_type _ _body _; })

ret_type is the return type of the "lambda". _ is the name of the function used inside it because it is an uncommon identifier name. _body consists of the arguments and body of the function. The trailing _ "returns" the "lambda".

This code is found at Let's Destroy C (which is an appropriate name). You shouldn't use it. It will make your code work only on compilers that support GNU C extensions. Instead, just write a function or macro.

If you use constructs like this a lot or want more features, I suggest using C++. With C++ you can do something similar to this and have portable code.

like image 27
S.S. Anne Avatar answered Nov 14 '22 23:11

S.S. Anne