Lambda's in GCC

J

Joe D

I'm posting this in case someone finds it useful, I've already posted
it a couple of times in answers to stack overflow. It's an macro to
create lambda expressions in GCC, however it only works in GCC no
other compilers support it (not even clang).

#define lambda(return_type, body_and_args) \
({ \
return_type __fn__ body_and_args \
__fn__; \
})

Use it like this:

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

Or with qsort:

qsort (array, 42, sizeof (int), lambda (int, (const void * a, const
void * b)
{
return *(int*)a - *(int*)b;
}));

As I've said, I'm just posting it in case anybody find's it useful.
 
J

Joe D

And if anybody is interested I can post an implementation of a foreach
loop, that works with ICC, GCC and Clang.
 
G

Gene

I'm posting this in case someone finds it useful, I've already posted
it a couple of times in answers to stack overflow. It's an macro to
create lambda expressions in GCC, however it only works in GCC no
other compilers support it (not even clang).

#define lambda(return_type, body_and_args) \
  ({ \
    return_type __fn__ body_and_args \
    __fn__; \
  })

Use it like this:

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

Or with qsort:

qsort (array, 42, sizeof (int), lambda (int, (const void * a, const
void * b)
  {
    return *(int*)a - *(int*)b;
  }));

As I've said, I'm just posting it in case anybody find's it useful.

It's a bit grand to call this lambda, since you can't bind lexically
enclosing variables. Nice trick though.
 
B

Ben Bacarisse

Joe D said:
I'm posting this in case someone finds it useful, I've already posted
it a couple of times in answers to stack overflow. It's an macro to
create lambda expressions in GCC, however it only works in GCC no
other compilers support it (not even clang).

#define lambda(return_type, body_and_args) \
({ \
return_type __fn__ body_and_args \
__fn__; \
})

Use it like this:

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

I don't think that is enough like a normal lambda to call it a lambda.
As I understand the GCC extension you are using, it can't capture
bindings that are in scope when the lambda returns its pointer.

<snip>
 
B

BGB / cr88192

Ben Bacarisse said:
I don't think that is enough like a normal lambda to call it a lambda.
As I understand the GCC extension you are using, it can't capture
bindings that are in scope when the lambda returns its pointer.

<snip>

yeah...

I once considered something similar (although possibly with variable
capture) as a compiler extension with a syntax like:
<type>(<args>) { <body> }

so, for example:
int(int x, int y) { x+y; }
would behave similarly to a lambda.

or, a keyword like "__fun" could reduce the addition of parser complexity
(or possible ambiguity).


however, I never really implemented this feature (I started later becomming
a bit more conservative with compiler extensions, mostly since I tend to
share a lot of code between my compiler and native compilers such as GCC or
MSVC, and more "extreme" compiler extensions essentially get in the way of
code-mobility).

the result then is that most of my extensions either:
exist in existing compilers;
serve some "necessary" role (can't be reasonably done by other means, rare);
offer a performance advantage and can be trivially emulated (such as my
vector extensions, which can use built in vectors in my compiler, and fall
back to generic SIMD types or structs for other compilers, and are generally
wrapped in macros or inline functions which themselves use the
compiler-specific mechanisms).

since a lambda does none of the above, I haven't added it.

or such...
 
J

Joe D

I don't think that is enough like a normal lambda to call it a lambda.
As I understand the GCC extension you are using, it can't capture
bindings that are in scope when the lambda returns its pointer.

<snip>

What exactly do you mean? If you mean you can't use local variables
from the enclosing scope then your wrong, try it out.
 
R

Rob Kendrick

What exactly do you mean? If you mean you can't use local variables
from the enclosing scope then your wrong, try it out.

Can you continue to use those automatic variables from the enclosing
scope if the enclosing scope returns a function pointer to your
"lambda" to its caller, who then calls it?

B.
 
B

Ben Bacarisse

Joe D said:
What exactly do you mean? If you mean you can't use local variables
from the enclosing scope then your wrong, try it out.

Yes, that's the general idea, but it goes slightly further than using
local variables from the enclosing scopes. With a true lambda form, the
enclosing scopes may have "finished" but the lambda still carries the
binding during its lifetime. For example:

#include <stdio.h>

#define lambda(return_type, body_and_args) \
({ \
return_type __fn__ body_and_args \
__fn__; \
})

int (*adder(int what))(int)
{
return lambda(int, (int x) { return x + what; });
}

int main(void)
{
int (*inc1)(int) = adder(1);
int (*inc2)(int) = adder(2);
printf("%d %d\n", inc1(1), inc2(1));
return 0;
}

This prints 3 and 3 rather than 2 and 3. If I duplicate the printf call
(which messes up that stack some more) I get a seg fault.
 
J

Joe D

Yes, that's the general idea, but it goes slightly further than using
local variables from the enclosing scopes.  With a true lambda form, the
enclosing scopes may have "finished" but the lambda still carries the
binding during its lifetime.  For example:

  #include <stdio.h>

  #define lambda(return_type, body_and_args) \
    ({ \
      return_type __fn__ body_and_args \
      __fn__; \
    })

  int (*adder(int what))(int)
  {
       return lambda(int, (int x) { return x + what; });
  }

  int main(void)
  {
       int (*inc1)(int) = adder(1);
       int (*inc2)(int) = adder(2);
       printf("%d %d\n", inc1(1), inc2(1));
       return 0;
  }

This prints 3 and 3 rather than 2 and 3.  If I duplicate the printf call
(which messes up that stack some more) I get a seg fault.

I see what you mean, thanks.

- Joe
 
U

Uno

Joe said:
I see what you mean, thanks.

$ gcc -std=c99 -Wall -Wextra lambda1.c -o out
$ ./out
3 3
$ cat lambda1.c
#include <stdio.h>

#define lambda(return_type, body_and_args) \
({ \
return_type __fn__ body_and_args \
__fn__; \
})

int (*adder(int what))(int)
{
return lambda(int, (int x) { return x + what; });
}

int main(void)
{
int (*inc1)(int) = adder(1);
int (*inc2)(int) = adder(2);
printf("%d %d\n", inc1(1), inc2(1));
return 0;
}

// gcc -std=c99 -Wall -Wextra lambda1.c -o out
$

Interesting. Been a while since I looked at this stuff.

Ben's in clc seem to be sharper than the rest of us.
 
M

Mark

Joe D said:
I'm posting this in case someone finds it useful, I've already posted
it a couple of times in answers to stack overflow. It's an macro to
create lambda expressions in GCC, however it only works in GCC no
other compilers support it (not even clang).

#define lambda(return_type, body_and_args) \
({ \
return_type __fn__ body_and_args \
__fn__; \
})

What gcc extension is being used? I failed to find anything relevant in my
"info gcc" for 4.1.1.
 
B

Ben Bacarisse

Mark said:
What gcc extension is being used? I failed to find anything relevant
in my "info gcc" for 4.1.1.

Two things:

(A) A block expression[1]. When gcc has extensions turned on, ({...}) is
an expression whose value can use the full syntax of a block to
calculate the result (__fn__ in the macro).

(B) Nested function definitions[2]. The line

return_type __fn__ body_and_args

will expand to a function definition nested inside the block in the
block expression.

[1] http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Statement-Exprs.html#Statement-Exprs

[2] http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Nested-Functions.html#Nested-Functions
 
U

Uno

Ben said:
Mark said:
What gcc extension is being used? I failed to find anything relevant
in my "info gcc" for 4.1.1.

Two things:

(A) A block expression[1]. When gcc has extensions turned on, ({...}) is
an expression whose value can use the full syntax of a block to
calculate the result (__fn__ in the macro).

(B) Nested function definitions[2]. The line

return_type __fn__ body_and_args

will expand to a function definition nested inside the block in the
block expression.

[1] http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Statement-Exprs.html#Statement-Exprs

[2] http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Nested-Functions.html#Nested-Functions


Ben,

I'm gonna read these links and have questions for you.

Block expression in particular.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top