Sunday 13 October 2013

CSC148: Comments on Modularity and Recursion

Hey look you guys I'm gonna talk about OOP and recursion and why they're important, ok?


Object Oriented Programming

Object-oriented programming (compare with functional programming) means modelling a program as abstracted objects interacting with each other.  Each object consists of attributes (values associated with it, like number_of_legs) and/or methods (functions associated with the object, like defenestrate(target)).  Each object is generated by a programmer-defined class, both of which can then be used or modified.  Classes can also be extended by importing properties from old classes to make new classes (inheritance).

The advantage of OOP is that it creates an excellent organizational structure around the entire program, which improves readability and makes logical sections of code more reusable.  For example, I can easily take out a DatabaseManager class from one project and reuse it elsewhere.  OOP also provides useful abstractions for high-level programming - if you want to create a linked list, instead of figuring out how it works and implementing it, you can just create the object and use its methods.

The funny thing is that there's practically nothing you can do with objects that you can't do with subroutines. But! objects make code far more reusable, as well as readable.  This means it's no longer necessary to create tightly controlled, monolithic programs (which do have their uses, such as hardware programming).  In the best case, each class can then be taken out of context and modified without consequence.  Finally, it's simply easier to think about how the pieces of a program work if you consider them as objects with properties; attributes become more organized, and therefore less likely to fail due to programmer error.  It's definitely recommended practice whenever possible, for the sake of your code's longevity.

PS >> Here's an interesting, albeit somewhat unrelated article I found while researching:  The difference between imperative and declarative programming styles


Recursion

If you're a functional programmer, this is pretty much the bee's knees.  When a problem can be divided into smaller versions of itself, you can use a recursive algorithm to reduce the length of code, and often greatly simplify the task (reducing likelihood of a bug).  Similarly to OOP, recursion lets you simplify a complex algorithm into abstractions.

For example, say you want to search through a nested list (lists containing lists containing lists containing..). You could try iterating over the list and checking cases:

l = [1, [2, 3], [4, [5]]]
for item in l:
  #Check if the item is a list, and iterate over it if it is
  #If that list has a list, loop over that..
  #More if statements to account for deeper nesting
  #If the item ain't a list, check if it's what we're looking for

As you can see, the code starts to nest a whole bunch of loops, and even then it's not very flexible (how do you handle a hundred lists nested within each other?).

Now try thinking recursively: We're looking for a value in this list.  If an item in the list is another list, we want to search it, and so on.  Since the search algorithm is the same in each case, we can just write a general statement:
1) Look through a list for a value.
2) If this list contains another list, look through that list using step 1.

Just like that, a monolithic algorithm full of looping and type checking can be shortened to just a few lines.

One big problem, however, is that debugging recursion is difficult, or at least different.  If a recursive function fails after 100 iterations, the traceback will be the function itself, 100 times.  This means you ought to take care to understand every possible case before implementing it (e.g. What if the array index goes out of range? What happens when we finish execution? Consider all the possible arguments).

All in all, recursion is a powerful tool, but with great power comes great responsibility.  Recursive functions should be thoroughly tested with a range of inputs, and kept as isolated as possible (think of it as a black box that will return the correct answer), because they're really annoying to debug when they fail.  Furthermore, thoroughly document such functions, because they can be difficult to read and understand for others reading your code.  But besides that, recursion can be particularly useful for shrinking down and conceptually simplifying code.

No comments:

Post a Comment