348

Maybe I am not from this planet, but it would seem to me that the following should be a syntax error:

int a[] = {1,2,}; //extra comma in the end

But it's not. I was surprised when this code compiled on Visual Studio, but I have learnt not to trust MSVC compiler as far as C++ rules are concerned, so I checked the standard and it is allowed by the standard as well. You can see 8.5.1 for the grammar rules if you don't believe me.

enter image description here

Why is this allowed? This may be a stupid useless question but I want you to understand why I am asking. If it were a sub-case of a general grammar rule, I would understand - they decided not to make the general grammar any more difficult just to disallow a redundant comma at the end of an initializer list. But no, the additional comma is explicitly allowed. For example, it isn't allowed to have a redundant comma in the end of a function-call argument list (when the function takes ...), which is normal.

So, again, is there any particular reason this redundant comma is explicitly allowed?

Columbo
  • 57,033
  • 7
  • 145
  • 194
Armen Tsirunyan
  • 120,726
  • 52
  • 304
  • 418
  • Note also that VIM's syntax indentation appears to push this style - I've found that indentation can be an issue if you don't use that extra comma. – new123456 Aug 12 '11 at 17:34
  • 12
    Every one seems to be agreeing to 'ease of adding new line' - but are _people_ defining language specifications really bother about such things? If they are really that understanding then why don't they ignore a missing `;` when it's clear next token is actually a next statement. – YetAnotherUser Aug 12 '11 at 17:54
  • 36
    @YetAnotherUser: Yes, language designers consider such things. Allowing you to drop semicolons would have a much larger impact and would be highly ambiguous in many parts of the language (remember, whitespace is not semantic in C). An extra comma is this case is not ambiguous. An extra semicolon is almost never ambiguous, and so is allowed as well. In the case where it is ambiguous (after a `for()` for instance), adding it throws a compiler warning. – Rob Napier Aug 12 '11 at 19:03
  • @Rob: +1, but a semicolon after a `for()` is not "ambiguous" at all. – Lightness Races in Orbit Aug 12 '11 at 20:47
  • 5
    @Tomalak: It is ambiguous to a human reader, and is often a mistake. That is why it throws a warning. Similarly `if (x = 1)` is not ambiguous in the grammar, but it is very ambiguous to humans, and thus throws a warning. – Rob Napier Aug 12 '11 at 20:54
  • 3
    @Rob: How it is ambiguous? It's well-defined what `for (a; b; c);` means. There is _no_ ambiguity here, neither for the compiler nor for the programmer. That it's often a mistake and easy to miss _is_ pertinent. – Lightness Races in Orbit Aug 12 '11 at 20:56
  • 12
    @Rob: Your `if` example is not ambiguous either. I don't think "ambiguous" means what you think it means! – Lightness Races in Orbit Aug 12 '11 at 20:57
  • 4
    @Tomalak: You're right in that it's unambiguous, but 87% of the time, it's also not what the programmer wants. – 3Doubloons Aug 12 '11 at 21:10
  • 1
    I've shot myself in the foot a couple times with this issue in javascript; IE (of course) doesn't like it and barfs when it finds one, but other browsers accept it. – jches Aug 12 '11 at 21:12
  • 1
    @Alex: Indeed. But "ambiguous" is not the correct term. – Lightness Races in Orbit Aug 12 '11 at 21:13
  • 5
    As long as we agree that it is something useful for the compiler to protect us from, while a trailing comma in an array declaration is not something useful for the compiler to protect us from. – Rob Napier Aug 12 '11 at 21:38
  • 1
    Reverse your question, and you end up with: "Why should this be **explicitly** disallowed?" Do you have an answer for _that_? – Lightness Races in Orbit Aug 12 '11 at 20:44
  • 3
    I find this feature indispensable, and it raises my ire to no end when I deal with languages that do forbid the trailing comma (SQL, I'm lookin' at *you*) – SingleNegationElimination Aug 13 '11 at 14:21
  • What's most surprising in this subject, is how such trivialities evoke such disproportional interest and voting frenzy. – Gene Bushuyev Aug 13 '11 at 19:57
  • 1
    Definitely useful and often seen in enum –  Aug 13 '11 at 23:19
  • 1
    Several related questions: http://stackoverflow.com/questions/2311864/history-of-trailing-comma-in-programming-language-grammars , http://stackoverflow.com/questions/6372650/trailing-commas-and-c , http://stackoverflow.com/questions/792753/is-the-last-comma-in-c-enum-required , http://stackoverflow.com/questions/2361265/why-is-this-c-snippet-legal . The last one could be argued to be a dupe, although it's asking for C# instead of C++. – Johannes Schaub - litb Aug 14 '11 at 10:04
  • 1
    @GeneBushuyev: http://en.wikipedia.org/wiki/Parkinson%27s_law_of_triviality – radomaj Jan 16 '15 at 16:22
  • I wish it was allowed for template parameters, too! – Benji Mizrahi Apr 23 '18 at 11:25
  • What about when using the Yoda comma? int a[] = {,1,2}; https://stackoverflow.com/questions/10483635 – Quentin 2 Apr 25 '18 at 11:56
  • I don't know how many of you use SQL, but it does not have this feature and commas there can feel absolutely antagonistic. I'm so happy to know the C and C++ developers took time to make this one little thing that much easier to use. (and so many others we often don't even think of) And this thread is great! Now I know indeed, this is NOT undefined in any way shape or form and I AM allowed to use it. And it was the question that answered me. – ebyrob May 01 '20 at 13:51

20 Answers20

443

It makes it easier to generate source code, and also to write code which can be easily extended at a later date. Consider what's required to add an extra entry to:

int a[] = {
   1,
   2,
   3
};

... you have to add the comma to the existing line and add a new line. Compare that with the case where the three already has a comma after it, where you just have to add a line. Likewise if you want to remove a line you can do so without worrying about whether it's the last line or not, and you can reorder lines without fiddling about with commas. Basically it means there's a uniformity in how you treat the lines.

Now think about generating code. Something like (pseudo-code):

output("int a[] = {");
for (int i = 0; i < items.length; i++) {
    output("%s, ", items[i]);
}
output("};");

No need to worry about whether the current item you're writing out is the first or the last. Much simpler.

Peter Alexander
  • 50,304
  • 10
  • 114
  • 163
Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • 1
    This is especially if you were using macros to add items to arrays. Using macros don't have the smarts to distinguish when not to add a comma, or rather adding such logic makes macros inherently more complex. – Ryan Aug 12 '11 at 20:43
  • 93
    Also, when using an VCS, the "diff" between two versions is cleaner since only one line changes when an item is added or removed. – Kevin Panko Aug 12 '11 at 21:05
  • 4
    If the justification is to make code generation simpler, then why not adopt the no parenthesis style of some funcional languages? and why not to infer all types? and remove the semicolons? and so on. I think the real reason was a very subjective and unfortunate criteria of the language designers. – Néstor Sánchez A. Aug 13 '11 at 00:20
  • 48
    @Néstor: Why "unfortunate"? What's the downside here? Just because some consideration has been given to code generation (and easy manipulation) for *one tiny part of the language* doesn't mean it has to be the primary motivation behind all decisions in the language. Type inference, removal of semi-colons etc have *huge* implications for the language. You're setting up a false dichotomy here, IMO. – Jon Skeet Aug 13 '11 at 05:59
  • 4
    Unfortunate because is inconsistent with other rules such as commas between method arguments, why the code-generation guys didn't get "helped" there? My reference to type inference, removal of semi-colons, etc. were to put an exaggerated example of a great help for code-generation. In other words, IMHO, or the language is fully consistent or is fully code-generation oriented. – Néstor Sánchez A. Aug 13 '11 at 22:43
  • 18
    @Néstor: That's where pragmatism wins over dogmatism: why does it have to be *fully* one thing or *fully* the other, when it's more *useful* to be a mixture of both? How does it actually get in the way, being able to add a comma at the end? Is this an inconsistency which has ever impeded you in any sense? If not, please weigh that irrelevant inelegance against the practical *benefits* of allowing a comma at the end. – Jon Skeet Aug 13 '11 at 22:47
  • 4
    its supported in a number of other languages besides c++ as well i know that php and c# support this so its not a c++ only thing – Chris McGrath Aug 14 '11 at 02:10
  • I once stumbled across this issue when I wrote a script generating C code describing a 3D-Model and was happy that I didn't have to handle the last entry separately. – h0b0 Aug 15 '11 at 11:21
  • 1
    Generating code - can we say its done 10% or less times; rest of the time it involves _typing_ in code. Statistically significant or not, those ferocious coders who blast off 100s of characters per minute, cannot afford to type in 2 more (or 20 more for that matter) characters? I'm not complaining, but this justification seems odd. I think it makes life easy on someone else's side, MS maybe? – Mrchief Aug 17 '11 at 04:09
  • 8
    @Mrchief: It's not a matter of typing rate - it's a matter of simplicity, when copying, removing or reordering items. It made my life simpler just yesterday. With no downside, why *not* make life easier? As for trying to point the finger at MS, I strongly suspect this has been in C since before Microsoft even existed... You say this justification seems odd, but I bet it benefits thousands of developers across hundreds of companies every single day. Isn't that a better explanation than looking for something that benefits compiler writers? – Jon Skeet Aug 17 '11 at 05:17
  • Totally with you, my thought is, why not make life easier in other places too? As a sidenote and a bit ironically, another MS product totally despises the trailing comma. :) – Mrchief Aug 17 '11 at 05:53
  • 1
    @Mrchief: I *suspect* it wouldn't be nearly as useful in other places - because most other places don't use a homogeneous list of items. For example, for method calls, reordering parameters is something which generally takes a lot more care due to the type system. The position makes a *semantic* difference, not just an order-of-appearance difference. (This doesn't hold as much water for named arguments, of course.) It feels like this was a single "let's put it in for this case for pragmatic reasons, but keep the language itself simpler elsewhere" decision. – Jon Skeet Aug 17 '11 at 06:02
  • Well, I was referring to other things, such as being able to say: `public property int Index;` (for auto-implemented properties primarily) which is much easier to type in (less chars, all in same row), more readable than ugly `public int Index { get; set; };` and I guess tad easier for code generation as well. – Mrchief Aug 17 '11 at 14:23
  • @Mrchief: Introducing new keywords after release is a tricky business. It's possible that this wouldn't cause any problems (like other contextual keywords), but I'm not entirely sure... and how would you make a public "getter" with a private "setter" that way? I wouldn't want to have two different syntaxes for it... (Personally I wish field-like events were declared as public event EventHandler Foo { add; remove; }; to make them clearer, but there we go...) – Jon Skeet Aug 17 '11 at 14:26
  • 1
    "another MS product totally despises the trailing comma" -- I think Mrchief was really talking about object and array literals in IE6, IE7, and IE8 too IIRC. – Roy Tinker Nov 17 '11 at 18:21
  • @NéstorSánchezA. I posted an [answer](http://stackoverflow.com/a/31726237/2567683) on this rationale, as expressed in _"Deep C secrets"_ – Nikos Athanasiou Jul 30 '15 at 14:27
  • I wonder if any languages use item-intiator or statement-initiator characters? If e.g. a language required each item of a list, including the first, to be preceded by a colon, then adding items to a list anywhere, whether at the beginning or end, would pose no problem, and in cases where an item or statement needed to span multiple lines, the lack of an item-initiator character on the next line might be more conspicuous than the lack of an item-terminator or item-separator at the end of the previous line. – supercat Aug 01 '15 at 19:36
  • This reminds me of the Oxford Comma debate. In any case, especially for matrix definitions, I think allowing the comma is much better: each line has a well-defined index-independent syntax. This is coding, not English! – djconnel Oct 07 '15 at 01:45
  • @Mrchief the annotated C++ reference manual says this came from C and the C99 rationale which I quote in my [answer below](http://stackoverflow.com/a/33213830/1708801) says *provides flexibility in adding or deleting members from an initializer list, and simplifies machine generation of such lists*. – Shafik Yaghmour Nov 05 '15 at 21:26
127

It's useful if you do something like this:

int a[] = {
  1,
  2,
  3, //You can delete this line and it's still valid
};
Skilldrick
  • 65,202
  • 32
  • 168
  • 226
37

Ease of use for the developer, I would think.

int a[] = {
            1,
            2,
            2,
            2,
            2,
            2, /*line I could comment out easily without having to remove the previous comma*/
          }

Additionally, if for whatever reason you had a tool that generated code for you; the tool doesn't have to care about whether it's the last item in the initialize or not.

vcsjones
  • 128,004
  • 28
  • 283
  • 274
31

I've always assumed it makes it easier to append extra elements:

int a[] = {
            5,
            6,
          };

simply becomes:

int a[] = { 
            5,
            6,
            7,
          };

at a later date.

Oliver Charlesworth
  • 252,669
  • 29
  • 530
  • 650
  • 3
    I do not think making editing slightly faster is a good reason for messing up the syntax. IMHO this is just another weird C++ feature. – Giorgio Aug 12 '11 at 20:59
  • 3
    @Giorgio: Well, it's inherited from C. It's entirely possible that it's just an oversight in the original language specification, that happens to have a useful side-effect. – Oliver Charlesworth Aug 12 '11 at 21:01
  • Ok, I didn't know that it comes from C. I just checked that it is allowed in Java, too. It feels kind of weird though: in my intuition the comma is a separator not a terminator. Furthermore, it is possible to omit the last comma. So, is it a terminator, a separator, or both? But OK, this feature is available and it is good to know. – Giorgio Aug 12 '11 at 21:16
  • 11
    @Giorgio - source code is for humans, not machines. Little things like this to keep us from making simple transposition errors are a blessing, not an oversight. For reference, it also works this way in PHP and ECMAScript (and therefore JavaScript and ActionScript), although it is invalid in JavaScript object notation (JSON) (e.g. `[1,2,3,]` is OK but `{a:1, b:2, c:3,}` is not). – Dereleased Aug 12 '11 at 21:51
  • @Giorgio - I'd say that rather than messing up the syntax, this improves the syntax. I can't count the number of times I've been glad you can do this. – Grokys Aug 12 '11 at 23:32
  • It's also allowed in the latest C# specification – Dan Diplo Aug 13 '11 at 08:46
  • 1
    @Groky: The more I think about it the more I am convinced that the syntax of a programming language should be as simple and consistent as possible and with as few exceptions as possible: this makes it easier to learn the language (fewer rules to remember). The advantage of saving one or two keystrokes when adding / removing an item to / from a list (which, by the way, I do not do that often compared to the total amount of time I spend coding) seems rather trivial to me compared to having a clearly defined syntax. – Giorgio Aug 18 '11 at 06:10
  • @Giorgio: And this is consistent: "foo = 1," wherever in the array that entry is. – Grokys Aug 18 '11 at 10:54
  • @Giorgio I posted an [answer](http://stackoverflow.com/a/31726237/2567683) considering this, as found in the book "Deep C secrets" – Nikos Athanasiou Jul 30 '15 at 14:30
21

Everything everyone is saying about the ease of adding/removing/generating lines is correct, but the real place this syntax shines is when merging source files together. Imagine you've got this array:

int ints[] = {
    3,
    9
};

And assume you've checked this code into a repository.

Then your buddy edits it, adding to the end:

int ints[] = {
    3,
    9,
    12
};

And you simultaneously edit it, adding to the beginning:

int ints[] = {
    1,
    3,
    9
};

Semantically these sorts of operations (adding to the beginning, adding to the end) should be entirely merge safe and your versioning software (hopefully git) should be able to automerge. Sadly, this isn't the case because your version has no comma after the 9 and your buddy's does. Whereas, if the original version had the trailing 9, they would have automerged.

So, my rule of thumb is: use the trailing comma if the list spans multiple lines, don't use it if the list is on a single line.

amoss
  • 1,471
  • 1
  • 12
  • 27
15

Trailing comma I believe is allowed for backward compatibility reasons. There is a lot of existing code, primarily auto-generated, which puts a trailing comma. It makes it easier to write a loop without special condition at the end. e.g.

for_each(my_inits.begin(), my_inits.end(),
[](const std::string& value) { std::cout << value << ",\n"; });

There isn't really any advantage for the programmer.

P.S. Though it is easier to autogenerate the code this way, I actually always took care not to put the trailing comma, the efforts are minimal, readability is improved, and that's more important. You write code once, you read it many times.

Gene Bushuyev
  • 5,294
  • 17
  • 19
  • 7
    I disagree completely; [It is my opinion that] it has found its way into many languages created long after C precisely because it is advantageous for the programmer to be able to shift around the contents of the array, comment out lines willy-nilly, and so on, without having to worry about silly transposition-induced syntax errors. Are we not already stressed enough? – Dereleased Aug 12 '11 at 21:54
  • 12
    @Dereleased -- by the same logic, why shouldn't trailing (anything) be allowed, how about `int a = b + c +;` or `if(a && b &&);` it will be easier to just copy-and-paste anything at the end and easier to write code generators. This issue is both trivial, and subjective, in such cases it's always good to do what's best for the code reader. – Gene Bushuyev Aug 12 '11 at 22:06
  • 1
    @Gene Bushuyev: Exactly! I often have long expressions with + or &&, with the operator at the end of the line and, of course, I have to spend some extra time when I want to remove the last operand of the expression. I think this comma syntax is really odd! – Giorgio Aug 18 '11 at 06:15
  • 2
    @GeneBushuyev - I disagree on those. While allowing trailing commas in arrays and the like is a bug-removing feature and makes your life easier as a programmer, I would for the pure sake of readability take measures to remove trailing AND (&&) statements, plusses and other miscellaneous operators from conditional statements. It's just plain ugly, IMO. – Sune Rasmussen Nov 22 '11 at 09:25
  • 2
    Regarding the `&&` operator, sometimes I do conditionals like `if (true \n && b1 \n && b2)` so that I can add and remove lines as I need to. – Christian Mann Jun 04 '16 at 14:12
13

I am surprised after all this time no one has quoted the Annotated C++ Reference Manual(ARM), it says the following about [dcl.init] with emphasis mine:

There are clearly too many notations for initializations, but each seems to serve a particular style of use well. The ={initializer_list,opt} notation was inherited from C and serves well for the initialization of data structures and arrays. [...]

although the grammar has evolved since ARM was written the origin remains.

and we can go to the C99 rationale to see why this was allowed in C and it says:

K&R allows a trailing comma in an initializer at the end of an initializer-list. The Standard has retained this syntax, since it provides flexibility in adding or deleting members from an initializer list, and simplifies machine generation of such lists.

Shafik Yaghmour
  • 143,425
  • 33
  • 399
  • 682
  • 2
    Upvote for the most backed-up answer by literature, and the true source of this feature. – Marko Apr 01 '20 at 14:02
13

One of the reasons this is allowed as far as I know is that it should be simple to automatically generate code; you don't need any special handling for the last element.

Fredrik Pihl
  • 41,002
  • 6
  • 73
  • 121
12

I see one use case that was not mentioned in other answers, our favorite Macros:

int a [] = {
#ifdef A
    1, //this can be last if B and C is undefined
#endif
#ifdef B
    2,
#endif
#ifdef C
    3,
#endif
};

Adding macros to handle last , would be big pain. With this small change in syntax this is trivial to manage. And this is more important than machine generated code because is usually lot of easier to do it in Turing complete langue than very limited preprocesor.

Yankes
  • 1,601
  • 16
  • 18
12

It makes code generators that spit out arrays or enumerations easier.

Imagine:

std::cout << "enum Items {\n";
for(Items::iterator i(items.begin()), j(items.end); i != j; ++i)
    std::cout << *i << ",\n";
std::cout << "};\n";

I.e., no need to do special handling of the first or last item to avoid spitting the trailing comma.

If the code generator is written in Python, for example, it is easy to avoid spitting the trailing comma by using str.join() function:

print("enum Items {")
print(",\n".join(items))
print("}")
Maxim Egorushkin
  • 119,842
  • 14
  • 147
  • 239
6

The reason is trivial: ease of adding/removing lines.

Imagine the following code:

int a[] = {
   1,
   2,
   //3, // - not needed any more
};

Now, you can easily add/remove items to the list without having to add/remove the trailing comma sometimes.

In contrast to other answers, I don't really think that ease of generating the list is a valid reason: after all, it's trivial for the code to special-case the last (or first) line. Code-generators are written once and used many times.

Vlad
  • 33,616
  • 5
  • 74
  • 185
6

It allows every line to follow the same form. Firstly this makes it easier to add new rows and have a version control system track the change meaningfully and it also allows you to analyze the code more easily. I can't think of a technical reason.

Mark B
  • 91,641
  • 10
  • 102
  • 179
6

The only language where it's - in practice* - not allowed is Javascript, and it causes an innumerable amount of problems. For example if you copy & paste a line from the middle of the array, paste it at the end, and forgot to remove the comma then your site will be totally broken for your IE visitors.

*In theory it is allowed but Internet Explorer doesn't follow the standard and treats it as an error

Thomas Bonini
  • 40,716
  • 28
  • 117
  • 153
  • JavaScript's "arrays" (which are just objects with a magical length property) are rather unusual anyway: `var x = [,,,]` is legal (except in IE < 9, but the spec says it's legal) – Peter C Aug 12 '11 at 21:12
  • According to the ECMAScript specification, it's perfectly valid; in theory it should work in any browser that implements JavaScript according to the said specification, particularly [the part of the specification found here](http://bclary.com/2004/11/07/#a-11.1.4). – Dereleased Aug 12 '11 at 21:59
  • 1
    Unfortunately JavaScript is all about making apps for the public. So no, it's not perfectly valid when ~50% users would have problems using your app. And yes, if I could I'd ban IE < 9 -- just too much hours spend on just making **good code** working there... – kgadek Aug 12 '11 at 22:44
  • @Dere: yes, I said as much in my answer =) – Thomas Bonini Aug 12 '11 at 22:48
  • @Dereleased microsoft invents its own specifications and commands that other abide at least that mentality is changing (thank god) – Chris McGrath Aug 14 '11 at 02:14
  • @Andreas Bonini: The problem you describe can be solved by running a syntax checker on your code before shipping. – Giorgio Aug 18 '11 at 06:17
6

It's easier for machines, i.e. parsing and generation of code. It's also easier for humans, i.e. modification, commenting-out, and visual-elegance via consistency.

Assuming C, would you write the following?

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    puts("Line 1");
    puts("Line 2");
    puts("Line 3");

    return EXIT_SUCCESS
}

No. Not only because the final statement is an error, but also because it's inconsistent. So why do the same to collections? Even in languages that allow you to omit last semicolons and commas, the community usually doesn't like it. The Perl community, for example, doesn't seem to like omitting semicolons, bar one-liners. They apply that to commas too.

Don't omit commas in multiline collections for the same reason you don't ommit semicolons for multiline blocks of code. I mean, you wouldn't do it even if the language allowed it, right? Right?

Louis
  • 2,216
  • 1
  • 15
  • 15
  • There are languages (e.g. Pascal) that allow that. I.e. you have to choose between ; as a terminator (C) or as a separator (Pascal). Same for ','. It would be ok for me if ',' is a terminator, but then {1, 2, 3} must be a syntax error. – Giorgio Aug 18 '11 at 06:19
5

This is allowed to protect from mistakes caused by moving elements around in a long list.

For example, let's assume we have a code looking like this.

#include <iostream>
#include <string>
#include <cstddef>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof *(array))
int main() {
    std::string messages[] = {
        "Stack Overflow",
        "Super User",
        "Server Fault"
    };
    size_t i;
    for (i = 0; i < ARRAY_SIZE(messages); i++) {
        std::cout << messages[i] << std::endl;
    }
}

And it's great, as it shows the original trilogy of Stack Exchange sites.

Stack Overflow
Super User
Server Fault

But there is one problem with it. You see, the footer on this website shows Server Fault before Super User. Better fix that before anyone notices.

#include <iostream>
#include <string>
#include <cstddef>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof *(array))
int main() {
    std::string messages[] = {
        "Stack Overflow",
        "Server Fault"
        "Super User",
    };
    size_t i;
    for (i = 0; i < ARRAY_SIZE(messages); i++) {
        std::cout << messages[i] << std::endl;
    }
}

After all, moving lines around couldn't be that hard, could it be?

Stack Overflow
Server FaultSuper User

I know, there is no website called "Server FaultSuper User", but our compiler claims it exists. Now, the issue is that C has a string concatenation feature, which allows you to write two double quoted strings and concatenate them using nothing (similar issue can also happen with integers, as - sign has multiple meanings).

Now what if the original array had an useless comma at end? Well, the lines would be moved around, but such bug wouldn't have happened. It's easy to miss something as small as a comma. If you remember to put a comma after every array element, such bug just cannot happen. You wouldn't want to waste four hours debugging something, until you would find the comma is the cause of your problems.

Konrad Borowski
  • 9,885
  • 2
  • 50
  • 68
4

Like many things, the trailing comma in an array initializer is one of the things C++ inherited from C (and will have to support for ever). A view totally different from those placed here is mentioned in the book "Deep C secrets".

Therein after an example with more than one "comma paradoxes" :

char *available_resources[] = {
"color monitor"           ,
"big disk"                ,
"Cray"                      /* whoa! no comma! */
"on-line drawing routines",
"mouse"                   ,
"keyboard"                ,
"power cables"            , /* and what's this extra comma? */
};

we read :

...that trailing comma after the final initializer is not a typo, but a blip in the syntax carried over from aboriginal C. Its presence or absence is allowed but has no significance. The justification claimed in the ANSI C rationale is that it makes automated generation of C easier. The claim would be more credible if trailing commas were permitted in every comma-sepa-rated list, such as in enum declarations, or multiple variable declarators in a single declaration. They are not.

... to me this makes more sense

Nikos Athanasiou
  • 24,831
  • 11
  • 72
  • 136
  • 2
    The prohibition against the comma in the `enum` case is somewhat interesting, since that's the case where the missing comma would pose the least ambiguity. Given `struct foo arr[] = {{1,2,3,4,5}, {3,4,5,6,7}, }`; there are two sensible meanings the language could assign: create a two-element array, or create a three-element array where the last item has default values. If C had adopted the later interpretation, I could see forbidding `enum foo {moe, larry, curly, };` on the principle that there should only be one way to write the statement (without the comma), but... – supercat Aug 01 '15 at 19:40
  • 1
    ...given that C is willing to ignore the comma in a case where it could reasonably have been (but wasn't) assigned a significant meaning (which would be a strong argument in favor of forbidding it there) it's curious that it isn't willing in a case where the comma couldn't have a meaning [even if one interpreted `enum foo {moe,,larry,curly,};` as skipping a number between `moe` and `larry`, it wouldn't generally matter whether the trailing comma was processed or ignored. The only case where it could matter would be if the last item was the maximum value for its declared type, and that... – supercat Aug 01 '15 at 19:44
  • 1
    ...could be handled by simply saying that overflow which occurs following the last assigned enumeration value should be ignored. – supercat Aug 01 '15 at 19:44
  • @supercat There are languages, like C#, where a priori design research goes as far as considering IDE features and integration when devoloping the language. C was not (and couldn't have been) one of these languages. – Nikos Athanasiou Aug 05 '15 at 12:43
  • Even with languages like C#, changing design objectives have resulted in some pretty severe design inconsistencies. For example, the language refrained from supporting any form of return-type overloading for normal methods and operators (even though the underlying framework could support it) because it was seen as contrary to the goal of having a simple-to-compile language, but lambda evaluation includes type inference rules whose resolution is NP-complete. Adding new method/operator overloading rules might break existing code (though I think good rules could minimize such danger)... – supercat Aug 05 '15 at 14:57
  • ...but I don't see such issues in C's trailing-comma rules. IMHO, one of the major factors in deciding what to allow/forbid should be whether people who generally knew a language but not a particular feature would likely to incorrectly guess that feature's meaning. By that standard, `int foo[] = {1,2,};` is much more dangerous than `enum {LARRY, CURLY, };`, and it is unlikely that the meaning of any existing code (including code allowed via compiler extensions) would change mening if the latter were made legitimate. – supercat Aug 05 '15 at 15:01
2

In addition to code generation and editing ease, if you want to implement a parser, this type of grammar is simpler and easier to implement. C# follows this rule in several places that there's a list of comma-separated items, like items in an enum definition.

Iravanchi
  • 4,969
  • 9
  • 38
  • 54
1

It makes generating code easier as you only need to add one line and don't need to treat adding the last entry as if it's a special case. This is especially true when using macros to generate code. There's a push to try to eliminate the need for macros from the language, but a lot of the language did evolve hand in hand with macros being available. The extra comma allows macros such as the following to be defined and used:

#define LIST_BEGIN int a[] = {
#define LIST_ENTRY(x) x,
#define LIST_END };

Usage:

LIST_BEGIN
   LIST_ENTRY(1)
   LIST_ENTRY(2)
LIST_END

That's a very simplified example, but often this pattern is used by macros for defining things such as dispatch, message, event or translation maps and tables. If a comma wasn't allowed at the end, we'd need a special:

#define LIST_LAST_ENTRY(x) x

and that would be very awkward to use.

Scott Langham
  • 53,246
  • 34
  • 122
  • 193
0

So that when two people add a new item in a list on separate branches, Git can properly merge the changes, because Git works on a line basis.

noɥʇʎԀʎzɐɹƆ
  • 6,405
  • 2
  • 38
  • 63
-4

If you use an array without specified length,VC++6.0 can automaticly identify its length,so if you use "int a[]={1,2,};"the length of a is 3,but the last one hasn't been initialized,you can use "cout<