Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Extended Aggregate Query Operator #9060

Closed
alrz opened this issue Feb 23, 2016 · 4 comments
Closed

Proposal: Extended Aggregate Query Operator #9060

alrz opened this issue Feb 23, 2016 · 4 comments

Comments

@alrz
Copy link
Member

alrz commented Feb 23, 2016

Currently VB's Aggregate Into accepts an aggregate function with the following signatures (§11.21.12):

Function <name>() As <type>
Function <name>(selector As Func(Of T, R)) As R
Aggregate item in list
Into ToDictionary(item.Key)

The idea is to extend it to accept more arguments,

Function <name>(selector1 As Func(Of T, R1), selector2 As Func(Of T, R2)) As R3
...
Aggregate item in list
Into ToDictionary(item.Key, item.Value)

Same semantics can be added to C#'s select to alter the projecting function, ... (see #100)

@svick
Copy link
Contributor

svick commented Feb 23, 2016

I have several comments:

  1. How would multiple range variables be handled?

    If I understand it correctly, what VB does is that you can have From followed by Aggregate, and the query implicitly returns an anonymous type. As far as I'm aware, C# never implicitly returns an anonymous type from a query, you always have to be explicit by writing something like select new { … }, so copying VB is probably not a good idea in this detail.

  2. Would methods that have parameters that are not projections work (e.g. select by Take(10))? If so, how do you decide how to compile a parameter?

  3. I think selectby (without space) would be more consistent with the existing operators. orderby also doesn't have a space and group by requires an identifier between the two words.

@alrz
Copy link
Member Author

alrz commented Feb 23, 2016

@svick

  1. Can you give an example? As far as I know, VB returns an anonymous type if you enumerate the members e.g. Select Foo = item is the same as select new { Foo = item } in C#. So I don't see what it has to do with Aggregate in particular.
  2. I think that makes it complicate; the compiler will need to check if any range variables are being used in the arguments and then convert it to a lambda if so. But currently we have a clear definition of an aggregate function that fortunately a lot of functions fall into this category. So I'm thinking that it's better to have separate operators for Take and Skip.
  3. Agreed. I just wanted to communicate the idea and state that it's not a totally new operator but a generalized one. select ... would be equivalent to selectby Select(...).

@svick
Copy link
Contributor

svick commented Feb 24, 2016

I meant something like:

from parent in parents
from child in parent.Children
selectby First()

Would this compile? What would it return?

Based on reading MSDN, I think the closest VB code is:

From parent In parents
Aggregate child In parent.Children
Into First()

This will return IEnumerable<T> of an anonymous type (even though there is no explicit Foo = …), with properties parent (containing the parent object) and First (containing the first child). Or, in C#:

parents.Select(parent => new { parent, First = parent.Children.First() })

(Note that I'm just trying to compare hypothetical C# with similar code in existing VB, I don't think C# should copy this behavior.)

@alrz
Copy link
Member Author

alrz commented Feb 24, 2016

@svick I see. In C# the query must be ended with a select (or group by) even if you just want to return the range variable. VB doesn't have this requirement and appreatly tries to return everything.

So to keep this explicitness, I would like to suggest use the previous select by syntax (in symmetry with group by which is also a query terminal) and mention the desirable expression.

from item in list
select item by Sum()

from item in list
select item.Key by ToDictionary(item.Value)

This one seems like a backward partial application. In this case I think considering other functions like Take can be an option.

from item in list
select item.Value by Take(5)

list.Select(item => item.Value).Take(5)

In this example, since Take doesn't take a selector we just use the regular Select.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants