Daily C++ Dose: Functional Functions
September 28, 2020•487 words
Goal
Trying to digest new C++ information everyday (personal goal). These posts aren't meant to rewrite the information read, but just for personal note taking and info digestion.
Actually got the idea from the same place I'm reading the new info. Fluent{C++}
Source
https://www.fluentcpp.com/2016/11/22/make-your-functions-functional/
Notes
- Try to avoid global variables. They can be accessed anywhere and can break functions.
- Be expressive with your functions. Define a clear input and output.
- Having global variables are hidden away from the function declaration.
- Global constants are fine to use, because they are not necessarily an I/O. They don't change through out the runtime.
- Generally pass reference to const as a parameter. Some types, inputs can come in as a value. (const T&)
- If you need to modify the I/O parameters, pass in a reference to not const (T&).
- Try to return the output through the return type.
Output f(const Input& input);
// looks more natural than
void f(const Input& input, Output& output);
Of course there are reasons why you wouldn't take this approach:
- Performance
- Error Handling
- Multiple Return types
Performance
- In C++, when returning a STL obj, it will move the data to a new STL obj, not copy. This prevents excessive memory usage.
- Don't have to master Return Value Optimization, just do it and run a profiler after to check performance. Most of the time it's a non-issue.
Error Handling
- What if there is an error and you don't want that function to crash the entire application? Perfect use case since you don't have to return anything.
- Alternative, return boolean if successful or not. That way you can modify the output if there are no errors with the inputs and in the case of handling the error, you can return False without modifying the output object.
- Best practice is to throw an exception when it fails.
- For this to work, surrounding code has to be exception safe.
- Another best practice. use the
boost::optional<Output>
return type. (natively available with C++17)- Don't forget to use
auto output = f(input);
where auto is the import additive. (version => C++14)
- Don't forget to use
Multiple Return Types
Best practice, use structs. Clear and concise.
struct MultipleOutputs
{
Output1 output1;
Output2 output2;
};
//Then we can use this as a return type
MultipleOutputs f(const Input& input);
There are other options outlined in the article, but I would like to stay current with the most recent versions of C++ if possible.
Another option for C++17 and greater:
auto [output1, output2] = f(const(Input& input);
// where f returns a tuple: std::tuple<Output1, Output2> f(const Input& input);
Summary
Try to be clear and concise by returning outputs through the return type.
When that doesn't work with your use case, then just be aware of the issue of using the other methods.