Simplify Your Code And Make It More Flexible At The Same Time
A good example of why you need function objects and lambdas can be found in a factory. I’m talking about an assembly line.
An assembly line is a widely accepted method to make things because it’s efficient. I’m using this as an example to build up to the need for function objects and lambdas. It’s a little hard to describe them without using something you can relate to like this.
Just think about how assembly lines bring something being built to each worker. Or these days, maybe it’s a robot doing the work.
The important part is the the thing being built arrives at a step on the assembly line and some work gets done. Some changes are made. Or something gets added. Then it leaves that station and goes to the next.
It’s easy to follow the progress as something gets built. It’s also easy to lose site of the pattern. Because each step is different, we sometimes forget the simpleness of the basic idea.
Instead of looking at an assembly line and following the things being built, look at it as a series of fixed steps. And just focus on one step for now.
Let’s say this step adds a knob. The worker has a big bucket of knobs that need to be attached to the days production. Instead of dragging the bucket of knobs around to each thing, he or she can just wait in one spot for the items to arrive and attach the knob. This person has also been trained to know exactly how to attach the knobs.
Every step in the assembly line is different but they all share this same basic property, just sit in one spot and do one task.
Now, if you had to write code to do something similar, how would you do it? Maybe you’re writing an adventure game and the hero just drank a magic potion that doubles the strength of all weapons. How is this related to the assembly line?
You could write code that went to each item the hero is carrying and double its strength if the item was a weapon. Maybe you wrap all this up in a method called doubleWeaponStrength.
But that would be like having the assembly line worker walk around to each item instead of letting them come on their own. It’s easy to forget the pattern of the assembly line because in this case, we only have one thing to do. Because all we need to do is double the weapons, we just go ahead and do everything in the method.
As the game gets more complicated though, we realized there’s a lot of things that could be performed. They just don’t all need to be done in order like a factory. As the game is played, maybe we sometimes need to double the weapon strength or sometimes cause all the food to spoil if it’s more than a day old.
Each of these acts like a step from the assembly line. We can get the same efficiency in code that assembly lines bring to a factory. All we need to do is focus the methods like doubleWeaponStrength so they work on a single item at a time. Just like how an assembly line worker works on one item at a time.
We need other code that knows how to go through each item the hero is carrying and call the method to double the strength or to spoil the food. What we do is write a method that accepts as one of its parameters the specific task that needs to be done. That way, the method that goes through all the items doesn’t know or care about what action is being done. All it knows is that it needs to perform some action on everything. Just like how the assembly line is unaware of the changes happening at each step.
How do we tell this navigation method what action to perform? An assembly line is constructed so it passes by each station. We need to do something in code instead. We could use a function pointer. We just pass it a pointer to the method that doubles the weapon strength or a pointer to the method that spoils the food. Both of these are the same type of pointer. The only difference happens when the pointer is called to do its work.
This goes really well until the game designers decide to add more variety to the game. Now there’s potions to triple weapon strength or even reduce it. And some areas in the game are hotter so food spoils faster. Now we have a problem because it’s not enough to be able to call individual methods. Unless, we start adding specific methods like doubleWeaponStrength and tripleWeaponStrength.
What we need now is a more general method that can modify weapon strength by either making the weapons stronger or weaker and by any amount. We need to configure this method by giving it arguments of its own so it knows the amount. In a way, the assembly line has the same problem and solves it by training the worker to know what to do.
Our navigation method isn’t setup to handle all the extra information. All it knows how to do is go through all the items the hero has and call some method to do something to each item. We need some trained workers of our own.
This is where function objects and lambdas come to the rescue. Both of them let you create a callable object that you can pass to something like the navigation method. The callable objects already have everything they need to know in order to do their job. They’re more than just function pointers but can still be used like simple function pointers. So the navigation method can go back to treating them all the same. And now we can get the variety we need.
This class explains function objects which are sometimes called functors.
You’ll learn how to create them and how to use them.
Then you’ll learn about lambdas which help create function objects for you. At least that’s one way to think of them. They’re better described as unnamed functions that can remember or capture extra information that can be used when the lambda is called.
Once you understand this, you’ll be able to make your code more flexible and adaptable to different scenarios. And you can accomplish this with just a change in how you approach problems. Your code can actually end up being much simpler than before.