LINQ is better than foreach
kodefuguru.com
kodefuguru.com
Most C# developers think LINQ is some fancy new concept but in reality they are just an implementation of Haskell list comprehensions ported to C# by Erik Meijer. I love watching the the imperative and functional languages converge like this.
(Sorry for nipticking, the reason I'm pointing this out because people get confused about the unfortunate Linq terminology all the time).
I believe that the point of author was that any time you are iterating over a list, you should really think about whether you can replace the iteration with a LINQ query. It really doesn't matter whether the list being iterated is an underlying list of objects, a table in an RDBMS, etc.
I believe that this is not the case if you are using LINQ to Objects unless you stick an explicit cast in there somewhere, but I could be wrong. I think that if you simply use the LINQ extension methods on an in-memory IEnumerable, they are simple method calls and involve no compilation to an expression tree.
IEnumerable's extensions are mostly iterators over sequences.
You've just described how compilers work, minus optional attempts at optimization and optional excess passes. Most of which take place either after the expression tree has been generated, or somewhere during the conversion process. Therefore I'd call what you've described "compilation".
(into [] (map full-name
(sort-by :last-name (filter #(= (:role %) 'developer) employees))))
It's good to see mainstream languages adding declarative constructs though.Entirely subjective. To me, "#(= (:" is pure line noise.
(fn [x] (= (:role x) 'developer))I suggest you learn the language you program in; problem solved.
All programming languages look more or less like words interspersed with line noise if you're not familiar with the syntax.
var foo = new List<int>{ 1, 2, 3};
var bar = foo.ConvertAll(x => x * 2);
over the the Linq equivalent: var foo = new List<int>{ 1, 2, 3};
var bar = from x in foo select x * 2var foo= new List<int> {1, 2, 3};
var bar = foo.Select(x => x*2);
One small difference with your example though is that Select requires "using System.Linq", and ConvertAll is defined on List<T>.
int countOfThings = DatabaseRepositoryType.GetThings().Count();
As it will go to the database, pull all of the matching rows locally, create all of the objects, and then iterate through them just increment a counter. Creating a .GetCount() method which calls down to a SQL "SELECT COUNT()" query is more work to write, but runs about a thousand times faster.
The SQL generated in this case depends on the return type of GetThings(). If it returns an IEnumerable<> then it is indeed a terrible thing to do, but if it returns an IQueryable<> then the SQL will be a SELECT COUNT() query, and no objects will be created.
Care does have to be taken when writing this sort of code!
Of course, calling the .Count property yourself is more efficient, but not by orders of magnitude.
I think there is still some validity in my post in confusing whether you are using native accessing or routing through an additional tool/library, but the fix definitely elimates the performance hit I was discussing, so much of my post was in error.
edit: Also 3.5 it seems, I need to be more up-to-date with my concerns.
foreach 00:00:01.7348710 linq 00:00:01.8607973
var developerNames = employees.AsParallel().AsOrdered()
.Where(e => e.Role == Role.Developer)
.OrderBy(e => e.LastName)
.Select(e => e.FullName)
.ToArray();
That's just gross IMHO. AsParallel() yuck. AsOrdered() eugh why are these functions being used to set parameters.In the above example, the state of employees is the same after the execution of the statement as it was before, if you were to set the "Parallel" flag or "Ordered" flag before hand each as their own assignment statement, then you would have modified the initial object and created a side effect.
I am not challenging your opinion, but simply answering your question as to why.
On what kinds of back-end do LINQ and PLINQ support parallelization?
PLINQ is just a parallel implementation of LINQ-to-Objects and LINQ-to-XML. It works in the same scenarios .Net programs work in, i.e. multicores or SMPs running Windows (not sure if PLINQ works with Mono).
var developerNames = from emp in employees.AsParallel().AsOrdered()
where emp.Role == Role.Developer
orderby emp.LastName
select emp.FullName; employees.AsParallel().AsOrdered()
to the more-traditional-C-style MaintainOrder(Parallelize(employees))
or the admittedly more attractive (maintain-order (parallelize employees))
and suddenly it seems perfectly sensible. I thought it was ugly first, too, but now I'm used to it. (maintain-order (parallelize employees))
vs MaintainOrder(Parallelize(employees))
"admittedly more attractive"?
I enjoy functional constructs, but now you're just talking syntax right? (->> employees parallelize maintain-order)
might be said to be more attractive because it looks more linear. The sequential order of application is thus maintained, and the parentheses which are perceived as additional levels of hierarchy are removed.Of course, the dot-dot-dot style in Java/C#/etc is doing the same:
employees.Parallelize().MaintainOrder()
is also linear, the parentheses are only used to specify parameters. someFunction.Memoize();
That's perfectly natural, right? (I mean, you could claim that "is memoized or not" should be a "flag" on a function, but that's starting to sound a little silly to my ears.) It's exactly analogous.LINQ is hardly unusual in having this risk. It is an easy mistake to make in many environments with many toolsets, and it is not particularly hard to avoid it with LINQ. But the toy benchmark doesn't address it. And the article makes fun of a software architect who has likely had bad experiences with developers messing up on this.
I disagree entirely. I know when I'm using LINQ to SQL, and when I'm using LINQ to objects. My experience is that LINQ to objects is more common and very useful. He's using larger data volumes than I generally am, so there's absolutely nothing "toy" about it.
- operates on lists of objects, not database queries.
- operates on small quantities of data. It doesn't matter if there are only five items in a list. If you have to filter them, you have to filter them
- is not that complex.
We use foreaches as well, or a combination. LINQ is great for automating simple things, e.g. turn a loop to find an item into a .FirstOrDefault(x => x.SomeCondition). It would be interesting to see if, as our grasp of LINQ improves, we run into any of these supposed corner cases. But it hasn't happened yet.