When we set our sights on improving LINQ debugging, we assumed that supporting LINQ's method-based Fluent API would be enough to please almost everybody.
Since we believe in creating features that our users actually want, we wanted to hear from actual, living, breathing, users. We gave our team this new version and sent them out into the world to show and demo the new feature, and gather feedback from C# developers. We gave our brilliantly insightful OzCode Magicians community a peek too. After a few weeks we felt good enough about the new LINQ debugging feature, and decided to launch our public Early Access Program so more developers (that means you) could tell us what they like and (more importantly) what they dislike about it.
We received excellent feedback from our users, and a lot of interesting ideas for improvements. One bit of feedback that kept on surfacing was the need to support the SQL-style LINQ queries - the so-called (at least by language geeks) "Query Comprehension" syntax.
And so we'd like to present you with the new version of OzCode EAP (v2.0.0.1826), which now also supports debugging the LINQ Query Comprehension syntax.
► Sign up for the Early Access Program and grab this latest build
To query or not to query, that is the question
When using LINQ to query, filter and transform collections, a developer has a choice between two flavours - the Lambda-filled Fluent API expressions, or SQL-like query expressions. A good example of the differences is shown in a post by Yan Cui, who is a functional programming expert:
Func<int, bool> isEven = i => i % 2 == 0; int[] ints = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // using Query expression var evensQuery = from i in ints where isEven(i) select i; // using Lambda expression var evensLambda = ints.Where(isEven);
The choice of which flavour of LINQ to use depends on the developer's preference, as well as the nature of the problem. The fluent syntax is more terse, and tends to be preferable when the query is simple. However, some more complicated queries are much more easily expressed with the query syntax.
Consider the following code:
var aboveAverageStudents = from department in StudentRepository.GetAllDepartments() let departmentAverage = department.Students.Average(student => student.Grade) from student in department.Students where student.Grade > departmentAverage select student.Name;
This calculates each department's average grade, and then returns the names of students with grades higher than the average - simple and readable.
Using the fluent API, the same functionality would look something like this:
var aboveAverageStudents = StudentRepository.GetAllDepartments() .Select(department => new { Department = department, Average = department.Students.Average(student => student.Grade) }) .SelectMany(arg => arg.Department.Students.Where( student => student.Grade >= arg.Average));
Not as readable, now is it?
This is a good example of how the compiler is doing some fairly complicated magic behind the scenes to allow you to express certain ideas with the Query Syntax that would be a lot more difficult to express with the fluent API. For a full list of these transformations, check out this post by Bart De Smet of Rx fame.
With the new OzCode EAP, you can easily visualize the flow the LINQ query, using code annotations and the LINQ Analysis window:
► Sign up for the Early Access Program and grab the latest build
Which LINQ syntax is better?
There are scenarios which benefit more from using the query syntax, such as when working with join, multiple from clauses or (our personal favorite) using the let keyword. On the other hand, there are operations which only exist in the method-based API - Count, Distinct, First, Take to name a few. And of course some developers feel more comfortable with methods, while others who may come from the relational database world naturally prefer their queries to look more like SQL.
To get more information, one of our interns wrote a utility which scans GitHub projects and gathers statistics about LINQ usage (more on that in a future blog post!). Our intern found that both APIs were widely used, and in fact many projects used both, in many cases even within the same LINQ clause. The point is that you do not have to choose, since the two are not mutually exclusive and work well together.
So in summary, you can have both cakes and eat them too!
Download the latest OzCode EAP which supports both ways of debugging LINQ queries, try it out and let us know what you think!