Proposal: add else
block to foreach
if no items are iterated
#4387
Replies: 22 comments
-
This would play off |
Beta Was this translation helpful? Give feedback.
-
what's the problem with following?
|
Beta Was this translation helpful? Give feedback.
-
also Count forces iteration of entire collection, alternatively you can use |
Beta Was this translation helpful? Give feedback.
-
@MkazemAkhgary That feels like a workaround more than a natural attempt, if we were going that route it would be better to make use of existing syntax with LINQ and work it opposite:
Yes, it's more syntax, but at least it preserves the current scope, and doesn't open us up to additional issues via the use of new variables. (Especially when you might have several of these on a page, then the second It should be completely natural within the scope of the language to do something specifically if no items were iterated, that way we don't introduce more error potential. |
Beta Was this translation helpful? Give feedback.
-
@jnm2 I agree, in a situation where you're omitting braces:
However, if you include braces, the syntax is no longer ambiguous:
And:
|
Beta Was this translation helpful? Give feedback.
-
Problem with that is
|
Beta Was this translation helpful? Give feedback.
-
define overhead, You are willing a feature for very rare case, it convoultes current c# syntax with very minor improvement. I dont see benefit of this syntax over existing solutions. also foreach is not if statement. They have completely different semantics. Lets not mix things together. |
Beta Was this translation helpful? Give feedback.
-
It's not very rare, especially in UI-land.
The |
Beta Was this translation helpful? Give feedback.
-
Since you have to assume that public static class IEnumerableExtensions
{
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> perItem, Action noItems)
{
var enumerator = enumerable.GetEnumerator();
if (enumerator.MoveNext())
{
var current = enumerator.Current;
perItem(current);
while (enumerator.MoveNext())
{
current = enumerator.Current;
perItem(current);
}
}
else
{
noItems();
}
}
} |
Beta Was this translation helpful? Give feedback.
-
Could ForEach return Boolean to indicate if it managed to iterate any objects? This would enable if(!ForEach(....)){} syntax with nothing else changed.
|
Beta Was this translation helpful? Give feedback.
-
@AartBluestoke cool, if thats breaking change, im not sure if it is, they can add method That would also handle NRE |
Beta Was this translation helpful? Give feedback.
-
I don't know if it a breaking change, would someone with more knowledge be able to comment on the feasibility of something like that? |
Beta Was this translation helpful? Give feedback.
-
There is no |
Beta Was this translation helpful? Give feedback.
-
In this case, we could just go full Rust and allow our iterator, switch, and other random control statements to return final values for assignment. 😏 Gotta love var foo = switch (bar)
{
case 1: return value1;
case 2: return value2;
default: return 0;
} |
Beta Was this translation helpful? Give feedback.
-
@whoisj and maybe try lock?
and
|
Beta Was this translation helpful? Give feedback.
-
I think I might need to start specifying #sarcasm on GitHub now too 😕 |
Beta Was this translation helpful? Give feedback.
-
@whoisj 😏 and 🙄 are good enough 😛 |
Beta Was this translation helpful? Give feedback.
-
@whoisj we're going to have
Simple example: var range = Enumerable.Range(1, 1_000_000_000).Where(e => e > 1_000_000_000 - 1);
int sum = -1;
if (range.Any())
{
foreach(var x in range)
sum += x;
}
else
{
sum = 0;
} var range = Enumerable.Range(1, 1_000_000_000).Where(e => e > 1_000_000_000 - 1);
int sum = 0;
range.ForEach(x => sum += x, () => sum = 0); The latter is 2x faster. |
Beta Was this translation helpful? Give feedback.
-
@AartBluestoke Making it Until we have |
Beta Was this translation helpful? Give feedback.
-
(Glad I found this -- have spent all evening trying to to find duplicates before raising it myself. It seemed too obvious to have not been raised before.) In short, would love to see this implemented and extended to all the loop constructs, not just Also recognise that using With regards to the other loop constructs, I could see the usefulness. The naive approaches are obvious, but I would prefer the most-optimal appraoches...
|
Beta Was this translation helpful? Give feedback.
-
It's even possible that when the IEnumerable<> is actually an iterator method that determines the result set dynamically, the first enumeration could return a non-empty collection while the second one would then return an empty collection. So, it could be possible that the foreach doesn't loop at all even though the Any() call has returned true before. A dedicated language feature of an or-clause for loops would be a clean way of avoiding multiple invocations of a generator. In the same way, you sometimes want to do stuff before iterating only when the collection is not empty. Having an extension to the foreach-syntax that would allow code to execute before the loop or after the loop only when the loop is actually run once, would be very helpful in avoiding multiple invocations of generators.
which would be equivalent of
|
Beta Was this translation helpful? Give feedback.
-
This feature is not worthy of 3 distinct new keywords and such radical syntax changes. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
@EBrown8534 commented on Sat Jan 28 2017
Consider the following ASP.NET Razor sample:
If one wishes to check that the collection would first return items it requires adding another level of testing to the Razor:
You could propose two major solutions currently supported by the language to solve this issue:
First: create an intermediary variable in the view:
Obviously this is not a pure solution: our view contains a local variable and requires a local variable if using this solution for each and every location we wish to operate on a collection in this manner with.
The second solution would be to add the
filteredCollection
to the model being passed to the view, then simply:This increases maintenance with the model, and requires this to be somehow derived from the model. (If it's a simple filter on another collection in the model that's easy enough, but the more complex our conditions become the more maintenance on the model is required.)
I propose we add an
else
block to be added directly after aforeach
block which would only execute if no items were iterated.This would be most helpful in ASP.NET applications where custom object sorting and filtering is more likely to be common and the potential to display a 'no items to display' message is much higher.
@jnm2 commented on Sat Jan 28 2017
I've had the same wish, and in the same circumstances. I wonder if it could just be Razor sugar or if it would really be helpful in C# itself.
Razor could insert a local bool which gets set each time the loop iterates, and generate an
if (!iterated)
block instead of theelse
keyword.@HaloFour commented on Sat Jan 28 2017
Dupe of #134.
@HaloFour commented on Sat Jan 28 2017
Even if reconsidered I think that there are ambiguity concerns to consider. The following is already legal syntax:
@jnm2 commented on Sat Jan 28 2017
Can you link the actual dupe?
@HaloFour commented on Sat Jan 28 2017
@jnm2 Oops, typo. #134 (I'll fix the original comment too)
@jnm2 commented on Sat Jan 28 2017
@HaloFour This isn't a dupe if it's implemented as Razor sugar
@eyalsk commented on Sat Jan 28 2017
@jnm2 Then why it needs to be implemented at the language? they can add a special syntax and deal with it themselves.
@jnm2 commented on Sat Jan 28 2017
@eyalsk
Correct, it would go in a different repo.
@alrz commented on Sat Jan 28 2017
There's no such thing as "razor sugar". Razor passes code sections as-is to the generated view class.
@jnm2 commented on Sat Jan 28 2017
@alrz Razor is sugar 😆
This doesn't seem that complex to add to the parser that separates C# and HTML.
@initram commented on Mon Jan 30 2017
For a lot of cases you can use the extension method DefaultIfEmpty(), where you can provide an element to return if the IEnumerable is empty.
@Thaina commented on Mon Jan 30 2017
We should just let else + any keywords format in the same line. And you should swap logic for empty on top
It already valid syntax (need to add
IsNullOrEmpty
extention method) just formatter make it annoying separate line@Thaina commented on Mon Jan 30 2017
On a second thought. if no one mind this syntax just it conflict with valid syntax we can just tweak any syntax
@TonyValenti commented on Tue Jan 31 2017
Wow! What an elegant solution! I love this proposal. I've always just resorted to doing something like having an extra count variable and then IFing off it. I really like this suggestion a lot.
@alrz commented on Tue Jan 31 2017
If this is common in Razor, you could use a partial view or even an action result filter. If there is a use case outside ASP.NET, that could be also addressed via similar mechanisms, depending on problem domain.
@jcouv commented on Sat Oct 21 2017
I'll move this to csharplang (where language design is now discussed). Thanks
Beta Was this translation helpful? Give feedback.
All reactions