6

Why did the original C language not support initial declarations in for loop initializations?

Obviously the original creators, and then the pre-C99 standardizations, didn't specify it that way. But I can't seem to find any rationale for why that design choice was made.

The closest thing to an answer I seem to find is this answer explaining how mixing declarations and code was prohibited in order to allow for compilers to be single-pass back when that was important. At first glance it makes sense that declarations in a for loop statement would have the same/similar problems as declarations mixed with code.

But, pre-C99 C did support declarations at the start of blocks:

{
    unsigned int i;
    for(i = 0; i < WHATEVER; i += 1)
    {
        /* ... */
    }
}

I don't personally see how the compiler logic for that is substantially different than for this:

for(unsigned int i = 0; i < WHATEVER; i += 1)
{
    /* ... */
}

Seems to me that if a compiler can do the former single-pass, it could also do the latter. It might require that a for statement always create a scope block (even if followed by just one statement and not a { ... } block of statements), but I can't think of a way for such semantics to break any other pre-C99 C code (either the for statement is followed by a block in which case it's already "scoped", or it's followed by a single statement, in which case a new declaration wouldn't have been allowed in that single statement anyway).

So, why was this syntax "feature" initially omitted? Am I wrong in thinking that it would've been trivial to support without violating performance goals of the time? Did known language parser/compiler techniques at the time make it seem harder? Did it just get omitted because of minimalist design/mentality, since functionally it was possible to do the same thing (block around for loop)? Or was there an explicit language design reason against it (e.g. how Go initially excluded exceptions because the designers thought that made for a better language)?

Where I've looked

  • I've tried finding an answer to this here and through general web-search-fu, with no luck: all search terms I thought of seem to be saturated with confused questions about C for loop initial declarations, the "used outside of C99 mode" error message, etc. (Except the search term "rationale", which guided me to useful information, but nothing that answered this specifically).
  • I searched over this article by Dennis Ritchie himself on developing the language, and didn't spot anything.
  • I searched through my copy of The C Programming Language (2nd Edition), first reading the actual for loop explaining section, then checking the index for other mentions of the "for"/"for loop". I've read over a couple of other places I thought might mention it, but found nothing.
Community
  • 1
  • 1
mtraceur
  • 3,254
  • 24
  • 33
  • 1
    Before C99, C did not allow you to define variables except at the start of a block. Variables defined in the control part of a `for` loop were not at the start of a block, so there was no expectation that they'd be supported. C++ introduced both concepts (define variables anywhere in a block, and variables defined in the control part of a `for` loo) — and C99 added them too. – Jonathan Leffler Jan 31 '16 at 08:42
  • The only people who can answer this are the authors, anyone else would just be speculating. These types of questions are considered off-topic. – cimmanon Jan 31 '16 at 14:10
  • @JonathanLeffler I upvoted your comment. Do you think it would be better incorporated into the currently given answer? It's similar to the "not adding features unless programmers are stopped from getting something done" idea in the answer, but captures a slightly different way of looking at the problem. – mtraceur Jan 31 '16 at 17:23
  • @cimmanon I don't think so (for a meaning of "speculation" that is sufficiently different from "sound reasoning based on the available evidence" to be useful): Historical evidence of prevailing thought at the time (quotes of computer scientists from the time), technical evidence of how it would worsen performance of compilers back then, or even sound logical reasoning could also produce an answer more certain/objective than just speculation. – mtraceur Jan 31 '16 at 17:31
  • 1
    Peter's paragraph beginning "Before 1999" and the next covers my point in slightly different wording; I don't think there's a need to edit his answer to cover my point. – Jonathan Leffler Jan 31 '16 at 17:35
  • @JonathanLeffler Alright. When I read it, I feel that the sentence component "so there was no expectation that they'd be supported" in your comment makes explicit an "it wasn't there before, why add it now?" aspect which is more implicit in Peter's answer. Still, if that's not something you think adds value to the answer, I'm not going to push it further - just wanted to explain my reasoning more. – mtraceur Jan 31 '16 at 17:46
  • @mtraceur See: http://meta.stackoverflow.com/questions/292416/is-a-question-that-can-only-be-answered-correctly-by-a-small-group-of-people-a-b – cimmanon Jan 31 '16 at 17:50

1 Answers1

12

I don't believe there was any specific decision to exclude such features, nor rationale mounted to do so.

As romantic as it may seem to believe the designers (Kernighan, Ritchie, etc) thought of all the possibilities, and excluded features only after deep and meaningful consideration, the reality is that the early years of designing C (like quite a few other programming languages) followed a much more humble philosophy something like "Start small, don't sweat about adding features unless programmers are being PREVENTED from doing something".

Features like variable initialisation in for loops are programmer convenience - their absence didn't stop things being done. So, even if there was someone begging or campaigning for such a feature (which there probably wasn't), it probably went down in the priority order.

As to how things evolved .....

Before 1999, variable declarations were at the start of blocks in C (code commenced with { and ending at the closing }), not within other statements. This is the way things originally worked in pre-standard (K&R) C, and preceding languages like B (which was actually a cut-down derivative of preceding languages).

Variable declaration/initialisation within a for loop was introduced first into C++. It appeared pretty early on (e.g. Section 19 in the ARM), and was eventually introduced in the first C++ standard that was ratified in late 1998.

There was some discussion in the C standard committee, during the process of drafting the C++ standard (which took a decade) about adopting some features of C++ into C. That discussion was often mostly along the lines of "would anything else in C break if we added this?". A number of compiler vendors had already implemented several such features into their C compilers as optional extensions (or their C compilers were actually C++ compilers, with settings to disable C++ features incompatible with C), so discussion about adding those features was pretty brief. Therefore, those features easily added to C from C++ appeared in the 1999 C standard. Variable declaration/initialisation within a for loop was one of those features.

From that history, there is no evidence of any particular decision or rationale to exclude such features from early C - in short, it probably simply wasn't thought of.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • 3
    K&R were just fed-up writing assembler and wanted a language that was simple and would translate nearly directly into assembler so they could continue working on UNIX. In my early days (1983), a good C programmer was someone who knew what assembler the compiler generated. – Paul Ogilvie Jan 31 '16 at 09:37
  • I think this answer would be even better with actual sources linked for certain hard-to-trivially-verify-with-a-google truth-claims (e.g. C design committee discussions re: "would anything in C break", and that "don't add features unless people are prevented from doing something" was a design philosophy commonly adopted back then). I totally find those believable based on what I know, but it would reinforce the parts that are the most likely to feel the most "un-objective" to some. Either way, unless something better comes along, I will accept this answer in another day or so. – mtraceur Jan 31 '16 at 17:39
  • 2
    Find the C99 Rationale. Near the start (first page of the introduction) it says: _The … overall goal was to develop a clear, consistent, and unambiguous Standard for [C] which codifies the common, existing definition of C and which promotes the portability of user programs… The original X3J11 charter clearly mandated codifying common existing practice, and the C89 Committee held fast to precedent wherever that was clear and unambiguous. The vast majority of the language … was precisely the same as defined in Appendix A of … The C Programming Language by Brian Kernighan and Dennis Ritchie…_ – Jonathan Leffler Jan 31 '16 at 19:11
  • @JonathanLeffler: I wish compiler writers would recognize that Undefined Behavior was meant as an invitation for compiler writers to use judgment with regard to precedents and the needs of programmers (which would often vary depending upon target platform and application field), rather than as an invitation to throw judgment out the window. If certain kinds of implementations have unanimously treated a certain action a certain way even though the Standard doesn't require it, it would seem implausible to think the authors of the Standard intended... – supercat Feb 21 '17 at 22:56
  • ...that compiler writers interpret the lack of a mandate as judgment that such precedent should be ignored. – supercat Feb 21 '17 at 23:02