Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

lambda functions proposal

24 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
to James...@dresdner-bank.de

James...@dresdner-bank.de wrote:

> 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 mean globals and static variables, don't you ?

> 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?

I run some tests with egcs/g++ and I found that it tries hard
to generate different names for different types (that is, I
haven't been able to define two types with the same name).

For types locals to one TU (with or w/o linkage), it uses
something like TU_ID ## type_name ## scope_ID.

TU_ID is the signature of the first non inline extern
function definition of the TU.

scope_ID is local to the TU.

You can define types with no functions at all in
the TU:

// foo.cc

namespace {
struct foo {};
}

// end foo.cc

but you can't really do anything with them, so you
can just forget them.

You can hardly use anonymous namespaces members in
inline functions because you wouldn't be able to
duplicate the definition of the function in any other TU.

Note: more recent tests indicate that it uses the file
name for the TU_ID, so I guess it's a recent change in
egcs (using:
Reading specs from
/usr/local/util/packages/egcs-050798/lib/gcc-lib/sparc-sun-solaris2.5/egcs-2.91.45/specs
gcc version egcs-2.91.45 19980704 (gcc2 ss-980609 experimental)
).

More precisely, egcs uses the local path to the files: foo.cc,
bar/foobar.cc, ect) but not /users/bonnard/C++/foo.cc
for example.

--

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

Valentin Bonnard

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

James...@dresdner-bank.de wrote:

> So what do they do?

I have just reported two egcs bugs so ignore my previous message
about how egcs does it: egcs simply gets it wrong.

However, I have found a solution:

use the signature of the first extern non inline function
definition; if there isn't one, discard the TU, and
document this behaviour.

Ziv Caspi

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

On 28 Nov 1998 23:41:31 GMT, James...@dresdner-bank.de wrote:

>Just curious, but how do implementors generate a name guaranteed to
>be unique.

[...]


>So what do they do?

An MSVC "Wizard" usually just creates a UUID.

---------------------------------------------
Ziv Caspi
zi...@netvision.net.il

Ziv Caspi

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

On 28 Nov 1998 23:56:53 GMT, sbn...@localhost.localdomain.COM (Siemel
Naran) wrote:

>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.

While I agree in principle, in practice I found out that "one-timer"
functions do not always increase maintainability, especially when
they need a large context to be provided by their caller.

>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.

Only if your "sub-algorithm" has any meaning in other contexts, which
many times it does not. I also tend to count "zero, one, many", but I
always make sure that this doesn't become "zero, many".

>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.

During the last ten years a lot of experience has accumulated
the "reuse" silver bullet. One of the conclusions, IMHO, is that one
cannot really write "sizable" reusable components unless one has
several instances of clients to work with, or prior experience in the
field. If a given sub-algorithm is used only once, and is really new
to the problem space, I don't even try to generalize it, simply
because I know from experience (meta-experience, in this case...)
that if I'd need a similar sub-algorithm again in the future, I'd
re-write the sub-algorithm as a function (or functor) to handle
both the old and the new contexts.

>Second, the external function forces us to pre-compute
>container.end() so that the sub-algorithm doesn't have to do it.

I don't consider this form of "efficiency" as an advantage. As you
said later, there are other ways to handle it. (Note that you
seem to refer to cases where end() changes during the loop; in
such cases, storing a pre-defined value of end() is certainly
incorrect.)

[...]

I realize that I place myself "on the other side" by saying this, but
it has been my experience that sometimes long functions with several
"stages" are easier to write, debug, and maintain than subdividing
them into sub-functions, that have no cohesion except that each is a
stage in a larger algorithm.

Just recently, for example, I left my former employer to a new job.
Before leaving, I conducted a long transference of responsibilities
to my replacement. This included several excercises (fixing known
bugs and incorporating new funcionality). Nowhere did my replacement
have any problems with my long functions, in part because
functionality was located in a single place.

Andrew Koenig

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

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

> 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.

One useful technique is to use a variant of the name of any of the global
entities defined in the translation unit. A translation unit that defines
no global entities is useless, as nothing in it can be referred to from
outside, and if it defines a global entity, it cannot be linked with any
other translation unit that defines the same entity.
--
Andrew Koenig
a...@research.att.com
http://www.research.att.com/info/ark

Andrei Alexandrescu

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

James...@dresdner-bank.de wrote in message
<73k6fl$cr7$1...@nnrp1.dejanews.com>...

>Just curious, but how do implementors generate a name guaranteed to
>be unique.

C'mon, you can't be serious. Just generate a GUID. If the machine has
a network card (which has a unique number in the world), it's
guaranteed to be unique. If the machine hasn't one, yet the
probability of having two identical GUIDs is smaller as the
probability that a "correct" compiler crashes because of a hardware
problem.

Andrei

Andrei Alexandrescu

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

Siemel Naran wrote in message ...

> 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 too heavily scaffolded, in my opinion. It just hides the
intent.

Andrei Alexandrescu

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

Siemel Naran wrote in message ...
>Interesting. I've found that the usage of external functions, and
>hopefully even local classes in the future, is a little clearer

My problem with this is that usually inside a function I have access
to some context that's clumsy to pass to those small functions. But in
principle, I tend to agree with you.

Siemel Naran

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

On 29 Nov 1998 21:32:13 GMT, Andrei Alexandrescu

>Siemel Naran wrote in message ...

>>Interesting. I've found that the usage of external functions, and
>>hopefully even local classes in the future, is a little clearer

>My problem with this is that usually inside a function I have access
>to some context that's clumsy to pass to those small functions. But in
>principle, I tend to agree with you.

Good point. But if local classes could access local variables, as
suggested by J Kanze, then we'd be all set towards a nice solution.

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

Siemel Naran

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

On 29 Nov 1998 21:32:02 GMT, Ziv Caspi <zi...@peach-networks.com> wrote:

>On 28 Nov 1998 23:56:53 GMT, Siemel Naran wrote:

>>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.

>While I agree in principle, in practice I found out that "one-timer"
>functions do not always increase maintainability, especially when
>they need a large context to be provided by their caller.

By "large context to be provided" do you mean the passing of fifty
or so local variables to the called function? This is indeed a
problem and defeats the use of small external functions. In fact,
much of my own code uses explicit for and while loops in the
function body because I don't want to pass fifty or so variables.
However, if local classes could access local variables, then the
problem wouldn't be so bad; we wouldn't have to pass the context
or environment as it would be automatically built into the local
class.


>>Two other advantages of using external functions are as follows.
>>First, you can reuse the function in two different places.
>
>Only if your "sub-algorithm" has any meaning in other contexts, which
>many times it does not. I also tend to count "zero, one, many", but I
>always make sure that this doesn't become "zero, many".

Good point.


>>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.

>During the last ten years a lot of experience has accumulated
>the "reuse" silver bullet. One of the conclusions, IMHO, is that one
>cannot really write "sizable" reusable components unless one has
>several instances of clients to work with, or prior experience in the
>field. If a given sub-algorithm is used only once, and is really new
>to the problem space, I don't even try to generalize it, simply
>because I know from experience (meta-experience, in this case...)
>that if I'd need a similar sub-algorithm again in the future, I'd
>re-write the sub-algorithm as a function (or functor) to handle
>both the old and the new contexts.

Fine, you seem to talk from much experience. Generalizing one's
code by using templates and multiple functions is elegant and
worthwhile for common operations. It's not necessary or even
useful for specialized operations. But the question is: how do we
distinguish specialized and general operations?

Sometimes operations that once seemed too specialized may later
seem to be variants of a more general operation. And other times,
an operation that seemed general seems like it should be split into
two specialized operations for each of various contexts.

For example, it sometimes seems that there should be one root solver
for all the 1D differential equations in our project. But then
we learn that the differential solver for Schrodinger's equation
is different from the differential solver for Poisson's equation.
So our one general diffeq solver must be specialized. Anyway, a
good solution may be to use the traits technique and callback
functions and callback objects. This way we get one general diffeq
solver that can be specialized for various contexts. Local classes
which can be used in template functions and which can access local
variables may make our work easier, so they would be most welcome.


>I realize that I place myself "on the other side" by saying this, but
>it has been my experience that sometimes long functions with several
>"stages" are easier to write, debug, and maintain than subdividing
>them into sub-functions, that have no cohesion except that each is a
>stage in a larger algorithm.

Sounds reasonable. Deciding when to use function objects and
functions seems to be a design decision, and there is no one
right design.

Jason Merrill

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

>>>>> Valentin Bonnard <bonn...@pratique.fr> writes:

> James...@dresdner-bank.de wrote:

>> So what do they do?

> I have just reported two egcs bugs so ignore my previous message

> about how egcs does it: egcs simply gets it wrong.

Not in the current development tree; when there is no suitable global
entity, we tack together the file name and a random number, which suffices.

>>>>> Andrew Koenig <a...@research.att.com> writes:

> One useful technique is to use a variant of the name of any of the global
> entities defined in the translation unit. A translation unit that defines
> no global entities is useless, as nothing in it can be referred to from
> outside, and if it defines a global entity, it cannot be linked with any
> other translation unit that defines the same entity.

What about template instantiations, which could occur in multiple
translation units?

Jason

Jens Kilian

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

"Andrei Alexandrescu" <alexan...@micromodeling.com> writes:
> 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).

I don't know if my first comment to your original proposal made it to you;
to reiterate

- I proposed that a lambda construct should be transformed into the
declaration and use of a functional object class
- The free variables in the lambda expression should become members of the
class

I think the important feature supplied by lambda, and lacking in C function
pointers and Java anonymous classes, is the automatic(!) management of free
variables. Another poster in this thread commented that he didn't like
functional objects because they don't allow him to access the local context
in a function. That's the point which shld be addressed by a lambda
construct, no matter whether you call it a "function" or a "class".

Back to my proposal:

// Original code
...
int i; // Variable declared in enclosing scope
vector<int> foo; // Container we'll iterate over
...
for_each(foo.begin(), foo.end(),
lambda<void>(int k) { cout << i+k; }
);

In this example, "i" is a free variable in the body of the lambda.
The compiler knows this, and also knows the type of "i". It can generate
the same code that it would for the following functional-object based source.

// Equivalent code; could be created by a source transformation

class __lambda42 : public unary_function<int, void> {
public:
__lambda42(int i_) : i(i_) { }
__lambda42(const __lambda42 &l) : i(l.i) { }
void operator()(int k) { cout << i+k; }
private:
int i;
};

...
int i;
vector<int> foo;
...
for_each(foo.begin(), foo.end(),
__lambda42(i)
);

Note that a human programmer would have had to write the same code,
including all the tedious details of constructing and copying functional
objects.

OK, feel free to poke holes into this.

Jens.
--
mailto:j...@acm.org phone:+49-7031-14-7698 (HP TELNET 778-7698)
http://www.bawue.de/~jjk/ fax:+49-7031-14-7351
PGP: 06 04 1C 35 7B DC 1F 26 As the air to a bird, or the sea to a fish,
0x555DA8B5 BB A2 F0 66 77 75 E1 08 so is contempt to the contemptible. [Blake]

Andrew Koenig

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

In article <3661a...@10.1.1.65>,
Andrei Alexandrescu <alexan...@micromodeling.com> wrote:

> C'mon, you can't be serious. Just generate a GUID. If the machine has
> a network card (which has a unique number in the world), it's
> guaranteed to be unique.

A nice property for a compiler to have is that if you compile the same
program using the same compiler on two different machines, or on two
different occasions, the resulting binary is identical. Configuration
management becomes more difficult otherwise.

[ comp.std.c++ is moderated. To submit articles, try just posting with ]

Andrew Koenig

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

In article <slrn76406e....@localhost.localdomain>,
Siemel Naran <sbn...@KILL.uiuc.edu> wrote:

> Good point. But if local classes could access local variables, as
> suggested by J Kanze, then we'd be all set towards a nice solution.

It may not be obvious, but the ability of local classes to access
local variables is a fundamental change to the execution model of
C++ programs. The C++ committee did discuss the possibility of making
just that change at one point, but decided not to do it.

Siemel Naran

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

On 30 Nov 1998 19:07:16 GMT, Andrew Koenig <a...@research.att.com> wrote:

>It may not be obvious, but the ability of local classes to access
>local variables is a fundamental change to the execution model of
>C++ programs. The C++ committee did discuss the possibility of making
>just that change at one point, but decided not to do it.

Can you elaborate on this please? I thought it should be easy as
the local class could inherit privately from a compiler generated
value struct that contains all the local variables. Maybe it is
in the D&E (I haven't got that yet)?


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

All...@my-dejanews.com

unread,
Nov 30, 1998, 3:00:00 AM11/30/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).

In article <73k6fl$cr7$1...@nnrp1.dejanews.com>,


James...@dresdner-bank.de wrote:
>
> 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?

I'm not an implementor, but it seems to me that they could simply
use fully-qualified names. This could include qualifications that
are not legal in C++ source code. For instance, if a class is
declared inside a global function, use that global function's
signature as a qualification, as in
myspace::foo(int,const char*,void*)::A
Starting with this scheme, the implementor could then modify it to
suit the local needs of the linker. For instance, change unusable
characters into legal-character combinations. We could change
space into $S, comma into $C, () into $L$R, and so on.

> (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.)

For symbols that do not need to be visible from other modules,
it's easy enough to simply not export the name. For symbols that
DO need to be visible, random numbers won't do at all -- else
how would you access those symbols in some other module?

--
All...@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

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

All...@my-dejanews.com

unread,
Nov 30, 1998, 3:00:00 AM11/30/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.

In article <slrn75rghe....@localhost.localdomain>,


sbn...@KILL.uiuc.edu wrote:
>
> 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));

Yes! That's the way to do it.

As far as I'm concerned, if the C++ name for "Pass a message" is
"Call a member function", then the C++ name for "Lambda Function"
is "Functor." (Besides, I like saying "Functor" in mixed company! 8^)

Siemel Naran

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

On 27 Nov 98 07:11:07 GMT, James...@dresdner-bank.de

>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.)

Nice, but what if want to return a local class from a function?
Also see Valentin's point to some question on this thread.

class Base
{
public:
virtual ~Base();
virtual int answer(int) const = 0;
};

auto_ptr<Base> f(int x)
{
int i;

struct Derived : public Base
{
Derived(int x_) : x(x_) { }
int answer(int y) { return (i+x)+y; }

private: int x;
};

int j;
return new Derived(abs(x));
} // oops: 'i' out of scope now

Or are you thinking about deriving from class __local_context so
that you can control whether the local context gets inherited or
not? I think that the inheritance should be automatic because it
looks like an implementation detail. Furthermore, the struct
__local_context contains all the variables defined up to the point
of the local class definition. So the above local class
f(int)::Derived can use variable 'i' but not 'j'. And the
variables should be values, objects, not references. This allows
us to return local classes from functions, encourages optimization,
and avoids the problem of whether a local variable of type "T"
should be "T &" or "T const &". So, putting this all together, the
above just becomes:

auto_ptr<Base> f(int x)
{
int i;

struct __local_context
{
int i;
__local_context() : i(<local i>);
};
struct Derived : private __local_context, public Base
{
Derived(int x_) : x(x_) { }
int answer(int y) { return (i+x)+y; }

private: int x;
};

int j;
return new Derived(abs(x));
}

The above is still a little problematic. Specifically, it should
result in a warning message because the value of 'i' is used before
it is set. Furthermore, different Derived classes will have
different values for the variable 'i' which seems to be a little
confusing as the two classes
Derived d1(1);
//... /* possibly change 'i' */
Derived d2(1);
will have different behaviour if the value of 'i' changed in the
"//..." part. So a safe rule seems to be that every local variable
that is included in __local_context must have a top level const.
So the local variable 'i' in f(int) should be "const int i". But
then, should the variable 'i' in f(int)::__local_struct be
"int i" or "const int i"? Or maybe we should just dispense with
this const rule.



>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.

Can you elaborate on why it obfuscates the code.

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

Paul D. DeRocco

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to

James...@dresdner-bank.de wrote:
>
> (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.)

How about a 32-bit CRC on the source code? A one-in-four-billion chance
of collision is probably much less than the chance that the computer
will burst into flames and kill the programmer.

--

Ciao,
Paul

David J. Littleboy

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to

Siemel Naran wrote in message ...

>On 27 Nov 98 07:11:07 GMT, James...@dresdner-bank.de

>>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.

>Nice, but what if want to return a local class from a function?


>Also see Valentin's point to some question on this thread.

Right. By using references, a local object will reflect the state of its
context at the point it is run, but that happens at the cost of not being
able to return such an object.

Lambda in Scheme creates a snapshot of the state of the context at the point
the lambda is encountered. This could be matched in C++ by using not
reference variables but normal variables initialized to the current values
of their corresponding enclosing context variables, at the obvious cost of
copying the objects. This would also require that the body of the local
class appear at the point it's used.

The following sort of syntax could be used:
(Assuming arr is an array of pointers to user_type, and loc is bound to a
locale or something similar.)

sort(arr, (bool lambda(user_type* a, user_type* b)
{return (a->key_value(loc) > b->key_value(loc);}));

Here, lambda would create an object with an operator() of the right type. Of
course, this is a temporary object and where and how it gets destroyed is
problematic. (In general, Scheme, having a garbage collector, makes the use
of such objects painless, whereas in C++, at some point the program would
have to take care of destroying function objects that get passed back or
stored in other objects. That makes lambda less attractive in C++ than in
Scheme.)

I suspect that these two problems (leaking lambda-created function objects
and the need for copying the free variables in the lambda body (closure
variables)) mean that this sort of notation may not be reasonable for C++.
Even worse, this is nothing more than a notational convenience: an
externally declared and defined class with an appropriate operator() and a
constructor that takes the required free variables as arguments would be
exactly equivalent. E.g.,

sort(arr, user_comparator(loc));

Is already perfectly good C++. (Question: does this argument also apply to
local classes, i.e. could constructors with reference arguments provide the
same functionality as James' local class proposal?)

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

Jens Kilian

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to

> From: sbn...@fermi.ceg.uiuc.edu (Siemel Naran)
> Date: 30 Nov 1998 21:26:43 GMT

>
> On 30 Nov 1998 19:07:16 GMT, Andrew Koenig <a...@research.att.com> wrote:
>
> >It may not be obvious, but the ability of local classes to access
> >local variables is a fundamental change to the execution model of
> >C++ programs. The C++ committee did discuss the possibility of making
> >just that change at one point, but decided not to do it.
>
> Can you elaborate on this please? I thought it should be easy as
> the local class could inherit privately from a compiler generated
> value struct that contains all the local variables. Maybe it is
> in the D&E (I haven't got that yet)?

Having a local class gain access to local variables makes it necessary
to support nested functions. This would make our discussion of lambda
superfluous, because we could just use nested functions directly
(with a minor syntactical inconvenience).

The main feature of the C/C++ execution model is its simplicity: Because
every function (including member functions of local classes) only has access
to global variables and its own local variables (including parameters),
each function only needs to access a single stack frame. In contrast,
with nested functions every function can have access to multiple stack frames,
which complicates stack management. Look up "displays" or "static link"
in any compiler construction textbook if you want to know more.

As to your idea (compiler generates a struct containing locals and derives
local class from it), consider the case where a member function of the local
class itself has a local class, and that has a member function etc.
If you manage to come up with a solution that handles this case completely,
you will have reinvented displays.

Regards,

Jens.
--
mailto:j...@acm.org phone:+49-7031-14-7698 (HP TELNET 778-7698)
http://www.bawue.de/~jjk/ fax:+49-7031-14-7351
PGP: 06 04 1C 35 7B DC 1F 26 As the air to a bird, or the sea to a fish,
0x555DA8B5 BB A2 F0 66 77 75 E1 08 so is contempt to the contemptible. [Blake]

Andi Kleen

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to

In article <u9sof15...@yorick.cygnus.com>, Jason Merrill wrote:
>>>>>> Andrew Koenig <a...@research.att.com> writes:

> > One useful technique is to use a variant of the name of any of the global
> > entities defined in the translation unit. A translation unit that defines
> > no global entities is useless, as nothing in it can be referred to from
> > outside, and if it defines a global entity, it cannot be linked with any
> > other translation unit that defines the same entity.

>What about template instantiations, which could occur in multiple
>translation units?

Or an object declaration that does all the work from its constructors/
destructors.

-Andi

Andrew Koenig

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to

In article <slrn765t7v....@fermi.ceg.uiuc.edu>,
Siemel Naran <sbn...@KILL.uiuc.edu> wrote:

> On 30 Nov 1998 19:07:16 GMT, Andrew Koenig <a...@research.att.com> wrote:

> >It may not be obvious, but the ability of local classes to access
> >local variables is a fundamental change to the execution model of
> >C++ programs. The C++ committee did discuss the possibility of making
> >just that change at one point, but decided not to do it.

> Can you elaborate on this please? I thought it should be easy as
> the local class could inherit privately from a compiler generated
> value struct that contains all the local variables. Maybe it is
> in the D&E (I haven't got that yet)?

The difficulty is that when you call a member of the local class,
that member has to know the location of the local variables in the
surrounding context. So in

void f()
{
int n;

// ...

class T {
public:
void g() { ...use of n... }
// ...
}

// ...
};

if you have a T object and you call member g of that object, it must
somehow know where n is, even if that call is through a pointer to T
that has been stored and later retrieved.

[ comp.std.c++ is moderated. To submit articles, try just posting with ]

Valentin Bonnard

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to Andrew Koenig

Andrew Koenig wrote:

> It may not be obvious, but the ability of local classes to access
> local variables is a fundamental change to the execution model of
> C++ programs. The C++ committee did discuss the possibility of making
> just that change at one point, but decided not to do it.

On the contrary, it's a resonnably simple translation. It only
change the local classes, and nothing else.

Note that the position of the definition of the struct is very
important: it will only see variables defined at this point:

void f()
{
int i = 2;
float f = 0.
struct T : __local_context
{
void operator () ()
{ return i + f // ok
+ j; } // not ok (now assume we cut that)
};
cout << T () (); // prints 2.
T x;
int j = 3;
struct U : __local_context
{
void operator () ()
{ return j; } // ok
};
cout << x (); // ok, prints 2.
}

The responsabillity, is, as ever, given to the user, who shall
not use the struct after the scope has ended. A bit similar to
the always well-formed:

int* f()
{
int i;
return &i;
}

But here it's much more difficult to do that because T and U
are only visible in the scope of the coresponding variables.

--

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

All...@my-dejanews.com

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to

In article <3663482D...@ix.netcom.com>,

"Paul D. DeRocco" <pder...@ix.netcom.com> wrote:
>
> James...@dresdner-bank.de wrote:
> >
> > (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.)
>
> How about a 32-bit CRC on the source code? A one-in-four-billion chance
> of collision is probably much less than the chance that the computer
> will burst into flames and kill the programmer.

Are you saying that each time I compile a program, I have probably MUCH
MORE than a one-in-four-billion chance of death by flaming computer?
Let's see, a one-in-three-billion chance is MORE, but not MUCH MORE...
A one-in-four-hundred-million chance is an order of magnatude more, so
perhaps that qualifies as MUCH more. If we've got about 200 computers
here, then I have a one-in-two-million chance of being in the same
building as someone that dies by flaming computer... that's better odds
than most state lotteries!

I guess my dad was right. Becoming an assassin for the CIA would have
been a lot safer. From now on, I schedule *ALL* of my compiles to run
in a batch overnight!

Anyone have a program for generating "lucky" lotto numbers? I'd write
one myself, but I'm afraid to compile it...

--
All...@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

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

Andrew Koenig

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to

In article <366435...@pratique.fr>,
Valentin Bonnard <bonn...@pratique.fr> wrote:

> Andrew Koenig wrote:

> > It may not be obvious, but the ability of local classes to access
> > local variables is a fundamental change to the execution model of
> > C++ programs. The C++ committee did discuss the possibility of making
> > just that change at one point, but decided not to do it.

> On the contrary, it's a resonnably simple translation. It only
> change the local classes, and nothing else.

I did not say it wasn't simple, just that it is fundamental.
And it is still true that the committee considered such a change and rejected it.

[ comp.std.c++ is moderated. To submit articles, try just posting with ]

Valentin Bonnard

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to sbn...@uiuc.edu

Siemel Naran wrote:

> Nice, but what if want to return a local class from a function?

You don't - at least, not in C++

> Also see Valentin's point to some question on this thread.
>

> class Base
> {
> public:
> virtual ~Base();
> virtual int answer(int) const = 0;
> };
>
> auto_ptr<Base> f(int x)
> {
> int i;
>
> struct Derived : public Base
> {
> Derived(int x_) : x(x_) { }
> int answer(int y) { return (i+x)+y; }
>
> private: int x;
> };
>
> int j;
> return new Derived(abs(x));
> } // oops: 'i' out of scope now

Do you have any other examples where a __local_context
can be returned ? Your example is the only case I have
been able to find.

Of course we just say that it's undefined behaviour
and be done with it (it isn't even something easy to
write accidentally).

> Or are you thinking about deriving from class __local_context so
> that you can control whether the local context gets inherited or
> not? I think that the inheritance should be automatic because it
> looks like an implementation detail.

At least the name looks ugly.

> Furthermore, the struct
> __local_context contains all the variables defined up to the point
> of the local class definition.

Yep, as I said in some other post

--

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

Siemel Naran

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to

On 1 Dec 1998 17:23:39 GMT, Andrew Koenig <a...@research.att.com> wrote:

>The difficulty is that when you call a member of the local class,
>that member has to know the location of the local variables in the
>surrounding context. So in
>
> void f()
> {
> int n;
>
> // ...
>
> class T {
> public:
> void g() { ...use of n... }
> // ...
> }
>
> // ...
> };
>
>if you have a T object and you call member g of that object, it must
>somehow know where n is, even if that call is through a pointer to T
>that has been stored and later retrieved.

Since class T derives implicitly from __local_context, it knows exactly
where 'n' is. The definition of __local_context is either one of these:

struct __local_context { int& n; __local_context(int& n_) : n(n_) {} };
struct __local_context { int n; __local_context(int n_) : n(n_) {} };

If the layout of a base class sub-object within a derived object is
specified, the location of 'n' is well known: assuming that
sizeof(int)==4 and that class T has no vptr, 'n' is the first 4 bytes
of struct T.


The 1st version couples the local class strongly to the local context.
So if the local context changes, the class changes accordingly.
Possibly, the type of the local class 'n' should be "int const&".
Because of the strong coupling, you can't return the local class from
the function.

The 2nd version allows you to return the local class from the function.


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

All...@my-dejanews.com

unread,
Dec 1, 1998, 3:00:00 AM12/1/98
to

In article <slrn7676...@colin.muc.de>,

a...@colin.muc.de (Andi Kleen) wrote:
>
> In article <u9sof15...@yorick.cygnus.com>, Jason Merrill wrote:
> >>>>>> Andrew Koenig <a...@research.att.com> writes:
>
> > > One useful technique is to use a variant of the name of any of the global
> > > entities defined in the translation unit. A translation unit that
defines
> > > no global entities is useless, as nothing in it can be referred to from
> > > outside, and if it defines a global entity, it cannot be linked with any
> > > other translation unit that defines the same entity.
>
> >What about template instantiations, which could occur in multiple
> >translation units?
>
> Or an object declaration that does all the work from its constructors/
> destructors.

Would have to be a global object, wouldn't it? If it's declared
static it might not be initialized until the first function in that
same module is called. Either way, you're going to need some global
entity.

--
All...@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

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

Hans Aberg

unread,
Dec 4, 1998, 3:00:00 AM12/4/98
to

Lambda functions are of course already present in C++, in the form of
functions and templates:

Write x |-> f for (lambda x.f).

Then the code
int N = 0;
void f(int k) { N += k; }
might be written
int N = 0;
f = int k, k |-> { N += k; return void; }
where "void" is value (nothing) that one can return, and "int k" is short
for "k in int".

Or we could write a template class
template<X T> class C { ... };
as
X T, T |-> class C { ... };

The questions are really
1) How to interpret the computer semantics of such expressions.
2) How and when (compile/run-time) the allowable covers should be built.

On 2) C++ then does not have a complete lambda theory in it, and the
restriction is that as much as possible should be built at compile time
(in the name of code efficiency).

Also 1) will probably cause some problems: Functional languages differ in
this matter. It helps to know something about the semantics of the objects
manipulated (like whether they have a copy constructor).

Hans Aberg * Anti-spam: Remove "REMOVE." from email address.
* Email: Hans Aberg <hab...@REMOVE.member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>

Stanley Friesen [Contractor]

unread,
Dec 4, 1998, 3:00:00 AM12/4/98
to

In article <slrn7642kp....@localhost.localdomain>,

Siemel Naran <sbn...@KILL.uiuc.edu> wrote:
>By "large context to be provided" do you mean the passing of fifty
>or so local variables to the called function? ...

>However, if local classes could access local variables, then the
>problem wouldn't be so bad; we wouldn't have to pass the context
>or environment as it would be automatically built into the local
>class.
>
I am leary of this "solution". One of the most difficult program to maintain I
ever ran across was a Pascal program that made heavy use of this "feature". It
was almost impossible to find the declarations of variables in
sub-sub-sub-functions, as they could be pages previous, and in any of several
nested locations. And it was difficult to tell which functions modified which
variables, even *given* the complete function prototype.

In short, this type of scoping just causes *all* of the same problems as global
variables, amplified by the number of nesting levels in use.

Tom Payne

unread,
Dec 10, 1998, 3:00:00 AM12/10/98
to

Hans Aberg (hab...@REMOVE.matematik.su.se) wrote:

: Lambda functions are of course already present in C++, in the form of
: functions and templates:

Not quite. Lambda expressions are to functions what literals are to
strings and numbers, i.e., a scheme for identifying them without
necessarily giving them a name. AFIK there is no provision for such
nameless identification of functions in C/C++.

Tom Payne

Hans Aberg

unread,
Dec 10, 1998, 3:00:00 AM12/10/98
to

In article <74oj6u$opn$2...@pravda.ucr.edu>, t...@vdo.ucr.edu (Tom Payne) wrote:
>: Lambda functions are of course already present in C++, in the form of
>: functions and templates:
>
>Not quite. Lambda expressions are to functions what literals are to
>strings and numbers, i.e., a scheme for identifying them without
>necessarily giving them a name. AFIK there is no provision for such
>nameless identification of functions in C/C++.

This is a good point: However, the reason these functions are named is
that one should be able to link them together, and not any underlying
logical reason of the function itself, which can well be described by a
lambda expression. (Perhaps this just leads to the denotational semantics
description of C++.)

Hans Aberg * Anti-spam: Remove "REMOVE." from email address.
* Email: Hans Aberg <hab...@REMOVE.member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>

Rus...@shevchenko.kiev.ua

unread,
Dec 11, 1998, 3:00:00 AM12/11/98
to

In article <haberg-1012...@sl51.modempool.kth.se>,

hab...@REMOVE.matematik.su.se (Hans Aberg) wrote:
>
> In article <74oj6u$opn$2...@pravda.ucr.edu>, t...@vdo.ucr.edu (Tom Payne) wrote:
> >: Lambda functions are of course already present in C++, in the form of
> >: functions and templates:
> >
> >Not quite. Lambda expressions are to functions what literals are to
> >strings and numbers, i.e., a scheme for identifying them without
> >necessarily giving them a name. AFIK there is no provision for such
> >nameless identification of functions in C/C++.
>

It is possible to write combinatory logic calculus on templates, up to
fixed point combinator .

Another question: can it be usefull ? ;)


> This is a good point: However, the reason these functions are named is
> that one should be able to link them together, and not any underlying
> logical reason of the function itself, which can well be described by a
> lambda expression. (Perhaps this just leads to the denotational semantics
> description of C++.)
>

using object without name means using object *once* which means
that we can use static (in "C" sence) generated names.

P.S. Are exists places, where proposal to extension C++ are collected ?

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

Jens Kilian

unread,
Dec 11, 1998, 3:00:00 AM12/11/98
to

> From: hab...@REMOVE.matematik.su.se (Hans Aberg)

> In article <74oj6u$opn$2...@pravda.ucr.edu>, t...@vdo.ucr.edu (Tom Payne) wrote:
> >Not quite. Lambda expressions are to functions what literals are to
> >strings and numbers, i.e., a scheme for identifying them without
> >necessarily giving them a name. AFIK there is no provision for such
> >nameless identification of functions in C/C++.
>
> This is a good point: However, the reason these functions are named is
> that one should be able to link them together, [...]

I beg to disagree. There is no inherent reason why a function needs a name;
if it is inline-expanded, the linker needs no name, and if it's not inline
the compiler can always think up a name.

Lambda functions are to named functions what temporaries are to variables.
You don't want to have to write

int foo = a + b;
int bar = foo * 2;
// ...

when you can write

... (a + b) * 2 ...

If a function is used only once, why should I have to think up a name for it?

Jens.
--
mailto:j...@acm.org phone:+49-7031-14-7698 (HP TELNET 778-7698)
http://www.bawue.de/~jjk/ fax:+49-7031-14-7351
PGP: 06 04 1C 35 7B DC 1F 26 As the air to a bird, or the sea to a fish,
0x555DA8B5 BB A2 F0 66 77 75 E1 08 so is contempt to the contemptible. [Blake]

Tom Payne

unread,
Dec 11, 1998, 3:00:00 AM12/11/98
to

Rus...@Shevchenko.Kiev.UA wrote:

: In article <haberg-1012...@sl51.modempool.kth.se>,
: hab...@REMOVE.matematik.su.se (Hans Aberg) wrote:
: >
: > In article <74oj6u$opn$2...@pravda.ucr.edu>, t...@vdo.ucr.edu (Tom Payne) wrote:
: > >: Lambda functions are of course already present in C++, in the form of
: > >: functions and templates:
: > >
: > >Not quite. Lambda expressions are to functions what literals are to


: > >strings and numbers, i.e., a scheme for identifying them without
: > >necessarily giving them a name. AFIK there is no provision for such
: > >nameless identification of functions in C/C++.

: >

: It is possible to write combinatory logic calculus on templates, up to
: fixed point combinator .

Clever stuff!

: Another question: can it be usefull ? ;)

It would be useful to those who prefer combinarory/lambda notation.
Are the details readily available?

Tom Payne

Hans Aberg

unread,
Dec 11, 1998, 3:00:00 AM12/11/98
to

In article <sflnkfm...@bstde026.bbn.hp.com>, Jens Kilian

<Jens_...@bbn.hp.com> wrote:
>> This is a good point: However, the reason these functions are named is
>> that one should be able to link them together, [...]
>
>I beg to disagree. There is no inherent reason why a function needs a name;
>if it is inline-expanded, the linker needs no name, and if it's not inline
>the compiler can always think up a name.

Well, from the logical point of view, the linker does not need the name
because the compiler links them together (and skips creating a function in
the cases it is not needed and if the compiler is clever enough).

>Lambda functions are to named functions what temporaries are to variables.
>You don't want to have to write
>
> int foo = a + b;
> int bar = foo * 2;
> // ...
>
>when you can write
>
> ... (a + b) * 2 ...
>
>If a function is used only once, why should I have to think up a name for it?

The original point though is that the lambda is just a way to define
functions. So the function definitions of C++ already uses an implicit
lambda, even though they are tied together with names.

One can do more with the lambda, of course, that is the point: Then what
is needed is to build more general covers.

Hans Aberg * Anti-spam: Remove "REMOVE." from email address.
* Email: Hans Aberg <hab...@REMOVE.member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>

Joe Buck

unread,
Mar 1, 1999, 3:00:00 AM3/1/99
to

In article <73k6fl$cr7$1...@nnrp1.dejanews.com>,
<James...@dresdner-bank.de> wrote:
>> 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.

a...@research.att.com (Andrew Koenig) writes:
>One useful technique is to use a variant of the name of any of the global
>entities defined in the translation unit. A translation unit that defines
>no global entities is useless, as nothing in it can be referred to from
>outside, and if it defines a global entity, it cannot be linked with any
>other translation unit that defines the same entity.

Unfortunately this statement is not correct: there are useful translation
units that define no global symbols. Specifically, a translation unit can
define only file-scope objects and still do useful work, if the side
effect of the constructor calls for those objects does useful work
(e.g. variants of the object factory pattern). In most implementations a
unique name must somehow be produced for the function that constructs the
file-scope objects in the translation unit.

This is not simply theoretical; the egcs team has an open bug report for
exactly this problem.

0 new messages