I recently run into the following situation.
class A{
public:
void calculate(T inputs);
}
Firstly, A
represents an object in the physical world, which is a strong argument for not splitting the class up. Now, calculate()
turns out to be quite a long and complicated function. I perceive three possible structures for it:
- write it as a wall of text – advantages – all the information is in one place
- write
private
utility functions in the class and use them incalculate
's body – disadvantages – the rest of the class doesn't know/care/understand about those methods -
write
calculate
the following way:void A::calculate(T inputs){ auto lambda1 = () [] {}; auto lambda2 = () [] {}; auto lambda3 = () [] {}; lambda1(inputs.first_logical_chunk); lambda2(inputs.second_logical_chunk); lambda3(inputs.third_logical_chunk); }
Can this be considered a good or bad practice? Does this approach reveal any problems? All in all, should I consider this as a good approach when I am again faced with the same situation?
EDIT:
class A{
...
public:
// Reconfiguration of the algorithm.
void set_colour(double colour);
void set_density(double density);
void set_predelay(unsigned long microseconds);
void set_reverb_time(double reverb_time, double room_size);
void set_drywet(double left, double right);
void set_room_size(double value);;
private:
// Sub-model objects.
...
}
All those methods:
- get a value
- compute some other values, without using state
- call some of the "sub-model objects" to change their state.
It turns out that, excepting set_room_size()
, those methods simply pass the requested value to sub-objects. set_room_size()
, on the other hand, does a couple of screens of obscure formulas and then (2)does half a screen of calling sub-objects setters to apply the various obtained results. Therefore, I have separated the function into two lambdas and call them at the end of the function. Had I been able to split it into more logical chunks, I would have isolated more lambdas.
Regardless, the goal of the current question is to determine if that way of thinking should persist, or is it at best not adding value (readability, maintainability, debug-ability etc.).
Best Answer
No, this is not generally a good pattern
What you're doing is breaking up a function into smaller functions using lambda. However, there is a much better tool for breaking up functions: functions.
Lambdas work, as you have seen, but they mean much much much much much more than simply breaking up a function into local bits. Lambdas do:
The instant you bring lambdas into the mix, the next developer to look at the code must immediately mentally load all of those rules in preparation for seeing how your code works. They don't know that you're not going to use all that functionality. This is very expensive, compared to the alternatives.
It's like using a back-hoe to do your gardening. You know that you're only using it for digging little holes for this year's flowers, but the neighbors will get nervous.
Consider that all you are doing is grouping your source code visually. The compiler doesn't actually care that you curried things with lambdas. In fact, I'd expect the optimizer to immediately undo everything you just did when it compiles. You are purely catering to the next reader (Thanks for doing that, even if we disagree on methodology! Code is read far more often than it is written!). All you are doing is grouping functionality.
// ------------------
between each part.EDIT: From seeing your edit with example code, I'm leaning towards the comment notation being the cleanest, with brackets to enforce the boundaries that the comments suggest. However, if any of the functionality was reusable in other functions, I'd recommend using functions instead