102

Why did old BASICs (and maybe other languages) use line numbers as part of the source code?

I mean, what problems did it (try to) solve?

11
  • 27
    If you have already done some serious reseach effort, don't bury information about it inside of comments, edit your question accordingly. Moreover, Google took me directly here: stackoverflow.com/questions/541421/… and here stackoverflow.com/questions/2435488/…
    – Doc Brown
    Feb 10, 2016 at 14:47
  • 13
    I'm voting to close this question as off-topic because the answer is already on stackoverflow.
    – Andres F.
    Feb 10, 2016 at 23:30
  • 8
    Applesoft BASIC was the first programming language I learned. I remember hearing that Pascal doesn have line numbers and going like "But how do I do a GOTO without line numbers? How is that supposed to work??" Feb 11, 2016 at 7:08
  • 15
    Funny, last time I checked, we were juding if the question was on topic basing on its content, not content of other sites(and presumably answers that lie there). Feb 11, 2016 at 10:03
  • 2

9 Answers 9

132

BASIC needs to be taken into context with its contemporary languages: early fortran, cobol and assembly.

Back when I was dabbling on 6502 assembly without labels, this meant that when you found that you needed to add an instruction somewhere in the middle of tightly packed code (I later added NOPs) you needed to go through and redo all of the jump addresses. This was time consuming.

Fortran was a line numbered based system that predated BASIC. In Fortran, columns 1-5 were a line number to be used for targets for branching. The key thing with Fortran was that the compilers tended to be a bit more intelligent than the BASIC interpreter and adding a few instructions was just a matter of punching some cards and putting them in the deck at the right place.

BASIC, on the other hand had to keep all of its instructions ordered. There wasn't much of a concept of a 'continuation of the previous line'. Instead, in Applesoft BASIC (one of the widely used dialects that I am familiar with and can find information on) each line in memory was represented as:

NN NN   TT TT   AA BB CC DD .. .. 00

It had two bytes for the address of the next line (NN NN). Two bytes for the line number of this line (TT TT), and then a list of tokens (AA BB CC DD .. ..) followed by the end of line marker (00). (This is from page 84-88 of Inside the Apple //e)

An important point to realize when looking at that memory representation is that the lines can be stored in memory out of order. The structure of memory was that of a linked list with a 'next line' pointer in the structure. This made it easy to add new lines between two lines - but you had to number each line for it to work properly.

Many times when working with BASIC, you were actually working in BASIC itself. In particular, a given string was either a line number and BASIC instructions, or a command to the basic interpreter to RUN or LIST. This made it easy to distinguish the code from the commands - all code starts with numbers.

These two pieces of information identifies why numbers were used - you can get a lot of information in 16 bits. String based labels would take much more space and are harder to order. Numbers are easy to work with, understandable, and easier to represent.

Later BASIC dialects where you weren't in the interpreter all the time were able to do away with the every line numbered and instead only needed to number the lines that were branch targets. In effect, labels.

23
  • 3
    Good gravy, I'd forgotten about the Mini Assembler. That brings back memories.
    – Blrfl
    Feb 10, 2016 at 16:17
  • 3
    @Blrfl If memory serves... ] CALL -936 * F666 G $ ... Yep, FP basic to start with.
    – user40980
    Feb 10, 2016 at 16:47
  • 4
    No, that was the line editor. Commands were identified by not having line numbers. Statements were preceded by line numbers to indicate both that they were statements and to indicate were they went and/or what line they overwrote. That was the built-in line editor part of BASIC, it wasn't a separate tool or environment. Feb 11, 2016 at 15:38
  • 3
    @RBarryYoung ] PRINT "FOO" was run by the BASIC interpreter immediately. It is a statement. If you wanted to run it later, you would do ] 10 PRINT "FOO" and then ] RUN. In the AppleSoft BASIC environment, every BASIC statement could be run immediately or delayed - there were only a very few commands that were provided by DOS that were not valid BASIC statements. The differentiation between a statement now and a statement later was the line number. You could also modify a delayed statement by reentering the corresponding line number. You could also put multiple statements on one line: :
    – user40980
    Feb 11, 2016 at 15:45
  • 4
    As noted in the Wikipedia article (en.wikipedia.org/wiki/Dartmouth_BASIC) "DTSS (Dartmouth Time Sharing System) implemented an early ... interactive command line interface. ... Any line beginning with a line number, was added to the program, replacing any previously stored line with the same number; anything else was assumed to be a DTSS command and immediately executed. ... This method of editing was necessary due to use of teleprinters as the terminal units for the Dartmouth Timesharing system." Feb 11, 2016 at 15:59
52

On early microcomputers editing was line based. You couldn't just move freely around in the source code and edit. You had a single line at the bottom of the screen where you could type commands and enter code. The rest of the screen was read-only code-listings and command output. If you wanted to edit say line 90 in the program you wrote "EDIT 90", and the contents of line 90 entered the single-line edit buffer. When you had edited the line you hit enter, and the program listing was updated. So you needed line numbers in order to be able to edit the program.

When code editors became more advanced and allowed you to move the cursor around in the code listing you didn't need line numbers anymore.

18
  • 40
    Editing a line? Luxury! The first BASICs I used made you re-type the whole line. Which really sucked when you had to renumber a subroutine.
    – TMN
    Feb 10, 2016 at 16:58
  • 49
    Screen? What screen? In my first Basic, the "screen" was a roll of paper.
    – ddyer
    Feb 10, 2016 at 20:05
  • 20
    @ddyer: I used to dream of having a roll of paper! All we had was a bunch of electrodes. In the evening when the work was supposed to be done, we would have to align ourselves in a row and observe who got electrocuted, to see if the program worked correctly. ... — Seriously, I'm awestruck that people actually managed to write working programs back in those days. Feb 11, 2016 at 10:14
  • 27
    Electricity! Bloody luxury. We used to chisel our commands out in granite Feb 11, 2016 at 10:46
  • 11
    @TMN & ddyer OK, you both know where this is heading, right...? ;-D ==> dilbert.com/strip/1992-09-08 ==> imgs.xkcd.com/comics/real_programmers.png Feb 11, 2016 at 13:47
46

If you are thinking of BASIC dialects of the 8-bit home microcomputers of 80's, then those computers did not have text editors (unless you bought some word processor application). There was no way to have the entire BASIC program source code "open in an editor", like you would have when programming today. Programmer wouldn't even think about the program as a source code file, or text, really.

Example problem

So, lets say you have a simple program without line numbers in your head:

FOR I=1 TO 42
PRINT I
NEXT I

You boot up your computer. You have a prompt "ready" or something like that, and cursor sitting in next line. This is much like today's REPL environments of different scripting languages, though not really as strictly line based, more like screen based. So not quite like REPLs of today, but close.

Now if you start entering the program, you might get error after first line, because BASIC interpreter tries to immediately execute (and forget) it, and it doesn't make sense without NEXT to end the loop. This is not text editor where you edit text, this is where you give commands to the computer!

Partial solution

So you need some way to say, this is program line, store it! You could have a special command or just a symbol telling that hey, this is program line, store it. Let's imagine this:

#FOR I=1 TO 42
#PRINT I
#NEXT I

Ok, now our imaginary BASIC interpreter stored the program and you can run it. But now you want to edit the PRINT line. How do you do it? You are not in a text editor, you can't just move cursor to the line and edit it. Or you want to add another line like LET COUNT=COUNT+1 in the loop. How do you indicate where the new line should be inserted?

Working solution

Line numbers solve this in a very easy, if rather klunky way. If you enter a program line with a number that already exists, the old line gets replaced. Now the screen-based REPL environment becomes useful, because you can just move cursor to program listing on screen, edit the line on screen and press ENTER to store it. This seems like you are editing the line, when in fact you are editing text on screen and then replacing the entire line with new one from the screen. Also, inserting new lines becomes easy if you leave unused numbers in between. To demonstrate:

10 FOR I=1 TO 42
20 PRINT I
30 NEXT I

After re-entering line 20 with changes, and adding new lines, it could be

5 LET COUNT=0
10 FOR I=1 TO 42
20 PRINT "Index", I
25 LET COUNT=COUNT+1
30 NEXT I

More problems we just solved

There's the benefit (or the curse, as it enables the famous BASIC spaghetti code) of being able to use line numbers as a language construct, at least as a target of GOTO AND GOSUB commands. This could be replaced by labels, but using line numbers is much simpler to implement in BASIC interpreter, which still was a definite bonus in a typical 8-bit home computer of the '80s.

More importantly, from user experience perspective, line numbers really are a surprisingly easy yet complete interface for editing the code. Just type a line starting with a number to insert new code. Use LIST 100-200 to show lines 100-200. To edit a line, list it on screen, edit text on screen, and re-enter line. To remove a line, edit it to be empty, that is simply give line number with nothing after it. One paragraph to describe this. Compare trying to describe use of old text editors like edlin of DOS, or ed or ex of Unix: you need one paragraph (only slight hyperbole) just to explain how the user can exit them, when started accidentally!

Conclusion

Other answers explain how line numbers came to be. I'm trying to cover here, why the line numbers survived as long as they did, how they kept solving a real-world problem: They offered a way to do the actual programming without a real editor, in a very simple way. Once proper, easy-to-use full-screen text editors became the mainstream way to edit code, both with hardware limitations disappearing and when inertia of people adapting new things was overcome, then line number based BASIC dialects quite quickly disappeared from use, because the core usability problem they solved was no longer an issue.

6
  • 4
    You nailed it. Having a multi-line screen rather than just a printing tty or single line makes it easier, but without a source file concept it's still line oriented.
    – JDługosz
    Feb 11, 2016 at 7:16
  • The fact that the system is an 8-bit architecture isn't really the limiting factor, though. Now, the fact that said system might have only a few kilobytes of RAM and a handful of kilobytes of ROM, and possibly even no permanent storage (if your casette tape recorder broke)...
    – user
    Feb 11, 2016 at 20:37
  • it's still hard to imagine coding without a text editor
    – phuclv
    Feb 12, 2016 at 14:12
  • @LưuVĩnhPhúc Well, there are plenty of emulators for running "the real thing", such as almost any 8-bit home computer, or MSDOS and its GWBASIC with dosbox. Just as an example, you could get one of the many C64 emulators, and then Google to find its User's Guide as PDF :-)
    – hyde
    Feb 12, 2016 at 15:31
  • 3
    @phuclv - Hard to imagine coding without a text editor now. At the time, hard to imagine the inconvenience of having to use a text editor, save it, and compile it before it could be run ... and that's really what came next to the PC world; Pascal and C. Both compiled languages, both freely editable with a text editor, both definitely not a programming environment in and of themselves (BASIC was both programming environment and runtime environment). Pascal was my next language, and in many ways quite liberating. Definitely more powerful. But in other ways, a little less thrilling.
    – DavidO
    Sep 3, 2019 at 2:55
18

In the place and era when Basic was developed, the best available I/O device was a teletype. Editing a program was done by printing (on paper) a listing of the whole program, or the interesting part of it, and then typing replacement lines with line numbers.

That's also why the default line numbering was by 10, so there would unused numbers between existing lines.

2
  • 1
    Actually, card readers (accompanied by keypunches) and line printer were better I/O devices than a teleprinter, but teleprinters were a lot cheaper.
    – supercat
    Feb 13, 2016 at 3:08
  • Line numbering by 10 was a de facto standard, not a rigorous requirement. And many BASICs had a 'ren' command, to renumber. A typical invocation was ren 10, 10 (renumber starting at ten, incrementing by ten -- the default behavior if one just typed ren. The goto and gosub and then (linenumber) commands would be automatically updated. But this was definitely not available in the earliest BASICs. But IIRC, was available in Apple Integer Basic, Applesoft FP basic, TI Basic/Extended Basic, MS Basic / GW Basic, etc.
    – DavidO
    Sep 3, 2019 at 2:59
13

"Line numbers" means a few different things.

First of all, keep in mind that the concept of "lines" hasn't been around forever. Many programming languages in this era used punched cards, and having sequence numbers (usually in the last few columns of the card) helped you recover your deck in the proper order if you dropped it, or something awful happened in the card reader. There were machines to do this automatically.

Line numbers for use as targets of GOTO statements is a totally different concept. In FORTRAN IV, they were optional, and preceded the statement (in columns 1-5). In addition to being easier to implement than free-form labels, there was also the concept of the computed and assigned GOTO, which allowed you to jump to an arbitrary line number. This was something most modern programming languages don't have (although switch statements come close), but was a familiar trick to assembler programmers.

BASIC was derived from FORTRAN, and intended to be simpler to implement and to understand, so forcing every "line" to have a line number (both for sequencing and as the target of GOTO/GOSUB statements) was probably a design decision made for that reason.

4
  • 2
    Ah, computed and assigned gotos. Memories of arrays of label variables in PL/1, looping through one array to find a match and then using that matches array index as the index in the array of label variables to do a goto to. Or Cobol altered gotos. And neither using line numbers! BBC basic had a renumber statement that was very useful.
    – Kickstart
    Feb 11, 2016 at 10:31
  • 1
    GCC allows computed GOTOs as an extension (although not with a line number directly of course) - you can do stuff like goto array_of_labels[some_computation()];
    – user253751
    Feb 11, 2016 at 21:34
  • Minor: FORTRAN required labels for targets of GOTO (or ASSIGN) and the original aka arithmetic aka threeway IF, and (rarely used) alternate returns in CALL, and sort-of-targets (arguably delimiters) of DO, and FORMAT statements. On other statements they were optional. Feb 12, 2016 at 12:28
  • Some BASICs (e.g., Atari's) even allowed arbitrary numeric expressions to be used in GOTO statements. So, with a proper line numbering convention, you could write GOTO 1000+N*100 to emulate a switch statement.
    – dan04
    Feb 26, 2016 at 23:39
6

I started programming in COBOL which used line numbers in columns 1-6 of each line. Because there were no IDE's in the 1970s everything was done via punched cards and the line number was used to identify which lines in the original source were to be replaced and which new lines added. We used to increment line numbers by 100 to give us room to add in more lines.

1
  • 14
    COBOL did not use those line numbers. They were strictly a convenience, so that when some poor schlub dropped his deck, and cards went everywhere, he could just gather them up and run them through the card sorter to get them back into the correct order. You were NOT required to punch the line numbers into the cards. (Students didn't. Production shops did.) Feb 10, 2016 at 15:41
5

BASIC came about later than FORTRAN, in the line-terminal era. It featured a read-exe-print-loop environment that was more interactive than a deck of cards.

I learned to program, in BASIC, on a one line display that held 24 characters. Line numbers were a natural way to specify where you wanted a line to go, whether editing one or inserting between others.

I really can't imagine how else you would do it.

7
  • 2
    this doesn't seem to offer anything substantial over points made and explained in prior 4 answers
    – gnat
    Feb 10, 2016 at 16:33
  • 2
    That makes it bad? I think Jaques didn't really cover the essence of one-line editing with respect to inserting lines and mentally tracking the code.
    – JDługosz
    Feb 10, 2016 at 17:11
  • 1
    @jameslarge Do I miss that point in the paragraph beginning with "Many times when working with BASIC..."? I also hesitate to call BASIC the operating system. That was DOS. And DOS didn't need BASIC, its just what you had most of the time to work in.
    – user40980
    Feb 10, 2016 at 21:42
  • 2
    @Ian while that's true, it was designed for a system that used teletypes for io (the Dartmouth Time Sharing System).
    – Jules
    Feb 10, 2016 at 22:12
  • 3
    @MichaelT, Oops! I'll retract half of my comment, but I'll stand by the part about BASIC being the OS on some computers. I'm thinking; Apple ][, TI 99/4, IBM 5100, HP 9830a, Compucolor 8001, TRS-80 Model 1, Comodore Vic20, Sinclair ZX80, and others. All booted up into BASIC from ROM. Some had an optional operating system that could be loaded from an audio casette or, from floppy disk if you paid the extra $$ for a floppy drive. Feb 11, 2016 at 0:21
1

One point no one's mentioned yet is that it's easier for beginners to reason about program flow where the branch targets are explicit. So rather than having to match (possibly nested) BEGIN/END statements (or whatever block delimiters were used), it was pretty obvious where the control flow went. This was probably useful given BASIC's target audience (it is the Beginner's All-purpose Symbolic Instruction Code, after all).

1

Dartmouth Time Sharing System used a teletype interface. Thus it used a command based interface. Originally, line numbers were just used as a means to edit the program. You could insert, replace, or delete by using a line number. It does not appear that the early version used line numbers for goto statements, but this was a later addition to the language.

Not the answer you're looking for? Browse other questions tagged or ask your own question.