An Interest In:
Web News this Week
- April 19, 2024
- April 18, 2024
- April 17, 2024
- April 16, 2024
- April 15, 2024
- April 14, 2024
- April 13, 2024
100 Languages Speedrun: Episode 50: COBOL
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$ ./helloHELLO WORLD
That's some 2D picture.
Let's take it line by line:
IDENTIFICATION DIVISION.
- some metadata about the procedurePROGRAM-ID. Hello.
- the name of the procedureDATA DIVISION.
- there's also one there usually, defines dataPROCEDURE DIVISION.
- code of the procedureDISPLAY 'HELLO WORLD.
- displays a string and newlineSTOP 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$ ./loop0102030405060708091011121314151617181920
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$ ./fizzbuzz001002FIZZ004BUZZFIZZ007008FIZZBUZZ011FIZZ013014FIZZBUZZ016017FIZZ019BUZZ...
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$ ./fibFIB(001)= 1FIB(002)= 1FIB(003)= 2FIB(004)= 3FIB(005)= 5FIB(006)= 8FIB(007)= 13FIB(008)= 21FIB(009)= 34FIB(010)= 55FIB(011)= 89FIB(012)= 144FIB(013)= 233FIB(014)= 377FIB(015)= 610FIB(016)= 987FIB(017)= 1597FIB(018)= 2584FIB(019)= 4181FIB(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.
Original Link: https://dev.to/taw/100-languages-speedrun-episode-50-cobol-2e7b
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To