Reposting my comment from the last time this was posted. There was a lot of nice discussion there: https://news.ycombinator.com/item?id=8374345

===

The older I get, the more my code (mostly C++ and Python) has been moving towards mostly-functional, mostly-immutable assignment (let assignments).

Lately, I've noticed a pattern emerging that I think John is referring to in the second part. The situation is that often a large function will be composed of many smaller, clearly separable steps that involve temporary, intermediate results. These are clear candidates to be broken out into smaller functions. But, a conflict arises from the fact that they would each only be invoked at exactly one location. So, moving the tiny bits of code away from their only invocation point has mixed results on the readability of the larger function. It becomes more readable because it is composed of only short, descriptive function names, but less readable because deeper understanding of the intermediate steps requires disjointly bouncing around the code looking for the internals of the smaller functions.

The compromise I have often found is to reformat the intermediate steps in the form of control blocks that resemble a function definitions. The pseudocode below is not a great example because, to keep it brief, the control flow is so simple that it could have been just a chain of method calls on anonymous return values.

AwesomenessT largerFunction(Foo1 foo1, Foo2 foo2)
{
// state the purpose of step1
ResultT1 result1; // inline ResultT1 step1(Foo1 foo)
{
Bar bar = barFromFoo1(foo);
Baz baz = bar.makeBaz();
result1 = baz.awesome(); // return baz.awesome();
} // bar and baz no longer require consideration

// state the purpose of step2
ResultT2 result2; // inline ResultT2 step2(Foo2 foo)
{
Bar bar = barFromFoo2(foo); // 2nd bar's lifetime does not overlap with the 1st
result2 = bar.awesome(); // return bar.awesome();
}

return result1.howAwesome(result2);
}

If it's done strictly in the style that I've shown above then refactoring the blocks into separate functions should be a matter of "cut, paste, add function boilerplate". The only tricky part is reconstructing the function parameters. That's one of the reasons I like this style. The inline blocks often do get factored out later. So, setting them up to be easy to extract is a guilt-free way of putting off extracting them until it really is clearly necessary.

===

In the earlier discussion sjolsen did a good job of illustrating how to implement this using lambdas https://news.ycombinator.com/item?id=8375341 Improvements on his version would be to make everything const and the lambda inputs explicit.

AwesomenessT largerFunction(Foo1 foo1, Foo2 foo2)
{
const ResultT1 result1 = [foo1] {
const Bar bar = barFromFoo1(foo1);
const Baz baz = bar.makeBaz();
return baz.awesome();
} ();

const ResultT2 result2 = [foo2] {
const Bar bar = barFromFoo2(foo2);
return bar.awesome();
} ();

return result1.howAwesome(result2);
}

It's my understanding that compilers are already surprisingly good at optimizing out local lambdas. I recall a demo from Herb Sutter where std::for_each(someLambda) was faster than a classic for(int i;i<100000;i++) loop with a trivial body because the for_each internally unrolled the loop and the lamdba body was therefore inlined as unrolled.