Anonymous functions in C.

E

Eric Sosman

Richard said:
But because names in a new scope can shadow outer ones, you have the
problem of inadvertent "variable capture", for example:

#define macro(x) {int t = (x)*2; ...}
...
int t;
macro(t+4);

There are obvious conventions to reduce the problem, but these are
likely to fail if you might have nested macro calls.

Correct me if I'm wrong (it's been known to happen ...),
but I think there's no problem with the example shown. The
scope of the "inner" t begins at the end of its declarator
(6.2.1/7), and the initialization is part of the declarator
(6.7/1). Therefore, in the expanded `int t = (t + 4) * 2;'
the initializer's t refers to the "outer" variable, not to the
variable being initialized.
 
G

Guest

Eric said:
Correct me if I'm wrong (it's been known to happen ...),
but I think there's no problem with the example shown. The
scope of the "inner" t begins at the end of its declarator
(6.2.1/7), and the initialization is part of the declarator
(6.7/1).

The initialization part is not part of the declarator. The grammar
(6.7/1) reads:

init-declarator:
declarator
declarator = initializer

The initializer is part of "init-declarator", which is a combination
of a declarator and an initializer. The initializer is not part of the
declarator itself.
 
E

Eric Sosman

Harald said:
The initialization part is not part of the declarator. The grammar
(6.7/1) reads:

init-declarator:
declarator
declarator = initializer

The initializer is part of "init-declarator", which is a combination
of a declarator and an initializer. The initializer is not part of the
declarator itself.

Thanks for the correction. The grammar seems clear enough,
but the wording in 6.7/6 seems unclear:

"[...] The init-declarator-list is a comma-separated
sequence of declarators, each of which may have [...]
an initializer [...]"

I was reading "have" as "incorporate" or "subsume," but in light
of the grammar I guess it must mean "be accompanied by."
 
J

jacob.navia

Richard Heathfield a écrit :
Michal Nazarewicz said:


Understood (multiple eval), but frankly I wouldn't go adding an entire
new language feature just to make extra work for myself when I can
already write this as:

int i = 2, j = 0, k = 2;

and in any case, the C community already knows not to risk such
expressions as yours when using macros. Are we going to muddy the
waters by introducing a language feature which makes it okay sometimes,
provided you're careful in the #define?

I don't see that as a win.
As you may know, macros and function calls are not
easy to distinguish in C.

You HAVE TO KNOW that you are calling a macro and not a function.
You may know that, or you may not.

What is important for language coherence and transparency is that

foo(i++);

evaluates i only once if it is a macro or not.
 
K

Keith Thompson

jacob.navia said:
Richard Tobin a écrit :

There is only one solution:
make real anonymous functions with arguments, etc.

There is another solution: use ordinary functions (inline if you
like).
How would they look like in C?

No idea.
 
C

CBFalconer

Richard said:
Michal Nazarewicz said:
.... snip ...


Well, this is another lousy example (sorry, Michal!) because it
can be done so easily in standard C:

#define max(a, b) (((a) > (b)) ? (a) : (b))

Doesn't work very well when a and/or b have side effects.
 
R

Richard Heathfield

jacob.navia said:

As you may know, macros and function calls are not
easy to distinguish in C.

It is generally quite simple to find out, if you have decent tools, but
I agree that they are superficially similar in appearance.
You HAVE TO KNOW that you are calling a macro and not a function.

Yes, you do.
You may know that, or you may not.

If you don't, you need to find out.
What is important for language coherence and transparency is that

foo(i++);

evaluates i only once if it is a macro or not.

Nevertheless, the risk exists that it may be evaluated more than once,
and this is well-known within the community. Introducing this new
language feature will not eliminate the risk.
 
M

Michal Nazarewicz

Michal Nazarewicz said:
Michal Nazarewicz said:

Richard Heathfield said:
Understood (multiple eval), but frankly I wouldn't go adding an entire
new language feature just to make extra work for myself when I can
already write this as:

int i = 2, j = 0, k = 2;

and in any case, the C community already knows not to risk such
expressions as yours when using macros. Are we going to muddy the
waters by introducing a language feature which makes it okay sometimes,
provided you're careful in the #define?

I'm not saying we should add this feature. I'm explaining what's it
all about.
 
I

Ian Collins

Richard said:
jacob.navia said:




That is certainly true, but irrelevant unless the caller is abusing the
preprocessor by using macro arguments which oughtn't to be evaluated
more than once. If the motivation for anonymous functions is simply to
make it possible to abuse the preprocessor in comfort, then I don't see
the value. No doubt there are better uses.
Maybe they were introduced before inline functions? The only use I
could see where inline functions don't apply was as a form of generics
inside a macro. But as you say, the need for this can be avoided by not
abusing the preprocessor.
 
A

Alan Curry

Anonymous functions are almost always going to be *nested* functions,
which opens the whole can of worms concerning non-local variables.
Can these functions refer to, and modify, variables in the containing
function?

Yes they can. The containing function passes its own frame pointer as an
extra hidden argument to the nested function.
What happens if you return the functions to outside the
scope of the containing function?

That's very similar to returning a pointer to an auto variable. The return
doesn't extend the lifetime of the thing being referenced. When you try to
call the nested function through that returned pointer, the GCC manual warns
us: "all hell will break loose".

A pointer to a nested function is actually 2 pointers: a pointer to the code
and a copy of the frame pointer of the corresponding instance of the
containing function. Whenever a pointer to a nested function is required, a
wrapper function is dynamically created to encapsulate those 2 pointers.
Passing this wrapper-pointer down to qsort works fine, but you can't return
it. Not only does it require the use of the containing function's local
variables which are now dead, the wrapper function (trampoline) itself died
along with them.
 
R

Richard Tobin

Anonymous functions are almost always going to be *nested* functions,
which opens the whole can of worms concerning non-local variables.
Can these functions refer to, and modify, variables in the containing
function?
[/QUOTE]
Yes they can. [...]

Just to be clear, I was not asking specifically about GCC's
implementation, but pointing out questions that had to be addressed
when adding them to a language.

-- Richard
 
R

Richard Tobin

Your example evaluates at least one argument twice. The example with
the GNU syntax doesn't.
[/QUOTE]
That is certainly true, but irrelevant unless the caller is abusing the
preprocessor by using macro arguments which oughtn't to be evaluated
more than once.

I think this confirms what I said in another article. That you
consider this to be an abuse of the preprocessor is just a consequence
of the language as it is; macro arguments in many other languages are
not expected to be limited in this way.

-- Richard
 
K

Keith Thompson

jacob.navia said:
As you may know, macros and function calls are not
easy to distinguish in C.

You HAVE TO KNOW that you are calling a macro and not a function.
You may know that, or you may not.

The convention is to use all-caps names for macros.
What is important for language coherence and transparency is that

foo(i++);

evaluates i only once if it is a macro or not.

No matter how many features you add to the language to make it
possible for foo(i++) to evaluate its argument only once, it will
still be possible to define a macro foo() that evaluates its argument
multiple times (unless you break existing code). If you write a call
to foo(), and foo() might be a macro, you *still* have to determine
how it evaluates its arguments. Or you can play it safe and do this:

foo(i);
i++;

(and if foo() does evaluate its argument more than once, complain
bitterly to the author for not calling it FOO()).
 
R

Richard Tobin

No matter how many features you add to the language to make it
possible for foo(i++) to evaluate its argument only once, it will
still be possible to define a macro foo() that evaluates its argument
multiple times (unless you break existing code). If you write a call
to foo(), and foo() might be a macro, you *still* have to determine
how it evaluates its arguments.

True, but determining this might merely amount to reading a statement
"all the macros in this library evaluate their arguments exactly
once", which is a guarantee that is currently hard to give.

-- Richard
 
K

Keith Thompson

Ian Collins said:
Maybe they were introduced before inline functions? The only use I
could see where inline functions don't apply was as a form of generics
inside a macro. But as you say, the need for this can be avoided by not
abusing the preprocessor.

The only form of control flow available in a function-like macro is
usually the ternary operator (and && and ||). gcc-like compound
statement expressions let you use, for example, if, while, and for
statements.
 
I

Ian Collins

Keith said:
The only form of control flow available in a function-like macro is
usually the ternary operator (and && and ||). gcc-like compound
statement expressions let you use, for example, if, while, and for
statements.
Eh?

#define fluf( array, size, n ) \
{ size_t index = 0; n = 0; \
while( index < size ) { n += array[index++]; } }
 
R

Richard Tobin

The only form of control flow available in a function-like macro is
usually the ternary operator (and && and ||). gcc-like compound
statement expressions let you use, for example, if, while, and for
statements.
[/QUOTE]
Eh?

#define fluf( array, size, n ) \
{ size_t index = 0; n = 0; \
while( index < size ) { n += array[index++]; } }

This is not function-like in that it cannot return a value. The GCC
extension lets you return a value from a block.

-- Richard
 
S

Steve Thompson

Michal Nazarewicz said:



Interesting. Perhaps something like this:

{ :formal parameter list: { body goes here } value; }


Yeah, this does look like a solution looking for a problem.

Please excuse my butting in here given my relative lack of experience and
expertise, but it seems that there is a point that everyone here is missing
about this problem. If it is usually considered necessary and good to
prevent side-effects from occuring when variables are expanded in macros,
then why is it that the pre-processor is not defined to ensure this doesn't
occur?


Regards,

Steve
 

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

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top