next up previous
Next: About this document Up: The Story of Mel Previous: The Story of


The Arpanet was the first computer network. That is, the first time that different computers were connected together so that information could be shared between them without using a separate medium like paper tape or magnetic disks. The Arpanet was born with five sites in 1969 (before video games (Pong didn't appear until 1972), before hand-held calculators (1972), home VCRs (1975), and personal computers (1976-1977)) as a way to let researchers funded by ARPA (the defense department's Advanced Research Projects Agency) collaborate. The original five sites on the Arpanet were: Bolt, Beranek, and Newman (BBN), a Cambridge Mass. based company that built the original Arpanet Interface Message Processors (IMP) that were used as the special-purpose computers that passed data on the Arpanet, UCLA, Stanford Research Institute (SRI), University of California at Santa Barbara, and the University of Utah.

The first public demonstration of the Arpanet came in 1972. By then the Arpanet has expanded to 37 nodes across the country. The public demonstration was at the International Conference on Computer Communications and was a great success.

As the Arpanet grew, other networks were developed that used the technology developed on the Arpanet. One of these, the USENET, was a collection of computers connected by phone lines but without the expensive IMPs that made the Arpanet run. USENET was slower, but anyone could connect if you had a phone connection to your computer. USENET came into being around 1979. Although there were special-interest email lists on the Arpanet almost since its inception (the SF-lovers list for science fiction fans was one of the first), it was on the USENET that the idea of interest-specific electronic bulletin boards (bboards) or newsgroups really blossomed. It was on just such a newsgroup that The Story of Mel, a Real Programmer was first posted on May 21, 1983.

Although I first saw this story without attribution, it turns out that the author is known. It is Ed Nather, then of the University of Texas who wrote the story in response to an earlier article in Datamation Magazine.

The article ``Real Programmers Don't Use Pascal'', by Ed Post, was published in Datamation Magazine in 1983. It is an article written as a humorous piece in response to the recent development of the computer programming language Pascal, and the concept of ``structured programming'' that went with the Pascal language. At the time of the introduction of Pascal, most scientific programmers used FORTRAN as a programming language.

FORTRAN, which stands for FORmula TRANslation, is a language that had its beginnings in the late 1950's as a mechanism for describing scientific expressions at a higher level than the direct machine instructions of computers. It was, and still is, designed to get the maximum computation speed from a given program. This makes it somewhat ``unfriendly'' in being able to program more symbolic or structured applications.

With a language like Pascal, the intent was to define a richer set of programming structures that could deal easily with non-numeric data such as text, strings, symbols, etc. Also, Pascal has a different view of how the control flow of the program should be described. Rather than being able to jump from any point in the program to any other point (instructions that perform this type of control change are called ``goto'' statements because they go to another part of the program), Pascal requires that the control be structured into a fairly strict hierarchal organization.

The main point of the Datamation article was to poke fun of Pascal as an academic language where ``real programmers'' would use a more fundamental language like FORTRAN which is harder to use, faster, and therefore more macho.

A not-completely-appropriate analogy might be to liken FORTRAN to a race car where the intent is speed, but the car is uncomfortable and difficult to drive, and trying to make it suitable for daily driving off the racetrack would require a lot of work, and Pascal to a standard sedan of some sort where the ride is more comfortable for daily driving, but the performance on the race track would suffer, and the features of the car that make it comfortable are what get in the way of getting all the performance that might be possible from the raw engine parts.

Electronic hand calculators first appeared in 1971, with the influential HP-35 pocket calculator arriving soon afterwards in 1972. This signalled the end of the slide-rule era in engineering.

The term ``user-friendly'' is used in quotations here in, I believe, a couple of different meanings. One is that software that is called ``user-friendly'' very often isn't. Oftentimes the extra window dressing put onto a piece of software to make it user-friendly serves mostly to make it harder to use. The other meaning is a reference to the ``real programmer'' ethic. One on-line collection of real-programmer-isms says something to the effect of ``Software is hard to write, it should be hard to use.'' To programmers of this ethic, adding extra code simply to make the program easier to use is wasted effort. People who value the contribution of the code should have to spend the effort to learn how to use it.

``Drums'' refers to drum memories which are magnetic data storage devices much like the familiar hard disks of today but shaped like cylinders instead of platters. In the 50's and 60's the state of the art in magnetic encoding of data didn't allow for very dense storage on the magnetic surface of the medium. So, in order to increase the surface area of the storage medium, to increase the speed at which the magnetic material passed by the read head of the device, and to keep the speed at which the heads encountered the magnetic medium constant, these devices were shaped like cylinders with the magnetic coating on the outside surface of the cylinder and the cylinder rotating along its long axis at very high speeds. Consider the early phonographs which were wax cylinders versus the now-becoming-obsolete vinyl record. The considerations are analogous to the drum versus disk question.

Vacuum tubes are electronic devices used to amplify electronic signals and to act as electronically controlled switches. Digital computers are constructed at their most basic fundamental building blocks as electronically controlled switches. The very first electronic computers used relays for these switches (in the 1940's). Vacuum tubes were used for the switches from the late 40's to the late 50's. The first commercial computer to use transistors for the switching elements was the IBM 1401 in 1959 starting the end of the tube era. Individual transistors gave way to integrated circuits in which hundreds, and eventually millions, of transistors were fabricated on a single silicon substrate, or chip. Integrated circuits have been used from the mid-60's to the present.

Machine code refers to the lowest level of program instructions. Machine codes are the instructions actually interpreted by the hardware of the computer. Every computer has a machine-code instruction set of operations that the machine knows how to do. These instructions are almost always simple add and subtract operations on internal computer registers, simple load and store operations on the computers memory (used to bring data from the memory into the internal registers), and a few basic control-flow operations that test values in the internal registers of the computer and decide whether to alter where the next machine instruction is fetched from in memory or not based on that test.

Machine code instructions are usually represented as strings of 1's and 0's that are interpreted by the binary logic of the computer. For example, an machine code instruction used to add the contents of two registers and put the result in a third might look like:

1010 0011 0100 0001

Where the 1010 part would be the indicator that this operation is to add two numbers, the 0011 is 3 in binary indicating that the first argument should come from register 3, the 0100 is 4 in binary signifying that the second argument should some from register 4, and the 0001 is 1 in binary which indicates that the result of the addition should be stored into register 1. This is an extremely simple, made up example. A real machine code instruction might have many more bits, and be quite a bit more difficult to explain.

The purpose of so-called high-level languages is to be able to express an addition in a more convenient text form and have the compiler translate that form into the machine code for you. As you can imagine, programming directly in machine code would require a special type of talent.

FORTRAN, as discussed in a previous note, is an early computer language used for scientific programming. Although FORTRAN was one of the earliest, if not the earliest, attempt at a high-level language, it is still used today (albeit in a many-times-updated form) for scientific applications.

Rational FORTRAN (RATFOR) is a dialect of FORTRAN that provides a richer set of control-flow possibilities. RATFOR is not a new language, rather it is a translator that translates Rational FORTRAN into FORTRAN. It allows the programmer to use features not found in the normal FORTAN language, and then translates those features into standard FORTAN automatically.

Assembly Language is a term used to describe the machine code of a particular computer, but as text rather than just bits. For example, consider the machine code for addition in the previous note. An assembly language version of that instruction might be:

ADD R3 R4 R1

Note that this is essentially the same machine language instruction, but text has been used instead of the actual bits that the machine sees. Programs written in the assembly language of a particular machine are translated into machine code by a program called an assembler.

Hexadecimal means base 16. Binary is a base 2 number scheme because there are only two symbols used: 1 and 0. Decimal numbers are a base 10 scheme because there are 10 symbols used: 0 1 2 3 4 5 6 7 8 9. After 9 numbers are represented using positional notation where the higher order symbols represent multiplying by the base. 15 for example is 1*10 + 5*1.

Hexadecimal is base 16 which means that numbers are represented using 16 different symbols: 0 1 2 3 4 5 6 7 8 9 a b c d e f. After counting to f, the same positional notation is used. 15 in hexadecimal notation (or hex for short) is 1*16 + 5*1 or 21 in base 10.

Hex is used in computer notation as a convenient way of expressing bit values. If you group a binary number into groups of four bits there are exactly 16 possible values for each of those groups. You can easily express each group of four bits as a single hex digit. For example, the previous machine code example was, in binary:

1010 0011 0100 0001

In hex, this same number would be expressed as:


where each hex digit corresponds to a group of four bits in the binary word. Hexadecimal is widely used as a compact way of describing bit encodings of things like machine codes.

The process of writing a program directly in machine code would be to write hex digits that correspond directly to each desired machine code bit-string for each instruction you want the machine to operate. Since it takes many many machine code instructions to execute even the simplest program, this would be tedious to say the least.

Even now tools that extract the raw unformatted data from a memory or from a disk are likely to return a file full of ``raw, unadorned, inscrutable hexadecimal numbers.'' However, the number of programmers who can write programs by writing those numbers directly are few.

To a programmer, the word ``code'' refers to the text of the program you are writing. It can be used as a noun. The ``source code'' is the program text in the language that the programmer is using (i.e. FORTRAN). The ``object code'' is the machine code produced usually by the operation of the compiler on the source code. Generically the code is the program in some form. It can also be used as a verb. ``To code'' is to write a program. If a programmer tells you he is ``coding up an application'' he is writing a program to perform a specific task.

The Royal McBee Company is a real company. I have found out little about the company except that the machines named in this story are real machines that were built in the late 1950's and early 1960's.

The LGP-30 computer was first sold in 1959. There were a number of these machines in use in various military installations from 1959 on. The Army Ballistic Missile Agency (now called NASA) for example had 10 LGP-30's in 1961.

The LGP-30 contained 113 vacuum tubes and cost $50,000 in 1959.

Recall the definition of a magnetic drum memory: a rotating cylinder with a magnetic coating on the outside and read and write heads that move across the rotating outer surface. A drum-memory computer is one where the main memory of the machine is a drum of this sort. There was no RAM like you would find in your PC at home, all the programs and data were stored on the drum. Imagine running all your programs from a floppy disk with no RAM on the machine at all and the floppy providing your system memory and your file storage. The result would be a much slower computer than you might be used to.

The following table shows the addition and multiply times for the LGP-30 and RPC-4000 computers. These are taken from records of the computers used by defense contractors in the 1960's. Note that the RPC-4000 computer makes a significant improvement in add times, but has the same multiply and divide time as the older LGP-30. In contrast, your PC at home is likely to have identical add and multiply times of about 10 nanoseconds, or .01 microseconds.

  8,000         17,000           17,000          LGP 30
  500           17,000           17,000          RPC 4000

Core memory is a type of random-access memory that stores bits by changing the magnetic field of a small magnetic doughnut. These torus-shaped magnets (or cores) can be magnetized or De-magnetized by passing a current through a wire that is strung through the center of the core. By passing a current through a different wire, also strung through the core, you can sense whether the core is magnetized or not. Core memory was faster, denser, and more robust than magnetic drums, although initially more expensive. Magnetic core memories were used in computers from the early 1960's through the 1970's.

Core memory ended up being so much faster than magnetic drums and disks that it quickly became the main-memory of choice for computers from the early 60's on. Initially expensive, core rapidly became more cost effective than drums. Companies that didn't make the switch soon enough were not likely to survive. By the same token, semiconductor memory in the late 70's offered the same dilemma. It was faster, smaller, and denser, but originally much more expensive. Some companies didn't believe that semiconductor RAM would catch on. You haven't heard of these companies either.

A compiler is a program that takes the original program text (source code) and translates it to machine code so that the computer can understand it. Initially compilers simply translated the program statements into the direct machine-code versions. As compiler technology advanced, however, the source programs could get further and further away from the machine code (become more ``high level'' languages) and the job of the compiler to translate these more abstract expressions into the simple machine code that the machine can actually execute became more and more complicated. Modern compilers are very complex programs indeed.

One of the great leaps of understanding in the early days of computing is attributed to John Von Neumann who, along with others, realized that a computer could use the memory that was then thought to be useful only for storing the data, to also store the program that it would execute. Before the advent of the ``stored program'' computer, the program would be communicated to the machine by setting huge numbers of switches on vast panels that controlled the operation of the machine. Once the switches were set, the machine would execute the indicated operations on the data that was stored in the machine's memory. Needless to say, switching which program was being run was a serious undertaking.

The advantage of the stored program approach is that the program, or set of instructions, for the computer is stored in the memory along with the data. That way the same mechanism that allows the computer to retrieve data from the memory can be used to retrieve the next instruction to execute.

Once you have the program stored in the machine's memory, that program can be thought of as stored instructions, or just as a different type of data. That is, you can have the program that is running modify the program data in a way that modifies how subsequent instructions are executed. This is known as ``self-modifying code'' because the program modifies itself by writing data in the section of memory that holds the program. Because of the small memories that early machines had, this was a common programming practice. It has since fallen out of favor because it makes programs very difficult to understand and debug. It's difficult to tell if a program is doing the right thing if the program itself might change after writing different instructions into the program data. Compilers, in general, forbid self-modifying code by specifically not generating such code in the machine code produced by the compiler. If you want to write this type of code, you have to do it by hand. Caveat Programmer.

Computer shows were (and still are) large conventions where manufacturers of computer hardware and software show off their latest and greatest products to potential customers. In the early days the highlights of these shows were as likely to be new hardware designed by a couple scruffy teen age hackers as from a big company like IBM, or like Royal McBee. The original Apple II computer that essentially started the home computer revolution was introduced at the West Coast Computer Faire in 1977.

Typical computer shows are organized in large convention centers where each company rents some space and puts up a booth. The size and placement of the booth are usually good indicators of the size and placement of the company in the computer world. However, the star of any particular computer show is likely to be a small booth tucked into a corner somewhere with a ground-breaking, but undiscovered product.

What does ``to port'' mean when talking about computer programs? To port a program is to translate it to another language, another system, or in some way modify the program to run under another set of circumstances. If you have a program that runs on a Macintosh, for example, it would have to ported to run on an IBM PC. Porting is assumed to involve modifying only small parts of the program, as little as necessary to get the program to run on the new system.

Computer programs are often designed to be portable by isolating the machine-specific part of the code to one well-defined part of the program. The theory is that to port the program to a new system, only that machine-specific part will need to be modified. In practice, this theory is often wrong and there are many subtle changes that need to be made in other parts of the program.

An addressing scheme to a computer is the mechanism by which the computer figures out the location in memory (the address) of the next instruction to be executed in the program. The address of the next instruction is usually either the next sequential location in memory or an instruction somewhere else in memory where the address of the ``somewhere else'' is encoded in the current instruction. In order to decode the ``somewhere else'' address from the machine code you would need to know the addressing scheme of the machine.

I don't have any examples actual LGP-30 code, but based on this description, an ADD instruction might look something like:

ADD 100 104

where the 100 is the memory location of the argument to the addition (``add the contents of memory location 100 to the current sum held in the internal register of the computer''), and the 104 is the address of the next instruction to execute (``When you are finished with the addition, find the instruction at memory location 104 and execute that instruction next'').

A ``goto'' instruction is one that changes where the program will find its next instruction. Most programming languages (unlike the LGP-30 machine language) execute instructions in the same sequence in which they are written in the program. That is, when the machine finishes one instruction, it fetches the next sequential instruction in the machine's memory and executes that one. The goto is an instruction that forces the execution to jump, or ``go to'' an instruction somewhere else in the memory that is not in sequence.

Influential computer science pioneer (and legendary figure himself), Edsgar Dijkstra considered the goto statement to be a bad idea because they make understanding the orderly flow of control in the program more difficult. (clearly Dijkstra is not a hacker) This was published in a famous (to computer scientists) letter: ``GOTO Statement Considered Harmful,'' Letter of the Editor, Communications of the ACM, March 1968, pp. 147-148.

The Pascal language, developed by Nicklaus Wirth in the mid 1970's, had as its goal to support exactly the type of ``structured programming'' that Dijkstra was advocating. Not only does Pascal not have a ``goto'' statement, but it forces the programmer to carefully structure the control flow of the program so that it can be more easily understood and reasoned about.

The first major reference to Pascal by its creator is: Wirth, N., Algorithms + Data Structures = Programs, Prentice Hall, 1976.

As discussed later in the story, while ``optimum'' is an absolute descriptor meaning the best that can possibly be, the verb ``to optimize'' to a programmer has come to mean ``to improve.'' The process of optimizing code is to take a computer program and improve it by making it faster, or smaller, or both.

A drum, like a hard disk, is a magnetic storage medium. That is, the bits that are stored on the drum are encoded as magnetized spots on a magnetic coating on the surface of the drum. In order to retrieve the information stored in this way, the drum needs to be able to read the data. The ``read head'' is the piece of the drum that senses the magnetic spots and reports the values to the computer. It ``reads'' the values on the disk in much the same way that a tape recorder reads the magnetic information on a cassette tape and reports them to an audio amplifier.

Drums, like disks, are rotating storage devices. That is, the drum rotates at high speed below the read and write heads. The read head is restricted to reading only spot that is currently directly under the read head. So, in order to read a specific spot on the drum, the read head must wait patiently for the desired spot to rotate around and come under the head. Although the drums might have spun quite quickly, electricity moves much faster. Put another way, even though the time it takes for the disk to rotate one complete revolution seems very short, it is long compared to the speed of the computer processor. In a computer where the drum is the main memory, a poorly optimized program would spend most of its time waiting for the disk to rotate to the right spot.

An assembler is a program that takes symbolic assembly language (like ADD 100 104), and converts it to the machine code equivalent that the computer can actually read (like 0011 111110100 1111101100). An optimizing assembler is an assembler that also tries to improve the program by analyzing the structure of the program ad using the analysis to remove unneeded instructions, replace wasteful sequences with more efficient ones, and in the case of a drum computer, locate the instructions on the drum in an efficient way by modifying the location of the instructions in the program.

One of the things an assembler does is take the symbolic assembly code and locate it somewhere specific in memory. Depending on where the assembler decides to place the code, all the addresses in the assembly program will have to be modified to take account the exact location. By ``...where it's going to put things'' the story refers to where the instructions will actually be located in terms of the locations on the drum.

``Constants'' in a computer program are simply numbers that will come in handy to the rest of the program. These numbers are typically stored in known locations so the programmer can use them as the need requires. For example, if incrementing a value is a common operation, it might make sense to store a 1 at a known location so that you could always increment a value by adding the contents of that special location.

In a machine instruction (or more exactly, an assembly instruction) like ADD 100 104, the ``ADD'' is also called the ``operation code'' because it defines the operation that the instruction will perform.

Operation codes, like the ``ADD'' in the instruction ADD 100 104 are, themselves, coded as a series of 1's and 0's so that the computer can read them. Because these are just strings of numbers, they could also, if you wanted to, be considered a number. For example, if the operation code for ADD was 0011, this could also be read as the binary number 3.

In the previous example, the operation code for ADD is 0011, which is also the number 3 in binary. So, if you wanted to multiply some value in the program by 3, you could conceivably multiply by the operation code for ADD since that operation code is, coincidentally, also 3.

You can imagine how difficult this would be to understand if you weren't looking for it...

Hand-optimized means that the improvements to the code were done by the programmer and not by any automatic means like using an optimizing assembler.

The verb ``to massage'' in reference to a computer program means to modify the code in some way. The connotation is that the structure of the program is changed by pushing, pulling, and molding the program code.

``Top down'' design refers to a system design philosophy that starts by looking a the overall picture (the top of the design) and working your way down to the specifics. This is a ``divide and conquer'' method of designing large systems where large pieces of the design are split into smaller and smaller pieces until each of the individual pieces are small and simple enough to build. For software, this method of design would involve starting with the big picture of the whole program and then refining that idea into smaller and smaller units before even starting to write the code.

In contrast to the ``top-down'' approach, there is the ``bottom-up'' approach. In this method of designing large systems, you start with the smallest pieces: the ones that you already know how to do well. These pieces are then assembled into larger and larger units until you have the entire design.

In this case the smallest units are ``the innermost loops'' of the program. Loops are a generic name for a programming language construct that repeats sections of the code some number of times. Suppose you were writing a program to add a monthly bonus onto each employee's paycheck. You would write a program loop that would repeat the ``add bonus'' process on each employee's record. Now suppose that in each employee's record your program would have to loop again, perhaps to repeat the bonus process for each month of the year (this is a very generous company). The ``repeat for each month of the year'' loop would be an ``inner loop'' because it is a looping structure inside a larger looping structure. If this hypothetical inner loop repeated its function 12 times (one for each month), and there are 100 employees in your company, this simple inner loop would execute 1200 times during one run of the program.

It is this property of inner loops, that they account for a large fraction of the total run time of a program, that makes them the first target for program optimization. A general rule of thumb in computer programming is that 90% of the execution time for a generic program is accounted for by only 10% of the written instructions. This is because a small number of inner loops execute over and over again. The other 90% of the code typically runs only a few times during the programs execution and so does not account for much of the total run time.

Remember the rotational latency problem on the drum memory. By placing the next instruction at a place on the drum such that when it was time to execute that instruction the read head was exactly in the right spot, the program would run much much faster.

This anthropomorphism of the assembler program (``The optimizing assembler wasn't smart enough'') is very common in the programming world. It is very common to talk about a computer program in terms that make it sound like it is thinking, making mistakes, or otherwise behaving like a human.

One property of even the early computers like the LGP-30 and RPC-4000 machines is that they are much faster at computing answers than the output devices (like printers) are at printing them. Modern solutions to this problem are to send the information to be printed all in one very quick burst to the printer where the information is stored while the slow output device manages to deal with it. In the early days, however, it was common to write computer programs so that they program slowed itself down enough to send a character at a time to a slow printer. The mechanism to slow down the program is called writing a ``delay loop.'' A delay loop is simply a looping structure in the program that doesn't do any computation, but instead has as its sole purpose to waste time. After looping around doing nothing for a while, enough time will be wasted so that another character can be sent to the slow output device.

A Flexowriter was a very popular early computer printer and input device made by Friden. It was essentially a computer controlled typewriter that could also produce and read paper tape. Paper tape is an input/output medium that looks like a long thin (about an inch) roll pf paper with holes punched it it. A programmer might use the Flexowriter to typein a program and have that program put on a paper tape. The paper tape could then be fed into the computer to enter the program into the computer. Alternatively, the computer could produce the results of its computation to the Flexowriter and have those results stored on a roll of paper tape.

The interface to the Flexowriter was for the computer to send individual characters to the Flexowriter one after the other. The problem was that because the Flexowriter had to move physical objects in order to punch holes in the paper tape, it was very slow compared to the computer. If the computer send characters to the printer too quickly, they were lost (or ``dropped on the floor'' as a programmer would say). Output procedures in programs would often use delay loops to slow things down enough for devices like the Flexowriter.

Remember the rotational problem with the drum memory. If locating an instruction so that it is under the read head just when you want it makes the program run faster, then locating the next instruction so that it was just past the read head when you went looking for it means that it would take another entire rotation of the drum before the correct location appeared at the read head. This rotation is a long as far as the computer is concerned.

Recall the definition of ``inner loops'' of a program, and the maxim that 90% of the run time of a program is account for by 10% of the instructions. It doesn't really make sense to worry about optimizing the other code since even if it were optimized to nothing at all, the most difference it would possibly make is a 10% difference in run time. Unless you're a Real Programmer, that is. Then you feel that all code deserves to be given attention and so even the initializer should be given the benefit of optimization.

A Change Request, sometimes called an ECO for Engineering Change Order, is a mechanism used by engineering companies to specify and track modifications to the systems they produce. These Change Requests follow a chain of command, and allow large engineering groups to collaborate without losing track of is going on. To an engineer, a change request from the sales department is not likely to be a meaningful engineering issue.

``Elegant'' is a widely used term of praise and respect by programmers. If a solution to a problem is simple, efficient, or otherwise aesthetically pleasing to a programmer, it would be given the tile of elegant.

Generating random numbers is a generic problem that s used in all sorts of applications. Games, in particular, require random numbers so that when they set up the initial conditions they are not the same each time you play the game. A computer program to play cards, for example, would us a random number generator to simulate shuffling the deck prior to dealing the cards.

In practice, generating truly random numbers is very difficult. Mathematicians could tell you a lot about what it means for a set of numbers to be truly random and why computer generated ``random'' numbers have all sorts of non-obvious regularity, but for purposes of shuffling a deck of cards, program generated random numbers are completely adequate.

Older computers typically had a console on the body of the machine where internal status information of the machine was displayed. There might also be a number of switches on the console that could be used to modify the state of the machine. In addition to the switches dedicated to particular actions, there would also be some switches that the program running on the machine to read to determine the value during program execution. These switches, called sense switches, could be used for input to the program. A program could, for example, get to a point in a program, and sense the value of a switch on the console to determine what to do next.

The Hacker Ethic is a code of conduct defined by hackers in their pursuit of computer knowledge. Simply put, it is that information should be free and available to all who so that they can use to to further their own exploration of the system. A hacker's program is an expression of his/her mastery of the system and as such, should be as elegant as possible (Even where in order to be elegant the programmer makes use of tricks so obscure that non-hackers can't understand what's going on. The beauty is still there for the real hacker). The idea of purposely making a program deceitful would definitely be considered by some as a violation of the hacker ethic.

It is well established in hacker lore that company higher-ups such as the Head Salesman and the Big Boss would know nothing about engineering, programming, and definitely nothing about the hacker ethic. The Dilbert cartoon series by Scott Adams has exploited this knowledge in an way that is both extremely humorous and possibly extremely close to the mark for most engineers. Scott Adams says that he gets many of his ideas for new comic strips from people working for big companies who send him ideas based on their actual workday experiences.

The Fellow Programmers referred to in this passage are clearly not Real Programmers!

``The test'' referred to is the process of testing the value of the sense switch to see if it is in the on or off position.

Although there are many stories about legendary programmers that circulate amongst programmers, it is thought by some that although they are admired and idolized, it's probably a good thing that there aren't too many of them around. The tricks that make a programmers code legendary typically make the code itself very hard to understand by anyone else.

Programming is often described in terms that relate to magic. Computers themselves are often considered as magical devices. People not used to how computers operate often describe the result of a program as magical somehow. Programmers also use these terms for their best programming tricks. If you were to look at the comments (non-program-text annotations) in the source of a hackers program listing you might see a comment about how the next routine involves magic, or if it is especially obscure, deep-magic.

In addition, programmers have since the early days used magical terms to describe themselves and their responsibilities. Terms like ``wizard'' and ``guru'' are commonly applied to programmers of special ability. To say someone is a ``UNIX wizard'' is to say they have deep knowledge of the UNIX system (a computer operating system liked by hackers) that allows them to make the computer do magical things.

Loops in a program are used to repeat a portion of the code a number of times. Each time the program executes the code in the loop a decision must be made of whether to loop again or whether this was the last iteration and the program can continue onto different activities. This is the test that is referred to in this part of the story. If a loop had not test it would have to loop forever. The test is what indicates that it is time to stop looping.

A program loop that has no test is known as an ``endless loop'' or ``infinite loop'' to a programmer.

That is, the program managed to check the loop's exit condition, find it changed, and exit the loop, even though no exit test was ever performed according to the code.

An index register is a feature of a computer processor that relates to the machine's addressing scheme (see note [24]). Using an index register in an addressing scheme involves adding the value in the index register to the value in the instruction for all memory references. If the index register is incremented automatically by the computer, the programmer could walk through sequential memory locations by simply setting the index register to the first location and then, with no further manipulation of the address by the program, look at sequential memory locations on each memory reference. This turns out to be very a very helpful addition to a basic addressing scheme.

The singular of data is datum.

It is a common technique to store data in the computer's memory so that data that are related to each other are also closely spaced in memory. A list of names, for example, might be placed in consecutive memory locations. Walking through the list of names would involve operating on each datum in the list by looking at consecutive memory locations.

A machine register is a temporary storage location that is inside the computer processor itself. All the data that a program uses is held in the main memory of the computer (in the LGP-30 and RPC-400 case, this would be the drum, in the case of your PC this would be the RAM). In order to operate on this data the computer brings it into a machines register in its CPU (central processing unit). The program typically operates on the data in the machines registers until the operation is complete, and then writes the updated values back to the main memory.

That is, write the updated value back to the drum to the location from which it came originally.

That is, instead of getting the instruction from the drum which would be the normal case.

That is, he's walking through a list by executing a single instruction, but each time through the loop, the instruction itself is modified to point to a different location. There is no test that says when to finish this loop.

Single bits are often used as flags to indicate which features are enabled or being used in a particular program. Computers generally have a number of these bits, sometimes called a Processor Status Register that is kept internally in the computer and accessible only to the operating system.

Although I don't have the exact instruction format for the either the LGP-30 or RPC-4000, this indicates that the bit that controls the use of the index register is in between the operation code bits on the left, and the address of the data on the right. The layout is something like:

operation-code index-bit address

Bits have only two states: on and off. Also called 1 and 0.

Having the index register contain the value 0 means to add 0 to every address before it's executed. That is, use the index register, but since it's adding 0, it never has any effect on the actual address.

Memory in a computer is addressed by number. Each number corresponds to a different location in memory. These addresses typically start at 0 and go to whatever the highest number is for a memory of that size. For example, if a memory had 1024 locations, they would be numbered 0 to 1023. The lower numbered locations are considered the bottom of memory, and the highest numbered locations are considered the top of the memory.

Arithmetic overflow is caused when the result of an operation is larger than the maximum size allowed for the result. Consider if you wanted to use only numbers that could be expressed in two decimal digits. You would be restricting yourself to numbers between 0 and 99 because 100 must use three digits. Now, if you performed addition on two legal numbers, say 55 and 62, you would get overflow because the answer, 117, is too large to fit in the two-digit limit. Because computers have fixed-bit-width arithmetic units, overflow is an issue that must be considered carefully.

Another way of looking at overflow is to consider the extra digit of an overflowed number as a carry to the next operation. Suppose you are adding 55 and 68. First computer 5+8=13. The 3 is given as the first digit, and the 1 is carried to the next operation. Now add 5+6+1 to get the next digit and you get 12. Again, the 2 is the digit and the 1 is carried to the next operation. If the operation is fixed at two digits long, the 1 is a carry-out from the operation which overflowed its size limit.

In this case, the carry out of the addition was allowed to be added into the next part of the instruction word. Looking at Note 68 you can see that if this were to be allowed to happen, you would add the carry value to the operation-code. Because the operation code is just another stream of bits, this would be the same as adding one to the operation code, and thus changing which operation code was being indicated.

A jump instruction is one that transfers program control to a different part of memory. When a program jumps it starts fetching instructions from a different location than it would if the instruction had not been a jump.

Consider that an arithmetic overflow in the right part of the instruction word has caused the carry bit that changed the ADD instruction into a jump. Because we were also told that the program was adding one to the contents of the ADD instruction to walk through data in a sequential series, it must be the case that adding 1 caused the overflow. If adding one caused the overflow, then the remaining bits in the right part of the word must be 0 because in binary numbers the number one larger than 111 is 1000 for whatever size numbers you are using. So, the resulting instruction after overflow must have been a jump instruction with an address of 0, telling the program to start executing its next instruction from location 0.

next up previous
Next: About this document Up: The Story of Mel Previous: The Story of

Erik Brunvand
Tue Oct 15 13:41:12 MDT 1996