.Net Enumeration Allows Comma in the Last Field

.NET Enumeration allows comma in the last field

It has no special meaning, just the way the compiler works, it's mainly for this reason:

[FlagsAttribute]
public enum DependencyPropertyOptions : byte
{
Default = 1,
ReadOnly = 2,
Optional = 4,
DelegateProperty = 32,
Metadata = 8,
NonSerialized = 16,
//EnumPropertyIWantToCommentOutEasily = 32
}

By comment request: This info comes straight out of the C# Specification (Page 355/Section 17.7)

Like Standard C++, C# allows a trailing comma at the end of an array-initializer. This syntax provides flexibility in adding or deleting members from such a list, and simplifies machine generation of such lists.

Enum syntax - extra comma allowed at end?

It is allowed by design. Similarly, you can have trailing commas in initializers as well. For example:

var ints = new[] { 2, 3, 4, 3, };

var obj = new SomeClass { Prop1 = "foo", Prop2 = "bar", };

I think that allowing trailing commas makes creating auto-generated code much easier because you don't have to add last-in-the-list logic when outputting a list in your code.

Unnecessary comma in enum declaration

I prefer second syntax because if you will add addition member to your enum you will have only one line difference in SCM.

Why can you have a comma at the end of a collection initializer?

Similar reason to .NET Enumeration allows comma in the last field

Why can you have a comma at the end of a collection initializer?

Similar reason to .NET Enumeration allows comma in the last field

Is the last comma in C enum required?

It's not required. Section 6.7.2.2 of C99 lists the syntax as:

enum-specifier:
enum identifieropt { enumerator-list }
enum identifieropt { enumerator-list , }
enum identifier
enumerator-list:
enumerator
enumerator-list , enumerator
enumerator:
enumeration-constant
enumeration-constant = constant-expression

Notice the first two forms of enum-specifier, one with the trailing comma and one without.

One advantage I've seen to using it is in things like:

enum {
Val1,
Val2,
Val3,
} someEnum;

where, if you want to add in (for example) Val4 and Val5, you just copy and paste the Val3 line without having to worry about adjusting commas.

It can also be to simplify automated code generators so that they don't have to have special handling for the final value. They can just output every value followed by a comma.

This can be likened to the oft-seen SQL:

select fld1, fld2 from tbl where 1=1 and fld1 > 8

In that case, the where 1=1 is there only so that you don't have to put a where before your first clause and an and before each subsequent one. You can just rely on the fact that the where is already there and just use and for all the ones you add.

Some people may think this reeks of laziness and they're right, but that's not necessarily a bad thing :-)

Any decent DBMS query optimiser should be able to strip out constant clause like that before going to the database tables.

Why does this superfluous comma compile?

Because the C# compiler writers choose to make an optional comma at the end a valid syntax.

I very much like this, as it means you don't need to special case the last line. You can copy-paste lines around, add new lines at any position (including the end) without thinking about where it is, remove lines without needing to fix commas, etc. There is no ambiguity or other problems introduced by allowing the superfluous comma.

Why does C# allow trailing comma in collection initializers but not in params?

So I'll take a stab at this even though I will never know the "true" reason as I wasn't on the compiler team - and the likelihood of one turning up is questionable.

Trailing commas are generally useful in a few scenarios, namely merging and code-generation. In the context of stuff like collection or property initialisers and enums, leaving a trailing comma is harmless (the compiler can safely infer "end of list" as there is also a closing block bracket it can hook on to.

Method parameters are quite explicit - the compiler needs a lot of control in this area so that it can provide good feedback when people are coding and for other ancillary features. Leaving a trailing comma on method arguments doesn't add any of the value as above and my start to cause confusion over how to handle "incomplete" code (did the user leave it there intentionally or are they just about to type in the next argument?).

You are correct that params fall into the conceptual gap in that you see them as an array, and you can specify them as comma delimited (which was supported prior to collection initialisers). So why do they depart in style from collection initialisers?

The language spec for the params bit doesn't explicitly specify trailing comma support, though it does for collection initialisers for parity towards other languages (C++ I think), which increases familiarity with developers migrating to C# from elsewhere.

My supposition: the fact that it wasn't in spec then causes YAGNI to apply, and from that point forwards the value proposition for the feature is a no-brainer in favour of not implementing it.

Why C# 4.0 tolerates trailing comma in anonymous objects initialization code?

To determine whether or not it's a bug in the compiler, you need to look at the C# spec - in this case section 7.6.10.6, which clearly allows it:

anonymous-object-creation-expression:    
new anonymous-object-initializer

anonymous-object-initializer:
{ member-declarator-listopt }
{ member-declarator-list , }

So no, it's not a compiler bug. The language was deliberately designed to allow it.

Now as for why the language has been designed that way - I believe it's to make it easier to add and remove values when coding. For example:

var obj = new { 
field1 = "test",
field2 = 3,
};

can become

var obj = new { 
field2 = 3,
};

or

var obj = new { 
field1 = "test",
field2 = 3,
field3 = 4,
};

solely by adding or removing a line. This makes it simpler to maintain code, and also easier to write code generators.

Note that this is consistent with array initializers, collection initializers and enums:

// These are all valid
string[] array = { "hello", };
List<string> list = new List<string> { "hello", };
enum Foo { Bar, }


Related Topics



Leave a reply



Submit