How Much Does Your Choice of Programming Language Limit You?
The first program I ever wrote was for a computer which never existed.
Somehow I got into the High School math club. The 'Smart Kid' had spent the summer hanging out at the David Taylor Model Basin learning stuff from the mathematician who ran it. He (the Smart Kid) came in and made a 'presentation' of how a computer worked and gave us a problem to try: sort a sequence of numbers in storage locations.
So I took the mimeographed paper home and 'invented' the exchange sort.
All the paper computer had was a couple of registers, maybe 10 instructions (with decimal op codes), maybe 20 or 30 storage locations, and a clock.
I programmed it in 'machine language'.
So when I made it to college and found out that they'd just gotten the second IBM 360, model 50, ever made, it made perfect sense to buy a copy of the IBM Principles of Operation for the machine. Again, I was reading machine instructions [the book was pretty thin at that time].
The next year I took a Numerical Methods course and 'learned' FORTRAN. Of course I was thinking in terms of machine instructions, so it also made perfect sense to me.
All this biased me towards thinking of programming as controlling the hardware.
I think it took another 10 years before I realized I was wrong and started trying to figure out what programming is really about.
I'm still working on it - but with such a backward start, it's been difficult.
"Huh?" you say?
Let me explain.
The first 'High Level Language' was probably FORTRAN - which is short for Formula Translator, or something like that.
It was designed for translating algebraic formulas into machine instructions that the computer could execute. It's possible - but very difficult - to use Fortran to do other things. Like the first computer game I ever saw - Adventure - was written in FORTRAN. All the twisty little paths were modeled as arrays of indices to other array elements, etc etc. I/O in FORTRAN was disgusting. Character strings were non-existent: they were usually stuffed into 32 (or 36) bit words, left or right justified, and blank padded. (blech!!!!)
But formula translation works really well for formulas and such - which is why it's still in use.
But the modern use of computers is really moving data around, drawing pictures, communication, control, operating machines, managing your burglar alarm system, (pant pant pant) and more stuff. Very little of this involves encoding and solving Algebraic Formulas.
So I - and a lot of other 'engineering students' - started out with a very limited view of what computers and what can be done with them.
Here's another example:
COBOL - maybe the 2nd (or 3rd) high level language 'invented'. Common Business Oriented Language (or something close to that). It's essential view of 'reality' is a business form - a spread sheet, as it were. About all it's good for is copying forms from one place to another while modifying some of the information - like giving the boss a raise as his record goes through.
Again, it's a very limited view of the world.
Then there was Algol - designed to encode algorithms, and Smalltalk - which sees the world as a bunch of autonomous objects (forgive me if I oversimplify). (let's forget about APL - it seemed to think the world was some sort of algebraic calculator with strange grouping rules)
A big wake up for me was when I started using *NIX systems and found awk - which sees the world as lines of text which can be broken into fields and messed with. And then lex, yacc, troff (and his friends: tbl, grap, and eqn).
My computing world started getting larger as I realized that you can create a language and that the concepts you can express in it are the limitations of what it's easy to do.
I eventually realized that programming is about building models of reality.
I'm going to repeat that, because I think it's important: programming is about building models of reality.
We've got some pretty good languages now - C, Python and Ruby. I guess you might want to include C++, C#, and Java - along with the thundering herd of Web oriented stuff - and that's OK, but it's not really the point I'm going for.
All of those languages start out trying to describe a limited set of features of Reality. And in doing that, they build limitations into the ideas you can easily express. When we - as coders - try to do something that language doesn't support directly, we have to 'work around' the language.
I ran across the difference between what a language supports, versus what a language allows during one of my many attempts to understand C++. Bjarne Stroustrup made the point that in designing C++ he built a language which not only allowed object oriented programming, but contained language constructs which support it. C allows object oriented programming - born out by the fact that his original C++ compiler generated C, not machine language, but C does not in any way support object oriented programming. (I know from experience in attempting to write C in an object oriented style)
So I think it's pretty much obvious that the design of a computer language strongly shapes how programmers program. More importantly, it creates a limiting context about how they see the world and create programming solutions which model it.
What view of reality is best for a Language to support?
Doesn't it seem reasonable to design a language using the most general model of reality we have? That is, assuming that the model can be made specific enough that we can compute precise representations of 'reality'.
So what's our most general model?
The most general model I know of is the mathematical concept of a function.
What's a function? You cooperatively ask.
Well, a function is a map from a domain to a range such that for any element in the domain there is at most a unique element in the range. How's that for a vacuous definition?
I'm going to sound more ridiculous, but I think it's worth the apparent diversion.
Remember - we are modeling 'reality'.
So here's something real: craps.
When shooting craps, you need a pair of dice, a flat surface, and some people who know the rules. To make it simple, we'll use a subset of the rules:
- the shooter throws the dice
- everybody counts the dots on the visible horizontal surface of both dice and adds them up
- everybody applies the rules and decides what happens next.
Here's the point: the 'function' which 'maps' the roll of the dice into a 'win', 'lose', or 'roll again' is the rules as it exists in the minds of the people. Given any roll, there is one and only one outcome.
If I want to write a program to simulate craps, I need to grab a couple of random numbers and apply the rules. But that's not the real function. What I am writing is a model. The real function exists in the event in the alley where the guys are 'shooting craps' (if it exists at all, but that's another story).
In order to model craps, I need to pick a language which at least allows all of the stuff I need to simulate the important stuff. You may think this is easy - and it's not too hard to find one - but I defy you to accomplish this in a language which does not allow repetition - such as HTML, CSS, or native SQL. You need to have numbers, arithmetic, some means of repeatedly throwing dice, and some logic operations to implement the rules.
The Point
So here's the point. (again in overly simplified terms)
Assembler sees the world as machine instructions and memory.
FORTRAN sees the world as Formulas
COBOL sees the world as business forms
C sees the world pretty much as an abstraction of computer hardware.
Ruby, Python, and Smalltalk (and friends) see the world as objects with state and methods.
Lisp sees the world as functions.
(yeah - I just snuck in Lisp)
Let's try it another way
Assembler is designed to translate text directly into machine instructions
FORTRAN is designed to translate formulas into machine instructions
COBOL is designed to translate business forms into machine instructions
C is designed to translate operating system concepts into machine instructions
Ruby is designed to translate object abstractions into machine instructions
Lisp is designed to translate arbitrary functions of finite arguments into machine instructions
So which language should give you the most flexibility in solving problems of arbitrary complexity and scope - i.e. building models of reality.
Paul Graham is on record as saying all programming languages are converging towards Lisp. I think he's right and that the reason is that the model of reality Lisp has is the most general one we currently have. Inasmuch as programming is modeling reality, it makes sense that the best way to expand the domain of possible things we can model is to use the most general language we have.
So why don't we dump all the specialized languages and all hack Lisp?
I don't know about you, but I'm not a good enough coder - yet. Like I wrote above: I started in the wrong direction to understand the abstraction that is programming. So after a lot of backtracking, poking around, etc I think I'm finally ready to tackle Lisp.
Oh, there's just one more thing
One of the things I learned this last year of studying Ruby and Rails is the importance of generating code at run time. The currently popular term for this is Metaprogramming - but I think that's really a yet another corruption of language (English, that is, not the Ruby Language).
The simple fact is that programming is hard and we don't have time enough to write all the code we need. In languages which do not allow dynamically generated code - such as Java - programmers have to resort to external resources to generate code which 'is the same, with minor variations'. Dynamic languages such as Ruby and Python allow run time generation of methods and objects, so they provide the possibility of making programmers more efficient.
But neither Ruby nor Python really support run-time generation of code. They allow it.
Lisp supports it.
So I think Lisp is a better language - and this year's project is to become a decent Lisp coder.
I'm really, really tired of being limited by the world view of my programming language.

