Skip to content

Commit 3eaa2d8

Browse files
committed
Add sandwich example
1 parent 4c35e9c commit 3eaa2d8

File tree

1 file changed

+89
-5
lines changed

1 file changed

+89
-5
lines changed

lectures/lambdas.md

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -611,16 +611,100 @@ And, on that note, now that we've discussed most of the syntax we use for lambda
611611
612612
613613
## When to use lambdas
614-
All in all, lambdas are neat and efficient. If we need a callable object to pass to some function and we don't think we'll ever want to reuse it, like in our example with sorting, lambdas should be out go-to tool.
614+
All in all, lambdas are neat and efficient. If we need a callable object to pass to some function and we don't think we'll ever want to reuse it, like in our example with sorting, lambdas should be our go-to tool.
615615
616-
Alternatively, if we are implementing some functionality in a header file and find ourselves writing a bit of a longer function, lambdas are a useful way to split such function into meaningful chunks without introducing public-facing functions and not relying on comments that can easily go out of sync with the code functionality. So use them without fear in most situations.
617-
<!-- Add a meme with a guy not approving and then approving -->
616+
Another typical use-case for lambdas is in situations when we find ourselves writing a long function and we end up outlining each logical step we take by a comment. Just to illustrate this, let's have a look at a small example code for, say, creating a sandwich. This process takes a bunch of steps, we need to prepare the bread, prepare the ingredients, and finally assemble the sandwich:
617+
<!--
618+
`CPP_SETUP_START`
619+
#include <string>
620+
using Sandwich = std::string;
621+
$PLACEHOLDER
622+
int main() {
623+
const auto sandwich = MakeGourmetSandwich();
624+
}
625+
`CPP_SETUP_END`
626+
`CPP_COPY_SNIPPET` sandwich_no_lambdas/main.cpp
627+
`CPP_RUN_CMD` CWD:sandwich_no_lambdas c++ -std=c++17 main.cpp
628+
-->
629+
```cpp
630+
#include <iostream>
631+
#include <string>
632+
633+
// 😱 Comments tend to drift out of sync with code.
634+
Sandwich MakeGourmetSandwich() {
635+
Sandwich sandwich{};
636+
637+
// Step 1: Prepare the bread
638+
sandwich += "Choosing the finest sourdough...\n";
639+
sandwich += "Lightly toasting it to perfection...\n";
640+
sandwich += "Spreading a generous amount of garlic aioli...\n";
641+
642+
// Step 2: Prepare the ingredients
643+
sandwich += "Grilling marinated chicken...\n";
644+
sandwich += "Adding fresh arugula and juicy tomatoes...\n";
645+
sandwich += "Topping it off with caramelized onions...\n";
646+
647+
// Step 3: Assemble the masterpiece
648+
sandwich += "Assembling the sandwich with care...\n";
649+
sandwich += "Adding a drizzle of truffle oil...\n";
650+
sandwich += "Plating it elegantly...\n";
651+
652+
return sandwich;
653+
}
654+
```
655+
The main issue with comments is that if we change the implementation it is really easy to forget to update the corresponding comments! So comments tend to drift out of sync with the code. I much prefer putting each step into a separate lambda function instead:
656+
<!--
657+
`CPP_SETUP_START`
658+
#include <string>
659+
using Sandwich = std::string;
660+
$PLACEHOLDER
661+
int main() {
662+
const auto sandwich = MakeGourmetSandwich();
663+
}
664+
`CPP_SETUP_END`
665+
`CPP_COPY_SNIPPET` sandwich_with_lambdas/main.cpp
666+
`CPP_RUN_CMD` CWD:sandwich_with_lambdas c++ -std=c++17 main.cpp
667+
-->
668+
```cpp
669+
#include <iostream>
670+
#include <string>
671+
672+
// ✅ Every step is encapsulated in a lambda.
673+
Sandwich MakeGourmetSandwich() {
674+
Sandwich sandwich{};
675+
676+
const auto PrepareBread = [&sandwich]() {
677+
sandwich += "Choosing the finest sourdough...\n";
678+
sandwich += "Lightly toasting it to perfection...\n";
679+
sandwich += "Spreading a generous amount of garlic aioli...\n";
680+
};
681+
682+
const auto PrepareIngredients = [&sandwich]() {
683+
sandwich += "Grilling marinated chicken...\n";
684+
sandwich += "Adding fresh arugula and juicy tomatoes...\n";
685+
sandwich += "Topping it off with caramelized onions...\n";
686+
};
687+
688+
const auto PlateSandwich = [&sandwich]() {
689+
sandwich += "Assembling the sandwich with care...\n";
690+
sandwich += "Adding a drizzle of truffle oil...\n";
691+
sandwich += "Plating it elegantly...\n";
692+
};
693+
694+
PrepareBread();
695+
PrepareIngredients();
696+
PlateSandwich();
697+
698+
return sandwich;
699+
}
700+
```
701+
Now it is a bit harder to make a mistake and in my experience the situation in which the function name does not correspond to what is happening inside of it is much more often caught during code review then a comment that went out of sync. This trick is sometimes useful for header-only libraries as we cannot use functions in [unnamed namespaces](namespaces_using.md#use-unnamed-namespaces) there.
618702

619-
One thing to be weary of though, is capturing all variables by default. While it might be tempting to always capture all the observed variables by reference by providing the ampersand in the capture list `[&]`, in my experience it sometimes makes it harder to understand what the lambda really does when reading the code. So in most of my code, I prefer to capture only the variables I _really_ need as opposed to blanket-capturing them.
703+
One thing to be weary of though, is to try not to get used to capture *all* variables by default. While it might be tempting to always capture all the observed variables by reference using the ampersand in the capture list `[&]`, in my experience it sometimes makes it harder to understand what the lambda really does when reading the code. So in most of my code, I prefer to capture only the variables I _really_ need as opposed to blanket-capturing them.
620704
<!-- But I'm interested in what you guys think about it, so please comment below the video with your experience with this. -->
621705

622706
## Summary
623-
And this is pretty much most of the things we need to know about lambdas. But if you ever need more details on anything here, please refer to their [cppreference.com](https://en.cppreference.com/w/cpp/language/lambda) page, as always.
707+
And this is pretty much most of the things we need to know about lambdas. But if you ever need more details on anything here, please refer to their [cppreference.com](https://en.cppreference.com/w/cpp/language/lambda) page, as always. And, as always, please play around with the examples I provided here or write your own. I firmly believe that the best way to learn is to make our own mistakes!
624708

625709
All in all, lambdas are a useful tool in our toolbox and we'll find that we want to use them quite often when writing modern C++ code. I hope that I could build parallels with what we have already learnt until now so that you can get all the use out of lambdas while not being scared of what they do under the hood.
626710

0 commit comments

Comments
 (0)