Solving Problems, aka, Nobody Codes Like This Anymore
When I was in college, I had a class in machine architecture/assembly language. At the time that I took it, I knew 6502 already and had published two video games for the Apple II written entirely in assembly. I love the drunken power of having access to the entire machine and making it do things it wasn’t precisely designed for – so the class was easy to me. We started off with a fake Von Neumann architecture machine called MANIAC. MANIAC was a basic accumulator-model machine – not too different from the 6502, so coding for it was familiar ground.
We then transitioned to VAX assembly and were writing code to run directly on the machine. Compared to the barren wasteland of 6502, VAX was like stepping into Paris. 16 registers? What the hell am I going to do with them all? Multiply? Divide? Floating point? SOBGTR (subtract one and branch on greater)? There was even an instruction to insert into a queue. Yikes.
In class, the final assignment was to write a program to maintain a family tree. The program needed to read a line and parse out a set of commands:
- CREATE name – create a new person named name
- MARRY name1 name2 – mark persons named name1 and name2 as married
- CHILD name1 name2 – mark person named name1 as a child of name2
- GRANDCHILDREN name – prints a list of name’s grandchildren
- COUSIN name1 name2 – prints TRUE if person named name1 is a cousin of name2
I looked at this task and thought, family tree? Really? In assembly? No. Wrong approach.
So I first wrote it in Pascal and got it working. Then I hand compiled each procedure (I didn’t know how compilers worked yet, but I had a pretty good idea). I noted that many of my peers were struggling with the argument passing in VAX, so I avoided the whole problem and adopted register passing as the protocol where the caller, not the callee was responsible for saving registers. Every subroutine was clear what it used as arguments and I set aside some registers that were free to be destroyed.
Once I had my “architecture” in place, it was a matter of writing little subroutines that matched the Pascal. I even included the Pascal in the source as documentation. The only documentation. Why would you need more?
It wasn’t without bugs, but it eventually worked just fine and I was done well before most of my peers, even though I technically wrote the program twice.
So, nobody really writes code like this anymore. Compilers are good enough that unless you doing something like image processing, you don’t really need to drop to the machine level. That doesn’t mean that we can’t learn something from the process.
This particular problem lent itself to being solved in a particular language domain – Pascal (or your favorite procedural or OOP language). So much so that writing it in another language was trivial. It became divide and conquer to factor the tasks out to reasonable pieces: a simple parser, a REPL, a structure definition, and five procedures. Then I picked a mapping strategy to go from my problem language domain into my solution language domain and followed through on it. This is still a valid way to solve problems, even though this particular solution language domain is obsolete. This particular approach is how we end up with domain specific languages and small virtual machines to run them.