Tracking Down DOPE, the First Computer Language for Normal Humans

BASIC holds an important place in computer programming canon. Hugely popular in the 70s and 80s this programming language introduced an entire generation to computing. The reason for its widespread adoption was simple: BASIC wasn’t meant for programmers, it was designed for beginners. The language meshed well with the egalitarian worldview of early home computing. If you could type then you could become a computer user, and if you could become a computer user you could become a programmer.

BASIC didn’t come from nowhere. Like any language it has a family tree complete with phylums and roots. The descendants of BASIC are fairly easy to spot, Visual BASIC is about as far afield as they get. But it’s ancestry is a different story that not many people know about. The language that inspired a generation does, in fact, have a predecessor called the Dartmouth Oversimplified Programming Experiment, or DOPE.

That name’s probably not familiar, but that shouldn’t be a surprise. I ran into it almost by chance. Once I learned of this obscure language I found myself in a pretty deep rabbit hole. At the bottom I became one of the few people to run a DOPE program in nearly 60 years. The language is strange, but undeniably shows the skeleton of BASIC starting to form.

What is DOPE, and where does it fit into the larger story of BASIC? 

The history of computing is easy to sum up in terms of problems. In the corporate parlance of IBM the worst of these problems were once called dragons, evocative of monsters that programmers were sent out to slay. In the earliest days of the computer one of the biggest dragons around was accessibility. That is, how to get people using computers in the first place. Early computers were hulking beasts in their own right: huge, expensive, and difficult to use. Most often programmers never even touched computers themselves. Instead they would drop off stacks of punched cards for technicians to carefully feed into well protected machines.

In isolation a computer is a novelty. It can hum, crunch numbers, and heat up a room. You need people to actually make computers useful, the more people the better. The state of the art in the late 50s was progressing at a steady pace, but there just weren’t enough people in the game. To make matters worse access to machines formed a tight bottleneck. It was never disputed that computers were going to be the future. How exactly that future would develop was another matter.

Programming languages came into being. FORTRAN, ALGOL, and a handful of ancient dialects have their roots in this period. The whole point in developing FORTRAN was to make computing more accessible to non-computer scientists. The key word here being scientists. If you follow FORTRAN’s logic then computers are tools for research, something you tuck away in a lab. And while that’s one important application it’s a limited one. In the grand scheme of things not that many people are scientists. Luckily for us not everyone was a devotee of FORTRAN’s vision of the future.

Enter the dragon slayers of our story: John Kemeny and Thomas Kurtz. Kemeny was the longtime chair of the mathematics department at Dartmouth college, and Kurtz was his colleague and fellow researcher. 

During WWII Kemeny was involved in the Manhattan Project as a mathematician. While on the project he worked directly with John von Neumann, one of the key figures in early computing. Kemeny spent a year on the project crunching numbers and running figures. In early 1945 his work was done using cumbersome IBM tabulating machines. By the end of the year the first electronic digital computers became operational, and Kemeny witnessed their impact on the Manhattan Project firsthand. The next year Kemeny wrote his first program.

Thomas Kurtz came to the field only slightly later. In 1951 Kurtz attended one of UCLA’s Summer Sessions where he saw a computer running for the first time. At the time he was enrolled in Pricneton’s graduate program for mathematics. That demo was enough to interest him. Once he learned to program, computing became an integral part of his career. Both saw for themselves how computers changed their own lives, and they realized the technology wouldn’t stop there. Computers would only get better and more widespread, the future was going to be digital.

Surrounded by young and impressionable minds the duo set out a task for themselves: teach every student at Dartmouth how to use a computer. STEM students at the college were already being exposed to computers, at least in a limited sense. But that only accounted for a fraction of the student population.

How can you teach an English student to talk to a computer? Why would an aspiring psychologist care about silicon? Sure, computers were going to change everything for everyone. That’s nice to say in a lecture, but how do you introduce students to machines?

This would eventually lead to BASIC. Unlike its contemporaries BASIC was designed for non-scientists, and really for non-programmers. Unnecessary constructs were stripped out, data was simplified, syntax was reduced to the bare minimum. The final language would be a masterpiece of restraint. It’s not a language a programmer can love but for the vast majority of the populace it’s easy to learn. 

Compared to its contemporaries BASIC is simple, almost to a fault. Take FORTRAN as an example. In that language variables need to be declared with specific data types, and variable declarations need to be made in specific locations within a program. BASIC doesn’t use explicit types, any variable can hold anything you want. You don’t even need to declare a variable, just say “LET A = 1” and you are done. Even BASIC’s syntax is a breath of fresh air. The language only uses letters, numbers, and a few mathematical operators. You don’t have to deal with line endings or brackets.

The downside is that more powerful features are dropped in favor of simplicity. Objects, abstraction, even the aforementioned variable typing, are all absent. BASIC offers just the necessities.

On campus BASIC was a hit. Teachers integrated the language into classes, and students were happy to adopt it. The transition to home computers was an obvious choice. BASIC became the de facto introduction to the digital realm for millions. 

The most authoritative source on BASIC’s development is the aptly named “Back to BASIC”, co-authored by Kemeny and Kurtz themselves. This is where I first encountered DOPE. Or, rather, where I first saw the language mentioned. During the late 50s and early 60s the duo experimented with how to introduce students to computers, specifically looking for a programming language for the absolute novice. When existing languages proved ill fit for this task they shifted to creating a new programming language.

The Dartmouth math department was armed with an LGP-30 computer, a relatively cheap and underpowered machine. In total it had 30 kilobytes of RAM to work with. That computer would see years of hard use and strange experiments. DOPE was one of those experiments, but details in “Back to BASIC” are slim. In a passage near the beginning of the book Kemeny wrote:

“I had a high school student, Sidney Marshall, who was taking calculus at Dartmouth. I had him experiment with a language called DOPE on that same LGP-30. DOPE was too primitive to be useful, but it was the precursor of BASIC.”

DOPE was used on the math department’s computer and Kemeny supervised it’s creation. As a programmer myself I don’t really do mysteries—I much prefer resolutions—and this was a massive mystery to me. I’ve written a good deal of BASIC, it wasn’t my first language but it was a big part of my diet early on. I always assumed it was it’s own language isolated from any others, and I think that’s an easy mistake to make. BASIC doesn’t look like anything but BASIC. It’s name doesn’t hint at some larger lineage. I was left with a glaring hole in my knowledge, and as I soon realized I wasn’t the only one out of the loop.

LGP-30.jpg

Image: Marcin Wichary/Wikimedia Commons

Running DOPE

There isn’t that much readily accessible information about DOPE. Notably a passage written by Thomas Kurts for the book “History of Programming Languages” has a small chunk of code. It’s a handful of lines of DOPE, not enough to understand the language but just enough to confirm it’s existence. Scouring through interviews and citations I started to build up a picture. DOPE had been developed in 1962. It was only used for a single term in a single math class. It was a step towards accessible programming but didn’t go far enough.

The trail led me to a file folder tucked away in Dartmouth’s archive. The manuscript within was simply titled “Dartmouth Oversimplified Programming Experiment”, filed under a collection of Kurtz’s notes. The paper was written in 1962, and for the time gave a radically different approach to programming. It’s definitely not BASIC, but it’s getting close.

First of all, the DOPE manuscript answered one of my biggest questions: why was there so little information about the language? The name should give a little away, DOPE was an experiment. It was used as a proving ground for ideas Kemeny and Kurtz were brewing. The paper describing DOPE was also never published. Partly, because it wasn’t really a formal language description. Instead it was part primer, part lesson plan. Students were being used as guinea pigs on the path to a better programming language.

The next step for me was clear. The DOPE paper laid bare all the details of the language, example problems, logical diagrams, and every idiosyncrasy. Reading it is one thing, but I wanted to understand DOPE, and the only way to understand a language is to use it. The larger issue was that there was no way to run DOPE code that really existed. GNU binutils—the most popular compiler package around—definitely doesn’t ship with support for the language, and I wasn’t able to track down any of the code for the original implementation. So I set to work reviving the language by building an interpreter. Simply put, an interpreter is a program that can understand and execute source code.

Making my own implementation of DOPE was a way to understand the language on a deeper level, and try to reason out why it failed and what ideas made it into BASIC. That, and preserving a dead programming language sounded like a fun challenge. How hard could it be?

As it turned out, not that hard. Even before I had a running interpreter I was starting to see the connection to BASIC. One of the reasons BASIC became so popular was because it was easy to implement. That was by design. The language was structured to make compilation simple, Dartmouth’s BASIC follows very rigid syntax structure. Each line of BASIC starts with a number, then an operation, then arguments. It’s simple, easy to parse with a computer, and easy to write for a novice.

Each line of DOPE starts with a line number, then an operation, then arguments. This is where BASIC got its structure. For someone implementing the language that saves a lot of time and code. You just break each line into tokens, the operation is always in the same place, arguments are right after. There is zero ambiguity and zero wiggle room. It’s easy to zoom through the process.

The Dartmouth team had similar mileage. According to Kemeny’s paper the DOPE compiler could turn code into executables in under a minute. That’s slow today, but sounds pretty good for the slow LGP-30. Later this same simplified syntax structure allowed Kemeny and Kurtz to pull some slick tricks with their BASIC implementation. Dartmouth BASIC was compiled, but presented to users as an interactive environment. On the backend BASIC code was compiled on runtime with minimal latency, to students it just looked like the school’s computer spoke fluent BASIC.

But there’s a hitch, and it’s one of the biggest issues with DOPE. BASIC deviates from the rigid format slightly. You can actually write mathematical expressions in BASIC, so “LET A = 1 + 1” is a valid line of code. Under the hood a mathematical expression may be treated as arguments, but to a user you can write math in BASIC the same as you’d jot down an equation.

DOPE doesn’t work that way. The language is much more terse, no doubt a result of the limited hardware it was developed on. Let me give you a taste. In DOPE that same BASIC statement, just adding 1 and 1, comes out to “+’1’1’A”. That’s not very pretty, is it? Superficially, DOPE looks a lot more like assembly language than anything else. Most operations are a single character, each line can only perform a simple operation, argument lists are all of a fixed length. All the usual operations for math, assignment, loops, and printing are present, just in a consolidated form.

The other fun complication is the matter of single quotes. DOPE doesn’t separate things with spaces, as near as I can tell this is due to its host hardware. Other languages used on the LGP-30 computer follow the same convention. I think it was just one of those functional restrictions that made life a little harder at Dartmouth. Better hardware was available on campus when BASIC was developed, so it escaped that fate.

Appearances aside, there is something deeper going on with DOPE. Variables are the bread and butter of any programming language, it’s where you store and manipulate data. It’s also another place where DOPE directly presages BASIC. DOPE has a very special kind of typing system. It’s almost implicit, but only slightly.

Every variable is a floating point number, that’s a number with a decimal point. Adding a little complication, DOPE has four special variables named E, F, G, and H. These are 16 element arrays, lists that can hold up to 16 numbers. When you work with DOPE you just have to remember that these four variables are different.

There are also no strings in DOPE, you can’t store or manipulate words or letters. Nearly every other programming language can handle strings in some way, so this restriction is pretty noticeable. DOPE was only ever meant for mathematical work so lacking strings isn’t a total dealbreaker. 

There is a little bit of subtlety here that I find intriguing. All variables are stored as floats, so any number you enter is converted. Set a variable to 1 and DOPE turns that into 1.000. When you print a variable DOPE figures out the most reasonable format and displays that. So if the float doesn’t have anything past the decimal place it shows up without the decimal. To a more serious programmer this should sound like a nightmare. DOPE takes away any control over data types by just not having data types. Programmers don’t like giving up control, this was especially true during the era DOPE was developed.

Counter_instruction_accumulator.jpg

Image: Marcin Wichary/Wikimedia Commons

This language wasn’t meant for programmers. It was meant for english students who didn’t know the difference between an integer 1 and a floating point 1. It was designed for political science majors who had never seen a computer before. The bizarre typing system in DOPE meant you could teach programming without teaching about data types. Instead of having to explain the subtle differences between 1.0 and 1 a teacher can just cut to the chase. To the uninitiated these rules don’t make that much sense, so just drop them. What you get is a much more gentle introduction to computers.

It may come as a surprise for BASIC users, but early versions of the language had a very similar typing system. In v1 of Dartmouth BASIC every variable was stored as a float, with smart formatting for input and output. Strings came in subsequent versions. But there is a key difference, and it comes in the form of arrays. In BASIC an array is declared using the DIM operation. It tells the computer to make room for a new array, and gives that array a name. In early versions this changed a variable into a 10 element array of numbers. This is one of the areas where BASIC broke from DOPE, and I think in a good way.

DOPE reserved four variables as arrays. That works just fine, but it’s clunky. Having to remember which letters are lists and which are numbers is annoying. It adds in a layer of illogical complexity. Why is E an array? Well, it just is. My educated guess is that E, F, G and H were hardcoded as arrays since those are common names for vectors in physics, but that’s just a shot in the dark. For a newcomer it’s just an arbitrary rule. Kemeny and Kurtz were right to ditch this one.

The last part of DOPE that bears mentioning is also one of the key parts of BASIC: line numbers. Anyone who knows BASIC, or has seen BASIC, will be familiar with this syntax. Each line has a number that doubles as a label and a way to edit your program. With line numbers being explicitly defined a programmer gets to name each part of their code. DOPE also uses line numbers, but in a more limited way. Each line has an implicit number, you start at 1 and go up to 99.

You don’t have control over DOPE’s line numbers, but each number does have it’s own label. These aren’t just superficial, line numbers in DOPE are what makes it into a fully fledged programming language. The much-maligned GOTO statement exists in this earlier language, just by another name. GOTO tells BASIC to jump execution to a specific line number. It’s a simple way to handle flow control of a program, but there are often better options. Many programmers dislike GOTO for that reason alone, but the statement can also make code hard to read and debug. You can’t instantly tell what “GOTO 11” means unless you know what is waiting for you on line 11.

In DOPE the “T” operation lets you jump TO a given line number. Once again, this is the kind of feature programmer’s don’t really like. GOTO, and by lineage T, has been called a danger to programmers everywhere. It can be unsafe to overuse, if code changes a stray GOTO can jump into the unknown. For large programs jumping by line number gets weird, but that’s an issue for programmers.

For the novice jumping by number is simple and understandable. You don’t need extra code to add labels. Since most new programmers aren’t writing massive and intricate programs a lot of the dangers of GOTO disappear. Conditionals work in a similar way in DOPE, specifying line numbers to jump to dependent on a comparison. Again, in line with early versions of BASIC. And again, kept as simple as possible.

The only outlier here are loops. One of the parts of BASIC that always struck me as strange is how it handles FOR loops. In general loops are how you repeat operations in a program. If you want to do something over and over again you use a loop. BASIC’s specific flavor of loop is the FOR loop. As in, do something FOR values of X from 1 to 10.

Most flow control in BASIC is handled using line numbers. Some later versions allow if statements to contain expressions but Dartmouth BASIC only allows for conditional jumps. Loops are different, a FOR loop in BASIC encloses a block of code, ending in a NEXT. Once again this quirk is straight from DOPE, loops enclose a chunk of code to run and rerun until complete.

However, DOPE loops have their downsides. And really, this gets into the problems I ran into with DOPE. Kemeny was right to say the language was too simple, and loops are a perfect example. Really, loops have been something of a thorn in my side during my journey. On the interpreter side that means extra code. Executing code by block instead of line number means loops have to be handled a little differently than anything else in the language. When I was actually able to get DOPE code running loops remained annoying because they only go one way. Loops in DOPE can only increment, and only in steps of 1. Fine. It’s a loop. It’s the most basic loop possible. It works, but it’s very restrictive. Something as simple as a countdown takes a little extra code to achieve.

The total lack of strings also restricts what you can do with DOPE. There are operations to output strings, sort of. One operation lets you print a newline character, and another outputs a string literal. This can be used to format and label your outputs, but without variable strings you can’t write very flashy code. I can write the classic “Hello World,” but you won’t be seeing any games in DOPE. Luckily BASIC would include strings after a fashion.

DOPE’s Legacy

What I’ve found is that DOPE works well for math and not much else. Calculating tables of values is straightforward. Running a loop to figure lists of roots or squares is easy. I’ve even been able to tackle larger equations in DOPE, so far the most complicated thing I’ve written is a program that approximates pi. There’s a certain zen to converting equations into simple operations, that is if you have some patience. Straying from simple math turns into a struggle. I keep trying to make a number guessing game but running into the wall of random number generation.

This restriction to simple math isn’t necessarily a bad thing. The language was developed by mathematicians as a way to introduce complete novices to computing. It’s not fully general purpose, true, but that’s not important. DOPE isn’t the kind of language you could stick with for a career, it was never intended to be. It’s just enough to show students what a computer is, what kinds of problems a computer can solve, and how a programmer might solve them.

So why haven’t more people heard about DOPE? Is it just a failed language? I don’t think so. DOPE has remained hidden because it was successful. The E stands for experiment after all, and after a single class at Dartmouth the experiment had ran its course. The ideas in DOPE worked well enough for Kemeny and Kurtz to continue their line of research. BASIC is the direct result of DOPE’s success. The reason BASIC worked so well in classrooms and on early home systems was because it was simple. The language was easy to learn, easy to implement, and easy to understand. DOPE itself didn’t last, but the core concept was sound enough to birth BASIC.