The C Charter outlines fifteen basic principles intended to guide the committee when considering changes to the standard. A significant number of recent proposals for changes have been at odds with two of those principles: to codify existing practice, and to avoid invention. This paper discusses the historical foundations of the principles, their value, and some of the problems that have stemmed from disregarding them. It concludes by proposing concrete steps for bringing future committee practice into harmony with the principles.
In the development of the original C standard (C89) the committee was guided by a small set of general, high-level goals. Their focus was primarily on facilitating portability of existing C programs to known or future implementations without sacrificing the expressiveness of the language, compromising the efficiency of implementations, or invalidating important extensions to the common subset. After C89 was ratified, as the committee started work on a revision of the standard, the goals were outlined in the form of specific principles in [The C99 Charter]. As the committee learned from its experience with the successes and failures of each subsequent revision of C, the process it followed to develop it, and important developments in the industry, it updated the charter with additional principles. An important goal of the charter has been to establish an agreed-upon set of acceptance criteria for submitters of change proposals to adhere to. They let the committee evaluate proposals based on objective criteria, and reduced the time spent in protracted and often emotionally charged debates, and lower the risk of failing to judge all proposals consistently.
As the committee was starting to work on the first revision of C, one of the first principles added in 1994 to the original six was the goal of codifying existing practice to fix bugs or limitations. The full description of the principle reads:
8. Codify existing practice to address evident deficiencies. Only those concepts that have some prior art should be accepted. (Prior art may come from implementations of languages other than C.) Unless some proposed new feature addresses an evident deficiency that is actually felt by more than a few C programmers, no new inventions should be entertained.
Unlike in C89 where the focus was primarily on preserving the meaning of existing code, existing practice in the context of this principle refers to existing implementations of the C language: compilers and C standard libraries. The important point worth stressing is that the principle left room for inventive changes provided they were necessary in order to address either flaws or serious limitations that impacted large numbers of programmers. The parenthetical note indicates that it was intended that such changes might be informed by prior art in other languages.
Along with the others, this principle came to form the C9X Charter, first published in N444. The charter noted that the principles in it might involve trade-offs, and that none is absolute or necessarily trumps all the others. However, it also stressed that significant deviations from any one of them would need to be justified by more rationale.
In contrast to the successful reception and rapid and broad adoption of C89, the adoption of C99 was viewed by both programmers and the committee as considerably slower and less successful. It was felt that there was low demand for some of the new C99 features and, as a result, a slow uptake among implementers. To this day, some of their aspects are still waiting to be implemented (e.g., some provisions of restricted pointers and variable length arrays). In light of this experience the committee found it necessary to expand principle #8 in The C1x Charter. Notably, it added the following bullet to the list:
13. Unlike for C9X, the consensus at the London meeting was that there should be no invention, without exception. Only those features that have a history and are in common use by a commercial implementation should be considered. Also there must be care to standardize these features in a way that would make the Standard and the commercial implementation compatible.
The principle was further underscored by a footnote in the Submission Guidelines section that asks proposal authors to explicitly mention the Prior Art of a feature:
This [prior art] should include all commercial implementations and the history of these implementations. An experimental implementation is not considered a commercial implementation.
The driving goal of this principle was to avoid introducing features that due to a lack of implementation or user experience might have flaws or otherwise weren't suitable for standardization, or those that were of questionable utility or of interest only to a minority of users or to a small subset of implementations.
To emphasize the impact for the sake of clarity: this C11 principle removed the C99 latitude to introduce inventive changes to address evident deficiencies. Only mature features shipping in commercial compilers (and system C libraries) that had been relied on in practice for long enough to have had a history of use were to be considered.
Since C17 was meant to be strictly a "bug fix" revision with no impact on conforming implementations no C17 charter was ever created.
Prior to embarking on the development of the current revision of C, C23, the committee reviewed the C1x Charter and reaffirmed it in N2021 - C - Preliminary C2x Charter. No new principles were initially added and none was removed. The footnote below the Submission Guidelines section was moved verbatim into the body of the section itself. The committee review of the preliminary charter confirmed that the principles enshrined in the C1x Charter would apply equally to C2X. The latest revision of the charter as of today is N2611 - Programming Language C - C23 Charter . It adds one new principle for C23 (unrelated to codifying existing practice) without removing or changing any of the historical ones, or substantively changing the Submission Guidelines. In particular, the "no inventive features, without exception" credo remains in place.
Despite the two principles effectively ruling out the adoption of novel, unproven features, each revision of C except C17 contained some new features with little implementation experience and sometimes with no prior art. Ironically, while the C99 Charter didn't preclude introducing novel features, C99 was arguably the most disciplined revision in adhering to the goal of codifying existing practice. With few exceptions most of the new features it introduced were based on at least one commercial implementation of C.
The subsequent C revision, however, C11, whose charter explicitly ruled out invention, entirely disregarded both of these principles in several instances and adopted a number of large and inventive language features despite the absence of prior experience. Chief among them were atomic types as a core language feature with no existing implementation in a shipping compiler, a threads library that was based on a single, little-used third-party implementation, the Analyzability annex with no existing implementation or prior art, and the controversial Annex of Bounds-checking interfaces with just a single implementation that failed to conform to the authors' own specification.
The case of the Bounds-checking annex is especially worthy of note. The annex is based on Technical Report TR 24731-1:2007 Information technology — Programming languages, their environments and system software interfaces — Extensions to the C library — Part 1: Bounds-checking interfaces. The goal recommended by ISO and conventionally pursued by the C committee of publishing a Technical Report is to provide information about the "state of the art" in an area and to gauge the likelihood of the adoption of the material by implementers and users. Successful reports (those with broad adoption) are then typically considered for inclusion in a future standard. Those with poor adoption are usually abandoned.
At the time TR 24731-1 was incorporated into C11 it was no more widely adopted than when it was published. Only a single implementation was in existence, that of the original proposers, and it was not fully conforming. The industry as well as the committee remained divided about the benefits of the interfaces, reflecting the absence of consensus among domain experts. The incorporation of the TR was a dramatic departure from the conventional committee process.
Today, more than a decade after C11 was ratified, both user as well as implementation experience with the unproven features above underscores the wisdom of the principles they parted with. The integration of the atomic types into C and their interoperability with C++ continue to be problematic and the subject of discussion and bug reports. C11 implementations were slow to adopt the often superfluous (in POSIX environments) threads library, and some still haven't. To the author's knowledge the Analyzability annex has never been implemented in any compiler. Implementations of the bounds checking interfaces are still few and far between and those that exist either fail to conform or suffer from other serious problems (including most of those discussed in N1969 - Field Experience With Annex K — Bounds Checking Interfaces). The committee remains as divided on their utility as does the software security industry, while modern technologies have been developed that offer vastly superior alternatives.
With the problems stemming from disregarding the two C11 principles being widely acknowledged, the committee might be expected to have redoubled its effort to avoid repeating the C11 mistakes in C23. The trend, however, has been in the opposite direction. A significant number of recent proposals submitted by long-term committee members and considered for C23 by the full committee are for enhancements that lack implementation experience and have no history in C. Of those that include a Prior Art section some cite extensions in popular implementations but (almost unavoidably) introduce substantive differences or (sometimes gratuitously) add extensions that have no user experience. Others point to similar features in languages other than C or C++, again with no history in C. Others still propose alternate ways of doing things that can be accomplished by existing mechanisms.
As a result of the lack of existing practice to guide its evaluation of proposals, the committee has been spending large amounts of time, in some instances entire days, discussing, dissecting, and refining the proposed features in Design By Committee sessions, moving even the few with prototype implementations ever further away from any practical experience with the redesigned prototype.
The table below surveys a subset of recent C23 proposals that fall into this category. With only rare exceptions mentioned in the Notes column, none of the features has been implemented in the proposed form. Most of the documents in the table are second or subsequent revisions of prior proposals with significant design changes requested in prior committee review, typically without any implementation experience, and thus with no user experience with the result.
It should be emphasized that most of the proposals are well thought out and the features might ultimately make good additions to C. The problems being brought to light here are the lack of implementation experience and history of use in practice, both of which are called out as nonnegotiable in the charter.
|N2809||Annex K Repairs||No||Might silently change behavior of existing code.|
|N2891||Type inference for variable definitions and function returns||C++|
|N2892||Basic lambdas for C||C++|
|N2893||Options for lambdas||C++|
|N2895||A simple defer feature for C||GCC, MSVC, POSIX||Novel interface to several extensions.|
|N2851||The constexpr specifier||C++|
|N2852||Queryable pointer alignment||No||Similar to MSVC IS_ALIGNED macro.|
|N2898||Preprocessor embed||No||Prototype implemented by author in Clang and GCC.|
|N2780||Forward Declaration of Parameters||GCC||Failed GCC feature with poor adoption.|
|N2955||Introduce storage-class specifiers for compound literals||No||Novel enhancement to a GCC extension.|
|N2965||Modern Bit Utilities||Clang, GCC||Enhanced interface to a Clang extension. Implemented by author in a 3rd party library.|
|N2962||__supports_literal||No||New preprocessor directive.|
|N2859||break break||No||New language statement, an alternative to goto.|
|N2853||The void-which-binds: type-safe parametric polymorphism||No||New attributes.|
|N2787||Wide Function Pointer Types for Pairing Code and Data||Borland C++|
|N2920||Tail-call elimination||No||New language statement to control a common optimization.|
|N2577||A Provenance-aware Memory Object Model for C||No||Widespread changes with no prototype and an unknown impact on implementations.|
To resolve the conflict between the charter and committee's actions in recent years and to avoid repeating the past mistakes that the principles outlined in the charter were added to avoid, we recommend taking the following steps.