multi keyword, a type safe generics friendly improvement over params #3133
Replies: 7 comments
-
Why does this need a keyword? Couldn't you have a type like this: using System.Collections;
using System.Collections.Generic;
struct Multi<T> : IEnumerable<T>
{
private readonly IEnumerable<T> _values;
private Multi(IEnumerable<T> values)
=> _values = values;
public IEnumerator<T> GetEnumerator()
=> _values.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> ((IEnumerable)_values).GetEnumerator();
public static implicit operator Multi<T>(T val)
=> new Multi<T>(new T[] { val });
public static implicit operator Multi<T>(T[] values)
=> new Multi<T>(values);
}
class Foo
{
void Bar(Multi<int> m)
{
}
void Quux()
{
Bar(1);
Bar(new[] { 2, 3 });
}
} Now you can call the single overload with either a single value, or multiple values. |
Beta Was this translation helpful? Give feedback.
-
Why is this commonly needed? |
Beta Was this translation helpful? Give feedback.
-
I don't see why overloads aren't the appropriate solution here. Trying to force both very different types through a single signature seems like an abuse of the type system, the kind of dispatch you'd use in a scripting language that lacks overloads. |
Beta Was this translation helpful? Give feedback.
-
I agree with Halo. And if you did explicitly need that somehow, this proposal seems much more limited in both scope and value than #399, which in theory would permit: public void Bar(IEnumerable<int>|int value) { ... } |
Beta Was this translation helpful? Give feedback.
-
While I have ran into this limitation on params a couple of times, I don’t think it’s worth wasting a keyword on. Particularly since it seems to me that it would be just as easy to just allow the existing keyword to be used in more places. I presume that the reason it is restricted to the final position is because it eliminates some kind of ambiguity. |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi Thanks for the struct Multi : IEnumerable suggestion. I tried it and it works great. The only type it cannot explicitly auto convert from is IEnumerable. void Quux(IEnumerable<int> numbers)
{
Bar(1); // ok
Bar(new[] { 2, 3 }); // ok
Bar(numbers); // syntax error
} So to use Multi it seems one has to replace all IEnumerate with it. But that is acceptable. |
Beta Was this translation helpful? Give feedback.
-
Alternatively: struct Int32 : IEnumerable<Int32> Ok, that horse is already out the barn 😀 |
Beta Was this translation helpful? Give feedback.
-
I find that params has constraints that are not useful in practice, namely that it has to be at the end of the parameter list, which eliminates the possibility of default parameters.
The main inconvenience I find often is a single item vs a collection that in either case should be handled the same.
So what I'd like is a new keyword that allows auto wrapping a single item into an IEnumerable such that I do not need that first wrapper method Foo. The name for that keyword should be multi since it is a short word that indicates the idea that the following parameter has multiple API signatures. The above code would become:
Since there is no restriction to have the multi parameter at the end, I could even use more than one multi parameter:
And of course it would be great if the multi keyword could be prefixed to any type of container/set to auto convert a single item into a container/set with having that one item. So besides IEnumerable also for arrays, lists, etc as well as any template type T version of those.
The closest existing keyword is params which has a ticket #179 to make it apply to IEnumerable, but this proposal here with multi instead is more targeted toward what is commonly needed and does not disable the use of default parameters.
The case that someone wants to explicitly declare the set of multiple elements at the point of method call is rare. I that case one can do:
Beta Was this translation helpful? Give feedback.
All reactions