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

Back to BCPL: using lambdas to do e.g. loops within expressions

49 views
Skip to first unread message

Alf P. Steinbach

unread,
Feb 25, 2017, 7:17:11 AM2/25/17
to
I'm not sure, but I think BCPL, which C was based on, supported control
structures within expressions; at least had curly braces in expressions?

Anyway, after C++11 and C++14 we can now do that in C++:


#include <p/expressive/use_weakly_all.hpp>
//
// #define $invoked $e::impl::Gurkemeie{} % []()
// #define $invoked_with( instantiation ) \ //
// $e::impl::Gurkemeie{} % []( decltype( instantiation ) =
instantiation )

#include <iostream>
$use_weakly_all_from( std );

struct Mutex
{
~Mutex() { cout << "Mutex::<destroy>" << endl; }
Mutex() { cout << "Mutex::<init>" << endl; }
};

struct Library_usage
{
~Library_usage() { cout << "Library_usage::<destroy>" << endl; }
Library_usage() { cout << "Library_usage::<init>" << endl; }
};

struct Tracing
{
~Tracing() { cout << "Tracing::<destroy>" << endl; }
Tracing() { cout << "Tracing::<init>" << endl; }
};

$just
{
$let sum = $invoked{ int s{}; for( int i = 1; i <= 8; ++i ) s += i;
return s; };
cout << sum << endl;

cout << endl;
$invoked_with( Tracing{} )
{
cout << "Hum!" << endl;
};
}


Here the % operator function is found via Argument Dependent Lookup and
invokes the specified lambda, producing an expression return value via
C++14 automatic return type deduction, and that works with MSVC 2015. :)


Cheers!,

- Alf

Ben Bacarisse

unread,
Feb 25, 2017, 10:13:41 AM2/25/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> I'm not sure, but I think BCPL, which C was based on, supported
> control structures within expressions; at least had curly braces in
> expressions?

It has expressions of the form VALOF <block> used like this:

LET l = VALOF $(
LET n, x = 0, 1
WHILE x < y DO n, x = n+1, f(x)
RESULTIS n
$)

In fact, that's how functions that need a block are defined.

> Anyway, after C++11 and C++14 we can now do that in C++:

Surely an example in pure C++ would have been better? The above in C++
is:

int p = [&]{
int n = 0, x = 1;
while (x < y) n++, x=f(x);
return n;
}();

There has to be a y and and f in scope in both examples.

In cases like this you don't need to capture anything in the lambda --
you can just pass arguments:

int l = [](int y, int (*f)(int)) {
int n = 0, x = 1;
while (x < y) n++, x=f(x);
return n;
}(123456789, [](int x){ return x*10; });


> #include <p/expressive/use_weakly_all.hpp>
> //
> // #define $invoked $e::impl::Gurkemeie{} % []()
> // #define $invoked_with( instantiation ) \ //
> // $e::impl::Gurkemeie{} % []( decltype( instantiation ) =
> instantiation )
>
> #include <iostream>
> $use_weakly_all_from( std );
>
> struct Mutex
> {
> ~Mutex() { cout << "Mutex::<destroy>" << endl; }
> Mutex() { cout << "Mutex::<init>" << endl; }
> };
>
> struct Library_usage
> {
> ~Library_usage() { cout << "Library_usage::<destroy>" << endl; }
> Library_usage() { cout << "Library_usage::<init>" << endl; }
> };
>
> struct Tracing
> {
> ~Tracing() { cout << "Tracing::<destroy>" << endl; }
> Tracing() { cout << "Tracing::<init>" << endl; }
> };
>
> $just
> {
> $let sum = $invoked{ int s{}; for( int i = 1; i <= 8; ++i ) s +=
> i; return s; };

I'm guessing this is the thunk being called and that it means:

auto sum = [&]{
int s{}; for( int i = 1; i <= 8; ++i ) s += i; return s;
}();

> cout << sum << endl;
>
> cout << endl;
> $invoked_with( Tracing{} )
> {
> cout << "Hum!" << endl;
> };
> }
>
>
> Here the % operator function is found via Argument Dependent Lookup
> and invokes the specified lambda, producing an expression return value
> via C++14 automatic return type deduction, and that works with MSVC
> 2015. :)

Where is the % operator being used? Is that masked by the $xyz stuff or
is it in the header?

--
Ben.

Alf P. Steinbach

unread,
Feb 25, 2017, 11:37:46 AM2/25/17
to
On 25.02.2017 16:13, Ben Bacarisse wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>
>> I'm not sure, but I think BCPL, which C was based on, supported
>> control structures within expressions; at least had curly braces in
>> expressions?
>
> It has expressions of the form VALOF <block> used like this:
>
> LET l = VALOF $(
> LET n, x = 0, 1
> WHILE x < y DO n, x = n+1, f(x)
> RESULTIS n
> $)
>
> In fact, that's how functions that need a block are defined.
>

Thanks! I was pretty sure it was supported, but I had some doubt
lingering. I never used the language.


[snip]
>>
>> struct Tracing
>> {
>> ~Tracing() { cout << "Tracing::<destroy>" << endl; }
>> Tracing() { cout << "Tracing::<init>" << endl; }
>> };
>>
>> $just
>> {
>> $let sum = $invoked{ int s{}; for( int i = 1; i <= 8; ++i ) s +=
>> i; return s; };
>
> I'm guessing this is the thunk being called and that it means:
>
> auto sum = [&]{
> int s{}; for( int i = 1; i <= 8; ++i ) s += i; return s;
> }();
>
>> cout << sum << endl;
>>
>> cout << endl;
>> $invoked_with( Tracing{} )
>> {
>> cout << "Hum!" << endl;
>> };
>> }
>>
>>
>> Here the % operator function is found via Argument Dependent Lookup
>> and invokes the specified lambda, producing an expression return value
>> via C++14 automatic return type deduction, and that works with MSVC
>> 2015. :)
>
> Where is the % operator being used? Is that masked by the $xyz stuff or
> is it in the header?

The `$defined` macro. I put the definition in a comment at top, but:

#define $invoked $e::impl::Gurkemeie{} % []()

Where `Gurkemeie` is an empty class defined in that namespace: its only
purpose is to guide Argument Dependent Lookup to find that `operator%`.

And now with your example to open my eyes, I see that this is just wrong
as a general definition. There should be a capture by reference. Thanks
again!

There is/will be a standard library invocation function in C++17,
¹`std::invoke`, and with C++11 the ²`std::reference_wrapper::operator()`
can invoke things. But these invokers put the invocation act, and any
arguments, textually after the lambda body. I feel that that's awkward,
that the most important information isn't up front, but later at the end.

Anyway, the starting point was `$invoked_with`, to define a way to add
RAII-like init and cleanup to a block of code, e.g. for automatic mutex
or a library envelope, without having to invent unnatural & unused names
for these objects. I implemented that first as a range based `for`, but
g++ complained with a warning about unused but assigned variable, even
when I made its constructor do things. Then I implemented it as a
conventional `for` loop, that iterated exactly once. But, during a visit
to a certain small room it occurred to me that if I did it with a lambda
with defaulted argument, then that same mechanism could be reused for
control structures in expressions, as with `$invoked`. I failed to see
that it would need a semicolon at the end, but I still think it's
better; just a single general mechanism.

Cheers!,

- Alf

Links:
¹ <url: http://en.cppreference.com/w/cpp/utility/functional/invoke>
² <url:
http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator()>

Alf P. Steinbach

unread,
Feb 25, 2017, 5:38:38 PM2/25/17
to
On 25.02.2017 19:10, Stefan Ram wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>> // $e::impl::Gurkemeie{} % []( decltype( instantiation ) =
>> instantiation )
>
> As once before, I recommend to either
>
> o use traditional comments or
>
> o use a Newsreader that will not break long lines or
>
> o to limit the line length so that the lines are not
> wrapped by the Newsreader.
>

The posted article is OK, but your newsreader doesn't recognize the
flowed format specified in the content type header:

Content-Type: text/plain; charset=utf-8; format=flowed

I.e. you're using a somewhat deficient newsreader.

Flowed format was specified in an RFC called "son of"-something.
Essentially it uses a space at the end of each line as a /line
continuation character/, like `\` in C and C++, or `_` in VBScript, or
`^` in the Windows command interpreter. I don't recall how it deals with
a line that originally has a space at the end.

Due to the comments in your headers I suspect that the newsreader is a
home-grown one. Please note that no archivers, in particular Google
Groups (formerly Deja news), will read and respect this comment:

X-No-Archive-Readme: "X-No-Archive" is only set, because this
prevents some services to mirror the article via the web (HTTP). But
Stefan Ram hereby allows to keep this article within a Usenet archive
server with only NNTP access without any time limitation.

Also note that X-No-Archive doesn't prevent servers from archiving
responses that quote all you wrote, and some people tend to quote
everything in what they respond to.

• • •

I believe all modern common newsreaders support flowed format, so you
have a large number to choose from, including just using Thunderbird, as
I do. ;-)


Cheers!,

- Alf

Tim Rentsch

unread,
Apr 16, 2017, 11:35:23 AM4/16/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> On 25.02.2017 19:10, Stefan Ram wrote:
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>> // $e::impl::Gurkemeie{} % []( decltype( instantiation ) =
>>> instantiation )
>>
>> As once before, I recommend to either
>>
>> o use traditional comments or
>>
>> o use a Newsreader that will not break long lines or
>>
>> o to limit the line length so that the lines are not
>> wrapped by the Newsreader.
>
> The posted article is OK, but your newsreader doesn't recognize the
> flowed format specified in the content type header:
>
> Content-Type: text/plain; charset=utf-8; format=flowed
>
> I.e. you're using a somewhat deficient newsreader. [...]

Perhaps so, but let me offer two comments in response.

1. I see wrapping problems more often in your postings than
other folks who use format=flowed.

2. If what you are posting is primarily code, it's probably a
good idea to turn off format=flowed.

(And if the newsreader you're using doesn't let you easily turn
off format=flowed then it too is a somewhat deficient newsreader.)

Alf P. Steinbach

unread,
Apr 16, 2017, 7:14:44 PM4/16/17
to
Flowed format is old, common technology now (I remember we added support
for it in clc++m in the 2000's), and it solves the problem.

It's a simple technical solution to a technical problem.

If Emacs doesn't handle it well, then just use a newsreader that does. ;-)


Cheers & hth.,

- Alf

Scott Lurndal

unread,
Apr 18, 2017, 1:26:13 PM4/18/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>On 16-Apr-17 5:35 PM, Tim Rentsch wrote:

>> Perhaps so, but let me offer two comments in response.
>>
>> 1. I see wrapping problems more often in your postings than
>> other folks who use format=flowed.
>>
>> 2. If what you are posting is primarily code, it's probably a
>> good idea to turn off format=flowed.
>>
>> (And if the newsreader you're using doesn't let you easily turn
>> off format=flowed then it too is a somewhat deficient newsreader.)
>
>Flowed format is old, common technology now (I remember we added support
>for it in clc++m in the 2000's), and it solves the problem.

Usenet was in existence for 30 years at that point, without
format=flowed. Google groups adding format=flowed was unnecessary.
>
>It's a simple technical solution to a technical problem.
>
>If Emacs doesn't handle it well, then just use a newsreader that does. ;-)

Not an acceptable solution to many.
0 new messages