COBOL - Common Business Oriented Language - is one of the oldest programming languages. It was universally considered to be shit for pretty much its entire existence, because it was shit.
It's essentially dead. There are frequent claims in the media of "um, actually Cobol is super popular", but they're all bullshit journalists love to repeat after each other without any evidence - which is pretty much in line with the quality of tech journalism. You can easily see from stack overflow, any jobs website, or such, that the only thing people still Cobol for is keeping zombie system from passing away completely.
Just like Fortran, the language changed many times while keeping the name. I'll try to stick to classic Cobol from the punched card era, with its fixed column layout, even though many of less archaic dialects of Cobol allow a bit more flexibility.
Hello, World!
* HELLO WORLD IN COBOL
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY 'HELLO WORLD'.
STOP RUN.
$ cobc -xg hello.cob
$ ./hello
HELLO WORLD
That's some 2D picture.
Let's take it line by line:
-
IDENTIFICATION DIVISION.
- some metadata about the procedure -
PROGRAM-ID. Hello.
- the name of the procedure -
DATA DIVISION.
- there's also one there usually, defines data -
PROCEDURE DIVISION.
- code of the procedure -
DISPLAY 'HELLO WORLD.
- displays a string and newline -
STOP RUN.
- exits the program
Everything in caps to keep with the spirit of Cobol.
And column by column:
- first 6 columns are for statement numbers
- column 7 is comment indicator - there are a few possible characters for it, we'll be using
*
- names, divisions etc. should start from column 8
- everything else should start from column 12
Loop
Let's create a loop that prints a number from 1 to 20:
IDENTIFICATION DIVISION.
PROGRAM-ID. LOOP.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 N PIC 9(2).
PROCEDURE DIVISION.
PERFORM VARYING N FROM 1 BY 1 UNTIL N > 20
DISPLAY N
END-PERFORM.
STOP RUN.
It works:
$ cobc -xg loop.cob
$ ./loop
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
Line by line:
- inside
DATA DIVISION.
, there'sWORKING-STORAGE SECTION.
which defines all local variables -
01 N PIC 9(2).
definesN
as two digit decimal number - that
01
is about nested data definitions (so a 6 character date variable can contain inside it three 2 character variables for year, month, and day etc.),01
means regular variable -
PERFORM VARYING N FROM 1 BY 1 UNTIL N > 20
toEND-PERFORM
loopsN
from1
to20
-
DISPLAY N
printsN
, with leading zeroes
The Y2K panic was largely about such PIC 9(2)
s used by old COBOL code from the 1960s and 1970s to define year fields, and similar poor practices in other systems. People pretty much forgot about Y2K panic by now, but it was a huge cultural phenomenon back then. Like most such panics, it was over pretty much nothing. After their predictions of doom all turned false, people tried to rewrite history and claim there weren't many bugs thanks to some heroic effort to preemptively fix them (Wikipedia still contains such lies). In reality, there wasn't much there to begin with, and it was just panic fueled by the media, and Big Tech of the day trying to sell Y2K preparedness services.
FIZZBUZZ
Let's write the FIZZBUZZ! As we're doing COBOL, it will be all caps and with leading zeroes.
IDENTIFICATION DIVISION.
PROGRAM-ID. FIZZBUZZ.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 N PIC 9(3).
01 M PIC 9(3).
01 3REM PIC 9(1).
01 5REM PIC 9(1).
PROCEDURE DIVISION.
PERFORM VARYING N FROM 1 BY 1 UNTIL N > 100
DIVIDE N BY 3 GIVING M REMAINDER 3REM
DIVIDE N BY 5 GIVING M REMAINDER 5REM
EVALUATE 3REM ALSO 5REM
WHEN ZERO ALSO ZERO
DISPLAY 'FIZZBUZZ'
WHEN ANY ALSO ZERO
DISPLAY 'BUZZ'
WHEN ZERO ALSO ANY
DISPLAY 'FIZZ'
WHEN OTHER
DISPLAY N
END-EVALUATE
END-PERFORM.
STOP RUN.
$ cobc -xg fizzbuzz.cob
$ ./fizzbuzz
001
002
FIZZ
004
BUZZ
FIZZ
007
008
FIZZ
BUZZ
011
FIZZ
013
014
FIZZBUZZ
016
017
FIZZ
019
BUZZ
...
What's going on:
- all variables defined to fit exact number of digits they need
- variable names can start with numbers, something that's not really a thing in any language these days
-
EVALUATE 3REM ALSO 5REM
is a case statement over two variables - interestingly a lot of languages don't really allow that. Apparently it was only added in COBOL 85 and not available earlier. -
WHEN ZERO ALSO ANY
etc. - are various matches, including wildcard matches
Fibonacci
This was surprisingly difficult to get working. I think a lot of functions like COMPUTE
use newfangled COBOL features from the 1970s+. When I tried to do more "classic" COBOL, GnuCOBOL was not too happy about it. Then again, the original COBOL didn't even have recursion, so it's hard to pick up the right year to target.
Interesting COBOL feature is M PIC Z(8)9
- we're defining M
as having 8 digits which should not be printed if zero (Z(8)
), and one regular digit (9
). Data storage and formatting are intertwined like this.
* MAIN PROGRAM
IDENTIFICATION DIVISION.
PROGRAM-ID. FIBLOOP.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
REPOSITORY.
FUNCTION FIB.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 N PIC 9(3).
01 M PIC Z(8)9.
PROCEDURE DIVISION.
PERFORM VARYING N FROM 1 BY 1 UNTIL N > 20
COMPUTE M = FIB(N)
DISPLAY 'FIB(' WITH NO ADVANCING
DISPLAY N WITH NO ADVANCING
DISPLAY ')=' WITH NO ADVANCING
DISPLAY M
END-PERFORM.
STOP RUN.
END PROGRAM FIBLOOP.
* FUNCTION FIB(N)
IDENTIFICATION DIVISION.
FUNCTION-ID. FIB.
DATA DIVISION.
LOCAL-STORAGE SECTION.
01 A PIC 9(9).
01 B PIC 9(9).
01 N1 PIC 9(3).
01 N2 PIC 9(3).
LINKAGE SECTION.
01 N PIC 9(3).
01 RESULT PIC 9(9) COMP BASED.
PROCEDURE DIVISION USING N RETURNING RESULT.
IF N IS LESS OR EQUAL TO 2 THEN
MOVE 1 TO RESULT
ELSE
SUBTRACT 1 FROM N GIVING N1
SUBTRACT 2 FROM N GIVING N2
COMPUTE A = FIB(N1)
COMPUTE B = FIB(N2)
ADD A TO B GIVING RESULT
END-IF.
GOBACK.
END FUNCTION FIB.
$ cobc -xg fib.cob
$ ./fib
FIB(001)= 1
FIB(002)= 1
FIB(003)= 2
FIB(004)= 3
FIB(005)= 5
FIB(006)= 8
FIB(007)= 13
FIB(008)= 21
FIB(009)= 34
FIB(010)= 55
FIB(011)= 89
FIB(012)= 144
FIB(013)= 233
FIB(014)= 377
FIB(015)= 610
FIB(016)= 987
FIB(017)= 1597
FIB(018)= 2584
FIB(019)= 4181
FIB(020)= 6765
There's a lot of weird stuff going on here. There's ENVIRONMENT DIVISION
listing which functions we're using. There's LINKAGE SECTION
for function's inputs and outputs.
Basically 90% of this trivial program is ridiculous boilerplate which you need to get just right. I wanted to check a bunch of examples of COBOL code, and every example used different boilerplate, and none would work on GnuCOBOL without serious tweaking - even ones tagged as being specifically for GnuCOBOL. The whole language is far more of a dumpster fire than I expected. Fortran was not amazing, but at least you could see imagine actual humans coding Fortran. I have no idea what kind of subterranean reptilian creatures from the Hollow Earth COBOL was designed for, because it sure as hell wasn't designed for any kind of human beings.
Should you use COBOL?
People knew COBOL was shit before Joe Biden was even born, so obviously no.
It might very well be the absolute worst language reviewed so far. Even Befunge and Thue were more enjoyable to code in.
Code
All code examples for the series will be in this repository.
Top comments (0)