What's the Point of a Lambda Expression

What's the point of a lambda expression?

First: brevity and locality:

Which would you rather write, read and maintain? This:

    var addresses = customers.Select(customer=>customer.Address);

or:

static private Address GetAddress(Customer customer)
{
return customer.Address;
}

... a thousand lines later ...

var addresses = customers.Select(GetAddress);

What's the point of cluttering up your program with hundreds or thousands of four-line functions when you could just put the code you need where you need it as a short expression?

Second: lambdas close over local scopes

Which would you rather read, write and maintain, this:

var currentCity = GetCurrentCity();
var addresses = customers.Where(c=>c.City == currentCity).Select(c=>c.Address);

or:

static private Address GetAddress(Customer customer)
{
return customer.Address;
}

private class CityGetter
{
public string currentCity;
public bool DoesCityMatch(Customer customer)
{
return customer.City == this.currentCity;
}
}

....

var currentCityGetter = new CityGetter();
currentCityGetter.currentCity = GetCurrentCity();
var addresses = customers.Where(currentCityGetter.DoesCityMatch).Select(GetAddress);

All that vexing code is written for you when you use a lambda.

Third: Query comprehensions are rewritten to lambdas for you

When you write:

var addresses = from customer in customers
where customer.City == currentCity
select customer.Address;

it is transformed into the lambda syntax for you. Many people find this syntax pleasant to read, but we need the lambda syntax in order to actually make it work.

Fourth: lambdas are optionally type-inferred

Notice that we don't have to give the type of "customer" in the query comprehension above, or in the lambda versions, but we do have to give the type of the formal parameter when declaring it as a static method. The compiler is smart about inferring the type of a lambda parameter from context. This makes your code less redundant and more clear.

Fifth: Lambdas can become expression trees

Suppose you want to ask a web server "send me the addresses of the customers that live in the current city." Do you want to (1) pull down a million customers from the web site and do the filtering on your client machine, or (2) send the web site an object that tells it "the query contains a filter on the current city and then a selection of the address"? Let the server do the work and send you only the result that match.

Expression trees allow the compiler to turn the lambda into code that can be transformed into another query format at runtime and sent to a server for processing. Little helper methods that run on the client do not.

What's the point of lambda in scheme?

A let is a lambda.

E.g.

(let ((x 1))
body)

can be translated into

((lambda (x) body) 1)

Furthermore, in Scheme all control and environment structures can be represented by lambda expressions and applications of lambdas.

So, lambda is strictly more powerful than let and forms the basis of many of the interesting constructs found in Scheme.

Concerning define and lambda, a top-level define adds a binding to the top-level environment.

When you write

(define (f x)
body)

you are really saying

(define f (lambda (x) body))

Nested defines are translated into letrec, which can be rewritten using lambdas as well.

So, again, a lot of Scheme constructs can be translated into something using lambda, and therefore it is really worthwile that you understand lambda well.

What's the reason for using lambda expressions to define functions in Scheme?

(define (x . a) ...) 

is just an abbreviation for

(define x (lambda a ...))

In the very first scheme report from 1975 you didn't have this abbreviation. In the revised report from 1978 it was introduced.

The little Schemer is just a later edition of The little Lisper from 1974. It predates Scheme and when fixed to follow Scheme they tried to keep is as close to the original as possible. Besides when you use (define x (lambda (arg1) ...)) it's obvious that procedure bindings are not different from other variable bindings other than the object it points to is closure code rather than data.

If you look at the SICP video lectures you'll see that Abelson and Sussman do have students who are confused with this so it's probably best using only one of these and since anonymous procedures are something you need to touch eventually it's obvious you want to teach the form with a explicit lambda instead of the syntactic sugar.

C# Lambda expressions: Why should I use them?

Lambda expressions are a simpler syntax for anonymous delegates and can be used everywhere an anonymous delegate can be used. However, the opposite is not true; lambda expressions can be converted to expression trees which allows for a lot of the magic like LINQ to SQL.

The following is an example of a LINQ to Objects expression using anonymous delegates then lambda expressions to show how much easier on the eye they are:

// anonymous delegate
var evens = Enumerable
.Range(1, 100)
.Where(delegate(int x) { return (x % 2) == 0; })
.ToList();

// lambda expression
var evens = Enumerable
.Range(1, 100)
.Where(x => (x % 2) == 0)
.ToList();

Lambda expressions and anonymous delegates have an advantage over writing a separate function: they implement closures which can allow you to pass local state to the function without adding parameters to the function or creating one-time-use objects.

Expression trees are a very powerful new feature of C# 3.0 that allow an API to look at the structure of an expression instead of just getting a reference to a method that can be executed. An API just has to make a delegate parameter into an Expression<T> parameter and the compiler will generate an expression tree from a lambda instead of an anonymous delegate:

void Example(Predicate<int> aDelegate);

called like:

Example(x => x > 5);

becomes:

void Example(Expression<Predicate<int>> expressionTree);

The latter will get passed a representation of the abstract syntax tree that describes the expression x > 5. LINQ to SQL relies on this behavior to be able to turn C# expressions in to the SQL expressions desired for filtering / ordering / etc. on the server side.

Do lambda expressions have any use other than saving lines of code?

Lambda expressions do not change the set of problems you can solve with Java in general, but definitely make solving certain problems easier, just for the same reason we’re not programming in assembly language anymore. Removing redundant tasks from the programmer’s work makes life easier and allows to do things you wouldn’t even touch otherwise, just for the amount of code you would have to produce (manually).

But lambda expressions are not just saving lines of code. Lambda expressions allow you to define functions, something for which you could use anonymous inner classes as a workaround before, that’s why you can replace anonymous inner classes in these cases, but not in general.

Most notably, lambda expressions are defined independently to the functional interface they will be converted to, so there are no inherited members they could access, further, they can not access the instance of the type implementing the functional interface. Within a lambda expression, this and super have the same meaning as in the surrounding context, see also this answer. Also, you can not create new local variables shadowing local variables of the surrounding context. For the intended task of defining a function, this removes a lot of error sources, but it also implies that for other use cases, there might be anonymous inner classes which can not be converted to a lambda expression, even if implementing a functional interface.

Further, the construct new Type() { … } guarantees to produce a new distinct instance (as new always does). Anonymous inner class instances always keep a reference to their outer instance if created in a non-static context¹. In contrast, lambda expressions only capture a reference to this when needed, i.e. if they access this or a non-static member. And they produce instances of an intentionally unspecified identity, which allows the implementation to decide at runtime whether to reuse existing instances (see also “Does a lambda expression create an object on the heap every time it's executed?”).

These differences apply to your example. Your anonymous inner class construct will always produce a new instance, also it may capture a reference to the outer instance, whereas your (Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName()) is a non-capturing lambda expression that will evaluate to a singleton in typical implementations. Further, it doesn’t produce a .class file on your hard drive.

Given the differences regarding both, semantic and performance, lambda expressions may change the way programmers will solve certain problems in the future, of course, also due to the new APIs embracing ideas of functional programming utilizing the new language features. See also Java 8 lambda expression and first-class values.


¹ From JDK 1.1 to JDK 17. Starting with JDK 18, inner classes may not retain a reference to the outer instance if it is not used. For compatibility reasons, this requires the inner class not be serializable. This only applies if you (re)compile the inner class under JDK 18 or newer with target JDK 18 or newer. See also JDK-8271717

Very simple explanation of a Lambda Expression

A lambda expression is, simply put, a re-useable expression which takes a number of arguments:

x => x + 1;

The above expression reads "for a given x, return x + 1".

In .NET, this is powerful, because it can be compiled into an anonymous delegate, a nameless function you can declare inline with your code and evaluate to get a value:

int number = 100;

Func<int, int> increment = x => x + 1;

number = increment(number); // Calls the delegate expression above.

However, the real power of a lambda expression is that it can be used to initialize an in-memory representation of the expression itself.

Expression<Func<int, int>> incrementExpression = x => x + 1;

This means that you can give that expression to something like LINQ to SQL and it can understand what the expression means, translating it into a SQL statement that has the same meaning. This is where lambdas are very different from normal methods and delegates, and normally where the confusion begins.

What is a lambda expression in C++11?

The problem

C++ includes useful generic functions like std::for_each and std::transform, which can be very handy. Unfortunately they can also be quite cumbersome to use, particularly if the functor you would like to apply is unique to the particular function.

#include <algorithm>
#include <vector>

namespace {
struct f {
void operator()(int) {
// do something
}
};
}

void func(std::vector<int>& v) {
f f;
std::for_each(v.begin(), v.end(), f);
}

If you only use f once and in that specific place it seems overkill to be writing a whole class just to do something trivial and one off.

In C++03 you might be tempted to write something like the following, to keep the functor local:

void func2(std::vector<int>& v) {
struct {
void operator()(int) {
// do something
}
} f;
std::for_each(v.begin(), v.end(), f);
}

however this is not allowed, f cannot be passed to a template function in C++03.

The new solution

C++11 introduces lambdas allow you to write an inline, anonymous functor to replace the struct f. For small simple examples this can be cleaner to read (it keeps everything in one place) and potentially simpler to maintain, for example in the simplest form:

void func3(std::vector<int>& v) {
std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}

Lambda functions are just syntactic sugar for anonymous functors.

Return types

In simple cases the return type of the lambda is deduced for you, e.g.:

void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) { return d < 0.00001 ? 0 : d; }
);
}

however when you start to write more complex lambdas you will quickly encounter cases where the return type cannot be deduced by the compiler, e.g.:

void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}

To resolve this you are allowed to explicitly specify a return type for a lambda function, using -> T:

void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) -> double {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}

"Capturing" variables

So far we've not used anything other than what was passed to the lambda within it, but we can also use other variables, within the lambda. If you want to access other variables you can use the capture clause (the [] of the expression), which has so far been unused in these examples, e.g.:

void func5(std::vector<double>& v, const double& epsilon) {
std::transform(v.begin(), v.end(), v.begin(),
[epsilon](double d) -> double {
if (d < epsilon) {
return 0;
} else {
return d;
}
});
}

You can capture by both reference and value, which you can specify using & and = respectively:

  • [&epsilon, zeta] captures epsilon by reference and zeta by value
  • [&] captures all variables used in the lambda by reference
  • [=] captures all variables used in the lambda by value
  • [&, epsilon] captures all variables used in the lambda by reference but captures epsilon by value
  • [=, &epsilon] captures all variables used in the lambda by value but captures epsilon by reference

The generated operator() is const by default, with the implication that captures will be const when you access them by default. This has the effect that each call with the same input would produce the same result, however you can mark the lambda as mutable to request that the operator() that is produced is not const.

What is the advantage of lambda expressions over method variables?

You should understand what the reflections API is for. It is made for you to do things that are not possible, or hard to do, with other language features.

An official documentation states one (and IMO the most important) use case:

Debuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite.

So using reflections can be very useful in testing where you want to have full access to the code you test. You get access to private methods and fields, you can change final fields and so on. The documentation states one big disadvantage:

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

The flexibility comes with performance drawbacks. There are more use cases and disadvantages that you can find in the documentation I've linked.

Using a lambda here in your case is just what a lambda is supposed to be used for (besides other things). Using reflections here is just not what reflections are made for. You can, but you shouldn't.



Related Topics



Leave a reply



Submit