06 September 2007

C# 3.0 Collection Initializers - Incomplete Feature?

I was really confused when I learned that "collection initializer" is so limited. I thought it was so natural to support extension methods for "Add" method, but it doesn't.

In short, collection initializer is the following syntax:

var list = new List<int> { 1, 2, 3 };
var dic = new Dictionary<int,string> { { 1, "a" }, { 2, "b" }, { 3, "c" } };


Each item in the braces is simply transformed to the call of Add method with appropriate signature.

var list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
var dic = new Dictionary<int,string>();
dic.Add(1,"a");
dic.Add(2,"b");
dic.Add(3,"c");


It's a bit more complex in reality, but it doesn't matter here.
So, when I first saw description of the feature I thought: How cool! I can specify extension method "Add" for "StringBuilder" and get the following:

var sb = new StringBuilder { "Text = ", Text, ";", "Value = ", Value };


But, restrictions are too strong - type being constructed should implement IEnumerable and have instance method "Add". IEnumerable is not of a big deal, but inability to use extension methods for Add is deal breaker.

How about this?

XmlDocument doc = new XmlDocument
{
new Node("person") { Attributes = { { "name", "John" }, { "age", "42" } },
Nodes =
{
new Node("phones") { Nodes =
{
new Node("number") { Value = "123 45 678" },
new Node("number") { Value = "777 77 777" },
new Node("number") { Value = "987 65 432" }
}
}
}


No way. You can't use collection initializer for XmlDocument, because it doesn't have Add methods. It is IEnumerable, though.

May be this?

var set = new PermissionSet( new ZoneIdentityPermission(...), new PrincipalPermission(...) };


No way. PermissionSet is IEnumerable too, but does have AddPermission instead of Add method.

If it only were searching for candidates as follows:

  • If type implements "IEnumerable", look for instance Add method with appropriate parameters,
  • If not found, if type implements "IEnumerable", look for extension method Add with appropriate parameters,
  • If not found, look for extension method AddToSequence with appropriate parameters.


This change, or something similar, would turn the otherwise very limited collection initializers into really powerfull object initialization feature.

6 comments:

Sean Kearon said...

I didn't realise the restrictions were so tight on this feature. I agree that it would be so much better if it were to be implemented as you describe. However, what's the chance of getting this change made......not very high, I'd guess!

Ilya Ryzhenkov said...

I agree that it is unlikely we will see this in C# 3.0 release. It doesn't seem to be very hard to implement, but I guess all the potential side effects, conflicts with existing code (Beta 2 has Go Live license, so you already may have "legacy" code) need to be examined by language team. Sad...

Kirill Osenkov said...

Nice idea, Ilya. This inspired me to do some wishful thinking on my blog http://kirillosenkov.blogspot.com/2007/09/c-30-collection-initializers-duck.html

Keep up the good posts!

Colin Jack said...

Good post and definitely seems like you have suggested a good solution.

Владимир said...

I recently found about using Structural Types in Scala. Although it's not directly related to your post, I think it is related, is a beautiful language feature, and is interesting to know.

Yurik said...

I just ran into this same issue, and asked MS to implement it: http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2743568-support-c-add-extension-methods-for-collection- Apparently it was even suggested in Connect, but got closed as external.