Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

Revisiting the Deprecation of File-Scope Static

Last updated Jan 1, 2003.

As opposed to many other programming languages, the standardization of C++ has usually been prudent and measured, thus guaranteeing that most rash design decisions and questionable features remain out of the standard. However, you can still find cases of rash deprecation of useful features in the standard. Take for example the deprecation of file-scope static. Nearly twenty years after that decision, committee members are starting to question it. It's about time.

Three Lame Arguments For Deprecating File-Scope static

File-scope static has been used since K&R C to denote internal linkage for functions and objects that would otherwise have external linkage. Here's an example:

//file app.c
static int func();  //func can only be called from app.c
static long ret_code=0; //ret_code is visible only in app.c
int main()
{
 ret_code=func();
}

Without the static storage type, func() and ret_code would be accessible from other translation units. In C, this technique is a primary means of encapsulation. So why was it deprecated in C++? No one can come up with a convincing argument for the deprecation of file-scope static. I admit that I also fell into this trap years ago, promoting the use of nameless namespaces as a "superior alternative" -- as the standard puts it -- to file-scope static. But what's so superior about nameless namespaces? Nothing, really. Committee members are recently realizing that the deprecation of file-scope static was a mistake, and that nameless namespaces aren't ideal. Before we get to that, let's first see what the excuses for deprecating static were back in the 1990s:

  • Visibility and linkage are two different concepts. When C++ programmers want to guarantee that an entity X shall only be visible from translation unit Y, they don't necessarily care about the linkage of X which is what file-scope static does; they simply want to deny other translation units access to X.
  • Not all C++ implementations are capable of guaranteeing internal linkage for entities declared static.
  • static is already loaded with other meanings in C++.

These claims are easily refuted. Indeed, when programmers want to hide X from other translation units of the same program, they needn't bother about the underlying ABI or how the linker's magic is implemented. However, programmers know that static does get the job done. The fact that C still uses static for that purpose suggests that there's nothing wrong with static.

It is also true that certain implementations aren't capable of guaranteeing internal linkage. Unlike with file-local static, the standard doesn't insist on internal linkage for members of a nameless namespace (the standard is purposely vague about the linkage of nameless namespaces' members). This underspecification was meant to appease certain vendors. However, it leaves C++ programmers unhappy because in some cases they do need to ensure internal linkage for certain entities, as I will show immediately.

The third arguments against file-scope static was a bit cavalier, suggesting that C++ programmers might find file-scope static confusing because the keyword static also denotes static member functions, static data members, and local static variables. Come on! Isn't virtual overloaded with meanings in C++ (for virtual member functions and virtual inheritance)? Should I start describing the dozen meanings of the keyword explicit in C++0x?

Exonerating File-Scope static

Today it's hard to believe that these arguments won. File-scope static is officially deprecated in the C++98 and C++03 standards. It's still deprecated in the C++0x Working Draft. In retrospect, its deprecation was rash and unjustified. It didn't solve any problem because there wasn't any problem with static to begin with. Secondly, the "superior alternative" that the C++ standard prescribes, namely a nameless namespace, is cumbersome, unintuitive (how many programmers understand it?) and worst of all -- committee members are now realizing that linkage is important, especially after the recent changes regarding template arguments' linkage.

There is another problem with the deprecation of file-scope static. The C++ standard itself forces you to use this deprecated feature! When you declare an anonymous union in the global scope, that union has to be declared static because the members of such a union must have internal linkage. When the standard itself forces you to use a deprecated feature, this is a clear sign that the deprecation was a mistake.

In recent months, several committee members have raised some of these issues. They realize that the linkage of entities is too important to be left "implementation-defined", and that nameless namespaces are certainly not a superior alternative to file-scope static. Hopefully, the rash deprecation of file-scope static will be removed from the C++0x standard. It won't be a moment too soon.