Collection expressions: Allow builder-pattern method to return different type than the type being built. #7398
Unanswered
CyrusNajmabadi
asked this question in
Language Ideas
Replies: 2 comments 16 replies
-
That would be great. So we would get: public static class ImmutableList
{
public static IImmutableList<T> CreateInterface<T>(ReadOnlySpan<T> values) => Create<T>(values);
public static ImmutableList<T> Create<T>(ReadOnlySpan<T> values){
}
[CollectionBuilder(typeof(ImmutableList), "CreateInterface")]
public interface IImutableList<T> { /* ... */ }
[CollectionBuilder(typeof(ImmutableList), "Create")]
public class ImmutableList<T> : IImutableList<T> { /* ... */ } |
Beta Was this translation helpful? Give feedback.
3 replies
-
I don't see a reason why not to allow this. Btw, is there a requirement that |
Beta Was this translation helpful? Give feedback.
13 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Proposal
This issue contains a change request to the current collection expressions specification that the working group would like to bring for LDM consideration.
The core use case we want to support is relates to the following APIs in the BCL. First, these types, with these members exist today:
With the above, the user can write the following:
But they cannot write:
This doesn't work because
IImutableList<T>
is currently not something the compiler knows how to create. This is unfortunate given such a canonical implementation. Fortunately, a solution seems readily available. Specifically, update the interface like so:+ [CollectionBuilder(typeof(ImmutableList), "Create")] public interface IImutableList<T> { /* ... */ }
Bringing it in line with the class. With this, the compiler would now be able to find
ImmutableList.Create
as the way to initializeC.Values
. However, as the spec is currently written, this would not work. Specifically, the specification says:Here the method return type is
ImmutableList<T>
(the concrete type) while the collection type isIImutableList<T>
(the interface type). This is not an identity conversion, so this is not allowed.However, given how trivial this is to support, and given that the BCL is fine adding these attributes to these collections (see PR here), we propose tweaking the above rule to one of either:
In other words, allow the user's code above because it would be equivalent to:
Given that the full form would be legal to write there, requiring an exact implicit conversion, instead of any implicit conversion is just onerous.
Costs here are minimal. BCL PR is already done, and runtime has indicated they are fine with this sort of pattern. Compiler PR would just be a minor tweak to the check, along with tests to validate behavior.
Alternatives
One suggestion would be to add the
[CollectionBuilder(typeof(...), "Create")]
attribute to tehse interfaces, and have them point at methods that do return an instance of the exact interface type the attribute is on.The runtime team is against this. They would be creating additional, highly redundant, surface area just to work around this limitation in the current specification. The methods would be clones (or dispatchers) to the existing methods, and would need to find some new place to live, or would live next to the existing Create methods, just with different names. This would be extra code, apis, and docs for methods users themselves would never be expected to call.
Conversely, the runtime already has the existing
Create
methods which work perfectly for our needs, if we're just willing to call them and not have this restriction interfere. So that seems to be the simplest, clearest, and most desirable path for both teams.Beta Was this translation helpful? Give feedback.
All reactions