3

What advantages are there to using lambda over using a #define macro?

I've encountered some situations where I've used lambda for convenience, but I could have easily used a similar define macro to solve the problem in the same way.

Example (Random code):

auto dyndelay=[=]()->bool{return(mode?(queue.front().initTime+delay)<GetTickCount():TRUE);};

Has no benefit over:

#define dyndelay (mode?(queue.front().initTime+delay)<GetTickCount():TRUE)

@Oli Charlesworth

#define dyndelay ....;
#define adifferentlambda ....;
#define myDefine(x) x:dyndelay:adifferentroutine
bool someCondition;

myDefine(someCondition)
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Nowayz
  • 1,882
  • 4
  • 21
  • 34
  • 15
    If you think avoiding a macro has no benefits, you don't understand the disadvantages of macros. The macro doesn't even have a type, it has no scope, it isn't a value, etc. The two aren't really comparable. – GManNickG Mar 02 '12 at 22:09
  • 1
    You reply to Oli *conveniently* forgets the most important part of the code snippet: the `return` statement in the last line. – André Caron Mar 02 '12 at 22:19
  • I never said a macros had benefits or not, I asked what some advantages of using lambda are. The scope of execution (like you said) is one of the only things that I know to be beneficial. I'm not trying to make a statement, I'm just asking a question. – Nowayz Mar 02 '12 at 22:20
  • @AndréCaron He added the return AFTER I had edited my post, so It's not left out since it didn't exist. Yet my example still exhibits the same function (code-wise) that the lamda's he wrote exhibit. – Nowayz Mar 02 '12 at 22:21
  • @Nowayz: Sorry, I hadn't looked at the edit times. You're still free to edit your answer since the return statement *is* the most important part of the snippet :-) – André Caron Mar 02 '12 at 22:22
  • 1
    @Nowayz: Returning is just one example; the general principle is that it can be passed around, just like any other object. – Oliver Charlesworth Mar 02 '12 at 22:23
  • @AndréCaron Yeah with the return I'm seeing how lambda are drastically more powerful and an entirely different concept than a macro replacement. (I realize that there's no way to return a macro with captured variable states and the like. I'll leave the code I added though so the discussions make sense) – Nowayz Mar 02 '12 at 22:31

5 Answers5

7

You're looking at things the completely wrong way. A lambda is a much more general construct. It models anonymous functions and a form of closure. It can even be captured into a common form using function objects which can then be used at runtime to model a form of indirect function call (similar to function pointers or virtual functions).

A macro is just a brute force text substitution mechanism.

However, it appears like you are comparing the two on a syntactical basis. Yes, if you want to achieve the shortest syntax possible, macros are the way to go. They're also the way to go to ruin your code. In fact, I can even reduce hello world, using macros, to something like this:

INCLUDE_EVERYTHING
MAIN
PRINT_HELLO_WORLD
END_BLOCK

We can invent whole new languages this way using the preprocessor! Of course we also won't be able to effectively trace through the code, we throw away a lot of the usefulness of C++ (scoping), and no one else will ever want to read or work with our code. But hey, the syntax is shorter...

Where you'll find no macro substitution will ever work is when you start involving generic algorithms which is one of the most obvious places for lambdas to be used.

vector<string> v = {...};
sort(begin(v), end(v), [](const string& str1, const string& str2){
    return str1.size() < str2.size();
});
// v is sorted based on string length starting from shortest string to longest

Of course, you could still go out of your way to create a bloated, crippled version of all the generic algorithms where everything is implemented as a macro and then you can work with just macros.

Next you can try to do things like implement a signals and slots mechanism using only macros, another place where lambdas are useful.

In summary, I think you need to understand why the preprocessor is discouraged so strongly in C++. That's a more general subject that goes into scoping, debugging, confusing errors (as a replace of sheer text substitution), etc. As GMan pointed out, to try to compare the two based on syntax alone suggests you lack fundamental understanding of both macros and lambdas and what purposes they are supposed to serve.

In fairness though, you can create a shorter syntax using macros. After all, a copy/paste-style text substitution mechanism will let you get away with a lot of shortcuts. But be very aware of the problems of doing that. As you get more comfortable with C++, you'll find yourself accepting some syntactical overhead in order to avoid macros when you start working in production code and seeing the problems that the preprocessor can cause firsthand. As you start getting more comfortable with things that involve function objects like generic algorithms (including parallel_for) and signals and slots, you'll also begin to appreciate the true power of lambdas much more.

stinky472
  • 6,737
  • 28
  • 27
  • Why would you even need a lambda in your example, you can easily just call the function directly... – Nowayz Mar 02 '12 at 23:00
  • @Nowayz thanks for pointing that out. I revised it with an example using sort to sort strings from shortest to longest with a lambda for the weak ordering predicate. I got tunnel vision trying to look for a quick way to demonstrate lambdas with a generic algorithm. Didn't want to use the obvious for_each since that would look too trivial to do with the preprocessor. – stinky472 Mar 02 '12 at 23:07
  • That's mainly why I was asking in the first place though, because many of the example I've seen are like the one you have and it was confusing me because I didn't see any reason to encapsulate something instead of calling it directly(Unless you're just filling one argument manually, and the rest of them automatically). – Nowayz Mar 02 '12 at 23:08
  • @Nowayz yeah, it's absolutely pointless. I narrowed my vision by trying to look for a superficial but not utterly pointless example using lambdas without involving for_each since I thought you might not see the point over a simple for loop using a macro. The sort example should be better, as it would be much more difficult to plug in a macro there - one would be forced to define a function or functor separately at which point the macro would not really reduce syntax at all. – stinky472 Mar 02 '12 at 23:11
  • The new example with string length is pretty cool, that's definitely a short cut worth taking. – Nowayz Mar 02 '12 at 23:12
  • I'm changing this answer to my accepted answer since it actually gives an example of lambda being used in a method where a define would not be practical. This is better than the example with looping through a list of labmdas where you could easily have used functions. – Nowayz Mar 02 '12 at 23:28
4

Consider calling someFunctionWithAnAsyncCallbackOnSuccessLikeInNodeJS(dyndelay). This is where the power of lambdas comes in: they can be stored and used later just like any other object. A macro could pass in the result of dyndelay at the time someFunction... is called, but it can't pass in the ability for someFunction... to call dyndelay on demand. Of course, a class with an operator() would do the same, and I believe many of the STL Algorithms use those, but lambdas are much less verbose.

(Edited for clarity.)

btown
  • 2,273
  • 3
  • 27
  • 38
  • 1
    Thank you! This is the first answer that describes a serious advantage without trying to fault find my code or original primacy of my question. – Nowayz Mar 02 '12 at 22:25
  • @OliCharlesworth Yes, but given your original answer I didn't fully understand the purpose of what your were doing. I do now though, thanks! – Nowayz Mar 02 '12 at 22:34
  • 1
    Just a side note here but you can also pass a function pointer to another function and call it just like a lambda, and if you're doing something like that I don't see why it wouldn't be declared as a function itself except maybe that lambdas can capture the state of the variables and ints cannot? I'm not sure if a lambda captures the variables at declaration, or when it's being executed... – Nowayz Mar 02 '12 at 23:21
3

Can you use that macro as an object? i.e. can it do this?

auto dyndelay=[=]()....;

return dyndelay;
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • I'm assuming those two lambdas are going to return the same thing type? Yes you can do that with a macro – Nowayz Mar 02 '12 at 22:09
  • @Nowayz: Not if you're going to invoke the lambda in a different scope. – Oliver Charlesworth Mar 02 '12 at 22:11
  • So your code is assumed to be in a function that returns one function or another? That's still the same result as my define. Invoke the lambda in a different scope?? You mean by using [] so that it doesn't capture anything? Not sure what you're trying to say – Nowayz Mar 02 '12 at 22:15
  • 1
    @Nowayz: How do you propose to return a macro from a function, and then "invoke" it from the caller? How do you propose to pass a macro into a function, and then "invoke" it from inside that function? – Oliver Charlesworth Mar 02 '12 at 22:16
  • @Nowayz : No it isn't. A macro has no scope, an object does. – ildjarn Mar 02 '12 at 22:16
  • I'm not trying to claim that it's possible to return a macro, I'm just trying to understand how using a macro in this case is any different from what you did, because I'm not seeing how it is... (See my OP, I've edited it to emulate what I assume to be the behavior) – Nowayz Mar 02 '12 at 22:17
  • @Nowayz: Being able to return a lambda is one of its advantages over a macro. Consider a slightly more complex scenario where the lambda takes arguments, or captures by reference. – Oliver Charlesworth Mar 02 '12 at 22:20
  • "auto myLambda = someCondition ? dyndelay : adifferentlambda;" Is this really possible? What will type of myLambda be, as each lambda is a unique type? You could probably use std::function<> myLambda instead, though, with some particular function prototype. – Suma Mar 02 '12 at 22:29
  • @Suma: Perhaps. I'm going to simplify my example, because it appears that the point it's trying to illustrate was lost on the OP... – Oliver Charlesworth Mar 02 '12 at 22:31
  • @Suma I think that's what he meant anyway, I was assuming as much. – Nowayz Mar 02 '12 at 22:35
3

You can pass lambda as a functor into a template like foreach. See e.g. this "How to use std::foreach" answer. This was also most likely the primary motive why lambdas were added. Such things were done with functors before, but the code was unnecessarily long and required a lot of duplicating to capture values.

Community
  • 1
  • 1
Suma
  • 33,181
  • 16
  • 123
  • 191
1

Macros just are not first class citizens in the language. For example, macros can't be passed as arguments to algorithms.

std::find_if(begin(a),end(b),
             [](foo const &f) { return f.v() < 10 && f.is_something() });

The preprocessor really isn't even part of the language. It has a few facilities that C++ can't do itself, but for everything else it's best to avoid the preprocessor.

Here's Herb Sutter's talk on lambdas for plenty more things lambda's are good for:

http://vimeo.com/23975522

bames53
  • 86,085
  • 15
  • 179
  • 244