Using the underscore for unused identifiers

359 views
Skip to first unread message

Stack Machine

unread,
Mar 7, 2014, 3:07:05 AM3/7/14
to std-pr...@isocpp.org
Idea: Give a single underscore "_" a special meaning in contexts where an identifier is expected. It means that the thing being defined is unused.
Examples:
std::lock_guard<std::mutex> _(mtx);
auto _ = finally([]{ std::cout << "scope exit\n"; }); // 'finally' runs a function at scope exit

void foo(int _);

struct _ { ... } my_single_object;
etc. etc.

This feature has been used extensively in functional languages. It solves the problem of unused variables nicely while being very explicit at the same time.

David Krauss

unread,
Mar 7, 2014, 3:53:43 AM3/7/14
to std-pr...@isocpp.org
I was just having this exact same thought. I’m currently writing a scope guards proposal and plan to include the idea, but only as a peripheral kind of suggestion.

Boost.ScopeExit generates “unnamed” guards by capturing the line number. You can already accomplish the task with

#define CAT_LITERAL( A, B ) A ## B
#define CAT( A, B ) CAT_LITERAL( A, B )
#define _ CAT( anonymous_, __LINE__ )

Of course, this fails as soon as you try to declare two of them on the same line. (NB: Do not use __COUNTER__ for this, at least not in a header file, as that is incompatible with the one-definition rule.)

- D

--

---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

morw...@gmail.com

unread,
Mar 7, 2014, 4:09:25 AM3/7/14
to std-pr...@isocpp.org
This would probably not play well with the gettext utility which makes an extensive use of _ as a translation function.

Ville Voutilainen

unread,
Mar 7, 2014, 4:10:24 AM3/7/14
to std-pr...@isocpp.org
On 7 March 2014 10:53, David Krauss <pot...@gmail.com> wrote:
> I was just having this exact same thought. I'm currently writing a scope
> guards proposal and plan to include the idea, but only as a peripheral kind
> of suggestion.

Regarding unused identifiers, see
http://cplusplus.github.io/EWG/ewg-active.html#35

Regarding scope guards, see
http://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3949.pdf

David Krauss

unread,
Mar 7, 2014, 4:27:57 AM3/7/14
to std-pr...@isocpp.org

On 2014–03–07, at 5:10 PM, Ville Voutilainen <ville.vo...@gmail.com> wrote:

> On 7 March 2014 10:53, David Krauss <pot...@gmail.com> wrote:
>> I was just having this exact same thought. I'm currently writing a scope
>> guards proposal and plan to include the idea, but only as a peripheral kind
>> of suggestion.
>
> Regarding unused identifiers, see
> http://cplusplus.github.io/EWG/ewg-active.html#35

Summary: the need was identified about a year ago; needs further study.

There are major issues, e.g. that a declarator for a totally inaccessible entity is nearly a contradiction in terms. Yes, functional languages have good reason to do it, but the rationale there doesn’t match C++. It may be better to weigh unused names against alternative solutions for each use case, and it’s only in that context that I plan to cover the subject.
Yes… I am taking a more analytical approach, examining the precedents and the enumerating the design decisions, so as to converge upon an optimum with less iteration and general argumentation.

Nevin Liber

unread,
Mar 7, 2014, 11:03:44 AM3/7/14
to std-pr...@isocpp.org
On 7 March 2014 02:07, Stack Machine <stackm...@hotmail.com> wrote:
Idea: Give a single underscore "_" a special meaning in contexts where an identifier is expected.

That would be a breaking change, which significantly reduces the chance that the committee will ever approve it.
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

Matthew Woehlke

unread,
Mar 7, 2014, 11:15:20 AM3/7/14
to std-pr...@isocpp.org
On 2014-03-07 03:07, Stack Machine wrote:
> Idea: Give a single underscore "_" a special meaning in contexts where an
> identifier is expected. It means that the thing being defined is unused.
> Examples:
> std::lock_guard<std::mutex> _(mtx);
> auto _ = finally([]{ std::cout << "scope exit\n"; }); // 'finally' runs a
> function at scope exit

I assume this also implies that the "actual" name of the variable is
anonymous?

IOW:

auto _ = ...; // okay
auto _ = ...; // NOT a duplicate declaration

Aside: I wonder if it would be acceptable to use e.g. '#' for this
purpose, so that there is no possible collision with existing
identifiers. (Also it would be that much more obvious that the name is
'special', since of course '#' isn't otherwise a valid identifier.)

As an added bonus we could maybe then allow writing e.g. 'auto# = ...',
which some people might find desirable.

> void foo(int _);

Not needed, already you can just omit the name entirely. Unlike giving
it a name and them later doing '(void)param' (which documents the
purpose of the parameter and/or is useful if the parameter is used e.g.
depending on some preprocessor condition), I don't see anything gained
by giving it an anonymous name versus simply omitting the name.

--
Matthew

Zhihao Yuan

unread,
Mar 7, 2014, 11:30:09 AM3/7/14
to std-pr...@isocpp.org
On Fri, Mar 7, 2014 at 11:03 AM, Nevin Liber <ne...@eviloverlord.com> wrote:
> On 7 March 2014 02:07, Stack Machine <stackm...@hotmail.com> wrote:
>>
>> Idea: Give a single underscore "_" a special meaning in contexts where an
>> identifier is expected.
>
>
> That would be a breaking change, which significantly reduces the chance that
> the committee will ever approve it.

Let throw one of my old suggestion here again:

with (make_scope_guard(...)) // tune the name or the syntax rule
{
} // lifetime the temporary ends here

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

Stack Machine

unread,
Mar 7, 2014, 11:42:19 AM3/7/14
to std-pr...@isocpp.org

Yes, but how relevant is it in practise? I do not see any good reason, why you would want to use _ as an identifier.
I haven't used gettext so far, so I am going to take a look at it. But I think even then, it's worth the trade-off.

Ville Voutilainen

unread,
Mar 7, 2014, 11:46:16 AM3/7/14
to std-pr...@isocpp.org
On 7 March 2014 18:42, Stack Machine <stackm...@hotmail.com> wrote:
> Am Freitag, 7. März 2014 17:03:44 UTC+1 schrieb Nevin ":-)" Liber:
>>
>> On 7 March 2014 02:07, Stack Machine <stackm...@hotmail.com> wrote:
>>>
>>> Idea: Give a single underscore "_" a special meaning in contexts where an
>>> identifier is expected.
>> That would be a breaking change, which significantly reduces the chance
>> that the committee will ever approve it.
> Yes, but how relevant is it in practise? I do not see any good reason, why
> you would want to use _ as an identifier.
> I haven't used gettext so far, so I am going to take a look at it. But I
> think even then, it's worth the trade-off.


There is existing code where people use _ as an identifier, precisely to express
that the variable exists only to be destroyed.
Message has been deleted

Stack Machine

unread,
Mar 7, 2014, 11:51:26 AM3/7/14
to std-pr...@isocpp.org

These cases will continue to compile, provided that the variable is not accessed anywhere. But in that case I'd rather give it a proper name anyways.

Nevin Liber

unread,
Mar 7, 2014, 12:00:14 PM3/7/14
to std-pr...@isocpp.org
On 7 March 2014 10:42, Stack Machine <stackm...@hotmail.com> wrote:
Am Freitag, 7. März 2014 17:03:44 UTC+1 schrieb Nevin ":-)" Liber:
On 7 March 2014 02:07, Stack Machine <stackm...@hotmail.com> wrote:
Idea: Give a single underscore "_" a special meaning in contexts where an identifier is expected.
That would be a breaking change, which significantly reduces the chance that the committee will ever approve it.

Yes, but how relevant is it in practise? I do not see any good reason, why you would want to use _ as an identifier.

It seems unlikely the committee will break 16+ years of saying that _ is a valid identifier just because you personally want to use it for something else.
 
I haven't used gettext so far, so I am going to take a look at it. But I think even then, it's worth the trade-off.

People who don't have to pay the price always seem to think it's worth the trade-off...

Matthew Woehlke

unread,
Mar 7, 2014, 12:02:40 PM3/7/14
to std-pr...@isocpp.org
On 2014-03-07 11:30, Zhihao Yuan wrote:
> Let throw one of my old suggestion here again:
>
> with (make_scope_guard(...)) // tune the name or the syntax rule
> {
> } // lifetime the temporary ends here

If we do that, what about 'with (expr as name)'? Also I think this
should support multiple declarations (probably separated by ',').

FWIW I'd probably keep the ()'s for consistency.

I assume the braces are optional, having the same meaning as any other
scoping keyword? (I.e. if omitted, scope is next statement.)


You could almost implement this right now as a macro, e.g.:

#define with(expr) if(with_t ANON = (expr))

...where with_t is a template helper class that binds an
rvalue-reference to anything and has an operator bool that always
returns true, and ANON is another macro to generate a unique,
"anonymous" name.

Of course this wouldn't support the 'as' syntax.


I definitely could see a use for 'with (expr as name)'; it's possible
right now with a bare scope, but those are ugly :-).


Such a syntax would also make it easy and convenient to create e.g.
'synchronized(object)' as a macro.

--
Matthew

Thiago Macieira

unread,
Mar 7, 2014, 12:07:26 PM3/7/14
to std-pr...@isocpp.org
Em sex 07 mar 2014, às 11:15:20, Matthew Woehlke escreveu:
> > void foo(int _);
>
> Not needed, already you can just omit the name entirely. Unlike giving
> it a name and them later doing '(void)param' (which documents the
> purpose of the parameter and/or is useful if the parameter is used e.g.
> depending on some preprocessor condition), I don't see anything gained
> by giving it an anonymous name versus simply omitting the name.

On that light: would the following be too difficult to accept, according to the
language grammar?

auto = 1;
auto = std::scope_guard(...);
auto = std::lock_guard<std::mutex>(mtx);

Since the right side has no name, it should trigger an rvalue move to the left
side, thus allowing uncopyable types to be used. The language should also
allow the compiler to elide the move and optimise to a simple construction.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358

Stack Machine

unread,
Mar 7, 2014, 12:09:56 PM3/7/14
to std-pr...@isocpp.org
Correct me if I'm wrong, but as I understood it, _ is just a shorthand for gettext and it looks like it can be replaced in source code by a regex search & replace.

Thiago Macieira

unread,
Mar 7, 2014, 12:21:11 PM3/7/14
to std-pr...@isocpp.org
Are you proposing we change tens of millions of lines of code using _ as a
translation shortcut?

Also note it's a #define, so I guess we won't break them, but they'll break
this feature instead.

Brent Friedman

unread,
Mar 7, 2014, 12:33:11 PM3/7/14
to std-pr...@isocpp.org
In a thread started here back on Oct 4 "Unnamed LValues", I suggested, alternately, 'auto' or '?' as an unnamed-identifier. 
? may cause some conflict with bitfields and the ternary operator. 

int ? : 4; //bitfield or ternary?

auto doesn't seem to create any such potential ambiguity, and being a keyword perhaps stands out better in the code.

int auto = 4;
lock_guard<mutex> auto;



Matthew Woehlke

unread,
Mar 7, 2014, 12:44:22 PM3/7/14
to std-pr...@isocpp.org
On 2014-03-07 12:33, Brent Friedman wrote:
> In a thread started here back on Oct 4 "Unnamed LValues", I suggested,
> alternately, 'auto' or '?' as an unnamed-identifier.
> ? may cause some conflict with bitfields and the ternary operator.
>
> int ? : 4; //bitfield or ternary?
>
> auto doesn't seem to create any such potential ambiguity, and being a
> keyword perhaps stands out better in the code.

'auto&& auto = expr'? That might be a little weird... :-)

What about '#'? AFAIK it is only used for preprocessor right now, so
there is no possible ambiguity with C++, and I believe all cases where
it would normally be used, it would be preceded by something. (And
otherwise, or in pathological cases, you can always use '/**/#'.)

I thought about '#' also because it is a comment specifier in many other
languages, which gives a little logic to using it for an "I don't care
about the name" identifier.

...or maybe '@', which I don't think is currently used at all?

I think either '#' or '@' would also stand out if only because they're
not otherwise used.

--
Matthew

Brent Friedman

unread,
Mar 7, 2014, 1:08:26 PM3/7/14
to std-pr...@isocpp.org
Yep, I'd be suggesting some form of auto auto = ...;

You'd have to add @ to the basic source character set which seems like a big change for what should be a small feature. # may require modifications to the preprocessor.


--

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

Thiago Macieira

unread,
Mar 7, 2014, 2:27:30 PM3/7/14
to std-pr...@isocpp.org
Em sex 07 mar 2014, às 11:33:11, Brent Friedman escreveu:
> In a thread started here back on Oct 4 "Unnamed LValues", I suggested,
> alternately, 'auto' or '?' as an unnamed-identifier.
> ? may cause some conflict with bitfields and the ternary operator.
>
> int ? : 4; //bitfield or ternary?

I don't think this one is a problem. First, a bitfield can only be declared in
a structure, so with context you know that it isn't a ternary operator.

Second, bitfields already allow anonymous fields:

int : 4;

> auto doesn't seem to create any such potential ambiguity, and being a
> keyword perhaps stands out better in the code.
>
> int auto = 4;
> lock_guard<mutex> auto;

Reminds me of:
auto int x = 4;

How would you use automatic detection?
auto auto = 4?

PS: I wonder if anyone has realised that "auto x = 4" is a valid B, C89 and
C++11 declaration.

Jeffrey Yasskin

unread,
Mar 7, 2014, 2:39:59 PM3/7/14
to std-pr...@isocpp.org
On Fri, Mar 7, 2014 at 8:03 AM, Nevin Liber <ne...@eviloverlord.com> wrote:
> On 7 March 2014 02:07, Stack Machine <stackm...@hotmail.com> wrote:
>>
>> Idea: Give a single underscore "_" a special meaning in contexts where an
>> identifier is expected.
>
>
> That would be a breaking change, which significantly reduces the chance that
> the committee will ever approve it.

Although "__" (two underscores) is currently reserved, so it might be ok.

Zhihao Yuan

unread,
Mar 7, 2014, 2:40:55 PM3/7/14
to std-pr...@isocpp.org
On Fri, Mar 7, 2014 at 12:02 PM, Matthew Woehlke
<mw_t...@users.sourceforge.net> wrote:
> On 2014-03-07 11:30, Zhihao Yuan wrote:
>>
>> Let throw one of my old suggestion here again:
>>
>> with (make_scope_guard(...)) // tune the name or the syntax rule
>> {
>> } // lifetime the temporary ends here
>
>
> If we do that, what about 'with (expr as name)'? Also I think this should
> support multiple declarations (probably separated by ',').
>
> FWIW I'd probably keep the ()'s for consistency.
>
> I assume the braces are optional, having the same meaning as any other
> scoping keyword? (I.e. if omitted, scope is next statement.)

The braces are intended to be not optional, because I also want

A(...) : with(lock), mA(...)
{ ... }

Just like the function/constructor try ... catch block.

; separated multiple declaration would be helpful. But I'm not
very interested in `with (e as name)`, since what would be one
more keyword (and one more declaration style for user to
remember. Unlike Python, which also uses `T as name` in
exception handling).

> You could almost implement this right now as a macro, e.g.:
>
> #define with(expr) if(with_t ANON = (expr))
>
> ...where with_t is a template helper class that binds an rvalue-reference to
> anything and has an operator bool that always returns true, and ANON is
> another macro to generate a unique, "anonymous" name.

Yes, if (auto&& ...) is where this idea comes from (of course,
apart from Python).

Thiago Macieira

unread,
Mar 7, 2014, 2:49:44 PM3/7/14
to std-pr...@isocpp.org
Em sex 07 mar 2014, às 11:39:59, Jeffrey Yasskin escreveu:
> Although "__" (two underscores) is currently reserved, so it might be ok.

That doesn't mean it's unused.

V8 (the JS engine from Blink / Chromium) uses it for the assembler:

https://code.google.com/p/v8/codesearch#v8/trunk/src/codegen.cc&q=__&sq=package:v8&type=cs&l=43
https://code.google.com/p/v8/codesearch#v8/trunk/src/x64/debug-x64.cc&q=__&sq=package:v8&type=cs&l=96

Etc.

Matthew Woehlke

unread,
Mar 7, 2014, 3:20:23 PM3/7/14
to std-pr...@isocpp.org
On 2014-03-07 14:40, Zhihao Yuan wrote:
> On Fri, Mar 7, 2014 at 12:02 PM, Matthew Woehlke wrote:
>> On 2014-03-07 11:30, Zhihao Yuan wrote:
>>> Let throw one of my old suggestion here again:
>>>
>>> with (make_scope_guard(...)) // tune the name or the syntax rule
>>> {
>>> } // lifetime the temporary ends here
>>
>> If we do that, what about 'with (expr as name)'? Also I think this should
>> support multiple declarations (probably separated by ',').
>
> ; separated multiple declaration would be helpful.

Hmm... ';' seems a little odd, but I guess e.g. for() is precedence.
Anyway, that's an unimportant detail.

> But I'm not very interested in `with (e as name)`, since what would
> be one more keyword (and one more declaration style for user to
> remember.

I think it would be a real shame if we introduced 'with' but it *only*
supported unnamed temporaries. I'm not wedded to a particular syntax for
declarations, though, e.g.:

with (a = foo(); b = bar(); one(); two())

...would also be fine.

>> I assume the braces are optional, having the same meaning as any other
>> scoping keyword? (I.e. if omitted, scope is next statement.)
>
> The braces are intended to be not optional, because I also want
>
> A(...) : with(lock), mA(...)
> { ... }
>
> Just like the function/constructor try ... catch block.

That's not quite the same, though. The braces in that case are related
to the ctor body. In fact I would argue this is a specific case of *not*
having braces for the with().

My point is I think I should be able to write:

with (foo())
statement; // no braces

...just like I can write:

if (auto a = foo())
statement; // no braces

(More pedantically, the syntax for 'with' should be that the so-declared
variables have scope for exactly the next «statement», where of course a
«compound-statement» is a type of «statement». This way it's consistent
with e.g. if(), while(), for(), etc. The ctor-scope form would be an
alternate syntax.)


Anyway, don't you mean:

A(...) with(lock) : ...initializer list...

...?

--
Matthew

Zhihao Yuan

unread,
Mar 7, 2014, 3:35:33 PM3/7/14
to std-pr...@isocpp.org
On Fri, Mar 7, 2014 at 3:20 PM, Matthew Woehlke
<mw_t...@users.sourceforge.net> wrote:
> I think it would be a real shame if we introduced 'with' but it *only*
> supported unnamed temporaries. I'm not wedded to a particular syntax for
> declarations, though, e.g.:
>
> with (a = foo(); b = bar(); one(); two())
>
> ...would also be fine.

= doesn't work, since you cannot disambiguate that from
an assignment expression. Introducing tentative parsing
or interaction with semantics analyzing here is not acceptable
(precedence is generic lambda [](a, b) {} -- works, but failed
by the committee).

>> The braces are intended to be not optional, because I also want
>>
>> A(...) : with(lock), mA(...)
>> { ... }
>>
>> Just like the function/constructor try ... catch block.
>
>
> That's not quite the same, though. The braces in that case are related to
> the ctor body. In fact I would argue this is a specific case of *not* having
> braces for the with().
>
> My point is I think I should be able to write:
>
> with (foo())
> statement; // no braces
>
> ...just like I can write:
>
> if (auto a = foo())
> statement; // no braces

You cannot write

try
statement;
catch (...)
;

either.

> (More pedantically, the syntax for 'with' should be that the so-declared
> variables have scope for exactly the next «statement», where of course a
> «compound-statement» is a type of «statement». This way it's consistent with
> e.g. if(), while(), for(), etc. The ctor-scope form would be an alternate
> syntax.)
>
>
> Anyway, don't you mean:
>
> A(...) with(lock) : ...initializer list...
>
> ...?

Yes, I mean that. And I believe that with() should be
consistent with that of try...catch block.

Andrew Tomazos

unread,
Mar 7, 2014, 5:11:23 PM3/7/14
to std-pr...@isocpp.org
Hi Stack Machine,

Have you considered proposing emission of the identifier instead?

Like in the following:

std::lock_guard<std::mutex> = mtx;
auto = finally([]{ std::cout << "scope exit\n"; }); // 'finally' runs a function at scope exit

void foo(int);

struct { ... } my_single_object;

The last two cases are already well-formed and used to declare an unnamed entity.

From this, there are a couple of ambiguities arising between expression statements and declaration statements with no declarator-id.  These would have to be resolved for backward-compatibility to the existing well-formed meaning, but for those currently ill-formed cases that remain, they could resolve to a declaration statement like you want.

Regards,
Andrew.


On Friday, March 7, 2014 9:07:05 AM UTC+1, Stack Machine wrote:
Idea: Give a single underscore "_" a special meaning in contexts where an identifier is expected. It means that the thing being defined is unused.
Examples:
std::lock_guard<std::mutex> _(mtx);
auto _ = finally([]{ std::cout << "scope exit\n"; }); // 'finally' runs a function at scope exit

void foo(int _);

struct _ { ... } my_single_object;

Andrew Tomazos

unread,
Mar 7, 2014, 5:16:48 PM3/7/14
to std-pr...@isocpp.org
Errata: I mean "omission" not "emission" of course. :)

David Krauss

unread,
Mar 7, 2014, 8:02:51 PM3/7/14
to std-pr...@isocpp.org


On Saturday, March 8, 2014 12:03:44 AM UTC+8, Nevin ":-)" Liber wrote:
On 7 March 2014 02:07, Stack Machine <stackm...@hotmail.com> wrote:
Idea: Give a single underscore "_" a special meaning in contexts where an identifier is expected.

That would be a breaking change, which significantly reduces the chance that the committee will ever approve it.

Not to personally endorse anything, but breakage can be avoided completely by making the rule an allowance to redeclare _ in the same scope, not to cease recognizing it as an id-expression.

Thiago Macieira

unread,
Mar 7, 2014, 8:06:09 PM3/7/14
to std-pr...@isocpp.org
Em sex 07 mar 2014, às 17:02:51, David Krauss escreveu:
> On Saturday, March 8, 2014 12:03:44 AM UTC+8, Nevin ":-)" Liber wrote:
> > On 7 March 2014 02:07, Stack Machine <stackm...@hotmail.com
<javascript:>>wrote:
> >> Idea: Give a single underscore "_" a special meaning in contexts where an
> >> identifier is expected.
> >
> > That would be a breaking change, which significantly reduces the chance
> > that the committee will ever approve it.
>
> Not to personally endorse anything, but breakage can be avoided completely
> by making the rule an allowance to redeclare _ in the same scope, not to
> cease recognizing it as an id-expression.

How do you deal with

#define _ gettext

morw...@gmail.com

unread,
Mar 7, 2014, 8:32:06 PM3/7/14
to std-pr...@isocpp.org
Here is how I would use the keyword with:

    with (auto foo: expr)
    {
        // do something with foo...
    }

The syntax would be consistent with the range-base foor loop syntax.

Vicente J. Botet Escriba

unread,
Mar 7, 2014, 8:52:42 PM3/7/14
to std-pr...@isocpp.org
Le 07/03/14 09:07, Stack Machine a écrit :
Idea: Give a single underscore "_" a special meaning in contexts where an identifier is expected. It means that the thing being defined is unused.
Examples:
std::lock_guard<std::mutex> _(mtx);
auto _ = finally([]{ std::cout << "scope exit\n"; }); // 'finally' runs a function at scope exit

void foo(int _);

struct _ { ... } my_single_object;
etc. etc.

This feature has been used extensively in functional languages. It solves the problem of unused variables nicely while being very explicit at the same time.

Hi,

some time ago I proposed in this ML something similar " let-in statements and anonymous variables" (see [1])
This covers the with expression proposed in another post in this thread  and the anonymous variable.  Instead of using a new keyword 'with' I proposed to use : to separate the declaration and the statement. IMO, the best name for an anonymous variable is nothing.

The following

  auto  = expression : statement

will be equivalent to

  {
    const auto __uid__= expression; statement
  }

where __uid__ is a new unique identifier generated by the compiler.

Vicente

[1] https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/BfAtczj81Kg

David Krauss

unread,
Mar 7, 2014, 11:18:31 PM3/7/14
to std-pr...@isocpp.org

On 2014–03–08, at 9:06 AM, Thiago Macieira <thi...@macieira.org> wrote:

> Em sex 07 mar 2014, às 17:02:51, David Krauss escreveu:
>> Not to personally endorse anything, but breakage can be avoided completely
>> by making the rule an allowance to redeclare _ in the same scope, not to
>> cease recognizing it as an id-expression.
>
> How do you deal with
>
> #define _ gettext

Usage of the gettext library wouldn’t be affected, because the compiler would never see _ appear in a declaration in the first place. Effectively the macro would override the special underscore semantics by hiding the underscore token completely. Of course, the user could opt to #undef it.

The library-provided _ macro would break other libraries which want that identifier, but that is nothing new! It’s obviously dangerous, so they should have had the common sense to optionally disable it, or at least warn users that it should be included only after other potentially sensitive headers which might use the _ token.

Again, I don’t want to suggest that it’s a really good idea, but it’s certainly workable. It might exacerbate, but it does not introduce a problem that didn’t already exist.

David Krauss

unread,
Mar 7, 2014, 11:23:47 PM3/7/14
to std-pr...@isocpp.org

On 2014–03–08, at 9:52 AM, Vicente J. Botet Escriba <vicent...@wanadoo.fr> wrote:

> some time ago I proposed in this ML something similar " let-in statements and anonymous variables" (see [1])

We already have unnamed parameters, whose lifetime duration is that of the function, and discarded-value expressions. What is proposed is only a handle to adjust the lifetime of a discarded value object that exists in any case. This cannot be related to functional semantics, because in functional languages variables do not have lifetimes.

Thiago Macieira

unread,
Mar 7, 2014, 11:27:05 PM3/7/14
to std-pr...@isocpp.org
Em sáb 08 mar 2014, às 12:18:31, David Krauss escreveu:
> The library-provided _ macro would break other libraries which want that
> identifier, but that is nothing new! It's obviously dangerous, so they
> should have had the common sense to optionally disable it, or at least warn
> users that it should be included only after other potentially sensitive
> headers which might use the _ token.

That also means you may never use the special _ in a header.

David Krauss

unread,
Mar 7, 2014, 11:34:01 PM3/7/14
to std-pr...@isocpp.org

On 2014–03–08, at 12:27 PM, Thiago Macieira <thi...@macieira.org> wrote:

> Em sáb 08 mar 2014, às 12:18:31, David Krauss escreveu:
>> The library-provided _ macro would break other libraries which want that
>> identifier, but that is nothing new! It's obviously dangerous, so they
>> should have had the common sense to optionally disable it, or at least warn
>> users that it should be included only after other potentially sensitive
>> headers which might use the _ token.
>
> That also means you may never use the special _ in a header.

I don’t understand. If you use gettext, then every declaration of _ will be munged to a declaration of gettext. This doesn’t change; the proposal merely makes the _ identifier more desirable. Anyway, either gettext provides a flag to disable that macro, or you can #undef it yourself.

If libraries besides gettext define macros named _, then they are all mutually incompatible. What do we care about such boneheaded interfaces?

My suggestion to allow declarations of _ to hide preceding declarations in the same scope is not a breaking change, because such declarations are ill-formed. Corner cases like overloading and elaborated-type-specifiers would need to be resolved somehow, but that’s immaterial.

Thiago Macieira

unread,
Mar 7, 2014, 11:40:40 PM3/7/14
to std-pr...@isocpp.org
Em sáb 08 mar 2014, às 12:34:01, David Krauss escreveu:
> On 2014-03-08, at 12:27 PM, Thiago Macieira <thi...@macieira.org> wrote:
> > Em sáb 08 mar 2014, às 12:18:31, David Krauss escreveu:
> >> The library-provided _ macro would break other libraries which want that
> >> identifier, but that is nothing new! It's obviously dangerous, so they
> >> should have had the common sense to optionally disable it, or at least
> >> warn
> >> users that it should be included only after other potentially sensitive
> >> headers which might use the _ token.
> >
> > That also means you may never use the special _ in a header.
>
> I don't understand. If you use gettext, then every declaration of _ will be
> munged to a declaration of gettext. This doesn't change; the proposal
> merely makes the _ identifier more desirable. Anyway, either gettext
> provides a flag to disable that macro, or you can #undef it yourself.

You missed the point.

If I'm writing a header, I don't know whether my header will be included after
the header that #defines _. If it is included after, then I can't use _ since
it will expand to gettext, which is not a special identifier.

Therefore, I may never use this feature in headers. Ever.

David Krauss

unread,
Mar 8, 2014, 1:10:06 AM3/8/14
to std-pr...@isocpp.org
On 2014–03–08, at 12:40 PM, Thiago Macieira <thi...@macieira.org> wrote:

You missed the point.

If I'm writing a header, I don't know whether my header will be included after 
the header that #defines _. If it is included after, then I can't use _ since 
it will expand to gettext, which is not a special identifier.

Therefore, I may never use this feature in headers. Ever.

Every time you use any identifier, you tacitly assume it hasn’t been defined to something by a header. Such conflicts do occur, but the sky isn’t falling.

Rather than arguing this further though, consider this example:

    make_scope_guard( [&] { t.rollback(); } ); // Expression-statement; no declaration.

This is a very dangerous kind of error.

The line immediately executes the guard body, but because that is a destructor (and noexcept), it probably doesn’t have very dramatic side effects. Most likely, it just deallocates some resources. But since it is executing at the earliest possible opportunity, there are likely to be no resources yet to deallocate, so it’s a complete no-op. But the correct usage also produces a no-op at this point, so there’s no detectable failure yet.

When we get to the end of the scope, we might do something like t.commit(). But that is also likely to free the same resources, and in most cases a transaction guard is supposed to be a no-op after a commit.

In the end, the guard protects nothing, and the software behaves fine until an actual exceptional condition occurs. There is no diagnosable error in the function call. At best a platform could provide an unportable [noignore] attribute, or give warnings specifically for the std:: facility, which then surprisingly vanish when it is encapsulated somehow.

This is totally unacceptable for a utility intended for reliable programming. Once this more serious issue is resolved, the motivation for unused identifiers might just go away. Or, it might not. But right now I think the focus is on the wrong problem.

Thiago Macieira

unread,
Mar 8, 2014, 1:31:33 AM3/8/14
to std-pr...@isocpp.org
Em sáb 08 mar 2014, às 14:10:06, David Krauss escreveu:
> On 2014-03-08, at 12:40 PM, Thiago Macieira <thi...@macieira.org> wrote:
> > You missed the point.
> >
> > If I'm writing a header, I don't know whether my header will be included
> > after the header that #defines _. If it is included after, then I can't
> > use _ since it will expand to gettext, which is not a special identifier.
> >
> > Therefore, I may never use this feature in headers. Ever.
>
> Every time you use any identifier, you tacitly assume it hasn't been defined
> to something by a header. Such conflicts do occur, but the sky isn't
> falling.

Indeed.

But usually I also take care not to name my variables after identifiers that
are usually #defined to something. That's why you never call your variables
O_RDONLY, interface, sun, linux, s6_addr, sa_handler, m_volume, or _.

> This is totally unacceptable for a utility intended for reliable
> programming. Once this more serious issue is resolved, the motivation for
> unused identifiers might just go away. Or, it might not. But right now I
> think the focus is on the wrong problem.

I think there's a valid use-case in this thread for anonymous variables, just
like we can have anonymous parameters and anonymous fields in a bitfield. I'm
simply arguing against using _ as a special identifier.

David Krauss

unread,
Mar 8, 2014, 2:24:03 AM3/8/14
to std-pr...@isocpp.org
On 2014–03–08, at 2:31 PM, Thiago Macieira <thi...@macieira.org> wrote:

But usually I also take care not to name my variables after identifiers that
are usually #defined to something. That's why you never call your variables
O_RDONLY, interface, sun, linux, s6_addr, sa_handler, m_volume, or _.

Libraries which use identifiers named _ or M or interface or noexcept or whatever put themselves in harm’s way, and libraries which define such things as macros much more so. There is such a thing as obsolescence due to poor interface design, and the death knell always comes down to some degree of bad luck.

This is probably the most pressing issue under the “modules” umbrella, given the preponderance of complex header libraries, and hopefully it will be solved.

Most things that define _ can probably be classified as domain-specific languages, and migration is always more complicated for such code, but the problem may at least be isolated to sources actually using the DSL. How often do implementations vary the ABI with the language dialect? A source compiled with -std=c++11 should link with a -std=c++14 one from the exact same compiler, right? Of course this is implementation-dependent but it seems like common sense.

I think there's a valid use-case in this thread for anonymous variables, just
like we can have anonymous parameters and anonymous fields in a bitfield. I'm
simply arguing against using _ as a special identifier.

I went and scanned the entire thread, and I don’t see any real use case illustrated besides guards. What’s missing?

Matthew Woehlke

unread,
Mar 10, 2014, 11:46:16 AM3/10/14
to std-pr...@isocpp.org
On 2014-03-08 01:10, David Krauss wrote:
> Rather than arguing this further though, consider this example:
>
> make_scope_guard( [&] { t.rollback(); } ); // Expression-statement; no declaration.
>
> This is a very dangerous kind of error.

...isn't that solved by making make_scope_guard warn if the return value
is unused? (And don't we already have facilities for doing that sort of
thing?)

--
Matthew

David Krauss

unread,
Mar 10, 2014, 7:43:25 PM3/10/14
to std-pr...@isocpp.org
No facility that I’m aware of. I explore the problem in my forthcoming paper, with three solutions:

1. explicit operator void() discard operator prevents discarding the return value — non-breaking core language change, with application to expression templates.
2. class & guard { class-head value category restriction specifier prevents the guard from being a temporary — non-breaking core language change, with a different application to expression templates.
3. class guard : std::guard_base { — the compiler knows about std::guard_base and warns if a derived class is a discarded value. No language extension needed. Derivation from guard_base may be useful for other reasons as well.

So far, I plan to recommend #3 as an immediate, compatible solution, but it still requires (optional) compiler support be added, because no similar facility exists. The others are superior and hopefully those changes can be included in C++17.

Matthew Woehlke

unread,
Mar 11, 2014, 11:45:29 AM3/11/14
to std-pr...@isocpp.org
On 2014-03-10 19:43, David Krauss wrote:
> On 2014-03-10, at 11:46 PM, Matthew Woehlke wrote:
>> On 2014-03-08 01:10, David Krauss wrote:
>>> Rather than arguing this further though, consider this example:
>>>
>>> make_scope_guard( [&] { t.rollback(); } ); // Expression-statement; no declaration.
>>>
>>> This is a very dangerous kind of error.
>>
>> ...isn't that solved by making make_scope_guard warn if the return
>> value is unused? (And don't we already have facilities for doing
>> that sort of thing?)
>
> No facility that I'm aware of.

...then what does __attribute__((warn_unused_result)) do? As I
understood it is *exactly* dealing with cases such as the above.

Although it doesn't address the case:

scope_guard{...};

...though I would be somewhat surprised if that isn't already warned about.

That said...

> 1. explicit operator void() discard operator prevents discarding the
> return value -- non-breaking core language change, with application
> to expression templates.

...this sounds like it would be an interesting addition. (I take it this
would make failure to assign such a class to a named identifier an error?)

--
Matthew

David Krauss

unread,
Mar 11, 2014, 12:35:15 PM3/11/14
to std-pr...@isocpp.org
On 2014–03–11, at 11:45 PM, Matthew Woehlke <mw_t...@users.sourceforge.net> wrote:

...then what does __attribute__((warn_unused_result)) do? As I understood it is *exactly* dealing with cases such as the above.

You seem to presume I know something :v) . Thanks for the info. But, a quick search suggests that a significant number of users may disable that warning, because it is used for return values that are merely insecure if ignored, not utterly wrong. A bit more contrived, the user could pass the result of make_guard to something, e.g. std::move( make_guard( … ) ).

Apparently MSVC lacks an equivalent feature. I think it would be better to standardize this, and not leave it to QOI.

Although it doesn't address the case:

 scope_guard{...};

...though I would be somewhat surprised if that isn't already warned about.

I see nothing there to generate a warning, but it’s a non-issue because we can assume the factory is the only useful handle.

Actually, one avenue I’ll explore is an implementation-defined guard class. I don’t think the user needs to be able to name it at all. Boost.ScopeExit hides both the class and the object.

That said...

1. explicit operator void() discard operator prevents discarding the
return value -- non-breaking core language change, with application
to expression templates.

...this sounds like it would be an interesting addition. (I take it this would make failure to assign such a class to a named identifier an error?)

That describes the second alternative. Here is a preview of the relevant section:

Alternative solutions, requiring core language changes, may be explored. Here are two.

2.1.1. Discarded value operator

As a purely diagnostic measure, the guard class could be forbidden from forming a discarded value expression. Another case where trapping discarded values is useful is a matrix expression template involving multiple assignment operations. Currently, an expression template must decay at each assignment operation, ignoring some loop interleavings. The relevance here is that such a feature would not be dedicated to guard safety.

The natural discarded value operator is operator void(). An expression-statement with type T could be considered as an implicit conversion from T to void, therefore a guard class would only need to declare explicit operator void() {} to give the example an illegal implicit conversion. Explicitly casting a guard object to void would still be legal.

2.1.2. Restriction of class value category

The class could be forbidden from forming a prvalue expression. This would forbid the guard ever being an anonymous, discarded object. Function return values are always of category prvalue though, so the best middle ground is to also permit a lifetime-extended temporary.

The restriction could be expressed by a class-head decorator such as &. The corresponding && decorator would conversely express that instances cannot be named (or lifetime-extended), such as expression template specializations. Inheritance of this decorator is a difficult question. One simple solution is to make them class-virt-specifiers implying final, thus prohibiting derivation.

This rather elegantly removes the danger, but it does not improve convenience. The ideal solution would simply fix the bare function call expression to be correct. Such a & specifier may be sufficiently expressive to allow the language to surmise that a discarded prvalue, rather than being ill-formed, should be interpreted as being bound to an anonymous reference.


Matthew Woehlke

unread,
Mar 11, 2014, 1:56:46 PM3/11/14
to std-pr...@isocpp.org
On 2014-03-11 12:35, David Krauss wrote:
> On 2014-03-11, at 11:45 PM, Matthew Woehlke wrote:
>> ...then what does __attribute__((warn_unused_result)) do?
>
> You seem to presume I know something :v) .

In that case, I will also point you to
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wunused-value-365,
which looks similar to your 'explicit operator void()' proposal and thus
might serve as a useful implementation precedent.

--
Matthew

David Krauss

unread,
Mar 11, 2014, 6:59:21 PM3/11/14
to std-pr...@isocpp.org
That one, I am aware of. It’s different because it can be disabled by a cast to void, and there is no hook. It applies to “values,” which according to GCC’s heuristic includes POD objects but nothing with a destructor.

Most compilers have one or more features along the right lines, but the requirements to protect against guard abuse are deceptively specific. Implementation difficulty should be very modest in any case.

Róbert Dávid

unread,
Mar 19, 2014, 6:23:56 PM3/19/14
to std-pr...@isocpp.org
That's.. not too smart - names containing double underscore are reserved to the implementation in all scopes. Also names starting with single underscore reserved in the global namespace ( 17.6.4.3.2 / [global.names] ). Thus, V8 code is ill-formed.

I'm not sure if it's a good idea to "downvote" a proposal because it would break ill-formed code.. If such code breaks, then suffer in silence, it was already broken.

Regards,
Robert

Thiago Macieira

unread,
Mar 19, 2014, 6:39:19 PM3/19/14
to std-pr...@isocpp.org
Em qua 19 mar 2014, às 15:23:56, Róbert Dávid escreveu:
> That's.. not too smart - names containing double underscore are reserved to
> the implementation in *all* scopes. Also names starting with single
> underscore reserved in the global namespace ( 17.6.4.3.2 / [global.names]
> ). Thus, V8 code is ill-formed.
>
> I'm not sure if it's a good idea to "downvote" a proposal because it would
> break ill-formed code.. If such code breaks, then suffer in silence, it was
> already broken.

Fair enough.

I was just pointing out that certain code usually takes liberties with the
standard and we should be aware of it when making certain identifiers have
special meanings or become keywords.

I've also seen many libraries use underscore + capital, such as this extracted
from glib:

typedef struct _GDir GDir;

https://github.com/GNOME/glib/blob/master/glib/gdir.h#L37
Reply all
Reply to author
Forward
0 new messages