16

Most programming languages delimit block structure with punctuation e.g. { ... } or keywords e.g. begin ... end. However, some languages such as Python and Haskell delimit it with indentation (sometimes called the 'offside rule') on the theory that this is how the human visual cortex recognizes block structure, so if the compiler does likewise, then we prevent a class of errors where we think the code says one thing and the compiler thinks it says another.

I found myself thinking 'of course that works great when you're editing code on screen, but it wouldn't have worked so well before that' and then 'wait, why not?'

Why not, indeed? Thinking about it more carefully for a few minutes, I cannot put my finger on any solid reason why something like an ASR-33 teletype, or a deck of punch cards, would have difficulty with indenting lines to delimit block structure, and the advantage of not spending an extra line on the closing delimiter would be worth more.

So:

Historically, was any indentation-based language ever used with pre-screen code entry technology like teletype or punch cards?

14
  • 3
    From my COBOL days (22 yrs ago) I remember that there was some indentation finickyness, a statement started on column 7 I think, and when it started further it was presumed a continuation line of the previous one. But nothing really syntactic.
    – chthon
    Nov 25, 2022 at 11:41
  • 3
    Also, blocks were already formalized by 1958. COBOL was written with explicit statement terminators, the dot (.), and FORTRAN was written in a way that made sure, however you wrote something, that it always could be analysed lexically and syntactically. That only leaves assemblers as indentation sensitive languages.
    – chthon
    Nov 25, 2022 at 11:52
  • 6
    Anyway, in my experience, the answer is no, beyond the obvious, which is that FORTRAN had definite columns for continuation, line number, an code; possibly COBOL did too don't remember. But setting up a card punch to tab to FORTRAN's two fixed columns wasn't hard, or easy to use worng.
    – davidbak
    Nov 25, 2022 at 13:17
  • 4
    @another-dave: I believe occam (1983) would be the first language which was implemented, slightly predating Miranda (1985) which in turn inspired Haskell (1990) and also predating ABC (1987), the predecessor to Python (1991). All of these would be after the age of punchcards. Nov 25, 2022 at 21:49
  • 7
    It's worth noting that when programs are held on punched cards, you edit the code by adding, removing, or replacing individual cards. Changing the indentation level of a block of code just to make it conditional would be very inconvenient. Nov 27, 2022 at 13:47

7 Answers 7

26

I agree to an extent that COBOL was "indentation-sensitive", but it really wasn't "indentation-sensitive" but rather "column-sensitive". The original COBOL coding format had specific requirements of where source code elements had to begin or the compiler would spit it back out as an error.

  • Column 1-6 was a sequence number
  • Column 7 was an indicator
  • Column 8-11 was "Area A" and certain elements had to start there
  • Column 12-72 was "Area B" and certain elements had to start and be contained there
  • Column 73 - 80 was a system generated number when printing - this area was ignored by the compiler

In modern COBOL (to the extent there is such a thing) there are other formats allowed that eliminate these requirements.

When programs were entered on punched cards (before my time) coding was done by paper and pencil first on coding forms that adhered to this layout - once it was laid out, you could get someone else to keypunch your program.

enter image description here

Column 1-6 was a sequence number - I think the original theory was that if you for example, dropped your card deck, it could use this to sort the cards (and your program) back into the correct order. In practice, this got used for a variety of purposes because the sequence number was not enforced. For example, we would use it to tag lines with a ticket number or version number for bug fixes.

Column 7 was used for indicators:

  • * meant it was a comment
  • - meant it was a continuation of the previous line
  • / meant that when printing your code listing, it would page break
  • D meant that the line would only compile if WITH DEBUGGING MODE is used

Column 8-11 was Area A and division, section, and paragraph names had to start there, as did things like FD (file declarations) and level numbers. If you tried to put a level number or paragraph name in column 12, it would cause a compiler error (or be recognized as something else). You could indent within the Area, but those elements had to start within there.

Column 12-72 was Area B and all code went here. If your code extended past column 72, that part would be ignored and likely cause a compiler error - or it could be the source of a bug if the line was syntactically correct without the part that was in column 73. (I've experienced this over the years.)

There was no indentation requirements within that area - your entire program could be entered there with no indents at all within the code.

So within Area B, it doesn't matter if I use:

PERFORM 0200-MOVE-DATA
       VARYING SUB-VAR FROM 1 BY 1
       UNTIL SUB-VAR > 20

or

PERFORM 0200-MOVE-DATA
VARYING SUB-VAR FROM 1 BY 1
UNTIL SUB-VAR > 20
2
  • 9
    +1, but this technically isn't an answer to 'was any indentation-sensitive language...', since it's arguing (convincingly) that COBOL is not an indentation-sensitive language.
    – dave
    Nov 25, 2022 at 14:53
  • As columns 73-80 were ignored, they could be used to put punched card sequence numbers there - typically spaced by 10 or by 100 to simplify insertions, similar to BASIC - so that if a deck is dropped accidentally (or in frustration), it could be sorted mechanically.
    – Leo B.
    Dec 1, 2022 at 2:39
20

COBOL and FORTRAN are both (or were) highly indentation-sensitive, precisely because they were created at a time when punch-cards were the most common data-entry medium. Modern editors and compilers are less restrictive.

COBOL standards

FORTRAN standards

8
  • 2
    Indentation matters only when you have multi-statement constructs (compound statements, blocks), and FORTRAN had no such thing in the timeframe under consideration. Maybe you'd want to indent DO-loop bodies for readability, but the end of a loop was indicated by a statement number given after DO, and indentation conveyed no syntactic meaning. Indeed, outside of Hollerith constants, spaces were entirely ignored in columns 7 to 72.
    – dave
    Nov 25, 2022 at 14:42
  • 2
    It may be relevant to separate intent from fixed column.
    – Raffzahn
    Nov 25, 2022 at 15:40
  • 2
    Maybe it's just me, but I would not use the word "indentation" to describe a requirement that certain things appear in certain columns of a punched card. I used both card-based systems and on-line/teleprinter-based systems back in the 1970s, and my recollection is each had its own nomenclature with not much overlap between them. Nov 26, 2022 at 23:21
  • 2
    Me neither. The acid test for me is, within the range of columns allowed for a statement, does the number of leading spaces change the semantics of the statement? For FORTRAN and COBOL (of that time), the answer is "no".
    – dave
    Nov 27, 2022 at 2:01
  • 1
    @psmears qq{Isn't "requiring a statement to begin in column N" more or less the same thing as saying that indentation is significant?} Well... no, IMHO. Not any more than respecting the left margin of the page when writing a text document is "indentation". Columns 1-6 and 73+ are effectively the card's margins.
    – FeRD
    Nov 28, 2022 at 19:37
12

Historically, was any indentation-based language ever used with pre-screen code entry technology like teletype or punch cards?

Of course, even the very first: Assembler

And it still does:

  • Any element starting in column 1 is a label/symbol definition, while
  • any element starting after at 2 or later must be a instruction/macro/control word

Note that there is a fundamental difference between Assembler being indent based (*1) vs fixed column notation used by data entry (and thus languages) in general. Formats like using column 1..4/6/8, or 73..80 for numbering, or 72 for line continuation (*2) are fixed column formats.


On a sidenote:

The question falls for the usual problem of asking for a certain behaviour before that behaviour was canonised as today. So any answer will include examples which may strictly not apply to the question made in hindsight, as any artefact will be an example of development prior.


*1 - Except some very early ones.

*2 - And were usually used with Assembly as well - as a fixed column layer around the indent based language structure

11
  • 2
    This is not the sense of the offside rule. In that assembler, there is no syntactic difference between starting something in column 2 versus starting in column 3, right? In no sense is a thing starting in column 3 'inside' the entity on the previous line that started in column 2.
    – dave
    Nov 25, 2022 at 14:50
  • @another-dave That would only matter if the question was about multiple levels, wouldn't it? Except, making it so, it would exclude an aweful lot of languages by default. Including in part the mentioned Python.
    – Raffzahn
    Nov 25, 2022 at 15:22
  • 3
    Python's the exemplar of the offside rule: e.g., what is controlled by an if statement must (if on a separate line) be indented. Multiple levels of indent is what resolves the 'dangling else' issue. Contrariwise, in Python you can't indent where it's not syntactically acceptable.
    – dave
    Nov 25, 2022 at 15:29
  • 1
    "Assembler" is not a single programming language, it is a generic name for a very large class of languages, all of which had different conventions for such things. Nov 27, 2022 at 13:45
  • 1
    @MichaelKay Well, I guess thare's an individual component. I've used at least a dozend different assemblers, on more than 20 different CPUs, ranging from micro to mainframe, and they all worked the same. It would be quite interesting to learn what you considere fundamental differences which are not tied to the instruction set. For example some not following the mentioned scheme?
    – Raffzahn
    Nov 28, 2022 at 1:13
7

The earliest programming language that I am aware of that was implemented using the "off-side rule" as referenced in the question (or any similar rule) is SASL (1972). It derives from a description of a 1966 language called ISWIM, which also appears to have been designed with such a rule in mind, but which was never actually implemented -- it was intended more as an example of what future languages might look like that than as a useful language itself. SASL is a direct ancestor of Haskell, one of the more common languages using this system today (SASL was later redesigned by its author to create Miranda, and Haskell originally began as an open source replacement for Miranda). IIRC SASL was also a direct inspiration for Python.

Teletypes were still in common use in 1972, so it seems likely that SASL was used with them. Punched cards seem less likely to have been used with it, however.

1
  • 1
    As an aside, I would welcome comfirmation that the original version of SASL used the off-side rule. I had originally believed all do, and certainly the version described in this document does ... but there's a modern reimplentation here that doesn't, and instead appears to use semicolons to disambiguate where problems would otherwise occur (according to the document in my first link, this was an optional alternative syntax that was rendered unnecessary by adhering to the offside rule).
    – occipita
    Nov 27, 2022 at 20:13
5

Don't forget about RPG (Report Program Generator, not Role Playing Game). The original versions before 2001 required data and instruction to be placed into certain columns for correct operation.

2
  • One can debate whether RPG was even a programming language :-)
    – dave
    Nov 27, 2022 at 2:04
  • Also Rocket Propelled Grenade :-)
    – cup
    Nov 28, 2022 at 7:32
3

Early languages were 'Fixed Format'. The meaning of different columns was fixed and defined. "a C in the first column means a comment". Those rules were later relaxed allowing "Free Format" rules like "all white space before the first text is ignored"

There was no reason why multiple indentation couldn't be assigned a meaning: card punches, like typewriters, were designed to support tabulation, and it was used for Fixed Format data entry: it could just as well have been used for significant white space, like in python.

But early languages didn't even have the concept of sub-scopes. You had global code, then you had a single level of subroutines. That was it. The idea of indented scope comes from the idea of sub-logic, which comes from the idea of structured programming, which replaced goto-loops with structures like While-Wend or Repeat-Until or For(){}.

Early language research projects, and functional languages, could have used indentation to mark scope, but in general, they didn't. They used (),[],{}, and syntax elements like 'begin'/'end'

My hypothesis is that (1) people were not used to using indentation to mark scope in hand-written math and philosophical proofs, and (2) the 80 column limitation was already causing too much problem with line length for early programmers.

1

Makefiles are indentation-sensitive: each rule starts with an unindented dependency line followed by indented lines with the commands (indented with a tab!). I think makefiles are old enough to have been used on teletypes or punch cards, but I'm not 100% sure on that.

We're talking here about a configuration language rather than a programming language, but I think that falls within the scope of the question.

2
  • 3
    Teletypes yes, punched cards unlikely (which is not to say 'never', just that they were not usual 'make' input)
    – dave
    Nov 27, 2022 at 16:15
  • 1
    Many makefiles needed tabs instead of spaces. When read from punched cards, it would not be possible to input a tab: some utility would have to be used to convert spaces to tabs.
    – cup
    Nov 28, 2022 at 7:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .