In your sense, you don't need them for 100% of the code.
Lambdas are NEVER required, as tons of other syntactic features are never required.
They are nice to have though, because they make the code more concise and reduce bugs but reducing boilerplate and repetition. Working without them when you have them at your disposal is idiotic.
That huge .Net 4.0 systems have been written without a single lambda probably speaks more about the programmers (not experienced enough?) than about lambdas.
I don't think that they reduce bugs at all - that's a bit of a wired assertion to make.
Its not about the programmers but the architecture. To be honest, the primary use case for lambda expressions in .net is LINQ and possibly container configuration. If you use NHibernate and do not expose IEnumerable anywhere (which is required across network boundaries and encapsulation boundaries) then you just don't see it anywhere.
> To be honest, the primary use case for lambda expressions in .net is LINQ
Uhm, yes, if you're incapable of using delegates and writing functions that take delegates as parameters, then you'll only use lambda expressions where other people have written such functions, for example in LINQ or the generic collections in the framework.
But if you can use delegates, and if you can use lambda expressions, they're a wonderful tool to make your code more readable, and that in turn reduces bugs.
If you're considering Action<T> and the numerous Func<T> implementations, then I disagree mostly.
They decrease efferent coupling but do not decrease bugs.
There is no direct correlation between readability and bugs from my experience. Some of the least buggy code I've seen is messy and likewise the most buggy can be the most readable. There is not enough correlation to draw that conclusion.
The metric that is important is the skill of the programmer who fulfilled the specification and their ability to understand the task fully and their ability to translate that understanding to the language at hand and know where and when things will go snap.
Things that DO increase bugs:
1. Crap programmers.
2. Coupling - log increase in side effects of a change.
3. Bad test coverage.
4. Poor design up front.
5. The killer: bad specifications (not even a code issue!).
Using more advanced language features does not necessarily improve things.
0. APIs that don't leverage the compiler to enforce correctness and catch bugs at compile time.
Designing APIs in such a way often requires FP language features. You can often model equivalent APIs without FP features, but they'll be so verbose as to be unusable.
I think the implication here is that if they require fewer lines of code, they are going to reduce the number of bugs.
Regarding LINQ: is there any .NET app out there that isn't using IEnumerable at some point? I can't recall every writing an app that didn't use it, unless it was an extremely simple app. Besides that, Lambdas are very useful in event subscription.
4 hand grenades waiting to go off in that expression. Try and spot them.
We have a 670kloc platform that doesn't have a single one in it (it's still .Net 2.0). 450 domain objects, 1000+ NH criteria queries and about 650 aspx pages...
I don't see any pitfalls that wouldn't arise with imperative techniques. Well, Single() throws if there is no or more than one item with the property name "Blah!" in the collection, but if you just want the first one or none you should use FirstOrDefault() anyway. The point is that you need to write roughly a dozen lines with more room for hand grenades to reproduce that functionality with imperative constructs:
Thing blah;
bool found = false;
foreach (var item in collection) {
if (item.Property.Name == "Blah!") {
if (!found) {
found = true;
blah = item;
} else {
throw new InvalidOperationException("collection contains more than one \"Blah!\" item!");
}
}
}
if (!found)
throw new InvalidOperationException("collection does not contain a \"Blah\" item");
Come on, that's ridiculously verbose and doesn't solve any problems of the lambda version. If you are concerned about nulls, then you have to insert != null expressions anyway. And you can easily refactor by introducing an additional right above the old one,
while inserting the null checks into the imperative code takes considerably more effort (locating the predicate, making a decision weather or not to turn the predicate into a 120 char wide monster or adding another if block etc.)
You miss one important point, which I've learned from many years of using .Net:
Which dereference in your LINQ expression is causing the NullReferenceException?
Try solving that problem when it goes pop in production and you have a couple of million quid in flight!
I'd write it as follows (probably wrapped as a generic function of T:
public Thing GetItemWithName(ICollection<Thing> collection)
{
Thing output;
int found;
// preconditions
Check.IsNotNull(collection, "collection was null");
foreach(var item in collection)
{
// ref checks
Check.IsNotNull(item, "item was null");
Check.IsNotNull(item.Property, "item.Property was null");
Check.IsNotNullOrWhiteSpace(item.Property.Name, "item.Property.Name was null or whitespace");
if (string.Compare(item.Property.Name, "Blah!", StringComparison.InvariantCultureIgnoreCase) != 0)
continue;
found++;
// rule check
Check.IsTrue(found <= 1, "Found more than expected single element in collection");
output = item;
}
// postconditions
Check.IsNotNull(output, "output null. Expected reference");
return thing;
}
Note: I tend to write proper industrial grade stuff that has to work every time without fail or any edge cases or conditions. These conditions are prescribed up front. Zero bugs and fail early is the only acceptable outcome which is why this is verbose.
Well, if the error reporting of Enumerable.Single() isn't good enough for you (i think it throws InvalidOperationExceptions with different messages for both error cases), nothing stops you from implementing it once for yourself and profit from the benefits everytime instead of writing the same looping constructs interlaced with error reporting again and again.
public static T MySingle<T>(
this IEnumerable<T> collection,
Func<T,bool> pred,
string foundNoneMsg,
string notUniqueMsg) {
Check.IsNotNull(collection, "collection was null");
var filtered = items.Where(item => pred(item));
Check.IsTrue(filtered.Any(), foundNoneMsg);
Check.IsFalse(filtered.Skip(1).Any(), notUniqueMsg);
return filtered.Single();
}
bool HasName(this Thing item, string name) {
Check.IsNotNull(item, "item was null");
Check.IsNotNull(item.Property, "item.Property was null");
Check.IsNotNullOrWhiteSpace(item.Property.Name, "item.Property.Name was null");
Check.IsNotNullOrWhiteSpace(name, "name was null or whitespace");
return item.Property.Name
.CompareTo(name, StringComparison.CultureInvariantIgnoreCase);
}
collection.MySingle(
item => item.HasName("Blah!"),
foundNoneMsg: "collection has no item with Property.Name 'Blah!'
notUniqueMsg: "collection contained more than one 'Blah!');
Lambdas are NEVER required, as tons of other syntactic features are never required.
They are nice to have though, because they make the code more concise and reduce bugs but reducing boilerplate and repetition. Working without them when you have them at your disposal is idiotic.
That huge .Net 4.0 systems have been written without a single lambda probably speaks more about the programmers (not experienced enough?) than about lambdas.