5

Out of a window procedure, I'm writing a switch statement using self-executing lambdas, like this:

LRESULT CALLBACK proc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg)
    {
        case WM_CREATE: return [&](WPARAM wp, LPARAM lp) {
            do_something(wp, lp);
            return 0;
        }(wp, lp);

        case WM_SIZE: return [&](HWND hWnd) {
            do_another_thing(hWnd);
            return 0;
        }(hWnd);
    }
    return DefWindowProc(hWnd, msg, wp, lp);
}

I believe compilers are free to optimize it pretty much the way they want, but generally speaking, would a compiler add much boilerplate code to this, comparing to not using these lambdas?

Could a compiler detect the redundant lambdas and remove them?

rodrigocfd
  • 6,450
  • 6
  • 34
  • 68
  • 7
    Just from curiosity: why? I mean what advantage do you seek from self-executing *anonymous* lambdas? You can't reuse them (because they are anonymous, not referenced in any other place), so...? – Adrian Colomitchi Oct 04 '16 at 23:39
  • I think compiler would simply replace `return []() {... return x; }()` with `{... return x; }`. Seems trivial optimization. However this Q is more of an "opinion based", as there is no deterministic ansr. – iammilind Oct 04 '16 at 23:40
  • @AdrianColomitchi Frivolous reason: because they are beautifully collapsed in Visual Studio IDE editor. – rodrigocfd Oct 04 '16 at 23:45
  • 5
    @Rodrigo you can just put them in `{...}` to get outlining to work. No need for this silliness. – 3Dave Oct 04 '16 at 23:55
  • @iammilind Non-deterministic compilers? – 3Dave Oct 04 '16 at 23:57
  • @DavidLively First thing I tried. It doesn't work in C++. – rodrigocfd Oct 05 '16 at 00:00
  • @Rodrigo See my answer. Sort of a duplicate, but I have a fancy screenshot which work in a comment. – 3Dave Oct 05 '16 at 00:06
  • Ok. Well, there's always '#pragma region' – 3Dave Oct 05 '16 at 00:17
  • @DavidLively Oh now I got what you mean: there's an option in VS to outline *all* statements. I disabled this some time ago because, well, it was _too much_ outlining... as I said, it's a frivolous motivation, pure sugar. Anyway I still would like to know the implications of such lambda constructs. Your insights are appreciated, though. – rodrigocfd Oct 05 '16 at 00:27
  • @AdrianColomitchi I guess my answer also answers your question? – Nir Friedman Oct 05 '16 at 02:19
  • @Rodrigo "because they are beautifully collapsed in Visual Studio IDE editor. " :D thanks, this made my day, never could imagine. – Adrian Colomitchi Oct 05 '16 at 02:22
  • @NirFriedman "I guess my answer also answers your question?" Not quite. While your answer is technically sound, I was looking for his personal reason (and must admit I was surprised). – Adrian Colomitchi Oct 05 '16 at 02:25
  • 3
    @Rodrigo `Anyway I still would like to know the implications of such lambda constructs. ` The biggest implication I can think of is that your future code maintainers will wonder why the code is written that way and what they're missing (how it behaves differently from the obvious solution). – Mark B Oct 05 '16 at 03:13
  • 1
    Good coding practice is to write short function. If you follow that and also have classes that follow **Single Responsability Principle (SRP)**, you will never need to collapse code. While collapsing and #region might sometime be useful, depending a lot on it is a red flag that something is wrong. By the way you already call a function like `do_something`, why not simply return the value from that function and then write `case WM_CREATE: return do_something(wp, lp);`. Much cleaner to read and no useless collapsing. – Phil1970 Dec 23 '21 at 14:02

2 Answers2

8

Optimization questions like this don't have a definite answer in the sense that the optimizer of a compliant compiler can do many, many things. However, in this case most modern optimizers are almost certainly going to inline the lambda, and generate the same assembly whether or not you use the lambda. Because lambdas have a unique type, the compiler can inline easily. Because the lambda is declared and immediately used and never assigned (a more common name is "immediately invoked/evaluated lambda instead of "self executing"), the compiler knows it can only be called once. So typically it will decide to inline.

To be sure, you can look at some assembly: https://godbolt.org/g/QF6WmR. As you can see, the generated assembly in this particular example is identical, but obviously it does not prove the general case.

In general, lambdas are considered low or zero cost abstractions in C++, if you think a lambda makes for the cleanest code then use one. If you need to you can always quickly verify the assembly is the same. Your reason for using the lambda that way is a bit unusual though; I wouldn't really consider code folding to be a good reason. A more common reason to use immediately evaluated lambdas is to be able to use const in situations where otherwise you can't:

int x;
try {
    x = foo();
}
catch (const ExceptionType& e) {
    x = bar();
} 

vs

const auto x = [] () {
    try {
        return foo();
    }
    catch (const ExceptionType& e) {
        return bar();
    }
}();

To persist x in the outside scope in traditional C++ code, we have to declare it first and then assign to it. By using a lambda that returns the value we want, we can declare and assign x at the same time, allowing it to be const.

Nir Friedman
  • 17,108
  • 2
  • 44
  • 72
  • The use of immediately invoked lambdas is pretty common in JavaScript land, where I've been wandering for the past 6 months. I guess I got too much used to them, since they're necessary to restrict scope in JS and used often. Oh I didn't know [this site](http://godbolt.org/), it's great. Thank you. – rodrigocfd Oct 05 '16 at 10:46
5

The question is a bit odd. The compiler doesn't "remove" the lambdas, because the lambdas are in your source code, and the compiler doesn't modify your source code. What it does is emit machine code that produces the behaviour of the program you expressed in source code.

The compiler is free to emit as much or as little machine code as it likes as long as the result behaves the way that your program expresses.

A compiler certainly does not have to emit separate function bodies and jumps/calls between them if it can inline all the code into one place, and that is a commonly applied optimization.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    When I said "remove the lambdas" I was referring to the machine code usually generated by a lambda construction. I mean, the compiler would ignore such a redundant lambda. So, rephrasing the question: would a compiler generally _inline_ these lambdas, resulting in no extra cost? – rodrigocfd Oct 04 '16 at 23:50
  • 5
    `The compiler doesn't "remove" the lambdas, because the lambdas are in your source code`. I think OP didn't mean either about literal removal of lambda related source code. I read the last line in Q as: "Can compiler optimize away the extra machine code (if any) generated due to redundant lambdas?" – iammilind Oct 04 '16 at 23:50
  • 1
    @iammilind: Unless you *already know* specific machine code that your compiler normally produces, that still doesn't make sense. And if you do, then you probably also know how to find out how the compiler translates the code in question. So whichever way you turn it, it doesn't really work. You can't both know and not know a thing. – Kerrek SB Oct 05 '16 at 00:01
  • @iammilind: To hammer home the point, the very idea of "removing machine code" is nonsense. That's just not how compilers work. If you don't know that, then there isn't really a useful answer. A better question might perhaps be whether the code in question results in worse performance than the simpler code. (And of course you know the answer to *that* kind of question.) – Kerrek SB Oct 05 '16 at 00:03
  • 1
    @Rodrigo: *A* compiler, *generally*? Yeah, sure, why not. (Would you ever be able to prove that I made a wrong statement?) – Kerrek SB Oct 05 '16 at 00:09
  • 1
    Perfect example of how *not* to answer a question. a) *no one* thought that the compiler modified the source code. b) your second paragraph just repeats a point the original asker already acknowledged in the question. Answer would have been good if it were just the third paragraph. – Catskul Sep 01 '18 at 07:00