103

In C++ it is possible to use the static keyword within a translation unit to affect the visibility of a symbol (either variable or function declaration).

In n3092, this was deprecated:

Annex D.2 [depr.static]
The use of the static keyword is deprecated when declaring objects in namespace scope (see 3.3.6).

In n3225, this has been removed.

The only article I could find is somewhat informal.

It does underline though, that for compatibility with C (and the ability to compile C-programs as C++) the deprecation is annoying. However, compiling a C program directly as C++ can be a frustrating experience already, so I am unsure if it warrants consideration.

Does anyone know why it was changed ?

David Hammen
  • 32,454
  • 9
  • 60
  • 108
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 5
    You declare objects at namespace scope in C? – Etienne de Martel Jan 18 '11 at 16:44
  • heh, thx, found where to get hold of it at. Tried to delete comment but you beat me there. – Edward Strange Jan 18 '11 at 17:10
  • Question arose from http://stackoverflow.com/questions/4725204/use-of-static-variables-and-functions-in-global-scope/4725237#4725237 – Fred Nurk Jan 18 '11 at 17:28
  • 2
    This also gives the C++ Committee the opportunity to unundeprecate something in the next version of the Standard :-) – James McNellis Feb 10 '11 at 22:48
  • http://stackoverflow.com/questions/4422507/superiority-of-unnamed-namespace-over-static – Martin Ba Jul 04 '13 at 12:07
  • @MatthieuM. - sorry, I just thought that that question should be linked in here (it wasn't afaict) and so I just dropped the link into the comments – Martin Ba Jul 04 '13 at 13:18
  • @MartinBa: Ah! Okay, I thought you wanted to ask some question and hit the Enter key too fast somehow but was surprised not to see the question coming after one hour :) – Matthieu M. Jul 04 '13 at 19:17
  • possible duplicate of [Why are anonymous namespaces not a sufficient replacement for namespace-static, according to the standards committee?](http://stackoverflow.com/questions/8460327/why-are-anonymous-namespaces-not-a-sufficient-replacement-for-namespace-static) – legends2k Dec 06 '13 at 10:40
  • @MatthieuM.: In above post, there're objective answers to your question, which tells where all `static` works when unnamed namespaces don't; the answers here seem primarily opinon based. – legends2k Dec 06 '13 at 10:41

3 Answers3

81

In C++ Standard Core Language Defect Reports and Accepted Issues, Revision 94 under 1012. Undeprecating static they note:

Although 7.3.1.1 [namespace.unnamed] states that the use of the static keyword for declaring variables in namespace scope is deprecated because the unnamed namespace provides a superior alternative, it is unlikely that the feature will be removed at any point in the foreseeable future.

Basically this is saying that the deprecation of static doesn't really make sense. It won't ever be removed from C++. It's still useful because you don't need the boilerplate code you would need with unnamed namespace's if you just want to declare a function or object with internal linkage.

Olivia Stork
  • 4,660
  • 5
  • 27
  • 40
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Thanks for the link, didn't thought of consulting the defects :/ – Matthieu M. Jan 18 '11 at 18:47
  • 4
    Well, it seems deprecation would encourage people to use unnamed namespaces instead, which would be a good thing. – sbi Feb 23 '11 at 16:04
  • 1
    @unaperson: If for no other reason, then because unnamed namespaces provides the same mechanism for making variables, constants, functions, and types internal to their TU. `static class ... `, OTOH, won't work. – sbi Apr 27 '11 at 06:57
  • 2
    @nbt: Because you can't use static symbols as template arguments and because many newbies would find static easier to use and then are untempted to try out and et al. Just a quick thought. – Sebastian Mach Jul 04 '11 at 13:48
  • 5
    " because you don't need the boilerplate code you need with unnamed namespaces"? What "boilerplate code"? Something beyond "`namespace {`" and "`}`"? – towi Feb 25 '14 at 08:24
  • 3
    @towi compared to static there are two additional braces and on many coding styles you will be writing at least 3 lines of code to indent the declaration. – Johannes Schaub - litb Feb 25 '14 at 10:35
  • 5
    i like to declare helper functions, globals, etc static and as close as possible to their usage. the namespace { } syntax is ugly for this purpose, and "static" is fine. other people like to put all their helper stuff at the top of a file. the namespace {} syntax is more useful there. so it's really a matter of style. they are both, ultimately, equivalent. – Erik Aronesty Jan 15 '15 at 18:13
  • 1
    @phresnel no such thing as a "static" class/typdef. local classes in a file aren't available outside that file. so no need for namespace{} around them. only functions (which can always be static) & global - which don't conflict with templates. – Erik Aronesty Jan 15 '15 at 18:17
  • Not to mention that they only talk about objects in the removed part, which was silly in itself. What about functions? The removal has my whole hearted approval lol. – BitTickler May 28 '15 at 20:59
  • 3
    @ErikAronesty If you have a "local class" in another file with the same name then you will commit an ODR violation. – L. F. Sep 22 '19 at 11:15
36

I will try to answer your question, although it is an old question, and it does not look very important (it really is not very important in itself), and it has received quite good answers already. The reason I want to answer it is that it relates to fundamental issues of standard evolution and language design when the language is based on an existing language: when should language features be deprecated, removed, or changed in incompatible ways?

In C++ it is possible to use the static keyword within a translation unit to affect the visibility of a symbol (either variable or function declaration).

The linkage actually.

In n3092, this was deprecated:

Deprecation indicates:

  • The intent to remove some feature in the future; this does not mean that deprecated features will be removed in the next standard revision, or that they must be removed "soon", or at all. And non-deprecated features may be removed in the next standard revision.
  • A formal attempt to discourage its use.

The latter point is important. Although there is never a formal promise that your program won't be broken, sometimes silently, by the next standard, the committee should try to avoid breaking "reasonable" code. Deprecation should tell programmers that it is unreasonable to depend on some feature.

It does underline though, that for compatibility with C (and the ability to compile C-programs as C++) the deprecation is annoying. However, compiling a C program directly as C++ can be a frustrating experience already, so I am unsure if it warrants consideration.

It is very important to preserve a C/C++ common subset, especially for header files. Of course, static global declarations are declarations of symbol with internal linkage and this not very useful in a header file.

But the issue is never just compatibility with C, it's compatibility with existing C++: there are tons of existing valid C++ programs that use static global declarations. This code is not just formally legal, it is sound, as it uses a well-defined language feature the way it is intended to be used.

Just because there is now a "better way" (according to some) to do something does not make the programs written the old way "bad" or "unreasonable". The ability of using the static keyword on declarations of objects and functions at global scope is well understood in both C and C++ communities, and most often used correctly.

In a similar vein, I am not going to change C-style casts to double to static_cast<double> just because "C-style casts are bad", as static_cast<double> adds zero information and zero safety.

The idea that whenever a new way to do something is invented, all programmers would rush to rewrite their existing well-defined working code is just crazy. If you want to remove all the inherited C ugliness and problems, you don't change C++, you invent a new programming language. Half-removing one use of static hardly makes C++ less C-ugly.

Code changes need a justification, and "old is bad" is never a justification for code changes.

Breaking language changes need a very strong justification. Making the language very slightly simpler is never a justification for a breaking change.

The reasons given why static is bad are just remarkably weak, and it isn't even clear why not both objects and function declarations are deprecated together - giving them different treatment hardly makes C++ simpler or more orthogonal.

So, really, it is a sad story. Not because of the practical consequences it had: it had exactly zero practical consequences. But because it shows a clear lack of common sense from the ISO committee.

Chef Pharaoh
  • 2,387
  • 3
  • 27
  • 38
curiousguy
  • 8,038
  • 2
  • 40
  • 58
  • 5
    As you yourself points out, the point of deprecating it is to discourage it's use. Yet you make no argument that discouraging its use is wrong. I certainly hope that nobody's out there encouraging people to use namespace-scoped static declarations over anonymous namespaces. Not unless they specifically need to cross-compile C. – Nicol Bolas Dec 10 '11 at 22:22
  • 4
    I don't care that much about people using global scope `static` or anonymous namespaces, I am not encouraging or discouraging either. My point is that if you really want to discourage people to use anonymous namespaces you have to give them good argument. In practice, I believe that in most implementations entities declared in an unnamed namespace are symbols exported with a random name, thus growing the export table. Entities declared as `static`, OTOH, are not exported in any way. Thus many people choose, based on that observation, to use `static`. – curiousguy Dec 11 '11 at 23:49
  • 4
    "_As you yourself points out, the point of deprecating it is to discourage it's use._" The point of discouraging its use is that it might disappear some day. My point is that namespace-scope `static` won't disappear ever, so it's wrong to deprecate it. "_Yet you make no argument that discouraging its use is wrong._" I have seen no convincing argument that shows that use of namespace-scope `static` is "wrong". Deprecating it just to discourage its use is wrong, because no one actually believes it's going to disappear, and because it doesn't convince people that using it is "wrong". – curiousguy Dec 11 '11 at 23:57
  • 2
    "_I certainly hope that nobody's out there encouraging people to use namespace-scoped static declarations over anonymous namespaces._" Some people think that `static` is better, and encourage its use over anonymous namespaces. My point isn't that either one is better than the other; my point is 1) that no feature (`static`, anon namespaces) is "wrong". 2) that deprecating a useful, well-defined, widely used feature that isn't going to go way - ever - is wrong. Doing that lowers the credibility of the C++ committee (and it is already quite low). – curiousguy Dec 12 '11 at 00:05
  • 8
    The whole language will "disappear some day". Let's deprecate C++. – Lightness Races in Orbit Jan 17 '13 at 18:24
  • @Non-StopTimeTravel Like Fortran did? (when?) You should know, as a time traveler. And COBOL? – curiousguy Jan 23 '13 at 18:57
  • @curiousguy: They haven't yet, which proves precisely nothing! – Lightness Races in Orbit Jan 23 '13 at 19:00
  • 1
    @NicolBolas it isn't just me: the CWG (core working group) voted "**Anonymous namespaces are not a sufficient replacement for the functionality.**" see [n3296](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3296.html#FI6) – curiousguy Aug 22 '15 at 13:22
  • 2
    "In a similar vein, I am not going to change C-style casts to double to static_cast just because "C-style casts are bad", as static_cast adds zero information and zero safety." My eternal fight with many software engineers that keep complaining about my libertinous use of C style casts from one primitive to the other. – Makogan Jul 19 '19 at 21:56
  • 1
    @Makogan If you use this as your argumentation you will probably cause some more fights, as it is obviously wrong: `static_cast` adds information, namely that this cast is done at compile time, while allowing at least some error checking. The reasons to avoid C-style casts are not so inane as "they are bad". Error checking may not always be required, but it is harmless and more obvious to other coders to use `static_cast`. – sigma Jan 01 '20 at 21:28
  • 2
    That's irrelevant for primitives. Primitve casting is ALWAYS a safe operation, there's nothing a static cast can do for you when primitve casting, there's no checks to do about whether or not you can cas a flaot to an int and vice versa. – Makogan Jan 01 '20 at 21:32
  • 1
    @sigma "_namely that this cast is done at compile time_" as opposed to what? what is "cast done at run time"? "_while allowing at least some error checking_" which checks, exactly? – curiousguy Jan 01 '20 at 21:47
  • @Makogan true, but it's not true that a static cast adds zero information or safety, because it's always more specific than a C-style cast, which does not provide *any* safety. @curiousguy: `dynamic_cast`, as you cannot statically downcast a pointer/reference to a polymorphic type if you don't know what its dynamic type will be. An example of a legal C-style cast that is not a legal `static_cast` is `char c = 0; auto *p = (int*) &c;`. This would require the "here be dragons" `reinterpret_cast`, which also makes abundantly clear to others that you are throwing type safety out of the window. – sigma Jan 01 '20 at 23:56
  • "which does not provide any safety" Neither does a static cast, when we talk about primitives. There exists 0 differences between (int)float and static_cast(float) aside from the length of writing. There's no information to be added to that operation – Makogan Jan 02 '20 at 00:01
  • 3
    @sigma Yes and when was a C style ptr cast interpreted as a `dynamic_cast`? Never obviously. And when was `dynamic_cast` related in any way w/ casting numbers like integers and fp? Never, again. So while your point about "new style" (they aren't "new" anymore) casts being more explicit and more readable (by making stuff "_abundantly clear to others_") is well received, they apply mostly to *casts involving ptr* at some point. **They don't apply in any way to a cast to a `double`.** You can't just use an argument about ptr casts and "transpose" it to some other type. – curiousguy Jan 02 '20 at 00:47
  • 2
    @Makogan: I agree if it's some local variable you control, but suppose the variable is later changed to a pointer: the static cast is now illegal but the C cast will continue to compile. Unlikely, but slightly less safe. curiousguy: Indeed never, yet it just allows too many things too quietly. My main point is that C++ casts show potentially helpful information not only to the compiler, but also to other readers/maintainers of your code, which the C syntax can't express. That said, you are entirely right that `(double)` casting is quite benign and I won't castigate you for doing it. – sigma Jan 03 '20 at 00:02
  • At the point where you are casting integer values to pointers and vice versa you are likely doing hardware stuff, i which case you should NOT use C++ casts as they will be very confused about everything. In fact, that's a scenario where you throw all of C++ out the window and do plain C – Makogan Jan 03 '20 at 18:43
  • 1
    @Makogan What can you do in C that you can't do in C++? – curiousguy Jan 03 '20 at 18:52
  • Nothing, but C isn;t name mangled and doesn't start raising a bunch of warnings and compilation errors when you do extraneous things like magically typecasting integers to pointers or touching memory you are "not supposed to touch". Which is 90% of embedded development – Makogan Jan 03 '20 at 19:16
  • 1
    @Makogan You can avoid name mangling with the huuuge effort of prefixing your function declaration with `extern "C"` You can cast pointers to integers and back in C++ just like you can in C. I have no idea which warning about "_touching memory you are "not supposed to touch"._" you are talking about. – curiousguy Jan 03 '20 at 19:55
  • @Makogan You can use the C++ specific syntax (`reinterpret_cast`) to perform these casts. Writing C interfaces in C++ is not writing C code. You can use all C++ feature in that code. Also, flagged. – curiousguy Jan 03 '20 at 20:19
  • There was no disagreement except at the end when you said all C++ features are available in an `extern C` block. The entire point of discussion is if C++ style casts serve any purpose when casting primitives, they don't. – Makogan Jan 03 '20 at 20:49
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/205323/discussion-between-curiousguy-and-makogan). – curiousguy Jan 03 '20 at 20:50
  • 3
    *`static_cast` adds zero information and zero safety* - from the view of the language parser it sure adds zero information. From the view of Ctrl-F in your editor, or the view of grep, it adds a way of locating all casts for audits/reviews. But given the availability of static code analysis frameworks such as libclang that make it easy to locate any such construct, the admonition against such C-style casts is indeed getting long in the tooth. – Kuba hasn't forgotten Monica Jan 21 '21 at 16:18
  • @Kubahasn'tforgottenMonica "_the view of Ctrl-F_" That could be an argument in O'Caml or other languages where all type conversions are explicit. With all the implicit conversions in C++, there is no chance to find all instances. Also I simply don't believe an `int` to `double` conversion is a such an important or dangerous operation that you need to tag it. – curiousguy Jan 23 '21 at 08:12
15

Deprecated or not, removing this language feature would break existing codes and annoy people.

The whole static deprecation thing was just wishful thinking along the lines of "anonymous namespaces are better than static" and "references are better pointers". Lol.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 3
    "References are better pointers"? No, smart pointers are smarter pointers. You can't use references for memory allocated from the heap, err, free store. – Dan Breslau Jan 18 '11 at 17:06
  • 4
    Sorry, I forgot to end it with an ironic smiley. – Maxim Egorushkin Jan 18 '11 at 17:09
  • 3
    @Dan: That's exactly what this answer says: "wishful thinking" along a similar faulty line of thought. Unnamed namespaces are an important feature, just as global-scope-static is, though for slightly different reasons, and even though they have some overlap in applicability. – Fred Nurk Jan 18 '11 at 17:26
  • @Fred, @Maxim: Sorry if I misunderstood, or if my memory's faulty. But I don't categorize "references are better pointers" as being equivalent to "anonymous namespaces are better than static" as a case of wishful thinking. I'm well aware of the attempt at making the latter stick, but I don't remember anyone making a serious proposal to replace pointers with references. Again, maybe it's my own awareness that's lacking. – Dan Breslau Jan 19 '11 at 01:09
  • @Dan: I do occasionally see people on SO and elsewhere that try to push "references are better pointers", but it of course didn't have the serious effort to remove it from the language that the other did. I think you simply misunderstood, because I can't see that Maxim was ever espousing it himself. *\*shrug\** – Fred Nurk Jan 19 '11 at 03:29
  • @Fred Nurk, @Maxim: OK, that's (at least one place) where we've disconnected: I didn't mean to suggest that Maxim had made that claim himself. The quotes in his post made it clear to me that he was quoting some third party. All I intended was to question whether any *significant* third party had ever made a *serious* claim that "references are better pointers", because I don't see how anyone could even begin to make that case. (I guess I've missed such discussions when they've happened here.) Perhaps I should have said "One can't use references..." instead of "You can't use references..." – Dan Breslau Jan 19 '11 at 03:56
  • @DanBreslau: `You can't use references for memory allocated from the heap, err, free store` Why's that then? – Lightness Races in Orbit Jan 11 '12 at 14:01
  • @Lightness Races in Orbit: That is, you can't do something like `char &foo = new char;`, and you certainly can't `delete foo;` if `foo` is a reference. – Dan Breslau Feb 03 '12 at 23:39
  • 2
    @DanBreslau: `char* foo = new char; char& ref = *foo;` Just because you are given a pointer initially says nothing whatsoever about your ability to use references. – Lightness Races in Orbit Feb 04 '12 at 02:54
  • The point (so to speak :-) is that a reference is always dependent on another variable; you can't *replace* a pointer with a reference variable. (Actually, I suspect you could, but it would require some incredibly ugly hacks that are probably implementation-dependent.) – Dan Breslau Feb 04 '12 at 05:35