Partager via


Req27: Allow query syntax in For Each

[This post is part of a series, "wish-list for future versions of VB"]

 

IDEA: Allow "For Each x In collection Where x>10", and other query expressions. We should allow this kind of code:

For Each x In collection Where x > 5

Currently we're forced to use awkward workarounds:

For Each x In From x_ In collection Where x_ > 5

For Each x In collection.Where(Function(x_ As Integer) x_ > 5)

For Each changedEntity In entityIndex.AllEntities.Where(
Function(x) x.ChangeTracker.State = ObjectState.Deleted)

 

IDEA 1: Allow only "Where" in For Each statements

IDEA 2: Allow arbitrary LINQ queries in For Each statements

 

This looks like a simple enough request, but it's not... The issue is that For Each uses the Collection Pattern: it looks for an accessible method or extension method named GetEnumerator, and on that it looks for MoveNext/Current; or failing that it looks for IEnumerable(Of T); or failing that it looks for IEnumerable. Meanwhile, a LINQ query use the Query Pattern : it looks for a conforming Select method, or failing that AsEnumerable/AsQueryable, or failing that Cast.

How to deal with this "impedance mismatch"? One solution is to go for IDEA 1, i.e. we figure out up-front which limited set of LINQ-like operators we want to allow. The problem with this is that it's so limiting, and we might get the set of operators wrong, and they wouldn't quite behave like thier LINQ counterparts.

Another solution is to go for IDEA 2, but say that every "querying For Each" statement is merely syntactic sugar for some LINQ query, e.g. "For Each x in coll where x>5" is merely syntactic sugar for "For Each x in (From x_ in coll where x_ > 5)".

Then we worry about performance. The compiler generates faster code when you "For Each" over an array than when you For Each over a collection. We would want "For Each x in coll Where x<5" to be exactly as performant as "For Each x in coll : If Not x<5 Then Continue".

 

Provisional evaluation from VB team: We're torn. It's a nice feature. But performance concerns push us to IDEA 1 with its problems, while generality/usability concerns push us to IDEA 2 with its problems.

What do you think? Would you like to see the more limited IDEA 1? With which LINQ-like query operators? Or would you prefer to see the more general IDEA 2?

Comments

  • Anonymous
    March 05, 2010
    I think IDEA 1 is going to be annoying when inevitably someone would want to do something obviously correct from a LINQ perspective, but is blocked because they didn't memorize a second set of rules. Per IDEA 2, why is there any particular performance issue?  If you do For Each x in query I think it's clear that the performance of this is going to be comparable to Dim query = <LINQ_QUERY> For Each x in query it's just syntactic sugar.  How could the compiler possibly do better than this, if query isn't something simple like an array?

  • Anonymous
    March 09, 2010
    I'd prefer to see other things before this one, since I like to use the LINQ lambda syntax on these situations, however it would add some nice syntactic sugar, and would look inline with the extended switch support VB has.

  • Anonymous
    March 17, 2010
    In C# I would just do this: foreach (var x in collection.Where(x => x > 5)) The fact that this is a "problem" in VB is, I think, attributable to the terrible and wordy lambda syntax in VB.  If lambda expressions were as concise in VB as in C#, I don't think it'd be a problem at all.

  • Anonymous
    August 01, 2010
    Why not introduce a new Keyword for For? For Every x In y Where x > 10 ' do stuff Next Now this follows the query pattern. So pass the option on the user to choose. Or introduce an alias for the Function keyword in Lambda Functions eg F (Its closer to the mathematical function symbol F) Or use a modified version of the C# syntax -> and  <- (Note: Not the standard operators => and <= )

  • Anonymous
    August 01, 2010
    Why not introduce a new Keyword for For? For Every x In y Where x > 10 ' do stuff Next Now this follows the query pattern. So pass the option on the user to choose. Or introduce an alias for the Function keyword in Lambda Functions eg F (Its closer to the mathematical function symbol F) Or use a modified version of the C# syntax -> and  <- (Note: Not the standard operators => and <= )

  • Anonymous
    September 01, 2010
    I think allowing arbitrary queries, using the current for-loop syntax, would be confusing. For example, the loop variable in "For e in collection select x = e + 1" would have to be 'x', but initially looks like it should be 'e'. I also think only allowing specific queries would be too restrictive. I suggest saying "For From" instead of just "For". That way it is clearer the loop is just syntactic sugar for the non-standard "ForEach" linq method. Example: For From x in Items1    From y in Items2    Select s = x + y    Zip i in Naturals    Print(i.ToString() + ": " + s.ToString()) Next

  • Anonymous
    June 27, 2014
    The comment has been removed