Note: "victim" is not victim's real name or real IRC handle. Every word that follows is true. This conversation really happened.
|<cowan>||I mean, <3rdParty>'s a Cobol programmer by training.|
|<victim>||Which I've met essentially none of.|
|<cowan>||Cobol programmers don't use subroutines. They're too inefficient.|
|<victim>||Dude, you need to put up warning tags.|
|<victim>||That literally hurt.|
|<victim>||Ow ow ow ow ow ow ow ow ow.|
|<cowan>||Cobol uses things like PERFORM A THROUGH B, which means "execute the statement labeled A ,then consecutive statements until after the statement labeled B has been executed, then return. That's efficient.|
|<victim>||That just takes "old school" to a new level. One that ignores the last 30 years of computer science. .|
|<cowan>||If there happen to be lots of GO TOs before B is reached, fine!|
|<cowan>||Cobol even has the insane ALTER A TO PROCEED TO B statement (though <3rdParty> says it, at least, is obsolete):|
|<cowan>||That means: Look past the statement labeled A until you find the next GO TO statement (of course, the looking is done at compile time) ...|
|<victim>||STOP IT YOURE HURTING MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE!|
|<cowan>||... and patch it into being a GOTO B statement.|
|<cowan>||Naturally, when code gets paged out, the ALTERs in the paged-out code are forgotten.|
|<victim>||OMFG, you just don't stop, do you?|
|<victim>||Wait a minute, wait wait wait.|
|<victim>||The looking is done at compile time, but the altering is done at run time?|
|<cowan>||After all, you might execute ALTER A TO PROCEED TO C next.|
|<victim>||Congratulations, you just made me scream out loud. Literally. I'm not kidding.|
|<victim>||I'm contemplating suicide for belonging to a species that could do this.|
|<victim>||(OK, that second part is not true, but the first is)|
|<cowan>||Dude, you're the Sail, I'm the Anchor.|
|<cowan>||In a heavy wind, the Sail can tear itself loose if it ain't strapped down tight.|
|<victim>||Yeah, but you're anchoring me to the fucking Scylla.|
|<cowan>||OTOH, Cobol has some really cool features.|
|<cowan>||Given two variables of the same structure type, you can say "MOVE A TO B" to do b = a (structure copy).|
|<cowan>||But if you say MOVE CORRESPONDING A TO B, then A and B do not have to have the same type,|
|<cowan>||and only the elements of A that also exist (by name) in B are copied.|
|<victim>||That's vaguely interesting, yeah.|
|<victim>||It's also three lines of code in most languages.|
|<cowan>||Well, no. Suppose that A's type has fields b, c, d, e, f, g and B's type has fields a, c, e, g, h.|
|<cowan>||Then it's equivalent to B.c = A.c; B.e = A.e, B.g = A.g|
|<cowan>||but if you add members to A's type or B's type, the compiler generates more assignments.|
|<cowan>||No searching through the code to make it so.|
|<victim>||C can't do that, but any language where you can inspect structure membership by name can.|
|<cowan>||You can do this in Python or Lisp if you go meta, yes, but Cobol compilers do it automatically.|
|<cowan>||at full machine efficiency.|
|<victim>|| foreach ||<cowan>|| great minds think alike.
||<cowan>|| Back to the evils of Cobol: looping is done by things like PERFORM A THROUGH B N TIMES.
||<cowan>|| So the loop statement doesn't need to be anywhere near the loop body, and often isn't.
||<victim>|| These are all labels, right?
||<victim>|| Oh fuck me.
||<cowan>|| Yes, except when I was talking about MOVE CORRESPONDING.
||<cowan>|| Now you can say COMPUTE A = B * C + D.
||<cowan>|| But the real Cobol way is
||<cowan>|| MULTIPLY B BY C GIVING X1
||<cowan>|| ADD X1 TO D GIVING A.
||<cowan>|| O' course, you better declare X1.
||<cowan>|| You can add an ON SIZE ERROR to any of these arithmetic statements to say what to do
||<cowan>|| if there is no room in X1 for the result, since it must be declared with a given
||<cowan>|| number of digits, thus:
||<cowan>|| WORKING-STORAGE SECTION.
||<victim>|| NUMBER OF DIGITS?
||<cowan>|| 77 X1 PICTURE 999999.
||<cowan>|| Sure. All Cobol arithmetic is done in decimal digits.
||<victim>|| Oh god, that's where pictures came from.
||<victim>|| I've hit those before.
||<cowan>|| Unless you add USAGE COMPUTATIONAL to the end of the picture
||<cowan>|| in which case it can be binary or floating point.
||<cowan>|| Note the magic 77, which means that this is not a structural variable.
||<cowan>|| Structures are declared by starting with 01; fields and substructures are 02;
||<cowan>|| fields in the substructures are 03; and so on. You don't have to increment the numbers
||<cowan>|| by one as long as you increment them.
||<cowan>|| Unless, of course, the structure will be used to hold a record from some file,
||<cowan>|| in which case you use FD instead of 01, of cours.
||<victim>|| You're enjoying the hell out of this, I hope.
||<cowan>|| You can add REDEFINES to a declaration to show that it shares storage with some other
||<cowan>|| declared element.
||<cowan>|| (Are you kidding? My ribs are aching!)
||<victim>|| Are you copying this from somewhere, or doing it on the fly?
||<victim>|| Wait, wait.
||<victim>|| Shares storage?
||<cowan>|| On the fly.
||<cowan>|| Sure. Suppose your data
||<cowan>|| has either a SSN number or a taxpayer ID number but not both.
||<victim>|| You're telling me that a language that has decimal digits as a storage unit also has type-casting?
||<cowan>|| SSN PICTURE 99-999-9999
||<cowan>|| TIN 99-99999999 REDEFINES SSN
||<victim>|| Oh no, you're going to pattern match to find out which it is aren't you?
||<victim>|| It's like C enums, but in hell.
||<cowan>|| No. You can define the SSN field and read the TIN field.
||<cowan>|| It's like C unions.
||<cowan>|| Horribly abused.
||<victim>|| Oh no, it really IS type-casting!
||<cowan>|| All variables are global.
||<victim>|| Please, for the love of goth, tell me this language doesn't have pointers.
||<victim>|| You just threw that in there.
||<cowan>|| More accurately, they're all static.
||<cowan>|| But since most programmers don't use subroutines (which are called PROGRAMs)
||<victim>|| I almost remember the difference.
||<cowan>|| it's a distinction without a difference.
||<cowan>|| static = stored in fixed location, but only accessible from the current PROGRAM.
||<cowan>|| Recursion is technically allowed, but without a variable stack it's sorta pointless.
||<cowan>|| No pointers, no.
||<cowan>|| Or at least only in Object-Oriented Cobol.
||<cowan>|| Which is very recent and most Suzie Cobols (Sammy Cobols if they're female) don't know it.
||<victim>|| There is OBJECT-ORIENTED COBOL?
||<cowan>|| Yeah. I'm not up on the details.
||<victim>|| So wait, you can try to do recursion, but variables are preserved throughout?
||<cowan>|| Then there's the CONTINUE statement. It does nothing.
||<victim>|| Oh dear god. Why?
||<cowan>|| But when you want to say THEN no-op, you say THEN NEXT SENTENCE.
||<cowan>|| Screen I/O, sorting, and such are built-in language statements.
||<cowan>|| You open a file with OPEN, but you don't mention the name of the file in the OPEN statement.
||<cowan>|| Instead, you mention the name of the structured variable you want to read into.
||<cowan>|| The actual association between the variable and the file goes in something called the
||<cowan>|| ENVIRONMENT DIVISION up at the front. The file name has to be fixed.
||<cowan>|| Ah, I just found out that the new, improved PERFORM A THROUGH B can now be PERFORM IN THREAD instead. Threaded Cobol.