My issue is with a certain style of code that very much resembles recursion, but isn't quite that. Recursion is, to quote Wikipedia, "a method of defining functions in which the function being defined is applied within its own definition". Similarly mutual recursion applies another function which, directly or indirectly, applies the function we are defining.
The problem is that the code I am thinking of, and dealing with, does not use the same function! It uses the same code in another function (as a method or closure).
The problem here is that while my code is the same, the functions are not. Take a look a the following basic mutual recursion example:
def is_even(x):
if x == 0:
return True
else:
return is_odd(x - 1)
def is_odd(x):
if x == 0:
return False
else:
return is_even(x - 1)
This is somewhat intuitive, and very clearly mutually recursive. However, if I wrap each function up as an inner function that is created once every call, it gets less clear:
def make_is_even():
def is_even(x):
if x == 0:
return True
else:
return make_is_odd()(x - 1)
return is_even
def make_is_odd():
def is_odd(x):
if x == 0:
return False
else:
return make_is_even()(x - 1)
return is_odd
def is_even2(x):
return make_is_even()(x)
def is_odd2(x):
return make_is_odd()(x)
Disregarding optimizations like implicit memoization etc., this produces a chain of function calls that isn't strictly recursive, creating and calling various new functions without ever calling the same one twice. Nonetheless all these functions follow a common template, and are just the same function created over and over again (possibly with different free variables.
And again, we can come up with a directly equivalent (after all, classes are really just closures, right ;) implementation using classes. This is especially significant, since this style of [insert name here] is used in, e.g., the Composite Pattern. The difference is that with the Composite design pattern, and most uses (even of the closures), the instances are not usually created on the fly. It is still essentially the same.
class EvenChecker(object):
def check(self, x):
if x == 0:
return True
else:
return OddChecker().check(x - 1)
class OddChecker(object):
def check(self, x):
if x == 0:
return False
else:
return EvenChecker().check(x - 1)
def is_even3(x):
return EvenChecker().check(x)
def is_odd3(x):
return OddChecker().check(x)
This time the chain is of object creation and method calls, but the principle is the same. (I would actually note that it's slightly different, in that Python defines a simple wrapper on a per-object basis which itself calls the very same function every time-- but this is not necessarily something we need to know, and it doesn't need to be true for other implementations of classes and objects. But yes, strictly speaking it is mutually recursive, as well as... something more, and it's that other thing that I want to know.)