Replies: 51 comments
-
Can we skip .Select(...) --> select On a side note, |
Beta Was this translation helpful? Give feedback.
-
Why limit it to a single class? It should be any available method, instance or extension. |
Beta Was this translation helpful? Give feedback.
-
This could be emulated with var string6789 =
from x in Enumerable.Range(1, 10)
|> @.Skip(5)
|> @.Take(4)
|> @.Aggregate("", (y, z) => y + z); this wouldn't: var sixseveneightnine =
from x in Enumerable.Range(1, 10)
|> @.Skip(5)
|> @.Take(4)
select SpellOut(x, CultureInfo.CurrentCulture); //error
|> @.Aggregate("", (y, z) => y + z); Our hypothetical
var sixseveneightnine =
from x in Enumerable.Range(1, 10)
foo Skip(5)
foo Take(4)
select SpellOut(x, CultureInfo.CurrentCulture);
bar Aggregate("", (y, z) => y + z);
var sixseveneightnine =
from x in Enumerable.Range(1, 10)
foo Skip(5)
foo Take(4)
select SpellOut(x, CultureInfo.CurrentCulture);
|> @.Aggregate("", (y, z) => y + z);
var sixseveneightnine =
from x in Enumerable.Range(1, 10)
skip 5
take 4
select SpellOut(x, CultureInfo.CurrentCulture);
bar Aggregate("", (y, z) => y + z);
var sixseveneightnine =
from x in Enumerable.Range(1, 10)
skip 5
take 4
select SpellOut(x, CultureInfo.CurrentCulture);
|> @.Aggregate("", (y, z) => y + z);
var sixseveneightnine =
from x in Enumerable.Range(1, 10)
foo Skip(5)
foo Take(4)
select SpellOut(x, CultureInfo.CurrentCulture);
aggregate from "" using string.Concat;
var sixseveneightnine =
from x in Enumerable.Range(1, 10)
skip 5
take 4
select SpellOut(x, CultureInfo.CurrentCulture);
aggregate from "" using string.Concat;
|
Beta Was this translation helpful? Give feedback.
-
Personally I don't like the idea of polluting the language with so many new keywords. I vote for C# being minimalistic when not-necessary otherwise, and I specially dislike the idea of I'd rather seeing what was proposed above, just one additional keyword (
We could expand it with some rules, i.e. if the materialization method takes a single reference/value parameter, or the same delegate/predicate with a parameter as the main type (
If the pattern isn't a type of
I'm fine with only part (A), I'm sure part (B) could be achieved in a much more efficient a way if necessary at all. |
Beta Was this translation helpful? Give feedback.
-
When working on the original LINQ design we did consider having a 'do' clause, but eventually decided against it because it just ended up being the same thing as dot. Maybe time to reconsider? |
Beta Was this translation helpful? Give feedback.
-
@mattwar, if you look at this one, it's not the same thing:
|
Beta Was this translation helpful? Give feedback.
-
@paulomorgado you're mixing up two |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox, why do they need to be different? Apart from |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox @paulomorgado they shouldn't. If the called method contains an iteration (i.e. |
Beta Was this translation helpful? Give feedback.
-
Any instance or extension method of the expression type with none or one expression (
Could work. But should it work? |
Beta Was this translation helpful? Give feedback.
-
I personally want this. However, i think one of the cleanest ways we could do this would be to make the syntax either: do binding-expression or apply binding-expression 'binding expressions' are what you can get after a Substantively, what this would mean is that your query would actually look like: var result = from c in customers
where c.Age > 21
do .ToList(); The reason i like this is that it feels inherently weird to me to just have a standalone expression Finally, i think it would be nice for the syntax to clearly call out that you're not calling some instance member of your own type (i.e. if you had your own ToList method in scope). By being |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi yeah, so how about params? |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi, at this point, looks like a punctuation character would be better than var result = from c in customers
where c.Age > 21
@.ToList(); Not wanting to discard the already existing infrastructure you mentioned, I would prefer something where I can do this: var result = from o in orders
from c in customers
do Distinct c.Id
where c.Age > 21
do ToList; over this: var result = from o in orders
from c in customers
do .Distinct(c => c.Id)
where c.Age > 21
do .ToList; because, in the end, I've gained nothing over: var result = (from o in orders
from c in customers.Distinct(c => c.Id)
where c.Age > 21
).ToList; |
Beta Was this translation helpful? Give feedback.
-
Sorry, not sure what you mean by that. Do you mean 'parameters'? Or actual 'params'?
In my mind, 'do/apply' is just a way to bridge to all things outside of queries. As such, what you put after 'do/apply' is simply a 'BindingExpression' with all the rules inherent therein. So, if you want to use ToDictionary, you write: previous-clauses
do .ToDictionary(x => x.Whatever)
following-clauses
Yes. I've been following since the beginning. But i thought i would weigh in on an approach that would stand the best chance of being implemented, while also solving the largest pain points for me, namely:
I'd like to be able to just add a |
Beta Was this translation helpful? Give feedback.
-
I disagree. For me, i get pulled out of the 'flow' of queries when i now have to go back, wrap it in parens, and then dot off it. Furthermore, if i want to continue the query onwards, that's another piece of awkwardness. I'd like a gentler way to bridge the two worlds. But i'm not really looking for a way to take a huge swath of C# constructs and have them auto-translated to some sort of 'new query syntax' that maps to/from them. -- Seriously, in your example, i find: var result = from o in orders
from c in customers
do .Distinct(c => c.Id)
where c.Age > 21
do .ToList(); To be far more readable than your lower piece of code. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour, why would |
Beta Was this translation helpful? Give feedback.
-
@HaloFour probably a function that changes type illustrates the problem better. var query = from x in Enumerable.Range(0, 10)
do .ConvertToString()
select x; // what the Heck is x supposed to be here? |
Beta Was this translation helpful? Give feedback.
-
@mattwar, what's the signature of Can you write, on today's LINQ, this? from i in ints
select i.ToString()
select i |
Beta Was this translation helpful? Give feedback.
-
@paulomorgado No, you'd have to write it this way. from i in ints
select i.ToString() or if you really want to select again, you'd do it like this from i in ints
select i.ToString() into s
select s |
Beta Was this translation helpful? Give feedback.
-
public static class MyExtensions {
public static IEnumerable<int> MultiplyBy2(this IEnumerable<int> numbers) {
foreach (var number in numbers) {
yield return number * 2;
}
}
}
It wouldn't have to be, but as a non-terminal operation is it certainly projecting a value different than the input values. There's no reasonable way to correlate any particular range variables leading up to that transform with whatever might be enumerated from that operation. It's not like the |
Beta Was this translation helpful? Give feedback.
-
@mattwar, so, why would |
Beta Was this translation helpful? Give feedback.
-
@HaloFour, so, |
Beta Was this translation helpful? Give feedback.
-
from x in xs
where x > 2 //there
do .ToString()
where x.EndsWith("0") //there
select x In two lines marked |
Beta Was this translation helpful? Give feedback.
-
That would be equivalent to: from x in xs
where x > 2 //there
select x.ToString()
where x.EndsWith("0") //there
select x Can you do that now? |
Beta Was this translation helpful? Give feedback.
-
@paulomorgado You can not write that today. 'select' ends a query. |
Beta Was this translation helpful? Give feedback.
-
IMO, a |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi isn't I think the only tricky part will be IntelliSense for the consecutive "do" clauses, but you definitely know more about that than anyone. |
Beta Was this translation helpful? Give feedback.
-
Right now this is the query grammar:
I'm proposing changing that to:
I think it should be fine. A If you have a continuation, i.e.
All of this should fall out naturally from both how we handle BindingExpressions today, and how 'into' continuations already work. |
Beta Was this translation helpful? Give feedback.
-
@mattwar: What about throwing all variables of the context into named tuples? Some custom linq statement implementations accepting an (See #117 (comment) for an example with a Zip()-Linq-Statement -- still using another syntax) |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi I've played around a bit with this change, and "All of this should fall out naturally from both how we handle BindingExpressions today" wasn't 100% true. Both types of binding access expressions were really attached to conditional access expressions and I had to slap them around a bit to make them accept a do clause as their new daddy. I'll see if this change can be made more polished after I'm done with |
Beta Was this translation helpful? Give feedback.
-
@paulomorgado commented on Wed Jun 17 2015
Every now and then there's a new request for a new query clauses (C#, Visual Basic).
Sometimes it's to add to C# some query clause that Visual Basic already has (Aggregate, Distinct, Skip, Skip While, Take, Take While), or materialization of the query (ToArray, ToList, ToDictionary or ToLookup) or soe other selection or aggregation (First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault, Count, etc.).
There are just too many and chances are that more will come.
How about extending the query language with an
apply
clause?This
apply
clause would be composed of anapply
keyword followed by the method name (instance or extension like already happens to Select or Where) and any other parameters.Then it would be possible to write something like this:
Or this:
Or this:
I don't know if I like this or not, but looks to me a lot more consistent and all-encompassing than individual proposals.
@svick commented on Thu Jun 18 2015
For the record,the previous proposals on GitHub are #3486 and #100 (and I'm sure there were some discussions on CodePlex too).
@svick commented on Thu Jun 18 2015
I would really like something like this, since it's completely general. But I think the syntax needs to be fleshed out much more. Some questions:
How do you
apply
methods with multiple parameters (like the two-selector overload ofToDictionary()
)?The variants consistent with this proposal are
apply ToDictionary c.ID c.Name
andapply ToDictionary c.ID, c.Name
, but personally I don't like either. Instead, I would prefer call-like syntax for all methods:apply ToDictionary(c.ID, c.Name)
and e.g.apply First()
.When no range variable is mentioned, how do you differentiate between normal parameters (e.g.
apply Take(10)
) and lambda parameters (e.g. the second parameter ofapply ToDictionary(c.ID, 0)
)?F# LINQ (which already has similar kind of extensibility) uses attributes for this. Another option would be to use the variant that compiles, while preferring one of them when both compile (though that might easily lead to confusing error messages).
How do you differentiate between methods that maintain range variables and so can be used in the middle of a query (like
Distinct
) and those that don't and so have to be used after the finalselect
(likeFirst
)?F# LINQ again uses attributes for this. And another option would be to just assume the user is right, but I think that would require lots of care to make the error messages understandable (instead of something like "Could not find an implementation of the query pattern for source type 'int'. 'Select' not found." for the query
from i in list apply First select 2*i
).@gordanr commented on Thu Jun 18 2015
'Apply' could be very good starting point for discussion.
Call-like syntax is maybe more suitable for C# language.
When there are not parameters, is it good idea to allow both forms?
Some methods are natural after the final select.
Some methods can be after the final select.
But also can be proposed in infix notation.
Some methods are maybe more natural in infix notation (as in sql).
But also can be written on the end
@paulomorgado commented on Thu Jun 18 2015
Not all methods of
Enumerable
are available through LINQ clauses. So, for the lack of better syntax, I intentionally left out those not translatable to this syntax.I intentionally did not use a call-like syntax because that's how all existing clauses were defined.
All the rules that apply now and to method invocation style would still apply. The fact that you don't have a
TResult Select<TSource, TResult>(TSource source, Func<TSource, TResult> selector)
where source and result are not enumerables doesn't mean you can't have. In fact, in the last few years, I've seen Bart de Smet twisting LINQ in very interesting ways.@gordanr commented on Sat Jun 20 2015
Can we make a minimum subset of methods that are suitable for implementation?
... select expression apply ToList
... select expression apply ToArray
... select expression apply ???
Is it good idea for the first time to avoid methods with parameters?
@gordanr commented on Sat Jun 20 2015
@paulomorgado
Can you explain this example.
I don't understand how this query can be translated into pure methods chain. Does it mean
Maybe you thought
When we talk about Distinct we should have in mind how works default comparator.
@gordanr commented on Sat Jun 20 2015
More precisely, I don't understand how to use 'apply' before 'select expression'.
Now we can write 'where' more times between first 'from' and the last 'select'.
For example, I usually write 'let' between two 'where'.
Do we think about this form of 'apply'?
Can we make a list of suitable methods in this case?
Is it good approach?
@paulomorgado commented on Sat Jun 20 2015
@gordanr,
The point of this proposal is to not be limited to any set of methods. And to allow methods with none or one parameter.
This:
will translate into:
On the other hand, this:
will translate into:
apply
is used as any other clause with the only difference that the first operand is a method.You can write this:
as this:
if you want to.
@gordanr commented on Sat Jun 20 2015
Thank you. Very, very interesting. I will think more about that.
@gordanr commented on Sun Jun 21 2015
That was a key.
Now, I understand better your proposal.
Yes. Now when I understand I agree with you regarding parameters.
@gordanr commented on Sun Jun 21 2015
This is a piece of code from one of my old WinForms application.
Now we can write
Very nice.
@gordanr commented on Sun Jun 21 2015
Element operations have Immediate Execution. These methods are always on the end of query or subquery.
Or in some form of possible infix notation. This notation can coexist with apply.
@gordanr commented on Sun Jun 21 2015
This group of my favourite methods have Immediate Execution. These methods are always on the end of query or subquery.
ToArray, ToDictionary, ToList, ToLookup
@gordanr commented on Sun Jun 21 2015
Methods All and Any have Immediate Execution. These methods are always on the end of query or subquery.
Here is one VB example.
And some F#.
I am not convinced that it is good to introduce special form of syntax for this purpose which exists in VB.
@gordanr commented on Sun Jun 21 2015
These methods have Immediate Execution. These methods are always on the end of query or subquery.
Here is VB syntax.
And some F#
We can avoid special form of Aggregate syntax that exists in VB.
Some possible infix improvements that can coexist with apply.
@gordanr commented on Sun Jun 21 2015
Here is VB syntax.
And some F#
C# Examples
@gordanr commented on Sun Jun 21 2015
VB example
C# example
Or some possible alternatives.
@paulomorgado I am not sure that method Distinct has correct syntax.
@gordanr commented on Mon Jun 22 2015
Some examples in C# and F#
@paulomorgado commented on Sun Jun 21 2015
@gordanr,
I was thinking of some of my extensions - LINQ: Enhancing Distinct With The SelectorEqualityComparer
@weitzhandler commented on Tue Dec 15 2015
dotnet/roslyn#100 (comment)
I strongly vote for this one.
I never use LINQ language queries and instead my coding guidelines is avoid using them and always use the extension methods directly, and that's because the ugly parentheses each query has to be wrapped in order to materialize it (
ToArray
,ToList
,Sum
,SingleOrDefault
etc.).Until this issue is addressed, language-build-in LINQ is merely useless.
I really hope to see this implemented soon. Maybe to a more limited extent (avoiding the introduction of a gazillion new language keywords.
I'd say the syntax should provide an operator that expects a shortcutted extension method available for
IEnumerable<TElement>
, for instance:Asynchronous methods should also be supported:
Maybe there should be a verbose LINQ fashioned way to pass the arguments and completely avoid the use of parenthesis, but I personally don't see it as necessary.
Anyway this feature is crucial for the completeness of the LINQ syntax.
Some suggestions above proposed the
ToList
at the beginning of the query, but that's a no go, since we want to be able to process it after the selection, and we don't want to be limited to parameterless ex. methods only. What if we wanna callToLookup
with a key selector, bottom line we can't tie it up to the language, we just need to find a way to call anyEnumerable
ex. methods on the current query state and treat its result as the final type of the query.Beta Was this translation helpful? Give feedback.
All reactions