Can the 'Type' of a Lambda Expression Be Expressed

Can the 'type' of a lambda expression be expressed?

No, you cannot put it into decltype because

A lambda-expression shall not appear in an unevaluated operand

You can do the following though

auto n = [](int l, int r) { return l > r; };
std::set<int, decltype(n)> s(n);

But that is really ugly. Note that each lambda expression creates a new unique type. If afterwards you do the following somewhere else, t has a different type than s

auto m = [](int l, int r) { return l > r; };
std::set<int, decltype(m)> t(m);

You can use std::function here, but note that this will incur a tiny bit of runtime cost because it needs an indirect call to the lambda function object call operator. It's probably negligible here, but may be significant if you want to pass function objects this way to std::sort for example.

std::set<int, function<bool(int, int)>> s([](int l, int r) { return l > r; });

As always, first code then profile :)

Is it safe to assume that identical lambda expressions have different types?

Is the compiler allowed to let c be of the same type than a?

No. [&counter](){counter++;} is a lambda expression and per [expr.prim.lambda.closure]/1:

The type of a lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type, called the closure type, whose properties are described below.

So, for each lambda expression, even if it is identical to a previous one, you will get a unique type.

You can use typeid to check that this is the case like:

#include <iostream>
#include <typeinfo>

template <typename T> void once(T t){
static bool first_call = true;
std::cout << typeid(t).name() << std::endl;
if (first_call) {
t();
}
first_call = false;
}

int main() {
int counter = 0;
auto a = [&counter](){counter++;};
once(a);
once(a);
std::cout << counter << std::endl; // 1

auto b = a; // same type
once(b);
std::cout << counter << std::endl; // 1

auto c = [&counter](){counter++;}; // different type
once(c);
once(c);
std::cout << counter << std::endl; // 2
}

result:

Z4mainEUlvE_                                                                                                          
Z4mainEUlvE_
1
Z4mainEUlvE_
1
Z4mainEUlvE0_
Z4mainEUlvE0_
2

and you can see there are two function template instantiations.

What happens if we add different parameter type in a function interface of a lambda expression?

First of all the Function you have written is wrong. It should be corrected as below.

Function<Integer, String> fn = s -> String.valueOf(s);

You can't state a different data type as above, only thing you can state is an integer. Any other data type as the input parameter would result in a compilation failure. The data type of the lambda function parameter is optional and is inferred by the compiler.

what is the type signature of a c++11/1y lambda function?

According to Can the 'type' of a lambda expression be expressed?, there is actually a simple way in current c++ (without needing c++1y) to figure out the return_type and parameter types of a lambda. Adapting this, it is not difficult to assemble a std::function typed signature type (called f_type below) for each lambda.

I. With this abstract type, it is actually possible to have an alternative way to auto for expressing the type signature of a lambda, namely function_traits<..>::f_type below. Note: the f_type is not the real type of a lambda, but rather a summary of a lambda's type signature in functional terms. It is however, probably more useful than the real type of a lambda because every single lambda is its own type.

As shown in the code below, just like one can use vector<int>::iterator_type i = v.begin(), one can also do function_traits<lambda>::f_type f = lambda, which is an alternative to the mysterious auto. Of course, this similarity is only formal. The code below involves converting the lambda to a std::function with the cost of type erasure on construction of std::function object and a small cost for making indirect call through the std::function object. But these implementation issues for using std::function aside (which I don't believe are fundamental and should stand forever), it is possible, after all, to explicitly express the (abstract) type signature of any given lambda.

II. It is also possible to write a make_function wrapper (pretty much like std::make_pair and std::make_tuple) to automatically convert a lambda f ( and other callables like function pointers/functors) to std::function, with the same type-deduction capabilities.

Test code is below:

#include <cstdlib>
#include <tuple>
#include <functional>
#include <iostream>
using namespace std;

// For generic types that are functors, delegate to its 'operator()'
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};

// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
//enum { arity = sizeof...(Args) };
typedef function<ReturnType (Args...)> f_type;
};

// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) > {
typedef function<ReturnType (Args...)> f_type;
};

// for function pointers
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType (*)(Args...)> {
typedef function<ReturnType (Args...)> f_type;
};

template <typename L>
typename function_traits<L>::f_type make_function(L l){
return (typename function_traits<L>::f_type)(l);
}

long times10(int i) { return long(i*10); }

struct X {
double operator () (float f, double d) { return d*f; }
};

// test code
int main()
{
auto lambda = [](int i) { return long(i*10); };
typedef function_traits<decltype(lambda)> traits;
traits::f_type ff = lambda;

cout << make_function([](int i) { return long(i*10); })(2) << ", " << make_function(times10)(2) << ", " << ff(2) << endl;
cout << make_function(X{})(2,3.0) << endl;

return 0;
}

Can Lambda Expressions only be used in the same Method they're defined in (Java)?

The type defined by a lambda expression can in theory be used anywhere, so I believe that your question stems from the fact that you've only seen limited examples.

I've worked on several codebases where methods returned implementations of functional interfaces specified by lambda expressions. I can give a simple example:

public class A {
public static Predicate<String> startsWithA() {
return input -> input.startsWith("A");
}
}

public class B {
public static void main(String[] args) {
System.out.println(A.startsWithA().test("Aardvark"));
}
}

Lambda Expression without types

Since the interface is a standard functional interface

It's a functional interface because it contains only one abstract method. This method takes one parameter and returns a [void] value

(Reworded for this question)

The lambda expression x -> { System.out.println(x); } can be re-written as an anonymous class.

new Foo() {
@Override
public void bar(Object x) {
System.out.println(x);
}
}

When you call doo, you pass this functional interface as f, which then executes f.bar("baz");, so "baz" is x, and it is printed.

All in one main method, this would look like

public static void main(String[] args) {
Foo f = new Foo() {
@Override
public void bar(Object x) {
System.out.println(x);
}
};

f.bar("baz");
}

Lambda Expression and generic defined only in method

You can't use a lambda expression for a functional interface, if the method in the functional interface has type parameters. See section §15.27.3 in JLS8:

A lambda expression is compatible [..] with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of [..] T. [..] A lambda expression is congruent with a function type if all of the following are
true:

  • The function type has no type parameters.
  • [..]

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.

Does a type that can be used in an Expression Tree in C# mean the same thing as being able to used in a Lambda Expression? Are they related?

Expression trees are represented in .NET as objects that point to other objects, that in turn point to other objects. For example, consider the following expression tree:

Expression expr = () => DateTime.Now.Hour > 18;

We can't actually write new <X> on most of the types in System.Linq.Expressions. But if we could write out the expression tree as a succession of object creations and initialization, it might look something like this:

new Expression<Func<bool>> {
NodeType = ExpressionType.Lambda,
Type = typeof(Func<bool>),
Body = new BinaryExpression {
NodeType = ExpressionType.GreaterThan,
Type = typeof(bool),
Left = new MemberExpression {
Type = typeof(int),
Expression = new MemberExpression {
Type = typeof(DateTime),
Member = typeof(DateTime).GetProperty("Now")
},
Member = typeof(DateTime).GetProperty("Hour")
},
Right = new ConstantExpression {
Type = typeof(int),
Value = 18
}
},
ReturnType = typeof(bool)
}

There are two basic ways to create expression trees:

  1. Have the compiler do it. Set a lambda expression syntax to a variable, property, or parameter of type Expression<TDelegate>. The C# compiler will automatically convert the code you write into a complete expression tree (as above).

  2. Call the factory methods on System.Linq.Expressions.Expression. Something like this:

    // using static System.Linq.Expressions.Expression

    Lambda(
    GreaterThan(
    MakeMemberAccess(
    MakeMemberAccess(null,
    typeof(DateTime).GetProperty("Now")
    ),
    typeof(DateTime).GetProperty("Hour")
    ),
    Constant(18)
    )
    )

Because that part of the C# compiler which creates expression trees hasn't been updated in a long time, it doesn't handle many newer C# constructs (such as value tuples).

But you can always construct the expression tree using the factory methods, and using whatever .NET types you might want.


(NB. I've written a library that generates string representations of expression trees, such as the ones in this answer.)



Related Topics



Leave a reply



Submit