Part III: Inventing languages
Chapter 08
#Teaching machines our words
A common misconception is that programming languages exist simply to tell computers what to do. If that were their only purpose, we wouldn’t need so many of them.
A computer doesn't need a programming language. Humans do.
Computers are perfectly fine executing instructions like this:
037744 016701 000026 012702 000352 005211 105711 100376
116162 000002 037400 005267 177756 000765 177550
https://en.wikipedia.org/wiki/Machine_code https://en.wikipedia.org/wiki/Assembly_language This machine code is written in octal, to make it slightly more readable for humans. But the first really usable step is to write it as assembly code: https://en.wikipedia.org/wiki/Machine_code https://en.wikipedia.org/wiki/Assembly_language
037744: 016701 000026 MOV 037776,R1
037750: 012702 000352 MOV #352,R2
037754: 005211 INC @R1
037756: 105711 TSTB @R1
037760: 100376 BPL 037756
037762: 116162 000002 037400 MOVB 2(R1),37400(R2)
037770: 005267 177756 INC 037752
037774: 000765 BR 037750
037776: 177550 .WORD 177550
And now with some labels and comments:
LOAD = 0x7400 ; Buffer address
0x7744 016701 BEGIN: MOV DEVICE, R1 ; Get Device CSR
0x7746 000026
0x7750 012702 LOOP: MOV (PC)+, R2 ; Get buffer offset
0x7752 000352 OFFSET: .-LOAD
0x7754 005211 INC @R1 ; Turn on reader
0x7756 105711 READY: TSTB @R1 ; Done?
0x7760 100376 BPL READY
0x7762 116162 MOVB 2(R1), LOAD(R2) ; Transfer
0x7764 000002
0x7766 0x7400
0x7770 005267 INC OFFSET ; Bump buffer offset
0x7772 177756
0x7774 000765 BR LOOP
0x7776 177550 DEVICE: 177550 ; Input device CSR address
http://gunkies.org/wiki/PDP-11_Bootstrap_Loader https://en.wikipedia.org/wiki/Bootstrapping This is the code to make a PDP-11 computer boot. It is commonly known as bootstrap code. http://gunkies.org/wiki/PDP-11_Bootstrap_Loader https://en.wikipedia.org/wiki/Bootstrapping
Even in this enhanced, more human form, this code is not very readable. Or expressive. Most humans don't code in assembly language. In the end, the machine still receives instructions.
The programming language is there for the humans who have to write and understand those instructions.
https://en.wikipedia.org/wiki/COBOL COBOL was designed to make business programs look more like business language. It was very successful and almost universally hated. https://en.wikipedia.org/wiki/COBOL
/
IDENTIFICATION DIVISION.
*-----------------------
PROGRAM-ID. UNLDBCU1
*
ENVIRONMENT DIVISION.
*
CONFIGURATION SECTION.
DATA DIVISION.
*
WORKING-STORAGE SECTION.
*
01 WORKAREA-IND.
02 WORKIND PIC S9(4) COMP OCCURS 750 TIMES.
01 RECWORK.
02 RECWORK-LEN PIC S9(8) COMP VALUE 32700.
02 RECWORK-CHAR PIC X(1) OCCURS 32700 TIMES.
*
PROCEDURE DIVISION.
*
CALL 'UNLDBCU2' USING WORKAREA-IND RECWORK.
GOBACK.
https://www.ibm.com/products/db2 https://www.ibm.com/products/zos https://en.wikipedia.org/wiki/OS/360 Believe it or not, COBOL is still in use today. The code above is copied from a current manual for DB2, an IBM database system that runs on z/OS mainframes. These are descendants of the famous OS/360 mainframes of the 1960s. https://www.ibm.com/products/db2 https://www.ibm.com/products/zos https://en.wikipedia.org/wiki/OS/360
That is not an accident. Business software tends to outlive the people who wrote it. Once a language becomes part of the machinery of an institution, replacing it becomes a social, economic, and political problem. Not just a technical one.
https://en.wikipedia.org/wiki/Fortran Fortran was built for scientists and engineers. It made formulas, arrays, loops, and numerical work easier to express. https://en.wikipedia.org/wiki/Fortran
Here is an example in Fortran 77:
PROGRAM MAIN
INTEGER N, X
EXTERNAL SUB1
COMMON /GLOBALS/ N
X = 0
PRINT *, 'Enter number of repeats'
READ (*,*) N
CALL SUB1(X,SUB1)
END
SUBROUTINE SUB1(X,DUMSUB)
INTEGER N, X
EXTERNAL DUMSUB
COMMON /GLOBALS/ N
IF(X .LT. N)THEN
X = X + 1
PRINT *, 'x = ', X
CALL DUMSUB(X,DUMSUB)
END IF
END
https://en.wikipedia.org/wiki/Lisp_%28programming_language%29
John McCarthy
Lisp
Finally we arrive at Lisp. A wizard called John McCarthy dreamed up Lisp between 1956 and 1958.
https://en.wikipedia.org/wiki/Lisp_%28programming_language%29
https://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)
Lisp is both very small and absurdly expressive. More importantly for this chapter, it makes it unusually easy to add new words to the language.
Here is a tiny example:
(defmacro unless (condition &body body)
`(if (not ,condition)
(progn ,@body)))
That is why Lisp keeps returning in conversations about programming languages, not because everyone should use it, or because parentheses are secretly beautiful if you stare long enough. But because Lisp makes language-building visible.
http://www.paulgraham.com/rootsoflisp.html A Lisp interpreter can be written in Lisp itself. Paul Graham shows one in Roots of Lisp, based on McCarthy's original. http://www.paulgraham.com/rootsoflisp.html
#Differences, commonalities, and why we can't have nice things
Computer languages are more commonly known as programming languages. They are designed to make a computer do something. Did you spot the lie?
Unlike human languages, programming languages are designed. However, they aren't designed to make a computer do anything. They are designed so you, a human, can reason and communicate about what it is that you want the computer to do. This may seem like a small difference, but it is in fact the reason behind the proliferation of programming languages.
Just like human languages, programming languages make it easier for some ideas to be expressed than others. The best programming language allows you to freely express all the ideas you need to solve a problem in as simple and straightforward a way as possible. And it does so with as little required learning as possible.
Unfortunately, that's also not true.
The problem is communication. Any other wizard who wants to work with your ideas, your code, will have to learn your version, your implementation of these ideas. And lord help them if you thought up some crazy new ideas.
https://en.wikipedia.org/wiki/Not_invented_here Reading code is hard. It is much easier to write code. This sounds nonsensical, yet it is true. It is the source of the NIH syndrome: Not Invented Here. https://en.wikipedia.org/wiki/Not_invented_here
https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping One answer is to make programming languages bigger. Add more standard stuff. Add design patterns. Add frameworks. Make sure all programmers are fed the same cookie-cutter solutions, so all code starts to look roughly the same. Create frameworks that force all problems into a Model-View-Controller solution on top of an Object-Relational Mapper. Boom, done! https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping
There is a reason this keeps happening. Code is easier to read when everyone uses the same patterns.
But there is a cost. Eventually the patterns become the language. Instead of writing code to solve the problem, you are adding controllers, models, maps and whatever else the framework requires, so that it can solve the problem for you.
So the natural pressure on programming languages is not to become smaller and more powerful, but bigger and less powerful.
Small, powerful languages are wonderful for the writer, but dangerous for the reader. Large, standard languages are easier to share, but they also make it harder to say unusual things simply.
Just like human languages.
You should be aware of this tension. You do not escape it by choosing the one true language, because the one true language does not exist. You escape it, when you can, by making the language of the program fit the problem more closely.