I would consider the following alternatives, in that order:
Start with the DRY variant, even it is less efficient. In most real-world cases, this won't matter. If a benchmark tells you here is your bottleneck, go to option 2.
Give the
get
function a parameter where it is told whether one wants the intermediate values back or not. The parameter could be, for example, a boolean flag or a pointer to the output structure (hereStack
) - when that pointer is NULL, no intermediate values will be returned.For this, I would keep the new
get
variant internal to the module (for example, call itget_internal
), and provide two new public entries, likeget
andget_all
.get
could callget_internal(...,NULL)
andget_all
could callget_internal(...,&stack)
. So you don't have to leak the new parameter into the public API.In the unlikely case testing the extra parameter is still the bottleneck (and you proofed this by profiling), goto option 3:
Live with the duplication, because a specific implementation is really so much faster that it is worth to ignore the DRY principle. This option is something I would only recommend after a thorough benchmark which proofsproves the two former variants are both too slow to fulfill your performance requirements, and #3 really solves it.
In case the duplication becomes really horrible, and you think #1 and #2 are definitely not fast enough, as a last resort, there is option 4:
Implement the
get_internal
function not with a runtime parameter, but make use of compile time parameters / macros, for providing actually two variants of the function (from one source code). In C++, one could make use of template meta programming to make a relatively clean implementation of this. In C, this can be sometimes necessary, but there is a certain risk to end up in some ugly macro hack where it is debatable if that's better or worse than sacrifycing DRY. So if you consider to go this route, better think twice if it is really worth the hassle.