Anonymous variables (moved "deferred destruction" topic)

466 views
Skip to first unread message

Francisco Lopes

unread,
Jul 10, 2016, 1:37:01 PM7/10/16
to ISO C++ Standard - Future Proposals
I'm moving the "deferred destruction" topic here to make things clearer.

The current proposal idea I'm moving forward with allowing (semi) anonymous variables.
The idea is to adopt _ as a special variable name that supports overriding, but in a backwards
compatible way:

  • _ should be allowed as a variable name.
  • _ should be allowed in redeclarations, overriding the previous declaration in the same scope.
This special variable would, for example, improve usage of:
  • any kind of guards, like std::lock_guard for example
  • multiple return (P0217R2)
  • scope_exit (P0052R2)

Here's some example code showing these features:


#include <mutex>
#include <tuple>
#include <scope>
#include <thread>
#include <memory>
#include <iostream>

using namespace std;

mutex m1, m2;

tuple<int, int> divide(int dividend, int divisor) {
    return  make_tuple(dividend / divisor, dividend % divisor);
}

int main() {
    auto _ = make_scope_exit([]{ cout << " bye"; }); // no need to care about scope_exit naming
    auto _ = make_scope_exit([]{ cout << "bye"; });  // _ is the only variable name that supports being overriding
    lock_guard<mutex> _(m1), _(m2);                  // it always refers to the last declaration in the current scope
    auto [_, remainder] = divide(14, 3);             // works on multiple return
}


Thanks Tony V E for the input in the previous thread.

Tony V E

unread,
Jul 10, 2016, 1:52:54 PM7/10/16
to Standard Proposals
I think "last declaration" is somewhat good for:

    Foo _{ 1, 2, 3 };
    _.setX(4); // unfortunately not available via constructor
    Foo _{ 5, 6, 7 };
    _.setX(8);

But I worry about cases like:

    // currently valid code
    Foo _{1,2,3};
    _.use();
    more();
    code();
    if (lots())
       of();
    else
      code();
    code();
    code();
    code();
    _.use_again();

And then someone copy-pastes another _ snippet in the middle.

    // currently valid code
    Foo _{1,2,3};
    _.use();
    more();
    code();
    if (lots())
       of();
    else
      code();
    Foo _{5,6,7};
    code();
    code();
    code();
    _.use_again();

Particularly when '_.use_again()' is '_.unlock()' on a scope-guard.

Of course, anyone who is currently using _ as a variable name AND is using it throughout their function, probably has other problems.

But I can imagine code that was using _ as a lock guard, then later someone realized that the guard should unlock early, so just added a _.unlock() without renaming the variable.

And then, later, the code evolves some more and another _ is added in the middle.

That is, unfortunately, how code is written.

Tony




--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/505fe073-a45b-4974-b1cb-df03ea39a5c6%40isocpp.org.

Francisco Lopes

unread,
Jul 10, 2016, 2:09:37 PM7/10/16
to ISO C++ Standard - Future Proposals
Thanks for the input again. Well that's an awful sample of bad practices, I agree with your point
though. So, between overring with accessibility vs overrinding disallowing accessibility, I'm left
in doubt which is nicer.

In any case I'd advocate that _.foo() should be frowned upon always.

Regards

Brandon Kentel

unread,
Jul 10, 2016, 2:39:07 PM7/10/16
to ISO C++ Standard - Future Proposals
Isn't _ typically / often used as alias for GNU gettext()? This could cause some resistance to the proposal as it is (regardless of how bad -- though convenient -- a choice it was to use this alias). Maybe it could be dealt with by treating this as a special case in the grammar? Again, likely to meet some resistance. Maybe reuse the now defunct register keyword /s ?

Patrice Roy

unread,
Jul 10, 2016, 2:39:42 PM7/10/16
to std-pr...@isocpp.org
One could envision "fun" things such as :

int _ = 3;
auto _ = _; // code maintenance just became even more frightening

An idea would be to make use of _ incorrect past initialization, such that the use of _ on the right hand would not compile, but I guess someone could want to use _ as a way to avoid caring about a pass-by-reference argument in some function :

pair<string,float> fct(int);
void f(int &, int&);
auto g() {
   int x = 3;
   auto _ = ""; // useless but would be legal
   auto [s,_] = fct(x); // fair enough, can live with this...
   f(x, _); // don't care about the 2nd argument... this seems like a legitimate use case, I guess, but f(_,_) and other unusual things become possible...
   return x + s.size();
}

I'm not totally against this feature, but it deserves detailed scrutiny before moving ahead...



Francisco Lopes

unread,
Jul 10, 2016, 2:51:24 PM7/10/16
to ISO C++ Standard - Future Proposals, bke...@gmail.com
Initially I was thinking about using ... instead of _ to avoid such naming issue. If adopting ...
as the placeholder, then I'd go for it not being referenciable at all, and would touch the current
usage of _.

Personally I'm open to such changes because I'm caring more for the core functionality.

Francisco Lopes

unread,
Jul 10, 2016, 2:54:18 PM7/10/16
to ISO C++ Standard - Future Proposals, bke...@gmail.com
woudn't touch*

Ville Voutilainen

unread,
Jul 10, 2016, 2:55:22 PM7/10/16
to ISO C++ Standard - Future Proposals
On 10 July 2016 at 21:51, Francisco Lopes
<francisco.m...@oblita.com> wrote:
> Initially I was thinking about using ... instead of _ to avoid such naming
> issue. If adopting ...

Don't go there, that idea clashes badly with packs.

Also, this is https://cplusplus.github.io/EWG/ewg-active.html#35

Francisco Lopes

unread,
Jul 10, 2016, 3:14:39 PM7/10/16
to ISO C++ Standard - Future Proposals
Many thanks for that reference Ville. I see there was invitation for a paper, but
no more information about it going forward, is there anything going forward already?

I think as demonstrated, with the current and future additions to the standard,
more usecases are showing up in favor of such feature.

Ville Voutilainen

unread,
Jul 10, 2016, 3:19:29 PM7/10/16
to ISO C++ Standard - Future Proposals
On 10 July 2016 at 22:14, Francisco Lopes
<francisco.m...@oblita.com> wrote:
> Many thanks for that reference Ville. I see there was invitation for a
> paper, but
> no more information about it going forward, is there anything going forward
> already?
>
> I think as demonstrated, with the current and future additions to the
> standard,
> more usecases are showing up in favor of such feature.


There hasn't been recent work on it, none after that invitation to
write a paper, as far as I'm aware of.

je...@unbuggy.com

unread,
Jul 10, 2016, 4:10:04 PM7/10/16
to ISO C++ Standard - Future Proposals
_ is already used as a placeholder in the MPL. It's also sometimes used as a local macro name. You have a neat idea, but _ seems pretty well spoken for. It's also unclear that this proposal would solve a real pain point, or whether it's convenience would be outweighed by (arguably) less readable code.

I would find the feature more useful if it offered slightly less functionality; in particular, I'd like a guarantee that no operation at all can be performed on such variables except the automatic destruction at end of scope.

To these ends, would it make sense to dispense with the variable name altogether, making the objects truly anonymous?

auto = std::lock_guard<std::mutex>(mtx1);
auto = std::lock_guard<std::mutex>(mtx2);

D. B.

unread,
Jul 10, 2016, 4:20:34 PM7/10/16
to std-pr...@isocpp.org
Can we be sure no one will ever want to specify a different type at LHS in order to force a conversion operator from RHS? I know use-cases for this are limited, but are they that limited?

 

D. B.

unread,
Jul 10, 2016, 4:21:40 PM7/10/16
to std-pr...@isocpp.org
Course, maybe i'm just being overly literal, and you meant that "auto" could be any type, in which case, carry on

Francisco Lopes

unread,
Jul 10, 2016, 4:30:00 PM7/10/16
to ISO C++ Standard - Future Proposals
Agree with D.B., I'd not remove this from the original idea. Not allowing referencing _ once it's
declared multiple times in the same scope (a case that would exist solely after the feature getting in)
seems acceptable tough. It's Tony V E original proposition in the previous thread.

Francisco Lopes

unread,
Jul 10, 2016, 4:33:36 PM7/10/16
to ISO C++ Standard - Future Proposals
By the way, fyi, the discussion referred by Ville tells about using __ instead of _

Francisco Lopes

unread,
Jul 10, 2016, 5:17:21 PM7/10/16
to ISO C++ Standard - Future Proposals
Related: I just noticed that it seems compiler writers have to special-case treatment of
std guards to not give unused variable warnings?

#include <mutex>

#include <iostream>

using namespace std;

mutex m;

int main() {
    lock_guard<mutex> a(m);
    int b{0};
}

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:10:9: warning: unused variable 'b' [-Wunused-variable]
     int b(0);

So, the unused variable analysis have to care about not warning on special cases
where non-usage is the norm.

Nevin Liber

unread,
Jul 10, 2016, 5:26:25 PM7/10/16
to std-pr...@isocpp.org
On 10 July 2016 at 16:17, Francisco Lopes <francisco.m...@oblita.com> wrote:
Related: I just noticed that it seems compiler writers have to special-case treatment of
std guards to not give unused variable warnings?

Far more likely that they don't warn on types that have non-trivial destructors.

--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com>  +1-847-691-1404

Nevin Liber

unread,
Jul 10, 2016, 5:33:39 PM7/10/16
to std-pr...@isocpp.org
Can we be sure?  Of course not.

If the user wishes to do this, they should be able to either cast the result or just name a variable.  It need not cover every possible weird use case.

Nevin Liber

unread,
Jul 10, 2016, 5:46:59 PM7/10/16
to std-pr...@isocpp.org
On 10 July 2016 at 15:10, <je...@unbuggy.com> wrote:
_ is already used as a placeholder in the MPL. It's also sometimes used as a local macro name.  You have a neat idea, but _ seems pretty well spoken for.  It's also unclear that this proposal would solve a real pain point, or whether it's convenience would be outweighed by (arguably) less readable code.

I would find the feature more useful if it offered slightly less functionality; in particular, I'd like a guarantee that no operation at all can be performed on such variables except the automatic destruction at end of scope.

This is, of course the problem.  You are looking to change functionality which has been there since C90 (or even longer).  This would break working code and introduce an incompatibility with C.  You could possibly mitigate the latter with a complicated rule (for instance, it only has the desired semantics for types with non-trivial destructors), but if you are stealing a name, you cannot help but break the former.

__ is different than _ in that it is reserved for implementations, so theoretically the breakage wouldn't be as bad.

IMO, finding a way to express this w/o using an identifier is a better approach (although then comes the debate about the feature being worth the cost of new syntax).

Ville Voutilainen

unread,
Jul 10, 2016, 5:51:03 PM7/10/16
to ISO C++ Standard - Future Proposals
On 11 July 2016 at 00:46, Nevin Liber <ne...@eviloverlord.com> wrote:
> IMO, finding a way to express this w/o using an identifier is a better
> approach (although then comes the debate about the feature being worth the
> cost of new syntax).


Also consider an idea like
Foobar = f();
vs. the syntax that already has a meaning, aka
Foobar() = f();
and the unfortunate subtlety of that difference.

Francisco Lopes

unread,
Jul 10, 2016, 5:57:20 PM7/10/16
to ISO C++ Standard - Future Proposals


Em domingo, 10 de julho de 2016 18:46:59 UTC-3, Nevin ":-)" Liber escreveu:
On 10 July 2016 at 15:10, <je...@unbuggy.com> wrote:
_ is already used as a placeholder in the MPL. It's also sometimes used as a local macro name.  You have a neat idea, but _ seems pretty well spoken for.  It's also unclear that this proposal would solve a real pain point, or whether it's convenience would be outweighed by (arguably) less readable code.

I would find the feature more useful if it offered slightly less functionality; in particular, I'd like a guarantee that no operation at all can be performed on such variables except the automatic destruction at end of scope.

This is, of course the problem.  You are looking to change functionality which has been there since C90 (or even longer).  This would break working code and introduce an incompatibility with C.  You could possibly mitigate the latter with a complicated rule (for instance, it only has the desired semantics for types with non-trivial destructors), but if you are stealing a name, you cannot help but break the former.

A far as I can see, both my proposal at the top, as well as Tony suggestion of disallowing being able to refer
to _ when multiple exist declarations exist in the same scope, are backwards compatible with what's allowed
today right? Counter example?

Also, you're correct about the compiler not giving non-used variable warnings for objects with non-trivial destructors.
I wonder whether the application of that is beneficial as such general rule or not. Non-trivial destructor are quite
an implicit use of variable.

Francisco Lopes

unread,
Jul 10, 2016, 6:18:27 PM7/10/16
to ISO C++ Standard - Future Proposals
Then, I'm just *really* surprised noticing this after this many years that
a simple "unused" std::string doesn't give a warning because of that
non-trivial destructor rule.

For me this is not a feature, it's sad!

I imagine a newcomer asking an instructor: "hey why int i gives a unused warning but string s not?"

Zhihao Yuan

unread,
Jul 10, 2016, 6:25:48 PM7/10/16
to std-pr...@isocpp.org
My suggestion has always been a simple

with (auto lk = unique_lock(lk)) {
}

which is already available as `if (auto ...; true)`,
and

with (lock_guard(lk)) {
}

whose the wording for introducing a unique name
has already presented in the structured binding
proposal.

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://blog.miator.net/

Nicol Bolas

unread,
Jul 10, 2016, 7:44:03 PM7/10/16
to ISO C++ Standard - Future Proposals
Wait a minute. Let's think about what we just added to C++: structured binding:

auto [a, b] = ...;

Now, the way structured binding works is that it takes the expression and stores it in a hidden variable. It then gets references to the members, either directly from public members or with a particular interface. That's how the concept is semantically defined:

auto &&temp = make_pair(3, 4.5f);
auto &a = temp.first;
auto &b = temp.second;

So... what happens if we do this:

auto [] = ...;

If we allowed this to work for any type, then what we'd be saying is that the expression would be stored in... a hidden variable. But since the structured binding list is empty, no references would be extracted from it. So all we'd have is what we want: an unnamed, unnamable variable that will be destroyed when scope ends.

So we'd have code like this:

auto[] = scope_exit(...);

I admit that this isn't great syntax. It looks too much like structured binding. But I think it's better than trying to define that a certain identifier name would have a new meaning.

Francisco Lopes

unread,
Jul 10, 2016, 7:59:33 PM7/10/16
to ISO C++ Standard - Future Proposals
That's interesting Nicol, but what about the other cases? For structured binding itself
for example, how would I let bindings unnamed? I think this is one of the more compelling
usecases, structured binding feels a bit lacking without that mechanism.

Francisco Lopes

unread,
Jul 10, 2016, 8:02:48 PM7/10/16
to ISO C++ Standard - Future Proposals
I mean, not all bindings.

Zhihao Yuan

unread,
Jul 10, 2016, 8:49:07 PM7/10/16
to std-pr...@isocpp.org
On Sun, Jul 10, 2016 at 6:44 PM, Nicol Bolas <jmck...@gmail.com> wrote:
> Wait a minute. Let's think about what we just added to C++: structured
> binding:
>
> auto [a, b] = ...;

Currently this syntax is outlawed, but I expect that
in the future we extend the identifier-list inside
structured binding to support pack expansion:

auto [a...] = expr;

where an empty pack naturally decompose an
empty product type. Sooner or later you will
find that smoothly and consistently handle the
zero cases will reward you back.

Nicol Bolas

unread,
Jul 10, 2016, 9:11:16 PM7/10/16
to ISO C++ Standard - Future Proposals
On Sunday, July 10, 2016 at 7:59:33 PM UTC-4, Francisco Lopes wrote:
That's interesting Nicol, but what about the other cases? For structured binding itself
for example, how would I let bindings unnamed?

Remember the goal: you want an object to be unnamed, because you want to use its construction and destruction only. The variables created by structured binding are not objects; they're references. Their destructors are irrelevant, so making them unnamed is equally irrelevant to this particular goal.

Don't try to solve every problem at once.

Nicol Bolas

unread,
Jul 10, 2016, 9:11:57 PM7/10/16
to ISO C++ Standard - Future Proposals


On Sunday, July 10, 2016 at 8:49:07 PM UTC-4, Zhihao Yuan wrote:
On Sun, Jul 10, 2016 at 6:44 PM, Nicol Bolas <jmck...@gmail.com> wrote:
> Wait a minute. Let's think about what we just added to C++: structured
> binding:
>
> auto [a, b] = ...;

Currently this syntax is outlawed,

I didn't mean `...` as in parameter pack. I meant `...` as in `something`.

Francisco Lopes

unread,
Jul 10, 2016, 9:53:11 PM7/10/16
to ISO C++ Standard - Future Proposals
 
That may look like the original goal in the previous thread, but to tell the truth it's not my goal. The rationale
here is for unnamed variables. It's just about to cover the intention of not providing names for things
that doesn't need them, as frequently happen (and will happen) in the cases presented.


Don't try to solve every problem at once.
 
Why not? It's a simple solution that covers the relevant problem: having a placeholder. It ends up
solving all in an understandable manner, in a uniform way. I ask why solve it in a case by case form?
or solving one special case while leaving the others for the future or plain unsolved, when in truth,
they all refer to the same core subject.


Francisco Lopes

unread,
Jul 10, 2016, 10:08:39 PM7/10/16
to ISO C++ Standard - Future Proposals
Besides _ or __ I'm thinking of other possibilities...

 @: I know of its presence solely in mangled names but I suspect it won't be an issue.

I dunno, maybe the range of special characters may be of some use here too.

Francisco Lopes

unread,
Jul 10, 2016, 10:12:32 PM7/10/16
to ISO C++ Standard - Future Proposals


Em domingo, 10 de julho de 2016 23:08:39 UTC-3, Francisco Lopes escreveu:
Besides _ or __ I'm thinking of other possibilities...

 @: I know of its presence solely in mangled names but I suspect it won't be an issue.

I dunno, maybe the range of special characters may be of some use here too.

If adopting such alternative characters, it would be placeholder only, without referentiability.

Francisco Lopes

unread,
Jul 10, 2016, 10:23:01 PM7/10/16
to ISO C++ Standard - Future Proposals


Em domingo, 10 de julho de 2016 23:12:32 UTC-3, Francisco Lopes escreveu:


Em domingo, 10 de julho de 2016 23:08:39 UTC-3, Francisco Lopes escreveu:
Besides _ or __ I'm thinking of other possibilities...

 @: I know of its presence solely in mangled names but I suspect it won't be an issue.

I dunno, maybe the range of special characters may be of some use here too.

If adopting such alternative characters, it would be placeholder only, without referentiability.

My preferred choices are _, @ or ?

Ricardo Fabiano de Andrade

unread,
Jul 10, 2016, 11:07:07 PM7/10/16
to std-pr...@isocpp.org
I've been following this with great interest but I disagree with using _, __, @, etc.

If the goal of a future proposal is having unnamed variables IMHO they should not use any character or sequence of characters to be... well ... named.

The examples where a member function needs to be called on a unnamed variable is just something that could be done by another function which the return is assigned to a unnamed variable.
Or other cases, another RAII class could wrap this and calling whatever member functions on its constructor/destructor.

Nicol's suggestion:
auto[] = foo();
It seems to me a better direction.

For the cases where named and unnamed variables are needed, may we just skip declaring a name?
auto [a,,c] = foo();
Or would that be too error prone?

A few other thoughts:
- Should unnamed variables should also be allowed whenever a structured binding is possible?
  I'm thinking unnamed statics/globals here.

- It was also mentioned that structured binding creates references... but which kind of references are they?
  const& and && are known to extend the lifetime of the assigned object until the end of the scope.

- Regarding structured binding type deduction and conversions: there was some discussion around allowing specifying the types of individual variables.
  How that would apply to unnamed variables?
  Wrap conversions in other functions or classes (as suggested above for when member function calls are needed)?
  Or just don't for now...
  If structured binding ever gets this ability in the future, then types for unnamed variables could be specified: auto[int a, int, int b] = foo();

- Is there a use case for unnamed class data members?
  Maybe for some crazy future use of parameter pack expansion?
  Then auto[] would not work.

- I'm trying to find similarities with other situations where an entity can be unnamed as a case for consistency ...
  anonymous unions/structs or namespaces, type of a lambda...
  Well, maybe those are different beasts.


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/69941075-9183-403b-86ac-3e37b7ddfae1%40isocpp.org.

Nicol Bolas

unread,
Jul 10, 2016, 11:38:32 PM7/10/16
to ISO C++ Standard - Future Proposals
On Sunday, July 10, 2016 at 11:07:07 PM UTC-4, Ricardo Andrade wrote:
I've been following this with great interest but I disagree with using _, __, @, etc.

If the goal of a future proposal is having unnamed variables IMHO they should not use any character or sequence of characters to be... well ... named.

@ is not even in the C++ basic character set. So it cannot be a valid identifier.

That being said, I dislike using @ for 2 reasons:

1: It requires adding `@` to the basic character set.
2: After having gone through the effort to add a character to the basic character set, we would then use up all of the possible syntactic potential of the character, just to get unnamed identifiers. Better to preserve the possibilities for `@` for something more worthwhile.

Francisco Lopes

unread,
Jul 10, 2016, 11:45:33 PM7/10/16
to ISO C++ Standard - Future Proposals
Hi Ricardo, maybe the topic name is improper. First, I'm advocating that if any special character
is to be used besides _ and __, which are already usable as indentifiers, then it would
not be possible to explicitly call member functions on them, they would simpler serve the purpose
of a placeholder name at declaration.

I like this idea of a placeholder variable name better than the current propositions. It's not the
same as truly anonymous for which you don't even give it a name at all, but it's better IMO.
I see no reason for tackling it solely by extending syntax of structure binding and missing the
oportunity for all the possible remaining usecases where the presence of a placeholder name would
solve it. A placeholder doesn't even need to tweak structure binding specification at all, it would be
solved as a consequence of a more general solution about variable naming.

Nicol Bolas

unread,
Jul 10, 2016, 11:47:14 PM7/10/16
to ISO C++ Standard - Future Proposals
On Sunday, July 10, 2016 at 9:53:11 PM UTC-4, Francisco Lopes wrote:

Em domingo, 10 de julho de 2016 22:11:16 UTC-3, Nicol Bolas escreveu:
On Sunday, July 10, 2016 at 7:59:33 PM UTC-4, Francisco Lopes wrote:
That's interesting Nicol, but what about the other cases? For structured binding itself
for example, how would I let bindings unnamed?

Remember the goal: you want an object to be unnamed, because you want to use its construction and destruction only. The variables created by structured binding are not objects; they're references. Their destructors are irrelevant, so making them unnamed is equally irrelevant to this particular goal.
 
That may look like the original goal in the previous thread, but to tell the truth it's not my goal. The rationale
here is for unnamed variables. It's just about to cover the intention of not providing names for things
that doesn't need them, as frequently happen (and will happen) in the cases presented.

Don't try to solve every problem at once.
 
Why not? It's a simple solution that covers the relevant problem: having a placeholder. It ends up
solving all in an understandable manner, in a uniform way.

But it is not a "simple solution". Indeed, I would go so far as to say that any placeholder which is currently a valid identifier is not a solution at all.

Breaking people's perfectly valid code should not be considered a solution to a problem. Not without really good reason. And let's face facts: unnamed variables are not that important.

Also, last time we tried to get something "uniform", we got Uniform Initialization. Which very much is not.

I ask why solve it in a case by case form?

Because it works. Not only does it work, it makes sense. That's one of the nice things about `auto[]`: based solely on the rules of structured binding, it does exactly what you want.

Indeed, as I think about it, if we ever wanted structured binding to be able to not capture all of the elements, we wouldn't want it to use placeholders. We would probably want `auto [x]` to bind to the first value of any tuple-like type. If that type has 30 variables in it, I don't care; I just want the first one. I shouldn't have to do `auto [x, @, @, @]` or even `auto [x, ...]` or whatever. I said that I wanted the first member, so give it to me.

Given that, `auto []` would bind to none of the values. Therefore, it would either be a compile error or it would work on anything, providing a hidden object that would be destroyed at the end of scope.

So really, I don't see this as a "case-by-case form". It's really the right way to go for both problems ;)

Zhihao Yuan

unread,
Jul 10, 2016, 11:53:34 PM7/10/16
to std-pr...@isocpp.org
On Sun, Jul 10, 2016 at 10:47 PM, Nicol Bolas <jmck...@gmail.com> wrote:
> Indeed, I would go so far as to say that any placeholder which is currently
> a valid identifier is not a solution at all.

How about

register lock_guard(lk);

Not a currently valid identifier, correct English :)

Ricardo Fabiano de Andrade

unread,
Jul 10, 2016, 11:59:10 PM7/10/16
to std-pr...@isocpp.org
If I'm following Francisco's line of thought that would not work for:
auto [a, register, c] = foo();

Or for:
[a, register = b, c]() { ... }

The suggestion is for something that can be used during the variable declaration which make it valid but inaccessible since it does not have a name.


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Jul 11, 2016, 12:09:45 AM7/11/16
to ISO C++ Standard - Future Proposals
On Sunday, July 10, 2016 at 11:59:10 PM UTC-4, Ricardo Andrade wrote:
If I'm following Francisco's line of thought that would not work for:
auto [a, register, c] = foo();

Why wouldn't that work? `register` is a valid keyword but currently has no meaning. Therefore, its usage in structured binding has no meaning.

Which means we can make it work however we want.

Ricardo Fabiano de Andrade

unread,
Jul 11, 2016, 12:12:43 AM7/11/16
to std-pr...@isocpp.org
Well, if that's the case, the idea is not half bad. :)
"register"ing a variable sounds even reasonable.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Francisco Lopes

unread,
Jul 11, 2016, 12:13:02 AM7/11/16
to ISO C++ Standard - Future Proposals


Em segunda-feira, 11 de julho de 2016 00:47:14 UTC-3, Nicol Bolas escreveu:
On Sunday, July 10, 2016 at 9:53:11 PM UTC-4, Francisco Lopes wrote:

Em domingo, 10 de julho de 2016 22:11:16 UTC-3, Nicol Bolas escreveu:
On Sunday, July 10, 2016 at 7:59:33 PM UTC-4, Francisco Lopes wrote:
That's interesting Nicol, but what about the other cases? For structured binding itself
for example, how would I let bindings unnamed?

Remember the goal: you want an object to be unnamed, because you want to use its construction and destruction only. The variables created by structured binding are not objects; they're references. Their destructors are irrelevant, so making them unnamed is equally irrelevant to this particular goal.
 
That may look like the original goal in the previous thread, but to tell the truth it's not my goal. The rationale
here is for unnamed variables. It's just about to cover the intention of not providing names for things
that doesn't need them, as frequently happen (and will happen) in the cases presented.

Don't try to solve every problem at once.
 
Why not? It's a simple solution that covers the relevant problem: having a placeholder. It ends up
solving all in an understandable manner, in a uniform way.

But it is not a "simple solution". Indeed, I would go so far as to say that any placeholder which is currently a valid identifier is not a solution at all.

Restating that it's not just about reusing already valid identifiers. 
 

Breaking people's perfectly valid code should not be considered a solution to a problem. Not without really good reason. And let's face facts: unnamed variables are not that important.

I've asked before about a sample where the proposals I've endorsed would break people's code, do you have one (seriously)?

For the case where _ can be overridden, there's no codebase that can compile with variables of equal name are declared, same
applies for the solution where _ can't be referenced if declared more than once in the same scope.
 

Also, last time we tried to get something "uniform", we got Uniform Initialization. Which very much is not.

I ask why solve it in a case by case form?

Because it works. Not only does it work, it makes sense. That's one of the nice things about `auto[]`: based solely on the rules of structured binding, it does exactly what you want.

Indeed, as I think about it, if we ever wanted structured binding to be able to not capture all of the elements, we wouldn't want it to use placeholders. We would probably want `auto [x]` to bind to the first value of any tuple-like type. If that type has 30 variables in it, I don't care; I just want the first one. I shouldn't have to do `auto [x, @, @, @]` or even `auto [x, ...]` or whatever. I said that I wanted the first member, so give it to me.

Given that, `auto []` would bind to none of the values. Therefore, it would either be a compile error or it would work on anything, providing a hidden object that would be destroyed at the end of scope.

You may like that, I don't. You are focusing on a special solution for the
sake of bad practice on multiple return. I'm looking for this solved:

auto [x, _, y] = foo()
auto [_, y, _] = bar()
auto [x, _] = baz()

Etc, which your solution where order matters, doesn't cover (besides not covering the other case).
The time I get a tuple of 30 as a return, I'd be looking for a refactor not support of the language for
pattern handling of that.
 

So really, I don't see this as a "case-by-case form". It's really the right way to go for both problems ;)


Which both? You mean the correct way is to patch the language around the same subject, but with
particular solutions?

Ricardo Fabiano de Andrade

unread,
Jul 11, 2016, 12:19:32 AM7/11/16
to std-pr...@isocpp.org
On Sun, Jul 10, 2016 at 10:45 PM, Francisco Lopes <francisco.m...@oblita.com> wrote:
Hi Ricardo, maybe the topic name is improper. First, I'm advocating that if any special character
is to be used besides _ and __, which are already usable as indentifiers, then it would
not be possible to explicitly call member functions on them, they would simpler serve the purpose
of a placeholder name at declaration.


Now I think I understand the reach of your suggestion. Any variable, anywhere, could be unnamed.
As long as it becomes inaccessible after being "declared" I can see some benefit.
 
I like this idea of a placeholder variable name better than the current propositions. It's not the
same as truly anonymous for which you don't even give it a name at all, but it's better IMO.

I can also see some problems.
- I'm not quite sure if I want unnamed variables everywhere.
  At the local scope, it seems pretty straightforward. Global, namespace, static and class scopes I'm not so sure.
  In the other hand, I'm also against artificial constraints to prevent such uses if this suggestion ever becomes a proposal.
- I was about to say that finding such placeholder "name" sounded difficult. But it seems we got a candidate "register".
 
I see no reason for tackling it solely by extending syntax of structure binding and missing the
oportunity for all the possible remaining usecases where the presence of a placeholder name would
solve it. A placeholder doesn't even need to tweak structure binding specification at all, it would be
solved as a consequence of a more general solution about variable naming.


Sounds reasonable. :)
 

Zhihao Yuan

unread,
Jul 11, 2016, 12:20:20 AM7/11/16
to std-pr...@isocpp.org
On Sun, Jul 10, 2016 at 10:59 PM, Ricardo Fabiano de Andrade
<ricardofabi...@gmail.com> wrote:
> If I'm following Francisco's line of thought that would not work for:
> auto [a, register, c] = foo();

I want to solve the problem of RAII, not structured
binding. Feel free to extend structured binding,
but I don't find making them work in the same
way very fascinating.

Tony V E

unread,
Jul 11, 2016, 12:28:25 AM7/11/16
to Zhihao Yuan
We could solve RAII with register, and leave it at that. 

But I solution for structured binding would also be nice. 
And if/when we get pattern matching, we will really need something short that means 'match any'. auto does that for types, but we need something for values. 

We could solve each of these independently, but if #3 also solves #2 and #1 *coherently*, then I'd rather have a single solution.

If a single solution is incoherent, then we shouldn't push it. But we need to explore it. 

I'm not sure solving any one problem is worth it on its own, but if you can solve all three (and more), then you have bang for the buck. 
 

Sent from my BlackBerry portable Babbage Device
  Original Message  
From: Zhihao Yuan
Sent: Monday, July 11, 2016 12:20 AM
To: std-pr...@isocpp.org
Reply To: std-pr...@isocpp.org
Subject: Re: [std-proposals] Re: Anonymous variables (moved "deferred destruction" topic)
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAGsORuD5GZataPFFfzKTxO7zMgLfkcTFS6uGq6GputasiwF10g%40mail.gmail.com.

Francisco Lopes

unread,
Jul 11, 2016, 12:33:11 AM7/11/16
to ISO C++ Standard - Future Proposals
About "which both", nevermind. I got what you suggests covers both guards, scope_exit
and structure binding, although for the last it doesn't look much useful as a solution.

Francisco Lopes

unread,
Jul 11, 2016, 12:40:17 AM7/11/16
to ISO C++ Standard - Future Proposals
ah, correction, as far as I can see it doesn't work very well for normal declarations
like with guards. Also, I have no idea whether structure binding should support things
that I have no idea can be destructured or not. So it looks pretty much trying to
sneak from recently added structure biding to other areas it's was not thought for.

Zhihao Yuan

unread,
Jul 11, 2016, 12:40:47 AM7/11/16
to std-pr...@isocpp.org
On Sun, Jul 10, 2016 at 11:28 PM, Tony V E <tvan...@gmail.com> wrote:
>
> We could solve each of these independently, but if #3 also solves #2 and #1 *coherently*, then I'd rather have a single solution.
>
> If a single solution is incoherent, then we shouldn't push it. But we need to explore it.

Let's say we use the keyword `register` as the placeholder
for the solution this thread is looking for, RAII will be written
as

auto register = lock_guard(lk);

Lengthy. And structured binding will be

auto [a, register] = ...;

I want to "ignore", not *not* to ignore.

This way damages both use cases.

>
> I'm not sure solving any one problem is worth it on its own, but if you can solve all three (and more), then you have bang for the buck.

Instead, if we have

register lock_guard(lk);

and

auto [a, std::ignore] = expr;

Both intentions seem to be expressed very well.

The point I'm making here is that, for the RAII case,
what you want is to emphasis the existence of the
unnamed variable, while in structured binding/pattern
matching, what you want is to eliminate the presence
of the unnamed variable. They are not necessarily
to be using the same solution.

Francisco Lopes

unread,
Jul 11, 2016, 12:55:38 AM7/11/16
to ISO C++ Standard - Future Proposals
Hi Zhihao. Of course it doesn't necessarily need to be any way.
I get your point, but the solutions you give to cover that point are
not much pretty.


Em segunda-feira, 11 de julho de 2016 01:40:47 UTC-3, Zhihao Yuan escreveu:
On Sun, Jul 10, 2016 at 11:28 PM, Tony V E <tvan...@gmail.com> wrote:
>
> We could solve each of these independently, but if #3 also solves #2 and #1 *coherently*, then I'd rather have a single solution.
>
> If a single solution is incoherent, then we shouldn't push it. But we need to explore it.

Let's say we use the keyword `register` as the placeholder
for the solution this thread is looking for, RAII will be written
as

  auto register = lock_guard(lk);

Lengthy.

register is not meaningful, it doesn't bring the sense of a placeholder, I think this is bad.
 
And structured binding will be

  auto [a, register] = ...;

I want to "ignore", not *not* to ignore.

Indeed, me too! Same for the previous.

This way damages both use cases.

>
> I'm not sure solving any one problem is worth it on its own, but if you can solve all three (and more), then you have bang for the buck.

Instead, if we have

  register lock_guard(lk);

OK so, register is still not meaningful about anything as a name, and what is it doing
at the variable type? I have to bend my mind to understand that's an anonymous declaration
of a lock_guard.

and

  auto [a, std::ignore] = expr;

Have you checked in a previous Nicol email how structure binding should expand behind
the scenes. Having a placeholder variable name fits well with that, now std::ignore doesn't,
I can't imagine what the implementation of that should be like. I agree the intention is
present though, in this case.

Zhihao Yuan

unread,
Jul 11, 2016, 1:08:36 AM7/11/16
to std-pr...@isocpp.org
On Sun, Jul 10, 2016 at 11:55 PM, Francisco Lopes
<francisco.m...@oblita.com> wrote:
>> Instead, if we have
>>
>> register lock_guard(lk);
>
>
> OK so, register is still not meaningful about anything as a name, and what
> is it doing
> at the variable type? I have to bend my mind to understand that's an
> anonymous declaration
> of a lock_guard.
>

It's even easier to understand than "unnamed variable".
Given

lock_guard(lk);

as an expression statement -- a _discarded-value
expression_ alone followed by a semicolon,

register lock_guard(lk);

statement will be a statement that keep the value to-be-
discarded. Or you can say, "registered".

Francisco Lopes

unread,
Jul 11, 2016, 1:13:03 AM7/11/16
to ISO C++ Standard - Future Proposals
Hah, ok, now I get it. In that sense it seems fine.

Francisco Lopes

unread,
Jul 11, 2016, 1:22:56 AM7/11/16
to ISO C++ Standard - Future Proposals
Now I agree with being an acceptable solution for the RAII problem, it covers both
scope_exit and guards. Sadly it doesn't touch binding as you already said.

The problem is that the time we get a mechanist to let variables unnamed (like
with got for types like Tony said), and I hope so this happens. Then we will end
up with two valid solutions for the RAII problem I guess. It would not happen only
if placeholders are put at work in specific places solely, which personally I'd not
like.

Zhihao Yuan

unread,
Jul 11, 2016, 2:02:27 AM7/11/16
to std-pr...@isocpp.org
On Mon, Jul 11, 2016 at 12:22 AM, Francisco Lopes
<francisco.m...@oblita.com> wrote:
> The problem is that the time we get a mechanist to let variables unnamed
> (like
> with got for types like Tony said), and I hope so this happens. Then we will
> end
> up with two valid solutions for the RAII problem I guess. It would not
> happen only
> if placeholders are put at work in specific places solely, which personally
> I'd not
> like.

Structured binding is a prototype for pattern matching,
IMHO it's acceptable for having some features not
usable outside [], as acceptable as having features
usable from outside but not inside, which is the status
quo.

To this specific "ignore" functionality, restricting it
within structured binding gives us a long list of
placeholder candidates:

.. // two dots
<>
- // minus, dash
~
:)

, while making it usable in other places is troublesome
in some cases:

int <placeholder> = get_raii_file_descriptor();

That RAII fd is implicitly convertible to int, so we
destroy the object and return an int? Or we restrict
the type to be `auto`? Oh wait, actually I need
`auto&&`! Welcome home, that is exactly how
structured binding handles the "capturing object",
and by doing this we subset the language in a
much larger scope...

Thiago Macieira

unread,
Jul 11, 2016, 2:44:00 AM7/11/16
to std-pr...@isocpp.org
On domingo, 10 de julho de 2016 15:18:26 PDT Francisco Lopes wrote:
> I imagine a newcomer asking an instructor: "hey why int i gives a unused
> warning but string s not?"

Answer: "because int is trivial, std::string isn't"

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

Thiago Macieira

unread,
Jul 11, 2016, 2:45:27 AM7/11/16
to std-pr...@isocpp.org
On domingo, 10 de julho de 2016 19:08:38 PDT Francisco Lopes wrote:
> @: I know of its presence solely in mangled names but I suspect it won't
> be an issue.

It's not part of the basic character set.

Tony V E

unread,
Jul 11, 2016, 7:20:02 AM7/11/16
to Zhihao Yuan
Hmmm
Maybe we should reserve _ as unusable in structured binding for now?

Sent from my BlackBerry portable Babbage Device
  Original Message  
From: Zhihao Yuan
Sent: Monday, July 11, 2016 2:02 AM
To: std-pr...@isocpp.org
Reply To: std-pr...@isocpp.org
Subject: Re: [std-proposals] Re: Anonymous variables (moved "deferred destruction" topic)

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAGsORuBtbE1doTfQAXXTtV%3DTLE%2Br%3DCyRVN-t_dLzSbw%3DDL_epQ%40mail.gmail.com.

Francisco Lopes

unread,
Jul 11, 2016, 10:08:34 AM7/11/16
to ISO C++ Standard - Future Proposals


Em segunda-feira, 11 de julho de 2016 08:20:02 UTC-3, Tony V E escreveu:
Hmmm
Maybe we should reserve _ as unusable in structured binding for now?

I consider it a wise move.

Francisco Lopes

unread,
Jul 11, 2016, 10:14:43 AM7/11/16
to ISO C++ Standard - Future Proposals


Em segunda-feira, 11 de julho de 2016 11:08:34 UTC-3, Francisco Lopes escreveu:


Em segunda-feira, 11 de julho de 2016 08:20:02 UTC-3, Tony V E escreveu:
Hmmm
Maybe we should reserve _ as unusable in structured binding for now?

I consider it a wise move.

If structured binding alone supported a placeholder already, it could be done in
a way that would support both auto [x, _, y] = ..., was well as auto [] = ...

Daniel Frey

unread,
Jul 11, 2016, 11:26:48 AM7/11/16
to std-pr...@isocpp.org
What is the real problem that this thread is trying to solve? Users write:

std::lock_guard<std::mutex>(mtx); // (1)

instead of

std::lock_guard<std::mutex> dummy(mtx); // (2)

and every attempt coming up with a new syntax like

auto = std::lock_guard<std::mutex>(mtx); // (3)

will not catch the above error at (1)! If I write (3), I could just as well write (2), it does not matter if I have to write dummy, dummy1, dummy2 (IMHO) - the real problem is when I create a temporary of std::lock_guard like in (1) that is immediately discarded.

Any solution which will prevent those bugs either has to make (1) an error or to extend its lifetime automatically similar to the effect of (2).

My 2ç.

signature.asc

Francisco Lopes

unread,
Jul 11, 2016, 11:37:36 AM7/11/16
to ISO C++ Standard - Future Proposals, d.f...@gmx.de
Removing from the language the problem regarding temporaries that
pop out of existence after end of expression was never my aim.

It's more about providing a feature than fixing a bug.

Francisco Lopes

unread,
Jul 11, 2016, 11:49:53 AM7/11/16
to ISO C++ Standard - Future Proposals, d.f...@gmx.de
Of the solutions presented, many of which I think are useful, I'm
still in favor os something along the lines of the language providing
a placeholder naming mechanism.

My main bias regarding that is because: as you have zero on counting,
on naming you have a placeholder. This is what happens in many other
programming languages, Python, Haskell, Rust, ...

I'd wish C++ moved on and embedded/learned that.

Fabio Fracassi

unread,
Jul 11, 2016, 11:50:47 AM7/11/16
to std-pr...@isocpp.org
On 11/07/2016 17:26, Daniel Frey wrote:
> What is the real problem that this thread is trying to solve? Users write:
>
> std::lock_guard<std::mutex>(mtx); // (1)
Catching this type of errors is taken care of in C++17 with the
attribute [[nodiscard]].
see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0068r0.pdf
for details.



---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

Francisco Lopes

unread,
Jul 11, 2016, 12:30:06 PM7/11/16
to ISO C++ Standard - Future Proposals
Em segunda-feira, 11 de julho de 2016 12:49:53 UTC-3, Francisco Lopes escreveu:
Of the solutions presented, many of which I think are useful, I'm
still in favor os something along the lines of the language providing
a placeholder naming mechanism.

My main bias regarding that is because: as you have zero on counting,
on naming you have a placeholder. This is what happens in many other
programming languages, Python, Haskell, Rust, ...

I'd wish C++ moved on and embedded/learned that.

Ah OK,
There was another topic on the subject some months ago:

- throwaway variable: https://groups.google.com/a/isocpp.org/d/msg/std-proposals/ioi76TkG6g4/G8WC37LVAAAJ

I've found it being referred at:

- Allowing unnammed loop variable in range-based for loops? https://groups.google.com/a/isocpp.org/d/msg/std-proposals/ioi76TkG6g4/G8WC37LVAAAJ

That's another usecase, range-for loops...

Sorry I don't follow much the discussion group, but it seems
this subject has been poping up with some frequency.

As other languages show (Python, Haskell, Rust, Go,...), and as
people are requesting, having a placeholder name is the natural
solution, which ends up solving all the usecases presented here.

Matthew Woehlke

unread,
Jul 11, 2016, 2:01:57 PM7/11/16
to std-pr...@isocpp.org
On 2016-07-10 18:25, Zhihao Yuan wrote:
> My suggestion has always been a simple
>
> with (auto lk = unique_lock(lk)) {
> }
>
> which is already available as `if (auto ...; true)`,
> and
>
> with (lock_guard(lk)) {
> }
>
> whose the wording for introducing a unique name
> has already presented in the structured binding
> proposal.

Would this be legal?

with (lock_guard(a); lock_guard(b))
{ ... }

I definitely have cases where I want more than one "guard". I'd prefer
to not need to create a scope for each one.

--
Matthew

Matthew Woehlke

unread,
Jul 11, 2016, 2:07:11 PM7/11/16
to std-pr...@isocpp.org
On 2016-07-10 16:33, Francisco Lopes wrote:
> By the way, fyi, the discussion referred by Ville tells about using __
> instead of _

I've probably said this before... what about `.`?

auto . = lock_guard(m_mutex);

Since `.` is not a valid identifier, there are no possible conflicts
with existing code. (Also, I think it looks slightly prettier :-).)

...`:` could be a candidate also...

As Nevin noted, `__` is reserved for *implementations*. In theory at
least, there might be an implementation actually *using* `__` that would
be broken if `__` were used for unnamed locals.

--
Matthew

Matthew Woehlke

unread,
Jul 11, 2016, 2:10:06 PM7/11/16
to std-pr...@isocpp.org
On 2016-07-10 19:44, Nicol Bolas wrote:
> Wait a minute. Let's think about what we just added to C++: structured
> binding:
>
> auto [a, b] = ...;
>
> Now, the way structured binding works is that it takes the expression and
> stores it in a hidden variable. It then gets references to the members,
> either directly from public members or with a particular interface. That's
> how the concept is semantically defined:
>
> auto &&temp = make_pair(3, 4.5f);
> auto &a = temp.first;
> auto &b = temp.second;
>
> So... what happens if we do this:
>
> auto [] = ...;

You get an error because the number of bindings does not match the
number of things to be bound (i.e. the PT-size). *This is a good thing.*

For that to work, you'd need slicing:

auto [] = ...[0:0];

(...or unnamed placeholders, but those only work if the PT-size is
known, or... if you don't use unpacking, in which case we're back to the
original proposal.)

That, or you're defining a new thing that *looks* like unpacking, but is
really something very different. Ick.

--
Matthew

D. B.

unread,
Jul 11, 2016, 2:20:51 PM7/11/16
to std-pr...@isocpp.org

Can someone explain to me what this actually offers over

{ std::lock_guard(whatever);
    // do stuff
}

because I must be missing something, as right now, it just looks like adding a new keyword for no reason whatsoever, and eschewing a perfectly valid use of temporary blocks in the process. IOW, completely redundant and counterproductive.

so i must've missed an undeniable benefit, right?
 

D. B.

unread,
Jul 11, 2016, 2:21:38 PM7/11/16
to std-pr...@isocpp.org
sorry, of course I meant to include a variable name in that declaration, e.g. a or b


Barry Revzin

unread,
Jul 11, 2016, 2:31:58 PM7/11/16
to ISO C++ Standard - Future Proposals
Can someone explain to me what this actually offers over

{ std::lock_guard(whatever);
    // do stuff
}

because I must be missing something, as right now, it just looks like adding a new keyword for no reason whatsoever, and eschewing a perfectly valid use of temporary blocks in the process. IOW, completely redundant and counterproductive.

so i must've missed an undeniable benefit, right?
 


sorry, of course I meant to include a variable name in that declaration, e.g. a or b

Or even writing a function template that does the same thing as "with" would?

template <class M, class F>
void with_lock(M& mtx, F f ) {
    std
::lock_guard _(mtx);
    f
();
}

with_lock
(mtx, [&]{
   
// stuff locked here...
});

 

Matthew Woehlke

unread,
Jul 11, 2016, 2:38:25 PM7/11/16
to std-pr...@isocpp.org
On 2016-07-11 14:21, D. B. wrote:
> On Mon, Jul 11, 2016 at 7:20 PM, D. B. wrote:
>> Can someone explain to me what this actually offers over
>>
>> { std::lock_guard(whatever);
>> // do stuff
>> }
>>
>> because I must be missing something, as right now, it just looks like
>> adding a new keyword for no reason whatsoever, and eschewing a perfectly
>> valid use of temporary blocks in the process. IOW, completely redundant and
>> counterproductive.
>>
>> so i must've missed an undeniable benefit, right?
>
> sorry, of course I meant to include a variable name in that declaration,
> e.g. *a* or *b*

You don't need to name the variable, therefore:

- You are guaranteed to not accidentally shadow some other variable
without jumping through complicated hoops to do so.

- You are guaranteed that the variable cannot accidentally be accessed.

- It can interact better with compiler warnings about unused variables.

Also, by making it part of the language, you don't have to "add" it to
every project in which you want to use it.

--
Matthew

Matthew Woehlke

unread,
Jul 11, 2016, 2:45:06 PM7/11/16
to std-pr...@isocpp.org
On 2016-07-11 11:26, Daniel Frey wrote:
> What is the real problem that this thread is trying to solve? Users write:
>
> std::lock_guard<std::mutex>(mtx); // (1)
>
> instead of
>
> std::lock_guard<std::mutex> dummy(mtx); // (2)
>
> and every attempt coming up with a new syntax like
>
> auto = std::lock_guard<std::mutex>(mtx); // (3)
>
> will not catch the above error at (1)! If I write (3), I could just
> as well write (2), it does not matter if I have to write dummy,
> dummy1, dummy2 (IMHO) - the real problem is when I create a temporary
> of std::lock_guard like in (1) that is immediately discarded.

Some folks (myself included) consider needing to provide a name to
already be a problem.

> Any solution which will prevent those bugs either has to make (1) an
> error or to extend its lifetime automatically similar to the effect
> of (2).

Doesn't [[nodiscard]] already accomplish this? Or at least offer a
significant improvement?

--
Matthew

Zhihao Yuan

unread,
Jul 11, 2016, 3:11:25 PM7/11/16
to std-pr...@isocpp.org
On Mon, Jul 11, 2016 at 1:01 PM, Matthew Woehlke
<mwoehlk...@gmail.com> wrote:
>
> Would this be legal?
>
> with (lock_guard(a); lock_guard(b))
> { ... }

Very likely. But the whole suggestion depends
on whether people can live with one extra
nested scope.

Francisco Lopes

unread,
Jul 11, 2016, 3:16:57 PM7/11/16
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com


Em segunda-feira, 11 de julho de 2016 15:07:11 UTC-3, Matthew Woehlke escreveu:
On 2016-07-10 16:33, Francisco Lopes wrote:
> By the way, fyi, the discussion referred by Ville tells about using __
> instead of _

I've probably said this before... what about `.`?

  auto . = lock_guard(m_mutex);

Since `.` is not a valid identifier, there are no possible conflicts
with existing code. (Also, I think it looks slightly prettier :-).)

I also think it's pretty, I've thought about it but didn't comment. The reason
I find it pretty is that it resembles mathematical notation f(·)

...`:` could be a candidate also...

Ville commented before it woudn't be a good idea because it would clash
with parameter packs.

But, for example, Rust has both "_" and "..", C++ has no use for "..", which
coud be used, although I'd prefer to see ".." always matching 0 or more, for
which purpose "..." already fits.

So, for me it's fine having stuff like

lock_guard<mutex> .(a), .(b);

auto [ . , x , . ] = foo()

or

auto [ . , x , ... ] = foo()

Matthew Woehlke

unread,
Jul 11, 2016, 3:28:21 PM7/11/16
to std-pr...@isocpp.org
On 2016-07-11 15:16, Francisco Lopes wrote:
> Em segunda-feira, 11 de julho de 2016 15:07:11 UTC-3, Matthew Woehlke
> escreveu:
>> ...`:` could be a candidate also...
>>
>
> Ville commented before it woudn't be a good idea because it would clash
> with parameter packs.

I think you misread :-): the proposed placeholder was `:` (note: the
backticks are just to show code; they're not part of the proposed
syntax). The "..." in the above was merely grammatical.

Offhand, I can't think of a use of a single ':' except in the ternary
operator, so it seems available...

That all said, `.` would be my first choice.

--
Matthew

Matthew Woehlke

unread,
Jul 11, 2016, 3:35:06 PM7/11/16
to std-pr...@isocpp.org
On 2016-07-11 15:11, Zhihao Yuan wrote:
> On Mon, Jul 11, 2016 at 1:01 PM, Matthew Woehlke wrote:
>> Would this be legal?
>>
>> with (lock_guard(a); lock_guard(b))
>> { ... }
>
> Very likely. But the whole suggestion depends
> on whether people can live with one extra
> nested scope.

Are you proposing `with` as a proper language extension, or as a macro
implemented with `if(expr; true)`? If the latter, is `if(expr; expr;
...; condition)` legal? (I guess it would be nice if it is, but I
haven't read the proposal or followed up on it to know offhand...)

--
Matthew

Daniel Frey

unread,
Jul 11, 2016, 3:36:46 PM7/11/16
to std-pr...@isocpp.org
> On 11.07.2016, at 20:42, Matthew Woehlke <mwoehlk...@gmail.com> wrote:
>
> On 2016-07-11 11:26, Daniel Frey wrote:
>> What is the real problem that this thread is trying to solve? Users write:
>>
>> std::lock_guard<std::mutex>(mtx); // (1)
>>
>> instead of
>>
>> std::lock_guard<std::mutex> dummy(mtx); // (2)
>>
>> and every attempt coming up with a new syntax like
>>
>> auto = std::lock_guard<std::mutex>(mtx); // (3)
>>
>> will not catch the above error at (1)! If I write (3), I could just
>> as well write (2), it does not matter if I have to write dummy,
>> dummy1, dummy2 (IMHO) - the real problem is when I create a temporary
>> of std::lock_guard like in (1) that is immediately discarded.
>
> Some folks (myself included) consider needing to provide a name to
> already be a problem.

Some people (like me) don't consider it a big problem. That does not mean any of us is right, though - the question is how important it is compared to the many other things that could be improved and if it warrants a language change.

>> Any solution which will prevent those bugs either has to make (1) an
>> error or to extend its lifetime automatically similar to the effect
>> of (2).
>
> Doesn't [[nodiscard]] already accomplish this? Or at least offer a
> significant improvement?

Maybe, but the compiler is (AFAIK) only encouraged to give you some warning, it might just as well ignore the attribute completely. Unlikely, I know, but the important thing is, it is still "just" a warning. I usually compile with -Werror, but a lot of (commercial) projects I know of have lots of warnings which they ignore.

So even as it is an improvement, I could imagine other features like an automatically prolonged lifetime of a unbound value returned by a function or constructor call. Not saying this is better, just an alternative to consider. Probably depends on what are the use-cases you consider important. The difference is that you'd make it invisible while this thread, so far, is concentrating on explicitly prolonged lifetime. My feeling is that the C++ syntax is complicated enough for the caller, so I'd prefer a new attribute (or something else) on the library side, maybe:

class [[autoexpand_scope]] lock_guard { ... };

(needs better name, I know)

signature.asc

Thiago Macieira

unread,
Jul 11, 2016, 3:37:13 PM7/11/16
to std-pr...@isocpp.org
On segunda-feira, 11 de julho de 2016 12:16:56 PDT Francisco Lopes wrote:
> As Nevin noted, `__` is reserved for *implementations*. In theory at
>
> > least, there might be an implementation actually *using* `__` that would
> > be broken if `__` were used for unnamed locals.

In practice, there is.

Zhihao Yuan

unread,
Jul 11, 2016, 4:17:20 PM7/11/16
to std-pr...@isocpp.org
On Mon, Jul 11, 2016 at 2:30 PM, Matthew Woehlke
<mwoehlk...@gmail.com> wrote:
>
>>> with (lock_guard(a); lock_guard(b))
>>> { ... }
>>
>> Very likely. But the whole suggestion depends
>> on whether people can live with one extra
>> nested scope.
>
> Are you proposing `with` as a proper language extension, or as a macro
> implemented with `if(expr; true)`? If the latter, is `if(expr; expr;
> ...; condition)` legal? (I guess it would be nice if it is, but I
> haven't read the proposal or followed up on it to know offhand...)

I'm not proposal anything at this point, just looking for...
standpoints?
`if(expression-statement; true)` still discard;
`if(simple-declaration; true)` doesn't, which can be used in
place of `with (auto x = ...)`.

janwi...@gmail.com

unread,
Oct 9, 2017, 6:11:25 PM10/9/17
to ISO C++ Standard - Future Proposals, z...@miator.net
I was going to propose a similar feature as described in this thread, fortunately, someone on slack mention this discussion thread, so I'll just post this here: 

https://github.com/janwilmans/janwilmans.github.io/blob/master/auto.md

I'm arguing for an unnamed variable also, but from a 'prevent using macros' perspective. Also it might have applications in TMP to introduce unnamed members into a class, by passing a reference from the unnamed variable's constructor into an outer scope.

I'm going to add a concrete example usecase to the document, but I'd like to get feedback on it so far...

Greetings,

Jan

Arthur O'Dwyer

unread,
Oct 10, 2017, 6:38:40 PM10/10/17
to ISO C++ Standard - Future Proposals, z...@miator.net
On Monday, October 9, 2017 at 3:11:25 PM UTC-7, janwi...@gmail.com wrote:
I was going to propose a similar feature as described in this thread, fortunately, someone on slack mention this discussion thread, so I'll just post this here: 

https://github.com/janwilmans/janwilmans.github.io/blob/master/auto.md
[...]
I'm going to add a concrete example usecase to the document, but I'd like to get feedback on it so far...

Seems plausible to me. Certainly omitting the variable name is more "C++ish" than the perennial proposal to make the variable name `_` magic.
However, I see a very obvious pitfall in your choice of examples. Today we have a major pitfall with people accidentally omitting the name of the lock_guard variable. With your proposed syntax, in codebases that use scope guards with arbitrary lambdas, we'll see people accidentally omitting the make_guard keyword itself.

auto = make_guard([]{ end_of_scope_action(); });
auto = []{ end_of_scope_action(); }; 

The former is what you want your codebase to look like.
The latter is what your new hires will write, at least once a month, until you train your linter to detect the problem automatically.
This is why it's so nice to use a macro to hide all the boilerplate, instead of leaving any boilerplate in the C++ code.
This is why I prefer to write:

Auto( end_of_scope_action(); ); 

Of course scope-guards are not the only use for anonymous variables. And many smart C++ programmers will tell you loudly that scope-guards are a Very Bad Pattern and shouldn't be used as justification for anything! But if you're proposing that anonymous variables should be involved in the best-practice way to declare scope-guards, I'd have to disagree: I see only a source of bugs there.

–Arthur

Jan Wilmans

unread,
Oct 11, 2017, 4:52:25 AM10/11/17
to std-pr...@isocpp.org, z...@miator.net
The feedback is highly appreciated! I can see the syntax as proposed with give room for a new class of errors, I had not considered that :)

Well, my main motivation for the introduction of an unnamed variable would be to prevent the need to rely on non-standard macro extensions to provide unique names for RAII objects in a local scope
Although the example speaks of a guard, its really just an example...

The logfuction is maybe a better example, although, in that case I would rely on a __FILE__ macro, so its also not such a convincing example.

Greetings,

Jan

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.



--
Met vriendelijke groeten,

Jan Wilmans

janwi...@gmail.com

unread,
Oct 12, 2017, 4:04:49 PM10/12/17
to ISO C++ Standard - Future Proposals, z...@miator.net
Update:

I have found multiple earlier discussions, references:

auto [] = make_guard([]{ end_of_scope_action(); });

Seems to be a better, less error-prone alternative syntax (an empty structured binding).
I've updated https://github.com/janwilmans/janwilmans.github.io/blob/master/auto.md with the appropriate attributions and references


 

Curious

unread,
Nov 3, 2017, 12:32:00 AM11/3/17
to ISO C++ Standard - Future Proposals, z...@miator.net
This might be slightly late but as I see it there are two options here.  I will try and list both below.

The first option is what is currently accepted
auto [] = make_guard([]{ ... });

This has the advantage of being consistent with what structured bindings do, they declare a hidden variable that cannot be referenced and used within user code.  In this case the structured bindings are not even being decomposed into anything so this approach seems natural.  A hidden variable is declared behind the scenes and will be destroyed when the scope exists.  

The second option that I have in mind is 
auto {} = make_guard([]{ ... });

This is not consistent with structured bindings.  However this slightly matches with the list initialization as it stands currently in C++14, a {} denotes a default construction for a class type, and can be used to initialize an object.  vec.push_back({}); is pretty cool.  The {} syntax seems to naturally scream unnamed object.  Especially given how prevalent JSON has become these days (although that is completely not directly relevant to c++)

This however has the advantage of also working in the following context
auto [{}, another] = make_pair(...);

Where the {} denotes an anonymous unnamed reference.  Which can be consistent with the other case.  

The consistent use of {} to denote an unused object seems like an attractive idea.  It however leaves some ambiguity with respect to what the semantics of {} are.  The best way to approach this would be to make {} an unused anonymous identifier.  With the type of {} being whatever preceeds it, for example
auto&& {} = make_guard(...);

Here {} would be a rvalue reference with its lifetime being extended to match the object returned by make_guard(...).  Same with the following case
auto [{}, another] = make_pair(...);

Here {} is a reference type, with the referenced type being std::tuple_element<0, std::decay_t<decltype(make_pair(...))>> 

The current alternative however, does not seem to naturally work within structured bindings themselves
auto [[], another] = make_pair(...);

The semantics of this are not very clear, the [] denotes a structured binding.  But what is the type of the binding within the binding?  It does not seem to have am auto type specifier before it, so will it be a reference or what exactly?  The {} case feels slightly more natural here. 

Trying to solve multiple (related but not really) problems at once.  Just another thought about the matter!  

janwi...@gmail.com

unread,
Feb 25, 2018, 4:18:34 AM2/25/18
to ISO C++ Standard - Future Proposals, z...@miator.net
I'm not sure why I missed this reply, I'm just seeing it now. This more food for thought, thank you. 
In the mean time I realized, that while this is a personal annoyance, it will never be on the top 20 things that C++ needs the most.

It does not enable new expressiveness, at best in cleans up the syntax a little, but if this introduces new ambiguities, as Arthur pointed out, I think this will not be worth it.
I will update the page for future reference, but other than that, I'm not pursuing this any further.
Reply all
Reply to author
Forward
0 new messages