Bottom-up programming is essentially about simplifying the interface you program in (-i.e. Lisp can be altered by defining functions which can alter the programming methods you use).
For example: Instead of defining/designing functions like this:
; Main function: behave
(dog
;...
which are difficult to extend, debug, read, and use we can make our code easier to use by adopting the bottom-up programming mythology.
I will demonstrate how to do bottom-up design, but first we need a few simple functions which you can use throughout this tutorial.
; Simple functions common to all below.
(defun scratch
-carpet
() (princ "destroy owner's stuff."))
We are used to setting up a function(s) that looks like this:
; Main function: behave
(dog
)
)
)
)
)
; Support function: dog
behavior)
)
; Support function: pig
behavior)
)
; Support function: cat
behavior)
)
Usage:
(behave 'dog)
(behave 'pig)
(behave 'cat)
As you can see we start off designing the `behave` function to do something we want based on certain conditions. We can call `behave` to something different based on the condition we give (-i.e. behave like a Dog/Pig/Cat/etc.). This code works but is not very flexible if we need to add a condition like "owl", "horse" or "mouse" or etc.. To add functionality, we'd need to build support functions and modify the main function `behave`. The amount of maintenace needed to extend the tool is entirely wasteful and can be avoided if we utilize bottom-up programming.
For example, It can be more flexible if we built the `behave` function more generically and supplied the methods we want to preform. Like the revision below (NOTE: below I am using SET instead of DEFUN, but there is no difference in operation between SET and DEFUN when used like this, only used to highlight and introduce). This simple redesign of the `behave` function will allow us to extend the conditions and cut down on maintenace time and mistakes.
(defun behave
(animal behavior
) )
behavior)))
behavior)))
behavior)))
Usage:
; Now you can call `behave` like this:
(behave 'dog '(wag-tail bark))
(behave 'pig '(rut oink))
(behave 'cat '(rub-legs scratch-carpet))
This simple redesign allows us to create as many `animals` and `behaviors` as we'd like and this redesign is a lot like using "methods" in "Object Orientated programming" (OOP) which is what bottom-up programming is about (we can change how we USE lisp). By using this method we essentially define--on the fly--what methods are sent to the `behave` function instead of using the predefined list.
A word about why I used SET instead of DEFUN in the last example. This is a on-going developing quirk of personal preference. In this case, I think of `dog`, `pig`, and `cat` as more of a `symbol` with a `method` then a full fledged `function` with an `operation`. I believe the use of DEFUN may be faster but again this is more of a personal preference thing. However the SET functions have a type of USUBR instead of SUBR if that means anything to you.Back to the bottom-up discussion; as you can see, we had to change the parameter list to the `behave` function and it's not quite as user friendly and as readable as the first example. Also, it still has the potential to support mistakes in coding so, we can rectify these short-comings by adding another function definition to build the functions based on the given arguments and thus make things a bit more user friendly and readable.
; Define a simpler version of `behave`
)
; Build a function generator helper.
(defun define
(binding body
) binding
)
)
)
)
Usage:
; Define what the dog function should be.
(define 'dog '(wag-tail bark))
(define 'pig '(rut bark))
(define 'cat '(rub-legs scratch-carpet))
; call the behave function.
(behave 'dog)
(behave 'pig)
(behave 'cat)
With a little bit of setup--one helper function--we can change the way we use the language (-i.e. to be more clear) with very little overhead.
This also has the added benefit of making things easier to debug (can you spot my mistake; I'll give you a hint: silly pig).
NOTE: according to my benchmarks this method also gives you a SLIGHT increase in speed of operation but that shouldn't be the major take away from the use of our `method like` design.