43

I'm having a discussion with a co-worker on Linq, I'll copy here:

Co-Worker: Lets be honest here. Linq syntax sucks. It's confusing and non-intuitive.

Me: oh come on, more confusing than T-SQL?

Co-Worker: uh, yes.

Me: it has the same basic parts, select, where, and from

Co-Worker: Linq, to me, is a bastardization of relational + OO. Co-Worker: Don't get me wrong - it's incredibly powerful, but they repurposed SQL to use agains object collections.

I'm of the opinion that using Linq + Lamda's is very powerful (he agrees), and also makes code easier to read (he disagrees on that point):

pickFiles = from f in pickFolder.GetFiles("*.txt")
where ValidAuditFileName.IsMatch(f.Name)
select f;

or

var existing = from s in ActiveRecordLinq.AsQueryable<ScannedEntity>()
where s.FileName == f.FullName && s.DocumentType != "Unknown"
select s;

or (VB code here)

   Dim notVerified = From image In images.AsParallel
     Group Join verifyFile In verifyFolder.GetFiles("*.vfy").AsParallel.Where(
      Function(v) v.Length > 0
      ).AsParallel
   On image.Name.Replace(image.Extension, ".vfy") Equals verifyFile.Name
     Into verifyList = Group
    From verify In verifyList.DefaultIfEmpty
    Where verify Is Nothing
    Select verify

To me this is clean and easy (at least easier than the alternatives) to read, what are your opinions on it?

18
  • 11
    Humans, in general, hate change. A large percent hate it so much that they actually fear it.
    – Tony
    Dec 9, 2010 at 16:05
  • 9
    Let's face it... linq is just a dumbed down functional programming syntax added to C# and VB.Net. Bashing linq and lambda expressions is basically saying "FP sucks". That's what your co-worker is saying. I think that debate has been hashed out elsewhere. Dec 9, 2010 at 16:12
  • 48
    Does it bother anyone else that people tend to use the word "intuitive" when they really mean "familiar"? Dec 9, 2010 at 21:52
  • 7
    Anyway, the C# team (including Eric Lippert) have gone out of their way to explain that Linq was not a porting of SQL, it was designed from the ground up like most other features. I would have to say that your co-worker is a Luddite.
    – Aaronaught
    Dec 9, 2010 at 23:34
  • 16
    For what it's worth: I just had my wife (office administrator - next to zero practical programming experience) look at aaronaught's 3 examples and was able to decipher the intent of the linq and lambda examples far more easily than the traditional imperative example. Dec 10, 2010 at 1:14

10 Answers 10

74

I can't find the right post anymore, but Eric Lippert (and possibly several other softies) have opined on several occasions about how Linq is declarative, which, for several classes of problems, is far more intuitive than imperative syntax.

Linq enables you to write code that expresses the intent, not the mechanism.

You tell me which is easier to read. This:

IEnumerable<Customer> GetVipCustomers(IEnumerable<Customer> source)
{
    List<Customer> results = new List<Customer>();
    foreach (Customer c in source)
    {
        if (c.FirstName == "Aaron")
        {
            results.Add(c);
        }
    }
    results.Sort(new LastNameComparer());
    return results;
}

class LastNameComparer : IComparer<Customer>
{
    public int Compare(Customer a, Customer b)
    {
        return x.LastName.CompareTo(b.LastName);
    }
}

Or this?

IEnumerable<Customer> GetVipCustomers(IEnumerable<Customer> source)
{
    return from c in source
           where c.FirstName == "Aaron"
           orderby c.LastName
           select c;
}

Or even this?

IEnumerable<Customer> GetVipCustomers(IEnumerable<Customer> source)
{
    return source.Where(c => c.FirstName == "Aaron").OrderBy(c => c.LastName);
}

The first example is just a bunch of pointless boilerplate in order to obtain the simplest of results. Anybody who thinks that it is more readable than the Linq versions needs to have his head examined. Not only that, but the first one wastes memory. You can't even write it using yield return because of the sorting.

Your coworker can say what he wants; personally, I think Linq has improved my code readability immeasurably.

There's nothing "relational" about Linq either. It may have some superficial similarities to SQL but it does not attempt in any shape or form to implement relational calculus. It's just a bunch of extensions that make it easier to query and project sequences. "Query" does not mean "relational", and there are in fact several non-relational databases that use SQL-like syntax. Linq is purely object-oriented, it just happens to work with relational databases through frameworks such as Linq to SQL because of some expression tree voodoo and clever design from the C# team, making anonymous functions implicitly convertible to expression trees.

7
  • 6
    +1 If you don't like LINQ its probably because "you ain't doing it right" :)
    – Darknight
    Dec 13, 2010 at 9:28
  • 1
    Linq is purely object-oriented +1 for this. This is also why our team style guide enforces using the fluent syntax over the query syntax. I find that makes the OO nature of link more obvious to somebody used to object notation in C-like languages.
    – SBI
    Feb 25, 2015 at 9:15
  • 2
    I know that the post is 7 years old. But here's the question: did you use functional languages as your main tools before meeting Linq? Dec 12, 2016 at 14:05
  • 4
    Quite frankly, I prefer the foor loop, because then I see right-away where we can and will have NULL-reference exceptions, how null is handled, and it's not deferred execution which makes debugging hard, and it doesn't create n lists as well, so the for-loop is more efficient as well.
    – Quandary
    Feb 7, 2017 at 13:32
  • 1
    @Aaronaught, If you remove the sorting and reformat the procedural code in Horstmann style, I shall say it is more readable than the LINQ version. And according to the principle of single responsibility, the sorting does not actually belong in GetVipCustomers(), which, as its very name suggests, shall only return a collection of VIP customers, in arbitrary order. For the rare cases where order is important, such as output to the screen, let the caller sort the collection. Dec 30, 2017 at 18:43
72

Co-Worker: Lets be honest here. Linq syntax sucks. It's confusing and non-intuitive.

You can't argue with that criticism. For your coworker, it sucks. We failed to design a syntax that, for them, was clear and intuitive. That's our failing, and you can pass on my apologies to your coworker. I am happy to take suggestions on how to make it better; what specifically does your coworker find confusing or unintuitive?

However, you can't please everyone. My personal opinion, and the opinion of most of the people I've talked to on the subject, is that the query comprehension syntax is much more clear than the equivalent imperative syntax. Clearly not everyone agrees, but fortunately we do not require consensus of all the millions of our customers when we do language design.

On the subject of what is "intuitive" though, I am reminded of the story of the English linguist who studied many different languages and finally concluded that English was the best of all languages because in English, the words come in the same order that you think them. Unlike French, where they're constantly saying things like "the dog white eats the meat red". How hard it must be for French people to think the words in the correct order and then have to say them in the French order! French is so unintuitive! It's amazing that the French manage to speak it. And German? where they think "the dog eats the meat" but then have to say "the dog the meat eats" !?! So unintuitive.

Often what is "intuitive" is merely a matter of familiarity. It took me months of working with LINQ before I stopped beginning my queries with the "select" clause. Now it is second nature, and the SQL order seems bizarre.

Which it is! The scoping rules are all messed up in SQL. Something you might want to point out to your coworker is that LINQ was carefully designed so that (1) introduction of variables and scopes happens left-to-right (*), and (2) the order that the query appears on the page is the order in which it is executed. That is, when you say

from c in customers where c.City == "London" select c.Name

the c appears in scope at the left, and stays in scope through the right. And the order in which things happen are: first "customers" is evaluated. Then the "where" is evaluated to filter the sequence. Then the filtered sequence is projected by the "select".

SQL doesn't have this property. If you say

SELECT Name FROM Customers WHERE City = 'London'

then "Name" is brought into scope by something to its right, not to its left, and the query is executed in a completely messed up order; the middle clause is evaluated first, then the last clause, and then the first clause. That now seems crazy and unintuitive to me, having worked solely with LINQ for so long now.


(*) Scoping rules are a bit weird in LINQ with join clauses. But other than that, scopes nest nicely.

12
  • 5
    Nitpick: In German, "Der Hund frisst das Fleisch" is actually the same order as in English, "The dog eats the Meat" :) Aside from that, I found LINQ Query syntax very readable once i realized it was not SQL. Mar 8, 2011 at 0:22
  • 18
    @gbjbaanb: I am not justifying the LINQ syntax on the entirely subjective basis of it being more understandable. Rather, I'm justifying it on the entirely objective basis that it is far easier to design tools that assist the user in the construction of LINQ queries because the LINQ syntax was designed with tooling in mind, and that it is easier to mentally understand the order in which events happen in a query because they come in the same order lexically. Jun 7, 2011 at 6:11
  • 2
    Eric, From a programming perspective of the declarative style I understand Linq is appropriate (i din say readable) than SQL. But is it more human readable than SQL? No way. If 'dog eats meat red' is hard, how much easier is 'from kitchen where colour is red get knife'? In fact we all talk and think like 'get that knife which is on top of the table from kitchen'. And that is where SQL is closer to real life than LINQ.
    – nawfal
    Nov 21, 2012 at 20:14
  • 6
    I want a cup of coffee from starbucks where the store is open until midnight. Does that sounds familiar to you? It's in the exact same order as a SQL query. Yes, LINQ may be more readable than the unnecessary code you have to generate to execute a standard SQL query, but LINQ is not more readable than the SQL query itself. So yes; it might be advantageous for the LINQ developers to scope from left to right, but as a user, why do I care? I only care about usability.
    – Kyle
    Mar 8, 2013 at 17:01
  • 8
    @KyleM: Of course; usability was a very important aspect of the LINQ design. In particular, being amenable to productivity tools was key. Because scoping flows from left to write in a LINQ query, by the time you type c. the IDE already knows the type of c and can give you IntelliSense. In LINQ you say "from c in customers where c." and boom, you get IntelliSense helping you by listing the members of Customer. In SQL when you type "SELECT name FROM customers" you can't get any IDE help to tell you that "name" is a good choice because you typed name before customers. Mar 8, 2013 at 17:41
23

Like anything else in the programming world, you gotta get used to the syntax, and then it is (potentially) easier to read.

Like anything else in the programming world, there is the potential for spaghetti code or other abuses.

Like anything else in the programming world, you can either do it this way or another way.

Like anything else in the programming world, your mileage may vary.

6

I saw a comment/remark where it stated something - in relation to LINQ/lambda - along the lines of: "Write code readable to humans, rather than readable to your computer".

I think that this statement has a lot of merit, however, consider the developer (such as myself) who has been through the full gamut of development languages from Assembly, through procedural, through OO, through managed, through leveraging high throughput task parallel solutions.

I have prided myself on making my code as readable and as reusable as possible and adopting many of the GOF design pattern principles in order to deliver production quality systems and services across a wide number of disparate business sectors.

The first time I encountered the lambda expression I thought: "What the hell is that!?!" It was immediately counter-intuitive to my familiar (and therefore comfortable) explicit declarative syntax. The younger < 5yrs in the job guys however lapped it up like it was manna from heaven!

That is because for years thinking like a computer (in the syntactic sense) translated very easily into direct coding syntax (irrespective of the language). When you have had that computational mindset for circa 20+yrs (30+ in my case) you have to appreciate that the initial syntactic shock of the lambda expression can easily translate into fear and mistrust.

Maybe the co-worker in the OP had come from a similar background as myself (i.e. been around the block a few times) and it was counter-intuitive to them at that time? My question is: what did you do about it? Did you try to re-educate your peer into understanding the benefits of the inline syntax, or did you pillory/ostracise them for not "being with the program"? The former would probably have seen your co-worker come round to your line of thinking, the latter would probably make them mistrust the LINQ/lambda syntax even more and thus exacerbating the negative opinion.

For myself I had to re-educate my own way of thinking (as Eric infers above, it's not an insignificant mind-shift, and I had to program in Miranda in the '80s so I've had my share of functional programming experience) but once I had gone through that pain the benefits were obvious but - more importantly - where its usage was over used (i.e. used for the sake of using it), over complex and repetitive (considering the DRY principle in that instance).

As someone who not only still writes a lot of code but who also has to technically review a lot of code it was imperative that I understood these principles so that I could review items impartially, advise where usage of a lambda expression may be more efficient/readable, and also to get developers to consider the readability of highly complex inline lambda expressions (where a method call would - in those cases - make the code more readable, maintainable and extensible).

So when someone says that they "Don't get lambda?" or LINQ syntax, rather than brand them a luddite try to help them understand the underlying principles. They may after all have an "old school" background such as myself.

1
  • Interesting comment - I had this when I switched from strongly-typed, static languages to dynamic languages. Took me a while to adjust (fear and mistrust) and now I find it hard to go back, honestly.
    – user26452
    Feb 12, 2014 at 21:31
4

Lambda Expressions leads to less readable code if queries are too long. However it's much better than too many nested loops.

It's better with a mixture of the two.

Write it in Lambda if it's faster (you need it to be fast) or easier to read.

2
  • Yes, but what would make it linq/lamda not easier to read?
    – BlackICE
    Dec 9, 2010 at 16:11
  • sorry, meant not easier to read than the alternative.
    – BlackICE
    Dec 9, 2010 at 16:22
1

I think it depends in most cases (except when doing something very bizarre) on if you mean "readable" as someone getting the idea of what is going on or if they can easily find all the tiny little details.

I think link helps with the former, but often (especially when debugging) hurts the latter.

IMHO when I am looking at code I am unfamiliar with the former is hugely more important than the latter, so I find it much more readable.

6
  • Good point. The latter is usually covered by good unit test. Dec 9, 2010 at 16:11
  • So you think the internals of linq evaluation makes it difficult to find all the details? Can you provide an example of when this may be?
    – BlackICE
    Dec 9, 2010 at 16:13
  • 3
    @David: Linq expressions are not just lazy evaluated, they're expressions. The receiving code of a linq expression can actually modify the expression so it does something completely different, like a lisp macro working on s-expressions. For instance, when working with linq to SQL, it actually takes the expression where e.FirstName == "John" and translates that into a SQL query! It does that by looking at the uncompiled (but parsed) expression, seeing it's a comparison of a property called FirstName on a persisted entity, and it's comparing to a string, etc. There's a lot going on. Dec 9, 2010 at 16:46
  • @david generally I dont find the details difficult to find until you start using linq against itself. A "simple" example of this that took me a long time to wrap my head around is this: bugsquash.blogspot.com/2008/07/y-combinator-and-linq.html but there are a lot more necessarily examples in some of the things people are doing with expressions in the dynamic, DynamicObject and IDynamicMetaObjectProvider areas. Where you draw the line as to what is linq is debatable, but as scott points out all of that stuff is available to/in linq because linq uses the same expression trees.
    – Bill
    Dec 9, 2010 at 17:40
  • @Bill all right, I'll give you that's tough, but y-combinator and high order functions are going to hurt most of our heads, it's like recursion, you get it or you don't. Is the recursive implementation of that easier to read (if you didn't know either one)?
    – BlackICE
    Dec 9, 2010 at 18:42
1

I agree with you that Linq syntax is not significantly different from T-SQL. I think your coworker might really be objecting to relational stuff getting mixed in which his nice and shiny OO code. On the other hand, functional programming takes a bit of getting used to, and a willingness to get used to it.

0

I find LINQ syntax intuitive and easy to read, especially since they put the FROM at the start where it belongs instead of in the middle like in SQL. But IMO lambdas are confusing and make the code harder to read.

7
  • Why do you think lambdas are confusing? Is it the type inference? Dec 9, 2010 at 17:30
  • 1
    @ChaosPandion: First the type inference, and second, the symbol. Putting an = and a > together looks like a >= that someone screwed up and wrote backwards, and it tends to throw my brain for a loop. Dec 9, 2010 at 17:45
  • @Mason - Do you like the syntax of Haskell (\x -> x * x) or F# (fun x -> x * x)? Dec 9, 2010 at 19:07
  • @ChaosPandion: No, not particularly. Lambdas may be quick to write, but I find them difficult to parse, especially when they become non-trivial in complexity. Your examples aren't that bad, but they tend to get a lot worse. Dec 9, 2010 at 19:14
  • 6
    @Mason: It sounds like you're objecting to lamdas being abused, rather than objecting to the idea of lamdas in the first place.
    – Anon.
    Dec 9, 2010 at 20:14
0

It depends. Obviously, T-SQL uniquely provides some DB-relational solutions. Obviously LINQ uniquely provides some OO solutions.

However; "more confusing than T-SQL?" - is discussed/asked in the initial question. This clearly implies some features that none of the existing answers address, instead accusing the (obviously SQL-acquainted) criticizer of being stuck in the past.

So although I appreciate LINQ for certain qualities, and don't greatly disagree with the existing answers here, I feel the counterpoint deserves representation:

Years after becoming familiar with LINQ, performing certain types of group operations, outer joins and non-equijoins, working with composite keys, and other operations in LINQ still make me cringe. (Especially when targeting a relational back-end with performance-sensitive questions.)

from c in categories
join p in products on c equals p.Category into ps
from p in ps.DefaultIfEmpty()

If you think that's intuitive, more power to you. ;)

-4

There is probably a reason why Linq sucks, just do try to make real world examples, instead of these textbook examples.

try to show this function in linqlamdathings and you will see, that all the beauty is gone, while the classic way remains readable. Not to mention deferred execution problems and setting breakpoints.

The truth is LinqLambdaThings are very useful in few cases and they are not thought to replace all the nifty object orientation that you guys never understood

    public IList<Customer> GetVipCustomers(IList<Customer> source, int maxCount)
    {
        var results = new SortedList<string,Customer>();

        foreach (Customer c in source)
        {
            if (maxCount == results.Count)
                break;

            if (c.IsVip && c.FirstName== "Aaron" || c.SecondName== "Aaron")
                results.Add(c.LastName, c);
        }

        return results.Values;
    }
4
  • 6
    I think its source.Where(c => c.IsVip && c.FirstName == "Aaron" || c.SecondName == "Aaron").Take(maxCount).OrderBy(d => d.LastName); but its hard to read yours so I may have made a mistake ;)
    – jk.
    Mar 14, 2013 at 14:18
  • 1
    In what way did you consider these to be textbook examples? That is actually production use code. It would help if you provided both your classic "readable" code and the linq/lamda version for comparison instead of expecting everyone to convert it.
    – BlackICE
    Mar 14, 2013 at 15:04
  • 3
    Did you register specifically to complain about LINQ?
    – KChaloux
    Mar 28, 2013 at 19:37
  • 1
    @KChaloux I think they were just trolling to be honest
    – jk.
    Mar 28, 2013 at 19:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.