lambda functions proposal

22 views
Skip to first unread message

Andrei Alexandrescu

unread,
Nov 24, 1998, 3:00:00 AM11/24/98
to
Hello,

I am new in this newsgroup and I noticed that here people use to propose
whatever changes to C++ they find suitable for the next revision of the
language (which will be after five years the earliest). Here I am proposing
a powerful feature: lambda functions. It's quite early, but it's worth
discussing about it and let it ripe nonetheless.
The proposal is half-baked, so please add to it if you find it of any value.

Rationale:
Lambda functions are a powerful concept used in LISP. They are anonymous
functions built "on the fly" that can be returned as values, passed as
arguments to other functions, etc.
The Standard C++ library brought many of the goodies that were for years
available only for LISP programmers such as iteration, for_each, accumulate,
find, and so on. However, in LISP their usage is much more expressive due to
the ability to create functions on the fly. In C++, if you have a specific
need, either you have to go outside the current scope and write a small
function, either you have to define a functor inside that scope, or you give
up and use hand-coded loops.

Syntax:
The proposed syntax for defining a lambda function in C++ would be the
following:

return-type-specification lambda(argument-list) = expression

This construct can be passed whenever it would be legal to pass a pointer to
a function with the same signature as the lambda function. The lambda
function has static linkage. It is equivalent to a function with the body:

static return-type-specification anonymous(argument-list)
{
return expression;
}

defined before the scope of its usage. Trivial casts and casts to void are
accepted.

Environment:
The problem on what environment can be part of the lambda function is a
thorny one. Consider the following example:

void f(int i)
{
vector<int> v;
// ...
for_each(v.begin(), v.end(), void lambda(int k) = cout << k + i);
}

Here the compiler has to generate a new function for each value of the
parameter i, which is unacceptable. So the rule is that lambda functions
will have no access to scope variables (just like ordinary functions,
they'll have access only to external names in their scope). Yet they can be
configured to get the environment needed in the form of parameters. A new
parameter specifier is static. Static parameters mean that they have static
storage inside the function, and they will be set at the lambda function
definition. The desired effect can be thus obtained as:

void f(int i)
{
vector<int> v;
// ...
for_each(v.begin(), v.end(), void lambda(int k, static int offset = i) =
cout << k + offset);
}

This is equivalent to the following:

static int __anonymous_int__;
static void __anonymous_fun__(int i)
{
cout << i + __anonymous_int__;
}

void f(int i)
{
vector<int> v;
// ...
__anonymous_int__ = i;
for_each(v.begin(), v.end(), __anonymous_fun__);
}

Please note that static arguments don't make part of the signature of the
lambda function. They are only storage that's common to the lambda function
implementation and the point of its definition.

Conclusion:
This way we combined the advantage of a simple, terse syntax, a single
function generation per lambda definition, and the ability to pass an
controlled amount of environment to the function by combining static
parameters with default parameter syntax.

Why are lambda fuinctions not compound statements (and simple expressions
instead)? I thought that allowing arbitrary complex lambda functions would
encourage arcane constructs. A lambda function that has multiple statements
ought to deserve the status of a full-blown external function. This way we
keep a good balance between lambda functions and external functions.

Please excuse me for all the mistakes I'm sure I made. I acknowledge the
fact that this is a half-baked proposal made in a short time and with lots
of loopholes. However, lambda functions are a great concept. Please
contribute to the proposal if you find it worthwhile. No flames please!

Regards to all,

Andrei
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]

Christopher Eltschka

unread,
Nov 24, 1998, 3:00:00 AM11/24/98
to

Andrei Alexandrescu wrote:

[...]

> Syntax:
> The proposed syntax for defining a lambda function in C++ would be the
> following:
>
> return-type-specification lambda(argument-list) = expression

I'd prefer a more C++-like syntax:

rettype lambda(argument-list) { code with return }

This code may contain statements as well as expressions (think of
local variables!)


[...]

> Environment:
> The problem on what environment can be part of the lambda function is a
> thorny one. Consider the following example:
>
> void f(int i)
> {
> vector<int> v;
> // ...
> for_each(v.begin(), v.end(), void lambda(int k) = cout << k + i);
> }
>
> Here the compiler has to generate a new function for each value of the
> parameter i, which is unacceptable. So the rule is that lambda functions
> will have no access to scope variables (just like ordinary functions,
> they'll have access only to external names in their scope). Yet they can be
> configured to get the environment needed in the form of parameters. A new
> parameter specifier is static. Static parameters mean that they have static
> storage inside the function, and they will be set at the lambda function
> definition. The desired effect can be thus obtained as:
>
> void f(int i)
> {
> vector<int> v;
> // ...
> for_each(v.begin(), v.end(), void lambda(int k, static int offset = i) =
> cout << k + offset);
> }
>

[...]

> Please note that static arguments don't make part of the signature of the
> lambda function. They are only storage that's common to the lambda function
> implementation and the point of its definition.

That's a quite nice solution. However, it has one problem:
Thread safety. While the standard doesn't tell you anything
about threads, in the real world such an extension will
probably not be accepted if it cannot be made thread safe.
Global variables are not thread safe, nor are static variables.

>
> Conclusion:
> This way we combined the advantage of a simple, terse syntax, a single
> function generation per lambda definition, and the ability to pass an
> controlled amount of environment to the function by combining static
> parameters with default parameter syntax.
>
> Why are lambda fuinctions not compound statements (and simple expressions
> instead)? I thought that allowing arbitrary complex lambda functions would
> encourage arcane constructs. A lambda function that has multiple statements
> ought to deserve the status of a full-blown external function. This way we
> keep a good balance between lambda functions and external functions.

A good example of a simple function which cannot be created with
your syntax:

vector<double> v;
// ...
for_each(v.begin(), v.end(),
void lambda(double x)
{ double y1=f1(x), y2=f2(x);
cout << x << '\t' << y1 '\t' << y2 '\t'
<< fabs(y1-y2)/y1 << endl; });

This calculates the values y1 and y2 using two different function,
and the relative error of y2 to y1. Note that each function is called
once only (imagine functions running for a long time).

[...]

Boris Schaefer

unread,
Nov 24, 1998, 3:00:00 AM11/24/98
to

"Andrei Alexandrescu" <alexan...@micromodeling.com> writes:

| Syntax:
| The proposed syntax for defining a lambda function in C++ would be the
| following:
|
| return-type-specification lambda(argument-list) = expression

I think it would only be useful, if the syntax were

return-type-specification lambda(argument-list) block

so that you can write two- and more-liners:

void f(int i)
{
vector<int> v;
// ...
for_each(v.begin(), v.end(),
void lambda(int k, static int offset = i)

{
...
cout << k + offset;
...
});
}

Any why do you need the static specifier before int offset? I think
the simple default argument syntax without static might suffice.

--
Boris Schaefer -- s...@psy.med.uni-muenchen.de

Everything should be built top-down, except this time.

sumrnot

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to

Andrei Alexandrescu <alexan...@micromodeling.com> wrote in message
news:36599...@10.1.1.65...


Here I am proposing
>a powerful feature: lambda functions. It's quite early, but it's worth
>discussing about it and let it ripe nonetheless.
>The proposal is half-baked, so please add to it if you find it of any
value.
>
>Rationale:
>Lambda functions are a powerful concept used in LISP. They are anonymous
>functions built "on the fly" that can be returned as values, passed as
>arguments to other functions, etc.
>The Standard C++ library brought many of the goodies that were for years
>available only for LISP programmers such as iteration, for_each,
accumulate,
>find, and so on. However, in LISP their usage is much more expressive due
to
>the ability to create functions on the fly. In C++, if you have a specific
>need, either you have to go outside the current scope and write a small
>function, either you have to define a functor inside that scope, or you
give
>up and use hand-coded loops.

I'm not sure that lambda functions are quite as powerful as Andrei suggests.
Since there are multiple ways in C++ of getting quite functional code
without
them, the only reasons I can see for having them is to save on typing or
to move the function body to where it is being used.

In LISP, of course, there are, or used to be I'm a little rusty
( ,several things
that are difficult to do without them. Local statics for example.

From his posting though, Andrei could be suggesting actually building a
function
from it's parts.
i.e. int lambda(int i)= first_line + second_line;

I'm not going to comment on this. All I know is I wouldn't want to write
the
compiler.

Pete Becker

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to
Andrei Alexandrescu wrote:
>
> Hello,
>
> I am new in this newsgroup and I noticed that here people use to propose
> whatever changes to C++ they find suitable for the next revision of the
> language (which will be after five years the earliest). Here I am proposing

> a powerful feature: lambda functions. It's quite early, but it's worth
> discussing about it and let it ripe nonetheless.
> The proposal is half-baked, so please add to it if you find it of any value.
>
> Rationale:
> Lambda functions are a powerful concept used in LISP. They are anonymous
> functions built "on the fly" that can be returned as values, passed as
> arguments to other functions, etc.
> The Standard C++ library brought many of the goodies that were for years
> available only for LISP programmers such as iteration, for_each, accumulate,
> find, and so on. However, in LISP their usage is much more expressive due to
> the ability to create functions on the fly. In C++, if you have a specific
> need, either you have to go outside the current scope and write a small
> function, either you have to define a functor inside that scope, or you give
> up and use hand-coded loops.

C++ isn't LISP, so what's the point? <g> From my recollection of LISP,
the reason this sort of thing is useful is because you can generate new
functions as the result of execution of code. C++ doesn't allow this --
all functions must be fully defined at compile time. So it looks to me
like this doesn't add anything that you can't do with templates, except
omit the name. So what am I missing? Please give an example of a
programming problem that is easier to solve with lambda functions than
with templates.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---

Jonathan Biggar

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to
Andrei Alexandrescu wrote:
> Environment:
> The problem on what environment can be part of the lambda function is a
> thorny one. Consider the following example:
>
> void f(int i)
> {
> vector<int> v;
> // ...
> for_each(v.begin(), v.end(), void lambda(int k) = cout << k + i);
> }
>
> Here the compiler has to generate a new function for each value of the
> parameter i, which is unacceptable.

Why can't the compiler just be smart enough to recognize that i is a
local variable and implicitly hoist it up as an extra argument to the
lambda function?
So it just implicitly rewrites the lambda function as:

void lambda(int k, int i) = cout << k + i;

and just calls the lambda function as lambda(k,i).

--
Jon Biggar
Floorboard Software
j...@floorboard.com
j...@biggar.org

Zalman Stern

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to
Andrei Alexandrescu (alexan...@micromodeling.com) wrote:
[Proposal to add anonymous code snippets to C++.]

I would like to see this done as syntactic sugar on STL function objects so
that lambda functions would cleanly play with existing infrastructure.
(Noting that a great deal more infrastructure will exist five years from
now.)

For example, I sometimes write code like so:

int added_index = ...; // Probably passed in or something.

struct adjust_index_op {
int m_index;

adjust_index_op(int index) : m_index(index) {};

void operator() (item_t &item) {
if (item.get_index() >= m_index)
item.increment_index(1);
};
};

for_each(item_list.begin(), item_list.end(),
adjust_index_op(added_index));

I'd prefer to write the struct inline with less glue around it. Something
like
int added_index;
for_each(item_list.begin(), item_list.end(), func_obj(item_t &item) {
if (item.get_index() >= added_index)
item.increment_index(1);
});

Note that I have avoided the term lambda because I do not want anyone to
think the above is a closure. If one tried to return the object from the
function or anything like that, it would not work. All lexically bound
variables from the contaning scope would be bound to references within a
temporary object of an anonymous class. The above would expand to
something like the following:

int added_index = ...; // Probably passed in or something.

struct __func_obj_00001 {
int __ref_added_index_00001;
__func_obj_00001(int &arg1) __ref_added_index_00001(arg1) {};
void operator() (item_t &item) {
if (item.get_index() >= __ref_added_index_00001)
item.increment_index(1);
};
};

for_each(item_list.begin(), item_list.end(),
__func_obj_00001(added_index));

It might also be nice to have the anonymous class autmagically introduce
typedefs for the argument and return types as the STL function objects
have. (I'm not sure if it would need to manifest an appropriate base class.
It is a possibility.)

-Z-

Siemel Naran

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to
Andrei Alexandrescu wrote:

>I am new in this newsgroup and I noticed that here people use to propose
>whatever changes to C++ they find suitable for the next revision of the
>language (which will be after five years the earliest). Here I am proposing
>a powerful feature: lambda functions. It's quite early, but it's worth
>discussing about it and let it ripe nonetheless.
>The proposal is half-baked, so please add to it if you find it of any value.

Lambda functions are basically nested functions.


>Rationale:
>Lambda functions are a powerful concept used in LISP. They are anonymous
>functions built "on the fly" that can be returned as values, passed as
>arguments to other functions, etc.

We have a way to create functions on the fly too in C++. Just use
classes. Eg, to generate a function that adds 7 to 'x', we write
in Scheme:

(lambda (x) (+ x 7))

We could pass this function and others to a transform function that
transforms the elements of a container by applying the lambda or
callback function to them. In C++ we write

std::bind2nd(std::plus<int>(),7)

The lambda function method has the disadvantage that code for the
function itself must be generated at runtime. In the C++ method,
code for the class is generated at compile time and the values
for an instance of the class -- ie, an object -- are filled in at
runtime, usually through ctors.

The C++ method has the further advantage that it can be easily
inlined. Ie, the compiler should be able to inline this

std::transform(array,array+N,array,std::bind2nd(std::plus<int>(),7));


>The Standard C++ library brought many of the goodies that were for years
>available only for LISP programmers such as iteration, for_each, accumulate,
>find, and so on. However, in LISP their usage is much more expressive due to
>the ability to create functions on the fly. In C++, if you have a specific
>need, either you have to go outside the current scope and write a small
>function, either you have to define a functor inside that scope, or you give
>up and use hand-coded loops.

No, there's a lot you can do with the function objects in <functional>.
But the notation is cumbersome looking and might lead you to think
that it is inefficient.

IMHO, the best solution is to change the linkage of local classes. At
present, local classes have internal linkgage. This means that they
can't be used in template functions. This is because in general, the
template will be instantiated at link time, and as the local class has
internal linkage, it can't be accessed by the linker. So this is an
error:

void f()
{
struct Function : public std::unary_function<int,int>
{
int operator()(int x) { return x+x; }
};

std::transform(...,Function());
}

But if local classes had external linkage, this would not be a
problem. And think how useful it would be for anyone wanting to
make a local class. Whenever a function object is too
specialized to be generated through the general purpose objects
in <functional>, we can write our own function objects. For
best organization, we'd like the function object or class to
be local to the function in which it is used, just as for our
function f(...) above.

Furthermore, we have a precedent endowing classes with external
linkage: classes in unnamed namespaces. These classes have
external linkage in that the linker can access them when it needs
to make an instantiation. But to everyone else and everything
else besides the linker the class has internal linkage. So why
not do the same for local classes?

There's an annoying problem with local classes. It's that we
can have different class with the same name at different scopes.
For example,

void f()
{
{ struct X {}; }
struct X {};
{ struct X {}; { struct X{}; } }
}

All four class X are different! But this sort of code is rather
bizarre. We will usually -- no, almost always -- have one local
class with the name 'X'. IOW, code like the above f(...) is
very uncommon. To make life easy for the compiler writers, the
rule I propose is this: each local function can define only one
local class with name 'X'. So the above function f(...) is
illegal. But the one below is fine

void f()
{
{ struct X {} }
}

>Syntax:
>The proposed syntax for defining a lambda function in C++ would be the
>following:

>return-type-specification lambda(argument-list) = expression

Perhaps 'expression' should be in braces.
return-type-specification lambda(argument-list) = { expression }

Eg,

struct Type { int show() const; int get(); };

f( int lambda(Type x) = return x.show(),x.get() );
// does this call f(int (*)(Type));
// or f(int (*)(Type),int);


>This construct can be passed whenever it would be legal to pass a pointer to
>a function with the same signature as the lambda function. The lambda
>function has static linkage. It is equivalent to a function with the body:

If the lambda function has static linkage, then how can it accessed
by the linker for use in the instantiation of a template function?
This is the same problem with local classes.


>static return-type-specification anonymous(argument-list)
>{
> return expression;
>}
>
>defined before the scope of its usage. Trivial casts and casts to void are
>accepted.

Fine.


>Environment:
>The problem on what environment can be part of the lambda function is a
>thorny one. Consider the following example:
>
>void f(int i)
>{
> vector<int> v;
> // ...
> for_each(v.begin(), v.end(), void lambda(int k) = cout << k + i);
>}
>
>Here the compiler has to generate a new function for each value of the

>parameter i, which is unacceptable. So the rule is that lambda functions
>will have no access to scope variables (just like ordinary functions,
>they'll have access only to external names in their scope). Yet they can be
>configured to get the environment needed in the form of parameters. A new
>parameter specifier is static. Static parameters mean that they have static
>storage inside the function, and they will be set at the lambda function
>definition. The desired effect can be thus obtained as:

The nicest thing about lambda functions in Scheme is that you can
reference local variables. Anyway, specifying 'static' as you
suggest below is not necessary as the compiler should be able to
deduce it by looking at the definition of the lambda function.
Ie, it can see that the variable 'i' is a variable outside the
lambda function and so you need not bother tell it this. IOW,
the "static int i" is implied.

>void f(int i)
>{
> vector<int> v;
> // ...

> for_each(v.begin(), v.end(), void lambda(int k, static int offset = i) =
>cout << k + offset);
>}

>This is equivalent to the following:
>
>static int __anonymous_int__;
>static void __anonymous_fun__(int i)
>{
> cout << i + __anonymous_int__;
>}
>

>void f(int i)
>{
> vector<int> v;
> // ...

> __anonymous_int__ = i;
> for_each(v.begin(), v.end(), __anonymous_fun__);
>}

OK.


>Please note that static arguments don't make part of the signature of the
>lambda function. They are only storage that's common to the lambda function
>implementation and the point of its definition.

Of course.

>Conclusion:
>This way we combined the advantage of a simple, terse syntax, a single
>function generation per lambda definition, and the ability to pass an
>controlled amount of environment to the function by combining static
>parameters with default parameter syntax.

But why not use the function objects in <functional> or even some
of your own making?


>Why are lambda fuinctions not compound statements (and simple expressions
>instead)? I thought that allowing arbitrary complex lambda functions would
>encourage arcane constructs. A lambda function that has multiple statements
>ought to deserve the status of a full-blown external function. This way we
>keep a good balance between lambda functions and external functions.

BTW, how does one distinguish simple and compound statements? Is a
simple statement one without a semi-colon and without braces { }.
If your expressions are really simple, then function objects will
certainly suffice. And you get some benefits: code generation at
compile time and inlining.


>Please excuse me for all the mistakes I'm sure I made. I acknowledge the
>fact that this is a half-baked proposal made in a short time and with lots
>of loopholes. However, lambda functions are a great concept. Please
>contribute to the proposal if you find it worthwhile. No flames please!

Sorry.

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Christopher Eltschka

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to
Siemel Naran wrote:
>
> Andrei Alexandrescu wrote:

[...]

However, this would be simple to resolve: Just give the internal
scopes internal names. That is, the first class would be (in
pseudo-notation): f()::__1::X, the second class would be f()::X,
the third f()::__2::X, and the fourth f()::__2::__1::X.
The mangled names might f.ex. look like

X__Cf__Fv__1, X__Cf__Fv, X__Cf__Fv__2, X__Cf__Fv__2__1

Note that class name mangling would be necessary anyways, since
you have to distinguish a local class X from a global class X.

> To make life easy for the compiler writers, the
> rule I propose is this: each local function can define only one
> local class with name 'X'. So the above function f(...) is
> illegal. But the one below is fine
>
> void f()
> {
> { struct X {} }
> }
>

I don't like this idea. It just feels wrong. Compiler writers know
how to cope with external names in different scopes (global, namespace,
unnamed namespace, class local). Therefore I don't think they would
have a problem with this extension.
However, I'm not a compiler writer, so I may miss some inherent
difficulty.

[...]

> >Conclusion:
> >This way we combined the advantage of a simple, terse syntax, a single
> >function generation per lambda definition, and the ability to pass an
> >controlled amount of environment to the function by combining static
> >parameters with default parameter syntax.
>
> But why not use the function objects in <functional> or even some
> of your own making?

There's one situation where this is not possible: Interfacing
with (probably existing) C code (or, for that matter, FORTRAN code).
This will need a function pointer, and won't accept functional objects.
And you won't rewrite all that existing C and FORTRAN code to
C++ just to be able to use function objects (note that even with C
functions, you'd have to change them to templates to accept
function objects - just recompiling with C++ dosn't help here)

[...]

Francis Glassborow

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to
In article <slrn75lv83....@localhost.localdomain>, Siemel Naran
<sbn...@localhost.localdomain> writes

>But if local classes had external linkage, this would not be a
>problem. And think how useful it would be for anyone wanting to
>make a local class. Whenever a function object is too
>specialized to be generated through the general purpose objects
>in <functional>, we can write our own function objects. For
>best organization, we'd like the function object or class to
>be local to the function in which it is used, just as for our
>function f(...) above.

I think that what you are after is that local classes should have the
linkage of the enclosing function.

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Andrei Alexandrescu

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to
Christopher Eltschka wrote in message
<365BC26D...@physik.tu-muenchen.de>...

>There's one situation where this is not possible: Interfacing
>with (probably existing) C code (or, for that matter, FORTRAN code).
>This will need a function pointer, and won't accept functional objects.
>And you won't rewrite all that existing C and FORTRAN code to
>C++ just to be able to use function objects (note that even with C
>functions, you'd have to change them to templates to accept
>function objects - just recompiling with C++ dosn't help here)

Christopher,

Please see my answer to Siemel. It is my strong belief that there is a lot
more about lambda functions than interfacing.

Andrei

Andrei Alexandrescu

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to

Siemel Naran wrote in message ...

>We have a way to create functions on the fly too in C++. Just use
>classes. Eg, to generate a function that adds 7 to 'x', we write
>in Scheme:
>
>(lambda (x) (+ x 7))
>
>We could pass this function and others to a transform function that
>transforms the elements of a container by applying the lambda or
>callback function to them. In C++ we write
>
>std::bind2nd(std::plus<int>(),7)
>
>The lambda function method has the disadvantage that code for the
>function itself must be generated at runtime. In the C++ method,
>code for the class is generated at compile time and the values
>for an instance of the class -- ie, an object -- are filled in at
>runtime, usually through ctors.
>
>The C++ method has the further advantage that it can be easily
>inlined. Ie, the compiler should be able to inline this
>
>std::transform(array,array+N,array,std::bind2nd(std::plus<int>(),7));
>


Siemel,

Maybe you haven't understood that lambda functions in the form I propose
them have inherently all the advantages you mentioned, while of course
lacking some key advantages of lambda functions in Scheme.

>No, there's a lot you can do with the function objects in <functional>.
>But the notation is cumbersome looking and might lead you to think
>that it is inefficient.


It's not this problem. The point is that whenever you have to customize
something in a non-trivial yet simple way - like simple expressions -, you
cannot getaway with <functional>. All in all, what Stepanov did was the best
possible thing next to lambda functions.

>IMHO, the best solution is to change the linkage of local classes.

The right solution is lambda functions. That's the need. You propose a way
to simulate them that's not as natural as the real thing.

>Perhaps 'expression' should be in braces.

> return-type-specification lambda(argument-list) = { expression }
>
>Eg,
>
>struct Type { int show() const; int get(); };
>
>f( int lambda(Type x) = return x.show(),x.get() );
> // does this call f(int (*)(Type));
> // or f(int (*)(Type),int);


In my opinion, it shouldn't. And please note that you have an "error"
(according to my proposal, hum) - return is not an expression, it's a
statement. The compiler can figure out easily an expression. I feel that
neither you nor "sumrnot" didn't understand exactly the proposed syntax.
It's just like initializing a variable.
So you might have written:

f( int lambda(Type x) = x.show(),x.get() );

Because the argument binding has precedence over the comma operator, this
calls (int (*)(Type),int). If you wanted the other way 'round:

f( int lambda(Type x) = (x.show(),x.get()) );

This issue is from the C days.

>The nicest thing about lambda functions in Scheme is that you can
>reference local variables. Anyway, specifying 'static' as you
>suggest below is not necessary as the compiler should be able to
>deduce it by looking at the definition of the lambda function.
>Ie, it can see that the variable 'i' is a variable outside the
>lambda function and so you need not bother tell it this. IOW,
>the "static int i" is implied.


It cannot if it has to pass a pointer to a function. In the for_each case
(for_each is an inline template), it can do what you said. Not in the
general case, though.

>But why not use the function objects in <functional> or even some

>of your own making?


The point is: lambda functions are a very powerful concept. They can help us
get rid of explicit loops. You cannot do this only with <functional> and if
you try to make lots of small external functions/objects, you get sick after
a while. It's simply counter-productive and counter-intuitive. What you need
is a way to build functions on the fly, and be able to pass a definite
amount of context to them. My proposal achieves both these requirements in a
statically-bound way.

But as no commitee guru didn't pay attention to this, it seems like I'm dead
wrong :,o(.
(The emoticon means: eyes, tear, my big nose, and mouth.)

>BTW, how does one distinguish simple and compound statements? Is a
>simple statement one without a semi-colon and without braces { }.
>If your expressions are really simple, then function objects will
>certainly suffice. And you get some benefits: code generation at

>compile time and inlining.


Earlier I said that my proposal is also static (compile-time). You've got a
point with inlining. What about having lambda functions generate anonymous
classes that define operator()? That would be a happy marriage between your
idea and mine.

Andrei

Andrei Alexandrescu

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to

Pete Becker wrote in message <365B04C1...@acm.org>...

>C++ isn't LISP, so what's the point? <g> From my recollection of LISP,
>the reason this sort of thing is useful is because you can generate new
>functions as the result of execution of code. C++ doesn't allow this --
>all functions must be fully defined at compile time. So it looks to me
>like this doesn't add anything that you can't do with templates, except
>omit the name. So what am I missing? Please give an example of a
>programming problem that is easier to solve with lambda functions than
>with templates.


Pete,

LISP (especially Scheme) uses lambda functions in a lot more situations, but
indeed their would-be C++ port loses many of them.

In the proposed C++ form, lambda allows you to express a computation exactly
in the place where it makes sense and to pass a controlled amont of
environment to that computation.
Of course you can do this with external classes or functions, but that's
actually only a verbose and non-intuitive simulation. With lambda functions
you can express what environment you pass and what computation is done in a
single place. You can get rid of almost all explicit loops without having to
add myriads of small external classes/functions. It's much, much clearer
this way.

What does <g> mean?

Andrei Alexandrescu

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to

Pete Becker wrote in message <365B04C1...@acm.org>...
[snip]

Pete,

I wrote to Siemel that "no commitee guru" paid attention to my proposal.
That was before seeing your message. Thanks for your attention.

Francis Glassborow

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to

In article <zalmanF2...@netcom.com>, Zalman Stern
<zal...@netcom.com> writes

>(Noting that a great deal more infrastructure will exist five years from
>now.)

I am seeing this quote of 'five years' too often. A standard is aimed
at a ten year life. Half way there are a few things that can be done by
way of formal amendments but these are limited I believe to
incorporation of technical corrigenda. Work can go on (if a work item
is granted by SC22) on technical reports that outline extensions but
these are not incorporated into a standard till the next version (i.e.
SC22 is not going to be happy if we want to make radical changes or
additions to C++ before 2008 -- work may start on that in 2003)


Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Andrei Alexandrescu

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to

Jonathan Biggar wrote in message <365B2168...@floorboard.com>...

>Why can't the compiler just be smart enough to recognize that i is a
>local variable and implicitly hoist it up as an extra argument to the
>lambda function?
>So it just implicitly rewrites the lambda function as:
>
> void lambda(int k, int i) = cout << k + i;
>
>and just calls the lambda function as lambda(k,i).


In the for-each case, it could, but if you have to pass the lambda to an
external function, you're out of luck.

Andrei

Siemel Naran

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to

On 25 Nov 98 16:17:26 GMT, Francis Glassborow

>I think that what you are after is that local classes should have the
>linkage of the enclosing function.

But doesn't the enclosing function have external linkage?

BTW, is it possible for a function to have internal linkage now
that the 'static' keyword is deprecated?

Also, is it true that inline functions must have external linkage?
This means that if the function were not inlined, each translation
unit can't get its own static internal linkage copy (the old rule).

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Siemel Naran

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to
On 25 Nov 98 13:54:00 GMT, Christopher Eltschka
>Siemel Naran


>> There's an annoying problem with local classes. It's that we
>> can have different class with the same name at different scopes.
>> For example,

>However, this would be simple to resolve: Just give the internal
>scopes internal names. That is, the first class would be (in
>pseudo-notation): f()::__1::X, the second class would be f()::X,
>the third f()::__2::X, and the fourth f()::__2::__1::X.
>The mangled names might f.ex. look like
>
>X__Cf__Fv__1, X__Cf__Fv, X__Cf__Fv__2, X__Cf__Fv__2__1

Interestingly, we see here a connection between the name of a local
class in the context of external linkage and the string returned by
type_info's name function. Specifically, typeinfo(X).name(), where
X is any of the local objects in function 'f', should return any
one of the strings you describe above. In the typeid.name() thread,
my answer for the name of a local class was similar to your answer.


>Note that class name mangling would be necessary anyways, since
>you have to distinguish a local class X from a global class X.

What is the meaning of "class name mangling"?


>I don't like this idea. It just feels wrong. Compiler writers know
>how to cope with external names in different scopes (global, namespace,
>unnamed namespace, class local). Therefore I don't think they would
>have a problem with this extension.
>However, I'm not a compiler writer, so I may miss some inherent
>difficulty.

You don't like the idea of giving local classes external linkage or
the idea of restricting one local class with name 'X' per function?

It seems difficult for the compiler writer to implement, hence the
restriction. Moreover, it doesn't seem very likely that anyone
will want to take advantage of this feature. That is, will some
programmer want to define two local classes with the name 'X' in
the same function? The case I have in mind in this: only one
local class in the function, just for use in some algorithm, like
std::for_each. But from your comment "It just feels wrong" I've
realized this:

Entering a new block is like entering an unnamed function:

void f()
{
int i,j;
struct X { void x1(); };
// unnamed function
{
struct X { void x2(); };
};
}

It is similar to writing

void f1(int i, int j) { struct X { void x2(); } }
void f() { int i,j; struct X { void x1(); }; f1(i,j); }


So multiple structs with the same name inside a function should be
allowed, if nothing than for aesthetic reasons!

>There's one situation where this is not possible: Interfacing
>with (probably existing) C code (or, for that matter, FORTRAN code).
>This will need a function pointer, and won't accept functional objects.
>And you won't rewrite all that existing C and FORTRAN code to
>C++ just to be able to use function objects (note that even with C
>functions, you'd have to change them to templates to accept
>function objects - just recompiling with C++ dosn't help here)

Good point.

David R Tribble

unread,
Nov 25, 1998, 3:00:00 AM11/25/98
to

Andrei Alexandrescu wrote:
> Here I am proposing
> a powerful feature: lambda functions. It's quite early, but it's worth
> discussing about it and let it ripe nonetheless.
> The proposal is half-baked, so please add to it if you find it of any
> value.
>
> Rationale:
> Lambda functions are a powerful concept used in LISP. They are
> anonymous functions built "on the fly" that can be returned as values,
> passed as arguments to other functions, etc.
> ...

What if we allow the definition of private functions within a
source file without having to declare them in the class declaration
(which is typically in a separate header file)? These private
functions would act like file-static functions except that they
would share access to the same class or class object, and would
behave a lot like lambda functions.

For example:
// foo.hpp

class Foo
{
public:
void bar();
};


// foo.cpp

/*syntax?*/ static int Foo::pri()
{
// Do something with *this, which is type Foo
...
}

void Foo::bar()
{
// Call the private func
pri();

// Pass the address of the private func
fizz(&pri);
}

The private function pri() above is known only within the "foo.cpp"
source file. It is not declared in "foo.hpp", but in all other
respects acts like a private non-virtual class member function.

Another alternative is to allow nested functions. Thus the example
above could be rewritten as:
// foo.cpp

void Foo::bar()
{
/*static?*/ int pri()
{
// Do something with *this
...
}

// Call the private func
pri();

// Pass the address of the private func
fizz(&pri);
}

Nested functions would also have to have some semantic restrictions,
such as not being recursively callable, in order to keep the C++
abstract machine (i.e., function invocation frames) simple.

Both solutions might have linkage problems when used within
template functions.

Both suggestions are only half-serious; I'm sure the need for
lambda functions is not that large, and most of the cases can be
solved with our existing language constructs (templates, static
functions, etc.)

-- David R. Tribble, dtri...@technologist.com --

Siemel Naran

unread,
Nov 26, 1998, 3:00:00 AM11/26/98
to
On 25 Nov 1998 16:54:25 GMT, Andrei Alexandrescu

>Siemel Naran wrote in message ...

>It's not this problem. The point is that whenever you have to customize


>something in a non-trivial yet simple way - like simple expressions -, you
>cannot getaway with <functional>. All in all, what Stepanov did was the best
>possible thing next to lambda functions.

If the function objects in <functional> are not sufficient, and the
functional objects you want are sufficiently generaly to be of use in
more than one function, then write your own functional objects. If
the functional object is very specific, write it as a local class
of the function that needs it (although this won't work at present
because of the linkage problem).

BTW, if the lambda approach is to work, the lambda functions must
have external linkage -- so that they can qualify for use in template
functions. So if the standard committee is going to adopt the usage
of lambda functions of external linkage, then why not adopt the
usage of local classes of external linkage?

I think that the local class notation is just as intuitive as the
lambda notation. Plus, it looks more C++ like to me and the
functions can be a lot more complex. As a workaround for local
classes having internal linkage you can do this:

// header file
namespace myspace { struct X { void f(int x) const; } }

// cpp file
namespace
{
struct f
{
f(int x); int x;
void operator()(const X&) const;
struct functional_object1; // 'local' class for use in op()
};
}
void myspace::X::f(int x) { return ::f(x)(*this); }


>>IMHO, the best solution is to change the linkage of local classes.

>The right solution is lambda functions. That's the need. You propose a way


>to simulate them that's not as natural as the real thing.

I feel pretty comfortable with the function object method. One
disadvantage with the function object method is that you have
to pass all the environment variables you need to the function
object's copy ctor. This is because local variables in the
function f() are not available in the struct f()::X. Example:

void f(int i)
{
struct X
{
int operator()(int x) const { return i+x; }
};

cout << X()(3) << '\n';
}

"a.c", line 7: error: reference to local variable of enclosing function is not
allowed
int operator()(int x) const { return i+x; }
^

The correction would be to give the struct a ctor X(int) and a data
variable 'i'. Your lambda function approach has the same problem.
But in the lambda function approach in Scheme, we don't have to
bother with these annoying details.


>So you might have written:
>

>f( int lambda(Type x) = x.show(),x.get() );

Sorry, I accidentally put the 'return' in there as I'm so used to
doing this.


>It cannot if it has to pass a pointer to a function. In the for_each case
>(for_each is an inline template), it can do what you said. Not in the
>general case, though.

OK.


>>But why not use the function objects in <functional> or even some
>>of your own making?

>The point is: lambda functions are a very powerful concept. They can help us


>get rid of explicit loops. You cannot do this only with <functional> and if
>you try to make lots of small external functions/objects, you get sick after
>a while. It's simply counter-productive and counter-intuitive. What you need
>is a way to build functions on the fly, and be able to pass a definite
>amount of context to them. My proposal achieves both these requirements in a
>statically-bound way.

Sounds reasonable.


>Earlier I said that my proposal is also static (compile-time). You've got a
>point with inlining. What about having lambda functions generate anonymous
>classes that define operator()? That would be a happy marriage between your
>idea and mine.

Someone recently asked on this newsgroup about the possibility of
making anonymous structs with constructors. The idea seemed
strange to me at the time although I did once wish for it. What I
wanted was the ability to initialize unnamed structs without the
possibility of creating any more instance. Ie,

struct X
{
X(int x); int x;
} x1(1), x2(2);

But now the user can do
X x3(3);
but we don't want them to be able to create any more X objects. So
instead we do this:

struct
{
(int x); int x;
} x1(1), x2(2);


Now in the context of lambda functions this idea makes more sense.
To add 7 to each number in a list, we do this:

std::transform(array,array+N,array,
lambda : public std::unary_function<int,int>
{ int operator()(int x) { return x+7; } }
);


However, in this case, we can use std::bind2nd and std::plus as
illustrated in the previous post.


I'm still in favor of the local function object with external
linkage approach. Sure, it doesn't allow you to create
functional objects on the fly. You have to take a few more
lines of code. OTOH, functional objects are complex things,
so they deserve a few extra lines of code :). Now as regards
tiny variable length arrays, it is a nuisance to use many
lines of code. So instead of
int v[3]; v[0]=0; v[1]=1; v[2]=2; f(v);
we prefer to write
f(Arg<int>(0)<<1<<2);
This is illustrated in the post on the proposal for variadic
functions on this newsgroup.

Christopher Eltschka

unread,
Nov 26, 1998, 3:00:00 AM11/26/98
to
Siemel Naran wrote:
>
> On 25 Nov 98 13:54:00 GMT, Christopher Eltschka
> >Siemel Naran
>
> >> There's an annoying problem with local classes. It's that we
> >> can have different class with the same name at different scopes.
> >> For example,
>
> >However, this would be simple to resolve: Just give the internal
> >scopes internal names. That is, the first class would be (in
> >pseudo-notation): f()::__1::X, the second class would be f()::X,
> >the third f()::__2::X, and the fourth f()::__2::__1::X.
> >The mangled names might f.ex. look like
> >
> >X__Cf__Fv__1, X__Cf__Fv, X__Cf__Fv__2, X__Cf__Fv__2__1
>
> Interestingly, we see here a connection between the name of a local
> class in the context of external linkage and the string returned by
> type_info's name function. Specifically, typeinfo(X).name(), where
> X is any of the local objects in function 'f', should return any
> one of the strings you describe above. In the typeid.name() thread,
> my answer for the name of a local class was similar to your answer.

Indeed, anything having external linkage will have to be given
different names on any implementation using a more or less
traditional linker. Therefore, generating different names for
typeid.name() is automatic, if you use the mangled name, and should
at least be possible with internal names. The only problematic
point is naming the non-external names.
However, even this problem should be solvable, since effectively
the same method as for unnamed namespace members can be used
(while for non-external symbols, it is not important to be unique,
it wouldn't hurt either).

Note that whith external local class names, you would have that
problem already: Consider

// file 1:

static void f() { class X {}; }

// file 2:

static void f() { class X {}; }

Since they are static, both functions are different, and so are
the classes named X both. So if those classes have to have
external linkage, they would have to get mangled differently.

I don't think it's basically different from mangling class names
in unnamed namespaces differently; however I wouldn't mind if
classes in file static functions would continue to have internal
linkage as an exception. It would make sense to do so.

>
> >Note that class name mangling would be necessary anyways, since
> >you have to distinguish a local class X from a global class X.
>
> What is the meaning of "class name mangling"?

"Name mangling" (or "name decoration") is modifying the name
for distinguising different things having the same name.
With "class name mangling" I just meant "mangling of class names".
That is, exactly what I've shown above (the X__Cf__Fv etc.).

>
> >I don't like this idea. It just feels wrong. Compiler writers know
> >how to cope with external names in different scopes (global, namespace,
> >unnamed namespace, class local). Therefore I don't think they would
> >have a problem with this extension.
> >However, I'm not a compiler writer, so I may miss some inherent
> >difficulty.
>
> You don't like the idea of giving local classes external linkage or

> the idea of restricting one local class with name 'X' per function?

I don't like the idea of restricting to one local class X per
function.

>
> It seems difficult for the compiler writer to implement, hence the
> restriction.

And my examples above showed why I don't think it is difficult.
With the disclaimer that I'm no compiler writer and may not see the
obvious, of course.

[...]

Christopher Eltschka

unread,
Nov 26, 1998, 3:00:00 AM11/26/98
to
Siemel Naran wrote:

[...]

> BTW, if the lambda approach is to work, the lambda functions must
> have external linkage -- so that they can qualify for use in template
> functions. So if the standard committee is going to adopt the usage
> of lambda functions of external linkage, then why not adopt the
> usage of local classes of external linkage?

Well, the function does not need to have external linkage.
It's the _type_ which is the template argument; and the type is
a function (pointer) type, which has "external" linkage as a
built-in type. Note that the function itself may well have
internal linkage. For example:

template<class F> void call(F f)
{
f(0);
}

static void f(int) {}

call(f); // Ok: equivalent to call<void(*)(int)>(&f);
// void(*)(int) is OK as template statement
// The actual argument to call has no relevance
// you may call a template with an automatic int variable!

[...]

Jaewoo Kim

unread,
Nov 26, 1998, 3:00:00 AM11/26/98
to
Andrei,

Interesting and pleasing, but not satisfactory.

I give you 2 questions

(1) Is lambda generic?

If not, what do you think about generic lambda constructs? Is it impossible
or impractical?

(2) Could be lambda functions used as return values? (The First class
functions)

If not, the lambda constructs couldn't replace the use of named function
objects as you expect... (Just my reasoning)

I don't mean __ I prefer (local) function objects in current C++ , the
externally linked local functors (Siemel's)__. Furthermore, I'm not
satisfactory with anonymous classes like the recent extension of Java P.L.

Why Java? The inner class extension of Java 1.1 for handling and
implementing event-listener models is nearly the embrace of Functional
paradigm, where anonymous class is much like lambda function except some
restrictions of referencing environment. I think real functional constructs
would be much better, though.

I think if we have to add some additional constructs (C++ has already too
much keywords, semantic restrictions (non-orthogonal features)), we should
add real one, neither the crippled nor the restrictive in non-expressive
way.

Expressiveness is much more than just syntactic convenience.

KiZOo

Pete Becker

unread,
Nov 26, 1998, 3:00:00 AM11/26/98
to

Andrei Alexandrescu wrote:
>
> Of course you can do this with external classes or functions, but that's
> actually only a verbose and non-intuitive simulation. With lambda functions
> you can express what environment you pass and what computation is done in a
> single place. You can get rid of almost all explicit loops without having to
> add myriads of small external classes/functions. It's much, much clearer
> this way.

Example, please. <g>

>
> What does <g> mean?

It means "grin", in case what came before it sounded a bit nasty.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com

Ziv Caspi

unread,
Nov 26, 1998, 3:00:00 AM11/26/98
to

On 25 Nov 1998 16:54:25 GMT, "Andrei Alexandrescu"
<alexan...@micromodeling.com> wrote:

[...]


>The point is: lambda functions are a very powerful concept. They can help us
>get rid of explicit loops. You cannot do this only with <functional> and if
>you try to make lots of small external functions/objects, you get sick after
>a while.

[...]

And another point is: Why would you want to use a 10-ton hammer to
slay a fly? If what you're after (as the poster who started this
thread wanted) is to be able to say 'X' when you mean

for ( ABC::iterator it = abc.begin(); it != abc.end(); ++it )
{
}

then you can simply use macros [1]. If not, I would echo Pete Becker's
thought that making C++ behave like LISP is perhaps taking it too far.

[1] Unlike Pete Becker, I *do* think that the construct:

LOOP_OBJECTS( it, abc )
//...
END_LOOP

is better than writing external functions (or external functors, if
context is needed). I have worked in a group where people used both
constructs, and after some time of use we all tended to the macro
form. YMMV, of course.

James...@dresdner-bank.de

unread,
Nov 26, 1998, 3:00:00 AM11/26/98
to

In article <36599...@10.1.1.65>,
"Andrei Alexandrescu" <alexan...@micromodeling.com> wrote:

> Lambda functions are a powerful concept used in LISP. They are anonymous
> functions built "on the fly" that can be returned as values, passed as
> arguments to other functions, etc.

Lisp is a functional language, so it is normal that it have lambda
functions. Since C++ is an object oriented language (sort of), it
would seem to me more normal that it have lambda classes.

It's interesting to note that Java actually does have lambda classes,
although it calls them anonymous classes, so the concept isn't new.
I've had some ideas along these lines as well, which I've presented
here in the past.

Note that in general, the only thing you could do with a lambda function
is pass its address to another function, which takes a pointer to
function as argument. In C++, such functions should be rare; it is
far more in keeping with the spirit of the language to pass a reference
to a functional object. Again, this demands lambda classes, rather
than lambda functions.

--
James Kanze GABI Software, Sàrl
Conseils en informatique orienté objet --
-- Beratung in industrieller Datenverarbeitung
mailto: ka...@gabi-soft.fr mailto: James...@dresdner-bank.de

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

Valentin Bonnard

unread,
Nov 27, 1998, 3:00:00 AM11/27/98
to
Jaewoo Kim wrote:

> (2) Could be lambda functions used as return values? (The First class
> functions)

Well, no:

int(*foo())()
{
int i = random ();
return (fun () -> i);
}

i is out of scope after the return; if you change that (make
automatics garbaged collected), then don't call the result C++.

But w/o local context yes, if it has function (not object)
type, there is no problem to return it.

--

Valentin Bonnard mailto:bonn...@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---

James...@dresdner-bank.de

unread,
Nov 27, 1998, 3:00:00 AM11/27/98
to
In article <slrn75pa28....@localhost.localdomain>,
sbn...@KILL.uiuc.edu wrote:

> I think that the local class notation is just as intuitive as the
> lambda notation. Plus, it looks more C++ like to me and the
> functions can be a lot more complex. As a workaround for local
> classes having internal linkage you can do this:
>
> // header file
> namespace myspace { struct X { void f(int x) const; } }
>
> // cpp file
> namespace
> {
> struct f
> {
> f(int x); int x;
> void operator()(const X&) const;
> struct functional_object1; // 'local' class for use in op()
> };
> }
> void myspace::X::f(int x) { return ::f(x)(*this); }

Of course, the real advantage to the lambda function is that it is
nested, and can access the local context. Which isn't currently true
even of local classes, and brings us back to the approach I favor:
define a built-in "class" __local_context. The semantics of this would
be to declare a class with local scope, with one (protected, public)
member variable for each variable visible in local scope, with the same
name as the visible variable, and the type a reference to the type of
the local variable. This class would also automatically initialize all
of the references to the corresponding variable. (This is the formal
semantic definition. I suspect that most compilers would be able to
supprime the class completely, and generate direct accesses to the
variables.)

Add this to your suggestion of giving local classes external linkage for
templates, and I think you really have all you need. Anything else
would be just trimmings.

The trimming I like is a special keyword and syntax:

cleanup { ... } ;

This generates a uniquely named class derived from __local_context, with
the code in the { ... } as destructor, and creates a local instance of
the class. The result: the code in the { ... } gets executed whenever
you leave the current scope.

I've thought about some sort of lambda class which implicitly derives
from __local_context and automatically creates a new temporary instance
of itself, but I've never been able to come up with a reasonable
syntax. My recent experience with anonymous classes in Java makes me
doubt the utility -- the largest single effect of using anonymous
classes is to obfuscate the code.

--
James Kanze GABI Software, Sàrl
Conseils en informatique orienté objet --
-- Beratung in industrieller Datenverarbeitung
mailto: ka...@gabi-soft.fr mailto: James...@dresdner-bank.de

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

Rus...@shevchenko.kiev.ua

unread,
Nov 27, 1998, 3:00:00 AM11/27/98
to
if lambda-functions, why not lambda-classes (as in java) ?

David J. Littleboy

unread,
Nov 27, 1998, 3:00:00 AM11/27/98
to
Pete Becker wrote in message <365CDBE3...@acm.org>...

>Example, please. <g>

Two papers, both by Guy L. Steele: "Lambda: the Ultimate Imperative" and
"Lambda: the Ultimate Declarative". MIT AI Lab memos from the late 70's.
Also see Susman's book on Scheme. Also, for the hard way to do it<g>, check
out Coplien's Scope, LocalScope, and EndLocalScope, and EndOuterScope macros
(in Advanced C++ Styles and Idioms).

One problem with lambda in C++ is that (modulo the unless below) it would
only be useful for what Lispers call the "downward funarg problem". Lambda
in scheme and function objects in C++ create closures that can be passed out
of (i.e. returned from) a function (to be used elsewhere), but lambda in C++
would have the problem that a free variable in the lambda could refer to a
local variable in the enclosing function whose destructor gets called when
said local function returns. (Unless free variables in lambda were defined
to construct new objects, and that sounds as though it could be an ugly can
of worms.)

David J. Littleboy <dav...@gol.nonspam.com>

Jaewoo Kim

unread,
Nov 28, 1998, 3:00:00 AM11/28/98
to
Valentin Bonnard:

>i is out of scope after the return; if you change that (make
>automatics garbaged collected), then don't call the result C++.

Yes, you're right. I think the lambda function (closure) of functional
langauges in C++ is very difficult and nearly impossible to implement
without changing the semantic structure of C++ . But If someone want to add
_anymous closure_ to C++, the most important aspect of _closure_ (embedding
the referencing env. of the definition point) shoudn't be discarded.

Although I'm neither a compiler writer nor a C++ expert, it's resonable and
not bad to restrict references in a lambda body to the static/const entity.

Const entities could be solved by duplication of values; copying.
Static entities by implicit referencing.

Though only restrictive referencing in a lambda body is possible, it'll be
still useful, I think.

>But w/o local context yes, if it has function (not object)
>type, there is no problem to return it.

What does w/o means?

[Moderator's note: "w/o" means "without". -mod(fjh).]

KiZOo

Siemel Naran

unread,
Nov 28, 1998, 3:00:00 AM11/28/98
to

On 26 Nov 1998 17:32:32 GMT, James...@dresdner-bank.de

>Note that in general, the only thing you could do with a lambda function
>is pass its address to another function, which takes a pointer to
>function as argument. In C++, such functions should be rare; it is
>far more in keeping with the spirit of the language to pass a reference
>to a functional object. Again, this demands lambda classes, rather
>than lambda functions.

Why bother with lambda classes? They may make your code look more
clumsy because struct/class definitions tend to be a little long.
Anyway, a nice notation for an unnamed struct would be
"struct(...)".

for_each(array,array+N,
struct(7) : public std::unary_function<int,void>
{ struct(int x_) : x(x_) { }
void operator()(int i) { cout<<i+x<<' '; }
private: int x;
}
);

This is the same as

struct Function : public std::unary_function<int,void>
{
Function(int x_) : x(x_) { }
void operator()(int i) { cout<<i+x<<' '; }
private: int x;
}
for_each(array,array+N,Function(7));

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Andrei Alexandrescu

unread,
Nov 28, 1998, 3:00:00 AM11/28/98
to

James...@dresdner-bank.de wrote in message
<73jta2$5hd$1...@nnrp1.dejanews.com>...

>Lisp is a functional language, so it is normal that it have lambda
>functions. Since C++ is an object oriented language (sort of), it
>would seem to me more normal that it have lambda classes.


After much thought and reading this thread, I think you and others are
right: lambda classes (anonymous classes built on the fly) are more in
the spirit of C++.

Please someone come with a coherent proposal on them. I would like
them to follow functional rules (to have an operator()() and member
variables to hold context).

Andrei

Andrei Alexandrescu

unread,
Nov 28, 1998, 3:00:00 AM11/28/98
to

Pete Becker wrote in message <365CDBE3...@acm.org>...
>
>Andrei Alexandrescu wrote:
>>
>> Of course you can do this with external classes or functions, but
that's
>> actually only a verbose and non-intuitive simulation. With lambda
functions
>> you can express what environment you pass and what computation is
done in a
>> single place. You can get rid of almost all explicit loops without
having to
>> add myriads of small external classes/functions. It's much, much
clearer
>> this way.
>
>Example, please. <g>


No examples. The advantage is apparent to me, though.

All this thread discouraged me. But, the bright part is that no single
language feature is necessary to write good programs in that language.

Plus, C++ cannot be all things to all programmers.

I hoped to find some gurus here who had the same idea about lambda
constructions and were willing to put together something, but I
haven't been lucky. But indeed, it's a good thing to be reluctant in
increasing the size of the language.

James...@dresdner-bank.de

unread,
Nov 28, 1998, 3:00:00 AM11/28/98
to

In article <365D5315...@physik.tu-muenchen.de>,
Christopher Eltschka <celt...@physik.tu-muenchen.de> wrote:

> Indeed, anything having external linkage will have to be given
> different names on any implementation using a more or less
> traditional linker. Therefore, generating different names for
> typeid.name() is automatic, if you use the mangled name, and should
> at least be possible with internal names. The only problematic
> point is naming the non-external names.
> However, even this problem should be solvable, since effectively
> the same method as for unnamed namespace members can be used
> (while for non-external symbols, it is not important to be unique,
> it wouldn't hurt either).

Just curious, but how do implementors generate a name guaranteed to
be unique. Within a compilation unit, they just number, of course.
But between compilation units. You can't use the file name; I can
still remember the problems that caused in CFront (which used the
file name to generate the names of the functions to construct and
destroy local variables). You can't really use the full path; I
can build a library in my home directory on one machine, and use
it with code developed in my home directory ("/home/kanze" in both
cases) on another, so the problem is the same as filenames. You
can't use the machine name, since this is only guaranteed unique
within the same domain. You can't use a time stamp, since with
many people working on the same project. You can't even really
use the fully qualified domaine -- most PC users don't have one.

So what do they do?

(Quite frankly, I'd hack it, and just generate a 256 bit random
number. With a good randomizing function, collisions should be
really rare, and of course, if you recompile, the collision
disappears. So even a user who stumbles onto the "bug" won't
be able to reproduce it.)

--
James Kanze GABI Software, Sàrl
Conseils en informatique orienté objet --
-- Beratung in industrieller Datenverarbeitung
mailto: ka...@gabi-soft.fr mailto: James...@dresdner-bank.de

-----------== Posted via Deja News, The Discussion Network ==----------


http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

Petter Urkedal

unread,
Nov 28, 1998, 3:00:00 AM11/28/98
to

The idea is inspiring. But these lambda-functions, can be implemented
with expression templates, with a syntax not so far from that of the
original post.

Here is a useless example:

template<typename Iterator1, typename Iterator2>
void useless_transform(Iterator1 u, Iterator1 u_end, Iterator2 v) {
placeholder<0, int> i;
placeholder<1, int> j;
placeholder<2, int> k;

transform(u, u_end, v,
lambda(i, apply(lambda(j, k, j*k),
i+value(10), i-value(10))));
}

A working implementation can be found at

http://matfys.lth.se/~petter/src/more/stlext/index.html

along with some examples. It's not so fully debugged, as it was done
yesterday, inspired by the present discussion. (The examples builds
with egcs and DEC cxx, at least.)

Of course, build-in lambda expressions would be faster and give nicer
compiler messages. So I'm not taking an opinion against the proposal.

-petter.

--
[- http://matfys.lth.se/~petter/ -]

Siemel Naran

unread,
Nov 28, 1998, 3:00:00 AM11/28/98
to

On 26 Nov 1998 17:32:24 GMT, Ziv Caspi <zi...@peach-networks.com> wrote:

>[1] Unlike Pete Becker, I *do* think that the construct:
>
> LOOP_OBJECTS( it, abc )
> //...
> END_LOOP
>
>is better than writing external functions (or external functors, if
>context is needed). I have worked in a group where people used both
>constructs, and after some time of use we all tended to the macro
>form. YMMV, of course.

Interesting. I've found that the usage of external functions, and
hopefully even local classes in the future, is a little clearer
because it seperates the main algorithm from sub-algorithms and
thereby makes code easier to read and maintain. IOW, the body of
the for loop or "//..." above is a sub-algorithm. The instruction
to invoke this loop or "LOOP_OBJECTS( it, abc )" is the main loop.
In your program above, the main algorithm and sub-algorithm appear
as one -- as one big algorithm. Yes, I have the habit of writing
code like this myself. That is, expand functions inline manually.
This is because I think of the algorithm as one big algorithm, not
as a main algorithm with sub-algorithms. In any case, this
approach is fine. But when I look at the code again three weeks
later, it's a little bulky and somewhat more difficult to understand.

Two other advantages of using external functions are as follows.
First, you can reuse the function in two different places. This
saves on the amount of code you have to write, and it also
eliminates code bloat in the final executable. It is often said
that OOP encourages reuse. But this is not true. Even using
plain old functions encourages reuse.

Second, the external function forces us to pre-compute
container.end() so that the sub-algorithm doesn't have to do it.
Then this end iterator can be stored in a register and can be
used throughout the sub-algorithm. But when you expand the for
loop manually, then since it is conceivable that the sub-algorithm
may change the container, the value of container.end() can't be
pre-computed and stored in a register:
for (iter i=container.begin(); i!=container.end(); ++i) { ... }
Since the "..." may change container by adding or removing elements,
container.end() can't be precomputed and stored in a register. This
problem is easily solved by doing
iter i=container.begin();
const iter end=container.end();
for (; i!=end; ++i) { ... }


--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Siemel Naran

unread,
Nov 28, 1998, 3:00:00 AM11/28/98
to

On 27 Nov 98 07:11:13 GMT, Valentin Bonnard <bonn...@pratique.fr> wrote:
>Jaewoo Kim wrote:

>But w/o local context yes, if it has function (not object)
>type, there is no problem to return it.

Yes, one can't return local objects because there's no way
to specify the return type. However, we could use something
like this:

class Base { ... };

auto_ptr<Base> f(int x)
{
class Derived : public Base { ... };
return new Derived(x);

Siemel Naran

unread,
Nov 28, 1998, 3:00:00 AM11/28/98
to

On 26 Nov 98 16:49:09 GMT, Christopher Eltschka

>Well, the function does not need to have external linkage.
>It's the _type_ which is the template argument; and the type is
>a function (pointer) type, which has "external" linkage as a
>built-in type. Note that the function itself may well have
>internal linkage. For example:

Oh, so obvious and I missed it :). Thanks. I was unconsciously
thinking of the lambda function as generating a lambda class
which would then be used in the template instantiation.

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Francis Glassborow

unread,
Nov 29, 1998, 3:00:00 AM11/29/98
to

In article <73k6fl$cr7$1...@nnrp1.dejanews.com>, James.Kanze@dresdner-
bank.de writes

>So what do they do?

Date/Time in milliseconds when it was compiled?

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Valentin Bonnard

unread,
Nov 29, 1998, 3:00:00 AM11/29/98