Please explain this tech geek joke

The closest was Chronos saying that FORTRAN programmers can write FORTRAN in any language. FORTRAN code has a certain style to it which is a bit antiquated these days.

The prime example of this is Numerical Recipes in C/FORTRAN. FORTRAN was the original, while C was the translated version. And the C code did in fact look like reformatted FORTRAN.

Among other things, C has zero-based array indexing, while FORTRAN is one-based. But with some pointer manipulation you can act as if your C code is one-based, and so that’s what they did. Ugly as heck, but that’s FORTRAN programmers for you.

Just note, though, OK, in Fortran array indices start at any number you want (not necessarily 1, though that is the default), while in C they are always based at zero— seems like C is the one looking less elegant and/or antiquated in the context of that criterion. Maybe in some hypothetical algorithm it really is natural to start counting from 2 or from −1…

[which is why mechanically “translating” Fortran into C is going to be ugly; they should not have done that…]

Hmm, I wasn’t aware that that was configurable.

It’s easy to have n-based arrays in C. Just:

#define MALLOC_N_BASED_ARRAY(type, count, N) ((type *)malloc(sizeof(type) * count) - N)
#define FREE_N_BASED_ARRAY(ptr, N) free(ptr + N)

Not that I’d advocate for such an approach… though really, a similar thing is done all the time. Quicksort, for instance, recursively sorts the left and right parts of an array. Instead of having to deal with an offset manually, we can just add the offset to the base pointer and then pretend that it’s zero-based.

FORTRAN was “elegant” in the same sense that the DEC PDP-8 was elegant, about which I waxed enthusiastic a few posts up. Both truly were elegant and clever designs, but the most important attribute creating that warm and fuzzy feeling was that they were simple enough to fully understand. I knew everything there was to know about the PDP-8, so I truly appreciated its elegance. It wasn’t hard to become familiar with the full spectrum of the FORTRAN language, and I used to pick the option to get an assembly listing and used to marvel at the assembly code it generated.

As computers and languages got more and more complex, it became impossible to know all of it inside-out, and the childlike fascination with elegance was gradually displaced by a sense of being overwhelmed by technology that was changing faster than one could keep up with.

Exactly this! Maybe the huge system had lots of elegance, but it was impossible to tell.

I think I can confidently say that even back in Ye Olde Dayes, the importance of commenting your code was recognized by most programmers, because it was as much out of self-interest as in helping any future programmer trying to decipher the code. And FORTRAN had subroutine and function capabilities so any half-intelligent programmer could figure out how to structure his code. So FORTRAN didn’t have conditional code blocks but had to rely on simply “IF” statements and GOTOs? I’ll say again that that sort of stuff doesn’t matter much compared to how well the overall program is structured, and even more so any larger system it might be part of.

A propos of all this and what Chronos was saying, your Fortran compiler must be… pretty old if it does not support syntax like DO WHILE. Yet it appears to be true that some people (Olde Schoole Fortran programmers) felt that this was unnecessary bloat, compromising the elegance of the language, while others (whose voice eventually won out) demanded it. See eg
https://dl.acm.org/doi/pdf/10.1145/155886.155888

The array indices are just one of several things. Another quirk, which is one more of style based on language limits, is variable naming. FORTRAN 77 had at most 6-character variable names. And a lot of code was itself pretty directly translated from mathematical operations, and we know how mathematicians are in love with short names. So the FFT code in Numerical Recipes looks like this:

void four1(float data[], unsigned long nn, int isign)
Replaces data[1..2*nn] by its discrete Fourier transform, if isign is input as 1; or replaces
data[1..2*nn] by nn times its inverse discrete Fourier transform, if isign is input as −1.
data is a complex array of length nn or, equivalently, a real array of length 2*nn. nn MUST
be an integer power of 2 (this is not checked for!).
{
unsigned long n,mmax,m,j,istep,i;
double wtemp,wr,wpr,wpi,wi,theta; Double precision for the trigonometric recurrences.
float tempr,tempi;
n=nn << 1;
j=1;
for (i=1;i<n;i+=2) { 

Sorta weird that they didn’t bother putting the comments into an actual comment block. But regardless, they are in love with short names, and none are even longer than 5 characters, with most being barely decipherable, like “wpr” or “wpi.” C always supported at least 31 characters (actually more, but the ones past 31 wouldn’t necessarily be distinguishable.

And a good thing too.

  • Pedantic_Man rushes in from stage left:

The C Standard specifies that any pointer may point to the first element or any element after the first of an array object allocated via static, automatic, or malloc() allocation, but not to any element before the first or any element after the one-past-the-first element (and a pointer pointing to the latter may not be deferenced)!

  • Practical_Programmer walks in from stage right:

But, you know, that’s likely to work fine the way @Dr.Strangelove specified it.

  • Pedantic_Man bristles at this heresy:

But this may throw a segmentation violation on old UNISYS computers! Also, and more relevant, modern optimizing compilers may spot this kind of chicanery and make optimizations that can make your relevant code do the wrong thing! Think of the children!

  • Pragmatic_Programmer shrugs:

Hey, it works on my platform right now. What are you gonna do?

  • Both exeunt

Which, as my dialog from above alludes to, isn’t quite the same thing, as quicksort never goes past the bounds of the allocated array, though using pointers in that fashion does make divide-and-conquer algorithms easy to express - much more so in C than in FORTRAN.

And I think that’s at least some of the reason for the rap that FORTRAN often gets in terms of “elegance” - a lot of depends on what you think is elegant. A lot of standard computer science algorithms (such as quicksort) are recursive - early FORTRAN (though IV at least) didn’t have any provision for recursion, so you couldn’t write those algorithms without converting them into an iterative form (and making them a lot less “elegant” from the CS perspective).

On the other hand, FORTRAN can assume that two arrays passed to one of its subroutines are disjoint; i.e. they do not refer to the same areas of actual memory. So a compiler can load up the array elements into a register (or bank of registers, on vector machines like the old Cray or modern SSE microprocessors) and then chug away on the algorithm without having the kind of memory traffic that the C version will require, since it has to worry about the memory areas overlapping. Someone who just wants to get their code running, and wants it to run as fast as possible, will probably consider this to be more elegant than the ability to apply Stupid Computer Science Tricks ™ to a problem - why complicate things so much?

More to the point, every language has its own certain style to it. Which is different for every language.

Aside from the unit-offset-array thing, the other feature that Fortran is most famous for is that passing values into a function is, by default, done by reference, where almost all modern languages (counting C as modern) instead pass by value. Which means that, if you don’t specifically write your function to avoid doing so, a function can change the value of its inputs. Which can get very interesting when you call a function using constants.

“But hey, who hasn’t given PI the value 3.5, am I right?”

There’s an old moviei called The Cheap Detective. It’s a parody of the old, hard-boiled detective movies of the '40s, with Peter Falk in the Humphrey Bogart role. In one scene, a woman meets Falk in his office and introduces herself as Denise Manderley. Ah, but he notices that she has a different name on her driver’s license. She gives him a different name, but that doesn’t match the initial on her handkerchief, etc. After she’s given about half-a-dozen aliases, he finally snaps.

“You give me the runaround one more time and I’m going to slap you around this office. I don’t care what your name is any more. Just make one up, so I know what to call you!”

I think that’s why I liked C so much. I don’t care if arrays are 0-based or 1-based, just pick one and stick with it so I know what to expect! When I used to program, I wanted to spend my effort focusing on the logic of what the program was trying to do. Every moment I spent thinking about the features of the language was a distraction from what I cared about. Keep it simple.

The FORTRAN I was referring to was FORTRAN IV, which indeed did not have those structures. This was FORTRAN IV initially for the IBM 7040/7044 before I even got to college, then later FORTRAN IV for the PDP-10 (DECsystem 10). Its control structure was only an “IF” statement of the form:

IF ( {condition} ) {statement}

If the condition was true, {statement} would be executed. It was almost always a “GO TO”.

There was no “DO WHILE”. The “DO” statement specified the end statement of the loop, a variable to iterate, the end value, and an optional iteration increment.

If FORTRAN IV is “pretty old”, then I’m pretty old. Wait! :astonished:

It also doesn’t care if the data type of the arguments match the data type of the formal parameters. This can lead to some fun bugs when, e.g., a function does floating point math on an integer value.

In C you can write code like

float f = (float)(v - 1);  
r = 1U << ((*(unsigned int*)(&f) >> 23) - 126);

:slight_smile: