Anonymous variables (moved "deferred destruction" topic)

457 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