New conditional operator: !: #622
Replies: 22 comments
-
In C# there is something like it, but it doesn't handle the default case: var i = 2;
var eg = new[] { 'a', 'b', 'c', 'd', 'e' }[i];
// eg will be 'c' in that example Easy enough to write a helper method for it though: var a = 2;
var b = Choose(a, new[] { "a", "b", "c", "d", "e" }, "default");
// b will be "c" since this value is on the specified index in the array
public static T Choose<T>(int index, T[] options, T @default)
{
if (options == null) throw new ArgumentNullException(nameof(options));
return index >= 0 && index < options.Length ? options[index] : @default;
} |
Beta Was this translation helpful? Give feedback.
-
Yeah okay, that's what I have sorta implemented in some case where I needed this, but why not just add this operator for simplicity? If you say no because something else like that also exists, then consider the ?: operator which is an alternative for something even simpler. |
Beta Was this translation helpful? Give feedback.
-
Requiring an array allocation to perform such an operation would make this pretty awful from a performance point of view. |
Beta Was this translation helpful? Give feedback.
-
I didn't say no, just adding to the discussion. However if I did say no it would be for a different reason. I am not convinced that this is a common enough scenario that using the helper method or a |
Beta Was this translation helpful? Give feedback.
-
It really is useful in such cases, even if they are rare enough. At least in my point of view, I do not see any reason why not to simply add such an operator. |
Beta Was this translation helpful? Give feedback.
-
The question is "why", not "why not". Every language feature has to be justifiable. This is a relatively rare operation that is already very easily solved today with a helper function or extension method. And even if such syntax is idiomatic in Python it would perform quite poorly in C# and thus shouldn't be encouraged. |
Beta Was this translation helpful? Give feedback.
-
@alfasgd Because it adds complexity and could block future scenarios we didn't think of yet that could have much more value. Every new feature starts at -1000 points at this point. |
Beta Was this translation helpful? Give feedback.
-
This is what I was going to suggest next for both perf and syntax, as it turns out: var y = Choose(x, ("a", "b"), "default");
public static T Choose<T>(int index, (T, T) options, T @default)
{
switch (index)
{
case 0:
return options.Item1;
case 1:
return options.Item2;
// etc
default:
return @default;
}
} |
Beta Was this translation helpful? Give feedback.
-
Good call. You'd need an method per arity but you'd only have to write that once. It's even nicer as an extension method: var y = ("a, "b").Choose(x, "default"); Extension operators could make that terser, whether that's a good thing or not: var y = ("a", "b")[x, "default"]; |
Beta Was this translation helpful? Give feedback.
-
@HaloFour I'd expect |
Beta Was this translation helpful? Give feedback.
-
This works today: int a = 2;
string b = new[] { "a", "b", "c", "d", "e" }.ElementAtOrDefault(a) ?? "default"; As a language construct, I would suggest a conditional indexer to look more like collection[?index] This would return the item if the index is valid, or int a = 2;
string b = new[] { "a", "b", "c", "d", "e" }[?a] ?? "default"; |
Beta Was this translation helpful? Give feedback.
-
@bondsbw What about value types? |
Beta Was this translation helpful? Give feedback.
-
@jnm2 In that case the problem isn't so much any of the new syntax, but Maybe as a separate proposal, |
Beta Was this translation helpful? Give feedback.
-
@bondsbw Actually, default-coalescing would not work here: var a = 2;
var b = new[] { 2, 1, 0 }[?a] ?defaultcoalesce? -1;
We need to be able to differentiate between returning an in-range value which happens to be default(T) and being out of range. |
Beta Was this translation helpful? Give feedback.
-
True, and there was a proposal (#328) for transforming Other ideas for syntax I considered posting earlier were: collection[?index : defaultValue] collection[index ?: defaultValue] I wasn't in love with these. But, they aren't quite as foreign either. (One upside is that they would work better with chaining.) |
Beta Was this translation helpful? Give feedback.
-
Also with that syntax we could still have collection[?index] as a shorthand for collection[?index : default(T)] for situations where the default is the preferred output when the index doesn't exist. |
Beta Was this translation helpful? Give feedback.
-
I'd put such an operator into the same category as dotnet/roslyn#5961, in that an expression applied to a parameter to another expression, whether that be a method call or an indexer operator, should not affect the execution of that method/operator. For as infrequently as such an operation is needed, and the fact that the functionality is already provided by LINQ, I don't see a reason for a language construct. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour The Though I agree about finding little value in it regardless of the syntax chosen. Readability suffers compared with existing mechanisms. |
Beta Was this translation helpful? Give feedback.
-
@bondsbw I think it would be confusing if both |
Beta Was this translation helpful? Give feedback.
-
> new[] { "a", "b", "c", "d", "e" }.ElementAtOrDefault(2) ?? "default"
"c"
> new[] { "a", "b", "c", "d", "e" }.ElementAtOrDefault(6) ?? "default"
"default" |
Beta Was this translation helpful? Give feedback.
-
There's no need to add a new operator to do this, it just increases the complexity and learning cost of language. What you need is simply an extension method: public static TSource ElemAtOrValue<TSource>(this IEnumerable<TSource> source, int index, TSource val)
{
if (null != source && 0 <= index)
{
if (source is IReadOnlyList<TSource> rlist)
{
if (rlist.Count > index) return rlist[index];
}
else
{
foreach (var src in source)
{
if (0 == index) return src;
--index;
}
}
}
return val;
} |
Beta Was this translation helpful? Give feedback.
-
@ufcpp As mentioned above, (E.g. |
Beta Was this translation helpful? Give feedback.
-
I've been told from a friend of mine that in Python there is a conditional operator like the following one:
In C# there is nothing like it, so I thought that it should be added in some way. Following the philosophy of the language, I came up with the idea of this new operator that goes like this:
As for that operator, I think it's a useful addition because of the existence of the ?: conditional operator, which only applies for booleans.
Beta Was this translation helpful? Give feedback.
All reactions