4

To use initialization syntax like this:

var contacts = new ContactList
{
    { "Dan", "dan.tao@email.com" },
    { "Eric", "ceo@google.com" }
};

...my understanding is that my ContactList type would need to define an Add method that takes two string parameters:

public void Add(string name, string email);

What's a bit confusing to me about this is that the { } initializer syntax seems most useful when creating read-only or fixed-size collections. After all it is meant to mimic the initialization syntax for an array, right? (OK, so arrays are not read-only; but they are fixed size.) And naturally it can only be used when the collection's contents are known (at least the number of elements) at compile-time.

So it would almost seem that the main requirement for using this collection initializer syntax (having an Add method and therefore a mutable collection) is at odds with the typical case in which it would be most useful.

I'm sure I haven't put as much thought into this matter as the C# design team; it just seems that there could have been different rules for this syntax that would have meshed better with its typical usage scenarios.

Am I way off base here? Is the desire to use the { } syntax to initialize fixed-size collections not as common as I think? What other factors might have influenced the formulation of the requirements for this syntax that I'm simply not thinking of?

Dan Tao
  • 125,917
  • 54
  • 300
  • 447

9 Answers9

10

I'm sure I haven't put as much thought into this matter as the C# design team; it just seems that there could have been different rules for this syntax that would have meshed better with its typical usage scenarios.

Your analysis is very good; the key problem is the last three words in the statement above. What are the actual typical usage scenarios?

The by-design goal motivated by typical usage scenarios for collection initializers was to make initialization of existing collection types possible in an expression syntax so that collection initializers could be embedded in query comprehensions or converted to expression trees.

Every other scenario was lower priority; the feature exists at all because it helps make LINQ work.

The C# 3 compiler team was the "long pole" for that release of Visual Studio / .NET - we had the most days of work on the schedule of any team, which meant that every day we delayed, the product would be delayed. We wanted to ship a quality product on time for all of you guys, and the perfect is the enemy of the good. Yes, this feature is slightly clunky and doesn't do absolutely everything you might want it to, but it was more important to get it solid and tested for LINQ than to make it work for a bunch of immutable collection types that largely didn't even exist.

Had this feature been designed into the language from day one, while the frameworks types were still evolving, I'm sure that things would have gone differently. As we've discussed elsewhere on this site, I would dearly love to have a write-once-read-many fixed size array of values. It would be nice to define a common pattern for proffering up a bunch of state to initialize an arbitrary immutable collection. You are right that the collection initializer syntax would be ideal for such a thing.

Features like that are on the list for potential future hyptothetical language versions, but not real high on the list. In other words, let's get async/await right first before we think too hard about syntactic sugars for immutable collection initialization.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Thanks, Eric—definitely helps put this in perspective. I think once a couple of people had mentioned LINQ, the realization started to set in (for me) that this was the real motivator for collection initializers; then it all started making sense. – Dan Tao Jan 14 '11 at 05:50
  • Incidentally, I don't suppose you've come across [this (unrelated) question](http://stackoverflow.com/questions/4642665/)? I don't mean to be obnoxious by bringing it up here; it's just a doozy. And your name has been mentioned in a comment or two... – Dan Tao Jan 14 '11 at 05:58
3

It's because the initialization statement is shorthand for the CLR. When it gets compiled into bytecode, it will call the Add method you've defined.

So you can make the case that this initialization statement is not really a "first class" feature, because it doesn't have a counterpart in IL. But that's the case for quite a lot of what we use, the "using" statement for example.

Chris B. Behrens
  • 6,255
  • 8
  • 45
  • 71
2

The main reason is Syntactic Sugar.

The initializer syntax only makes writing programing in C# a bit easier. It doesn't actually add any expressive power to the language.

If the initializer didn't require an Add() method, then it would be a much different feature than it is now. Basically, it's just not how C# works. There is no literal form for creating general collections.

jjnguy
  • 136,852
  • 53
  • 295
  • 323
  • 2
    It does add expressive power to the language; it allows you to express the initialization of a collection *as an expression tree lambda*. – Eric Lippert Jan 14 '11 at 00:43
  • @Eric, can't you do that in a select block anyway? Or encapsulate it in a method? – jjnguy Jan 14 '11 at 04:58
  • Select doesn't take a block, it takes an expression. And how does encapsulating it in a method help in the expression tree case? How does the query translator know that the method initializes a collection, and that the "initialize a collection" semantics are to be translated into instructions in the data access layer? – Eric Lippert Jan 14 '11 at 06:50
  • @Eric, I suppose my knowledge of the language is inferior to yours. To me the collection initialization looks like simple Syntactic sugar. I've been wrong before, and I will be wrong again. – jjnguy Jan 14 '11 at 14:44
2

Not an answer, strictly speaking, but if you want to know what sort of things influenced the design of collection initialisers then you'll probably find this interesting:

LukeH
  • 263,068
  • 57
  • 365
  • 409
2

The reason for this is that it was retrofitted. I agree with you that using a constructor taking a collection would make vastly more sense, but not all of the existing collection classes implemented this and the change should (1) work with all existing collections, (2) not change the existing classes in any way.

It’s a compromise.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
1

What should the initialization syntax use, if not an Add method? The initialization syntax is 'run' after the constructor of the collection is run, and the collection fully created. There must be some way of adding items to the collection after it's been created.

If you want to initialize a read-only collection, do it in the constructor (taking a T[] items argument or similar)

thecoop
  • 45,220
  • 19
  • 132
  • 189
1

As far as I understand it, the collection initializer syntax is just syntactic sugar with no special tricks in it. It was designed in part to support initializing collections inside Linq queries:

from a in somewhere
select new {
   Something = a.Something
   Collection = new List<object>() {
      a.Item1,
      a.Item2,
      ...
   }
}

Before there was no way to do this inline and you'd have to do it after the case, which was annoying.

Alex J
  • 9,905
  • 6
  • 36
  • 46
1

I'd love to have the initializer syntax for immutable types(both collections and normal types). I think this could be implemented with a special constructor overload using a syntax similar to params.

For example something like this:

MyClass(initializer KeyValuePair<K,V>[] initialValues)

But unfortunately the C# team didn't implement such a thing yet :(

So we need to use a workaround like

MyClass(new KeyValuePair<K,V>[]{...})

for now

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
1

Collection initializers are expressions, so they can be used where only expression are valid, such as a field initializer or LINQ query. This makes their existence very useful.

I also think the curly-bracketed { } kind of initialization, smells more like a fixed size collection, but it's just a syntax choice.

digEmAll
  • 56,430
  • 9
  • 115
  • 140