Replies: 10 comments 1 reply
-
Threw this proposal together based on this comment about how the C# compiler already gets collection initializers wrong with the types in System.Collections.Immutable. |
Beta Was this translation helpful? Give feedback.
-
What is the advantage of this compared to a |
Beta Was this translation helpful? Give feedback.
-
The ability to use collection initializer syntax. The method could be |
Beta Was this translation helpful? Give feedback.
-
How is a method that always allocates a garbage array going to help with efficiency? What I would prefer would be some way for the collection initializer to tell the collection how many items are there going to be. For example, (I'm not completely sure this is good enough, because it could decrease performance in cases like
How does this proposal help with that? What attributes could be applied to
How does the compiler know how to create the collection? Or did you mean "a collection interface" and the compiler will always create an array? |
Beta Was this translation helpful? Give feedback.
-
Heh, that's definitely true. Perhaps multiple overloads could be decorated and the compiler would pick the most appropriate one via normal overload resolution? public class MyList {
[CollectionInitializer]
public void Add(int x) { }
[CollectionInitializer]
public void Add(int x, int y) { }
[CollectionInitializer]
public void Add(int x, int y, int z) { }
[CollectionInitializer]
public void Add(params int[] x);
}
///
var list = new MyList { 1, 2, 3 };
// equivalent to
var list = new MyList();
list.Add(1, 2, 3);
That should be
I left that kind of vague intentionally. Easiest route would be via an array, like I'm also aware of the "weirdness" around having one attribute mean multiple things. I'd also be game for multiple attributes or properties of that attribute that would provide the hints to the compiler, e.g. [CollectionInitializer(Range = true)]
public void Add(params int[] x) { ... }
[CollectionInitializer(Builder = true)]
public MyList(int x) { ...; return new MyList(...); } After your comment about the compiler doing the wrong thing in certain cases and not being able to change that due to backward compatibility I thought about what might be possible to "fix" these scenarios and to make the initializers smarter based on hints provided by the developer. |
Beta Was this translation helpful? Give feedback.
-
@svick In what instances would collection initializers be used in the kind of performance critical code where it makes any meaningful difference whether the collection is specified with a default size or allocated an array for Seems like premature optimization to me. I think this proposal is useful for the 99% of cases where collection initializers are executed only once (not in an inner loop of something). |
Beta Was this translation helpful? Give feedback.
-
@MgSam That's a good question. I think if you can easily make a change to the generated code that sometimes improves performance at least by a small amount (and never decreases it), then that's a change that should be taken. Though it's not clear to me whether my suggestion fits any of these criteria. On the other hand, what is the point of adding support to |
Beta Was this translation helpful? Give feedback.
-
I agree about However, I like this proposal because it takes a narrowly applicable feature and makes it more broadly usable. The fact that collection initializers currently only work for |
Beta Was this translation helpful? Give feedback.
-
Having just created a custom collection class which does some additional work after Another possibility might be some sort of deferred update interface (eg. |
Beta Was this translation helpful? Give feedback.
-
IMHO the most important thing is to avoid wrong code for use cases like immutable data types as suggested in #3211.
Everything else like performance is IMHO nice to have, cf. extensive discussion IEnumerable ./. params. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
Allow developers to provide hints to the C# compiler as to how best to emit method calls for collection initializer syntax.
Motivation
Collection initializers currently follow a convention to discover how to add elements to the target. That convention is that the target type implements
System.Collections.IEnumerable
and offers an instanceAdd
method accepting a single argument. This works pretty well for the most part but it has the two following problems:Add
for each item rather than a method likeAddRange
which would allow the type to add the items in bulk.ImmutableArray<T>
the convention doesn't work asAdd
doesn't mutate the current instance but instead returns a new instance.Furthermore, improving the current initializer behavior to, say, support
AddRange
overAdd
could introduce breaking changes to people's code.Detailed design
Instead of making the compiler automatically "smarter" in selecting better methods to perform the initializer, a new attribute (or attributes) could be provided to give the compiler hints as to what code to emit. That would allow the change to be more intentional and a lot less likely to be "breaking".
I propose the addition of the attribute
System.Runtime.CompilerServices.CollectionInitializerAttribute
which the C# compiler would recognize by the full type name, as it does withSystem.Runtime.CompilerServices.ExtensionAttribute
. Further, I propose the following behaviors when a method is decorated with this attribute:When the method accepts an array or a collection all of the elements in the initializer will be passed to that method in a single method call:
When the method returns the same type as the target method then the return value of the method will be the resulting expression of the collection initializer:
The two above behaviors can be combined:
Drawbacks
Alternatives
Unresolved questions
Design meetings
Beta Was this translation helpful? Give feedback.
All reactions