Personally like the first one best, shrug, that just does a simple branch on id
inside the loop. Polymorphism is usually the straightforward alternative to conditional branching with if/switch
, but may or may not be unwieldy if your elements IDs are dynamic and change.
Just to be a bit wacky and since this question seems to be language-agnostic, here you go:
// Applies 'true_func' to elements in the the random-access sequence
// that satisfies 'pred' or 'false_func' otherwise.
applyIf(array, pred, true_func, false_func)
{
for (int i=0; i < array.length; i++) {
if (pred(array[i]))
true_func(array[i]);
else
false_func(array[i]);
}
}
// Returns true if the element has a negative ID.
hasNegativeId(element) {
return element.getId() < 0;
}
And in the caller:
applyIf(array, hasNegativeId, doThisStuff, DoOtherStuff);
Or simply:
applyIf(array, function(element) {element.getId() < 0;}, doThisStuff, DoOtherStuff);
I don't actually like this solution. I might even hate it. But it does dice up your simple function into two even simpler ones: one uber simple unary predicate that returns true if an element has a negative ID, and one very generally-applicable algorithm (applyIf
) that calls one function or another on each element in a random-access sequence (of which arrays are but one type) based on a predicate.
Of course the client still has to compose this stuff together, but the individual functions all do something even simpler now. You can make it even more generalized by depending on a forward iterator/enumerable instead of a random-access sequence, allowing applyIf
to work on any data structure which is forward iterable, including singly-linked lists, doubly-linked lists, binary search trees, arrays, hash tables, tries, quadtrees, you name it (as long as it can be iterated through sequentially).
It's playing to the kind of uber generality and code reuse mindset since that applyIf
function can be made to work for just about anything with any combination of predicates and functions to apply, so it has much, much more reusability than a function hard-coded to check IDs (the kind of thing that might go into a standard library). But I still don't like it and like your plain old first solution better. These days I don't care as much about these uber flexible solutions. I like that plain old loop with the if
inside unless you have to redundantly check for negative IDs all over the place (then I'd consider something else). We could generalize it further:
// Calls 'true_func' if pred(element) is true,
// 'false_func' otherwise.
iif(pred, true_func, false_func) {
return function(element) {
return pred(element) ? true_func(element): false_func(element);
}
}
// Calls 'func' for each element in the container.
forEach(container, func) {
for (it = container.begin(); it != container.end(); ++it)
func(it.element())
}
At which point we can do this:
forEach(array, iif(hasNegativeId, doThisStuff, doOtherStuff));
There are ways to keep going further and dicing things up and generalizing them even more, but I'll stop there. Again I don't really like this. Just kinda putting it out there for people who get a kick out of dicing their code up into the teeniest, most reusable functions (something I used to enjoy but not so much these days).
The main reason I don't like this solution is that functional programming loses so much of its elegance if you use it to cause side effects. If doThisStuff
and doOtherStuff
cause side effects, which I'm assuming they do since you don't use a return value, then you only get the difficulty associated with functional programming of complex control flow combined with the side effects. The combo of those two can make things really difficult to reason about. So you often need simple control flow if you want to cause side effects, or no side effects if you want complex control flow (not a combination of the two). That's why I like your simple loop with an if
statement inside the best. It's so easy to debug and follow in terms of control flow.