Cyberpig 1973

Last Updated: 09/11/2023

My attempt to resurrect a FORTRAN swine farm simulation from 50 years ago

Avatar, Matthew Piercey

Matthew Piercey

Ah, FORTRAN. An elegant language of a more civilized age. Well, not exactly…

But I wanted a good excuse to play around with it, OK? To get a taste of what it was like to be a programmer in the early 1970s. And while my attempt to resurrect a swine farm simulation from half a century ago wasn’t entirely successful, it was a wild ride that I don’t regret going on.

I’m writing this post to document my journey, to commemorate 50 years of this program’s existence, to share the ups and downs of this digital archaeology project, and to hopefully shed some light on the history, present, and future of computer programming.

This post is dedicated to the memory of Jay Loren Strom, PhD (1937 - 2020). Farmer, economist, programmer, teacher, entrepreneur, and a man who placed great value on family and faith.


Our story starts in January 2021. Through a series of events, I managed to get my hands on a PhD thesis, that I had heard contained a hidden treasure. Well, a treasure for someone like me.

It was called Simulation of a Swine Breeding Herd. For a while, I seriously questioned if I would ever be able to find it, since even Purdue’s library seemed to have lost it. But eventually, it showed up.

The title page for a thesis submitted to the faculty of Purdue University by Jay Loren Strom in partial fulfillment of the requirements for the degree of doctor of philosophy may 1973

You don't know how happy I was to see this title page

Now that it was finally in my posession, I had to know. Where was this FORTRAN program? Was it just a myth? Was it in a separate document? With bated breath, I scrolled down the document. Past paragraphs, and mathematical formulae, and flowcharts, and matrices, and tables.

I started to worry, was this just the documentation? Had the program itself been lost to time? After obtaining the proverbial treasure chest, was I about to find it all but empty? Because don’t get me wrong, the scientific paper part is fascinating, and well-researched, and full of practical insight into how to build usable mathematical models of complex agricultural systems. But that wasn’t what I was interested in.

But lo and behold, the program itself had been preserved.

Appendix C The Fortran Program

Now, that's what I'm talking about!

Great, I thought. As long as it had been all typed out, surely there was hope that it could be re-compiled on a modern system.

But as I scrolled past the cover page for Appendix C, my eyes were flooded with this. And from then on, I knew this was no easy task ahead of me.

A full typewritten page of code, part of which appears to be near-indecipherable

Oh...

So that’s what I was up against! Huh. And not 1, not 10, but 75 pages of this. Wait, 75 pages?!

Alright, sign me up! XD

OK, to be fair, it wasn’t that bad. Most of the pages weren’t filled up half as much as the first one. Some way to set my expectations, though! No, most of the pages looked a lot more manageable, at least to someone with programming experience. Although, I’d imagine it still looks fairly arcane, even for a programmer.

A full page of typewritten FORTRAN code

Hey, at least I can make out variables, keywords, line numbers, function calls, and comments. Those are things I recognize from normal computer code!

At this point, I decided (for whatever reasons) to take it upon myself to attempt to resurrect this program. I had no idea how far I’d get, but I just wanted to go for it. To see if I had the patience to type all of this out, and to see what modern programming tools might allow me to do with it.

Now, at this point, there’s a gap of about two years in the story. Truth is, I was in way over my head, and didn’t know what to do with the code, once I had typed it all out. So this project sat on my “back burner” for a while, as I finished university, and did some other things.

In the meantime, I picked up some programming books, including some for FORTRAN IV and its descendant, FORTRAN 77. Being a pretty much self-taught programmer is a doubled-edge sword sometimes. Because you can learn whatever you want, but sometimes it’d be nice to have more help with things.

Honestly, I would’ve loved to have had a chat with Jay Strom before his passing. Just in general, but I definitely would’ve picked his brain about this beast of a program. The cruel irony being, I only learned about this program from his obituary. Either way, I can’t help but respect the guy. Many people would’ve been satisfied with a career in agriculture, or economics, or business, or education, or programming. But it takes a certain type to pursue all of those fields simultaneously. I hope one day people can look back at my life and accomplishments half as admirably as I can look back at his.

Anyway, this felt like some way for me to experience what it might have been like to be a computer programmer in such a formative time in the industry. In the late ‘60s and early ‘70s, we were on the cusp of many of the advancements we take for granted to this day. From the UNIX operating system, to the C programming language, to the advent of the microprocessor and eventually the personal computer. It’s honestly incredible how similar the code they were writing back then looks - at least syntactically, if not cosmetically - to much of the code that’s written these days. Because things were so fundamentally different back then, it’s funny how familiar some of these concepts seem. Especially for someone like me, who’s looking back on this from a modern context.

This project really helped me to appreciate the timelessness of programming, to an extent. As long as humans will continue to communicate with computers through code, there are certain paradigms that are going to stay with us. I’m not about to claim that things haven’t drastically changed in the last 50 years, in every conceivable way. But I think it’s a good exercise to connect with the past in this way.

Because this program is a historical document. I’m no historian, but I think this it’s fascinating and extremely valuable to study our digital past, just as much as our analogue past. If not more so, to some extent, because it’s so often neglected. I think there’s a common misconception that once a document is digitized, or a piece of information is posted online, that it’s there to stay.

But websites go offline. Software and media companies go out of business. Physical media degrades, or becomes obsolete and difficult to interface with as technology progresses. Lossy compression or poor-quality digitization efforts can irrepairably reduce the “quality” of captured images, video, or audio. Accidents, sabatoge, or just plain poor decision-making can lead to the irrevocable loss of data.

The “digital world” is just an abstraction - it’s just as much at the whims of entropy as the “physical world” is. In some ways, moreso. Because in a world where information is so accessible, it’s easy to reject its ephemerality. Why bother trying to preserve something that’ll always be around?

Well I disagree.

Maybe this whole thing was crazy. Maybe I didn’t exactly get anywhere with it in the end. But it gave me an appreciation how vehemently FORTRAN developers have fought, and continue to fight, to preserve their code. Call me overly-sentimental, but I feel like I’ve stumbled upon something truly special. And I’m excited to share it.

Speaking of sharing, I’m pretty proud of the personal library that I’ve started to compile. So let me share some some of the old FORTRAN programming books I picked up during 2021 and 2022:

Cover of A Guide to Fortran IV Programming (Second Edition) by Daniel D. McCracken
This new edition of a popular bestseller contains material on operating systems (both batch and time-sharing), validation of input, object-program efficiency, and writing programs for comprehension and ease of checkout.
A graphical presentation of the solution of LaPlace's equation to a pipe carrying a hot liquid and partially immersed in ice water
A page full of columns of US draft lottery numbers for men born in 1953
The cover of An Introduction to Computer Programming by Adolph C. Nydegger
Pages of a book, displaying text, mathematics, FORTRAN code, and a flow chart
A pamphlet and two larger books on Microsoft FORTRAN are displayed on a table
A reference page describing the SUBROUTINE keyword in Microsoft FORTRAN
A FORTRAN Coloring Book by Dr. Kaufman, 1st and last edition The MIT Press. Learn Computer Programming the Painfully Funny way!
If you do all the programming problems at the back of this book and don't learn FORTRAN in the process, you deserve your money back. *Offer void within or without U.S.
Wacky illustrations of a Shakespearean bard, a bird with a top hat, and a giraffe with a twisted neck serve to illustrate the looping DO statement in Fortran77
A cartoon of a character jumping in the air, and slamming a computer with a mace. Under the caption - Bending the Computer to Your Will

McCracken is a revered name in vintage programming circles, and for good reason. This is his quintessential Guide to Fortran IV Programming.

What, I have an odd taste in literature, OK?

Funny enough, the Fortran Coloring Book, at least, has been scanned and saved to the Internet Archive. I’d recommend checking it out, if you’re interested. It’s definitely an oddity, but it’s something special.

Now let’s pick back up on this project, shall we? I’ll set the stage. It’s the spring of 2023, and I had…

I wanted to get this code to compile, using a modern Fortran compiler, like gfortran. I had tried to set up a mainframe emulator and use it to run this program, but I eventually gave up on that idea. It was too complex, and I wasn’t going for “authenticity”. I was willing to use all manner of modern tools at my disposal to get this job done. Although for anybody crazy enough to look into the weird world of mainframe emulation, I’d suggest the Hercules project:

http://www.hercules-390.org/

In the meantime, I did find out about the Michigan Terminal System (MTS), a mainframe operating system released in 1967, that was originally designed for use by university computer science departments.

https://try-mts.com/

https://en.wikipedia.org/wiki/Michigan_Terminal_System

I was able to get IF66 (Interactive Fortran 66) to work for me on MTS. It’s basically a REPL (Read Evaluate Print Loop) for FORTRAN IV, and I made a little “Hello World” program with it. I didn’t feel like it was going to help me with this project, but still, fascinating stuff.

For reference, here’s the FORTRAN IV “Hello World” program I used to test IF66:

fortran
      DO 10 I = 1,5
      WRITE (6, 20)
10    CONTINUE
      STOP
20    FORMAT(13H HELLO, WORLD)
      END
C     PRINTS "HELLO, WORLD" TO THE CONSOLE FIVE TIMES, ON A NEW LINE EACH TIME

Now, back in 2021 I had typed it all out, but I made the mistake of trying to edit the code as I went along. Because there were certain things I thought I could “modernize”. But it wasn’t worth it - I realized that the first step had to be to transcribe this program in as accurate of detail as possible. As it was originally written. So it was back to square one.

My first idea was OCR (Optical Character Recognition). But I soon realized, as good as OCR has gotten, it wouldn’t be enough. Because the way this code was typed out, and the way the typed page was photographed and eventually digitized meant some letters were inconsistent.

“O’s” suffered the most. Some looked like “O’s”, some looked like “C’s”. Even from line to line it wasn’t consistent.

A page of typewritten code, with a number of arrows pointing to inconsistently-typed letter "O"'s

See what I mean? OCR wasn't going to like this

So OCR was out of the question. Because the characters were inconsistent, the code was dense and relied on many short variable names, and the line numbers and formatting had to be preserved.

OCR is much better for making documents (somewhat) searchable. Although sometimes it has false positives/false negatives. And for prose (or poetry) it does a lot better than for code, because everything’s an actual word. But in this case, I had to do it myself.

I knew that this code was written in a language called FORTRAN IV. Which is also colloquially called FORTRAN 66, since the main specification for the language was released in 1966. Well, turns out the modern compiler I was using - gfortran - really only liked FORTRAN 77 code. And it didn’t seem to be willing to accept anything older. But I realized that FORTRAN 77 was backwards-compatible with almost everything from FORTRAN IV. So I didn’t have to worry too much about trying to “modernize” this code, as long as I typed it out as diligently and accurately as possible. Part of me wishes this simulator came out five years later, as it probably would have been written in FORTRAN 77, which is widely regarded as a more standardized language. But hey, I figured it would be close enough.

I guess in some ways, it’s similar to the whole Python 2 versus Python 3 situation. Where it’s definitely the same language overall, but there are enough changes that they’re not 100% compatible out of the box.

So, line after line, page after page I typed out. As close to the source material as I could. But I had a trick up my sleeve, that they most certainly didn’t have in the ‘70s - VS Code!

A screenshot from the modern code editor VS Code, showing several lines of FORTRAN

Line numbers, syntax highlighting, linting, and dark mode. Now, that's more like it!

Like I said, I wasn’t going for authenticity in the experience. My compliments (and condolences) to the secretary who had to type all of this out back in the day, presumably all without hitting backspace once, or having to start the whole page over!

But if that weren’t enough, consider this - every line of code (there are over 3000 of them in this program) was a punch card back in the day. Seriously. Every line, including the comments!

As much as I like to romanticize the “good old days” of programming in the ‘60s and ‘70s, I’m so glad we’ve moved on from this. As it stands, I’ll take my fancy code editor and creature comforts any day of the week! I don’t think it’s admitting weakness, it’s just being practical.

So yeah, it took a while to type this all out. Especially the COMMON statements. Another contrivance of the day I’d rather not return to. They’re basically global/shared variables that you can declare at the top of a part of code (like a subroutine). And they’re awful.

A screenshot of several incredibly-dense lines of COMMON statements, comma-separated lists of variable names (short made-up words) that looks like gibberish

Is this what code looks like to a non-programmer?

I’m not going to pretend like that was fun to type out. But I did it, and I’m 99% positive it’s verbatim to the original.

Oh, and speaking of the original, I typed this all out in fixed form. What that basically means is it was all uppercase, with six spaces before the start of every line of code (other than comments, or labels). There’s a certain elegance to it, when everything lines up and has consistent margins. But it’s probably more trouble than it’s worth. I only typed it out in fixed form, so the code editor would recognize it as really old-school FORTRAN, as opposed to kinda old-school FORTRAN.

Anyway, COMMON statements and fixed form aside, I saw some interesting stuff while typing out all of this code. For one, there was something that will probably still be recognizable to many modern programmers - an implementation of the bubble sort algorithm:

fortran
C   BUBBLE SORT
      I = 1
10    J = I
11    IF(KS(1, I) - KS(1, I + 1)) 98, 98, 9
9     KTS1 = KS(1, I)
      KTS2 = KS(2, I)
      KS(1, I) = KS(1, I + 1)
      KS(2, I) = KS(2, I + 1)
      KS(1, I + 1) = KTS1
      KS(2, I + 1) = KTS2
      IF(I .EQ. 1) GO TO 98
      I = I - 1
      GO TO 11
98    I = J + 1
      IF(I .LT. 500) GO TO 10
C FINISHED BUBBLE SORT

Overall, while I don’t claim to understand this simulator at a low level, I found it very enlightening just how succinct FORTRAN IV can be in places. It can take complicated mathematical expressions that would take a page or more to write out and explain, and fit them onto a handful of punch cards. It’s certainly not as clear or easy to read as more modern math-centric programming languages like R, Julia, or even newer incarnations of Fortran. But for the punch card era, some of this stuff is downright impressive.

Speaking of being succinct, I think that’s the biggest difference between this code and most code that is written today. Nowadays, it’s good practice to give variables longer, human-readable names, to have a lot more comments to aid the reader in understanding what’s going on, and to strike more of a balance betwen code that’s very reusable, and code that’s easy to understand at a glance. And whereas in FORTRAN IV, the names of variables could determine their type, many developers these days want to be explicit about the types of their variables, and for good reason.

For instance, in FORTRAN IV, a variable starting with the letter I through N, unless denoted otherwise, is considered an integer (i.e., 0, 1, 2, 3, etc.). But any other variable name is implicitly considered a real number (like 1.0 or 3.14 or 6.987, etc.) unless specified otherwise. This is undeniably weird.

But back then, contrivances like short variable names and variable name-based implicit typing weren’t considered “poor form” (as they very much would be today). They were space-saving measures of the punch-card era.

Another pattern I noticed was lots and lots of FORMAT statements. Those were especially tricky to type out, since they originally spanned multiple lines and were in a very archaic format.

These days, when you want to write a piece of code that “prints” some information for the user, you might do something like this:

javascript
let numberOfSales = 5
let dayIndex = 30

console.log(`Report of ${numberOfSales} sales on day ${dayIndex}`
// Prints:
// Report of 5 sales on day 30

Or in the C programming language, it might look more like this:

c
int numberOfSales = 5;
int dayIndex = 30;

printf("Report of %d sales on day %d", numberOfSales, dayIndex);
// Prints:
// Report of 5 sales on day 30

The C implementation is a lot closer to how FORTRAN IV does it. A “format string” has sequences of characters (like “%d”) which are substituted for the variables you place after the string.

In FORTRAN IV (well 77 in fixed form) you do something like this (notice how there are four different format statements):

fortran
      IF(ISALS) 1243, 1243, 1201
1201  IF(KTOT46) 1243, 1243, 1202
1202  WRITE(IJK, 1203) KTOT46, NOWT
1203  FORMAT(/////' SALES SEASONAL REPORT'/1X, 60(1H=)/16X'REPORT OF'I5' SALE(S) ON DAY'I5)

      IF(NS4) 1903, 1903, 1204
1204  WRITE(IJK, 1205) NS4, AVWT, VS4
1205  FORMAT(/' FROM FINISHING HOUSE'/7X'SOLD'I3' HOGS AT'F6.1' POUNDS AVERAGE WEIGHT'/7X'SALES VALUE WAS'F10.2' DOL.')

1903  IF(NS6) 1906, 1906, 1904
1904  WRITE(IJK, 1905) NS6, AVWT6, VS6
1905  FORMAT(/' CULL SOWS AND GILTS '/7X'SOLD'I3' HEAD AT'F6.1' POUNDS AVERAGE WEIGHT'/7X'SALES VALUE WAS'F7.2'DOL')

1906  WRITE(IJK, 1210) NSTOT
1210  FORMAT(/' TOTAL NUMBER SOLD TO DATE=' I5/ '====END SALES REPORT' 40(1H=))

If you’re programming-inclined, you can probably see how it’s a similar concept - inserting variables into a string. Some languages still require you to be explicit about how many characters the variables should take up, or how many decimal places you want a decimal number to have when you print it out.

The JavaScript example I gave above is far less demanding in terms of format. But as demanding as FORTRAN looks here, I came to discover it’s actually quite forgiving. At least with the help of modern tools.

Alright, after I typed everything out, I tried to see what it would take to get gfortran to compile the program. So I could run it on my computer.

There were a few hiccups along the way. I had made a few typos, for one (way fewer than I thought I would, though). And gfortran didn’t like the original “format” of the FORMAT statements. Because it was expecting quotes, where the original code has asterisks. That took a while to figure out, but my old programming books, and looking at example code online did help.

There are actually quite a few resources for modernizing old Fortran code. I’ll link them here for anybody crazy enough to be interested:

https://fortranwiki.org/fortran/show/Modernizing+Old+Fortran

https://www-uxsup.csx.cam.ac.uk/courses/moved.OldFortran/paper_2.pdf

https://www.matecdev.com/posts/fortran-legacy-code.html

Also, remember when I said that each line of code used to be a single punch card? Well punch cards looked like this:

A rectangular paper card with rows of numbers and small rectangular holes, with the name FORTRAN STATEMENT at the top

From Arnold Reinhold on Wikipedia

Now, good luck making much sense of that from the holes in the card alone. But one thing that is relevant is how many columns the card has. If you count the tiny little numbers at the top and bottom of the card, you’ll realize it has space for exactly 80 characters.

Traditionally, if you had a line go over 80 characters, you’d need another card, for a “continuation”. As long as you put the numbers in the right place, you could make the line keep going. This was especially useful if you had a long FORMAT statement that couldn’t fit on one card.

Three cards' worth of code technically make up one statement, due to the 2 and 3 placed before the second and third lines

A relatively benign example. I've seen FORMAT statements in this code go for 6 cards or more!

Anyway, as interesting as it was, I wasn’t really a fan of that. So I told the compiler not to cut-off lines over 80 characters. And I just reformatted any long statements, so they fit on one line. Like this:

fortran
706   FORMAT(//' FREE FORM IDENT CARD FOLLOWED BY DEFAULT DATA, USER OPTION CARDS '/' APPEAR AFTER CORRESPONDING DEFAULT CARD'//5X,10A8)

It’s a style choice, some people might not prefer it. But I bring it up because it goes to show how forgiving modern Fortran actually is.

The gfortran compiler has a lot of options, and the -ffixed-line-length-0 option let me write lines as long as I wanted them to be.

Some might call it messy, or bad practice, to allow for “non-standard” code like this. But I don’t think so. It’s think it’s a clever solution to a complicated situation.

You see, Fortran is a unique language. From its original creation in 1954 (you read that right) to the upcoming (as I write this) Fortran 2023, it’s a paradoxical amalgam of old and new ideas.

Some languages are “systems languages”. Some are “scripting languages”. Some are “application-specific” languages. I think Fortran is a modelling language. In its relative simplicity, it allows for the representation of complicated phenomena in succinct, mathematical terms. Whether it’s modelling an economy, a chemical reaction, an ecosystem, a rocket, a nuclear power plant, or indeed a swine farm, Fortran continues to justify its own existence in the minds of those who find it useful. I think there’s something really cool about that. Because you don’t necessarily have to be a programmer by trade to understand it, you just have to have to understand how to build mathematical models. And there are a lot of professions that involve mathematical modelling as an integral part of the job.

Many books have been written with the title “Fortran for Scientists and Engineers” and I think that’s fitting. It may not be an elegant language, but it’s mostly certainly a practical one. It’s a language that simply refuses to die out, even if it’s not as relatively popular as it used to be. Although when you think of it, there might be more Fortran programmers around today than there ever were. Because computer programming used to be a much less accessible art. It’s a fun thought, in my opinion, although I might not be correct. Nowadays, I think the Python programming language scratches a lot of the itches that FORTRAN scratched back in the day. I think there’s a good reason it’s so popular in data science and AI research circles. Maybe Fortran walked so Python could run?

Anyway, back to the story.

There was now one major thing holding me back from being able to compile this program. There were a few calls to functions that gfortran didn’t recognize. In other words, this was machine-specific code that was being called.

Once I realized this, I panicked a bit. See, while Fortran IV did have an actual “standard” specification, there were many little details that varied from manufacturer to manufacturer, and machine to machine. That’s another thing I’m glad we’ve mostly been able to move past. While there are still different CPU architectures out there (like i386, x86_64, arm, arm64, and now riscv to name a few) and different operating systems to target, a lot of “high-level” software has enough infrastructure supporting it that it can be cross-platform.

There are still notable hold-outs - like Apple - that want you to do things their way or the highway. But it’s a lot easier for, say, a web developer to reasonably presume their software will run similarly on most devices. But in some ways, some things never change - Firefox, Chromium, and Safari still have their differences.

Anyway, I had to make sure what machine this Fortran code was written on. Thankfully, that was mentioned in the paper.

The research model was implemented in the form of a computer program written in FORTRAN IV for the CDC 6500 computer at Purdue University.

Nice.

Actually, interestingly enough, I know the exact machine this program was written for. And it’s still around!

A massive, room-sized computer, with two desks each with a keyboard and two circular screens for operating, and a large collection of cables connecting various parts of the computer in the back
A close-up of the control panel. Two circular screens displaying green text, with several knobs below them, what appears to be a telephone to their right, and a keyboard below them

Purdue's CDC 6500

Unfortunately, the future of the Living Computers Museum and Labs seems to be in doubt, after closing in 2020. I’d love to go there someday, and see this beast and the rest of their collection in person, if that’s ever going to be possible. But as much as I can appreciate a computer the size of a room, I’m definitely glad we they don’t need to be that big anymore!

Anyway, knowing it was a CDC 6500, I was able to find a contemporary reference manual for CDC Fortran, which gave me enough information about the built-in machine-specific subroutines that the swine farm simulator used. So that was fortunate.

OCR was actually helpful this time, because it was a 429-page document, and I didn’t feel like looking through the whole thing to find a few code snippets. And it was a good scan of a well-printed document with actual words instead of just one big program, so OCR had a much easier time.

Let me just take a moment to ackowledge how amazing bitsavers.org is!

It’s an awesome site, with millions of pages of beautifully-scanned manuals, reference materials, and other documentation for vintage computers. I really appreciate the dedication to the preservation of computing history. And I’m sure the bitsavers project has saved many old computers from the scrap heap, by providing easy access to the original documentation.

Control Data Corporation Fortran Extended Reference Manual (6000 version 4)

Copyright 1971, so this checks out

fortran
C     ORIGINAL LINE WAS DAY=DATE(0), DATE() WAS A CDC FORTRAN BUILT-IN SUBROUTINE
999   CALL DATE_AND_TIME(VALUES=DATE)

C     ORIGINAL LINE WAS WRITE(NW, 998) NDAYS,DAY,RR
      WRITE(DAY,'(I4.4, "-", I2.2, "-", I2.2)') INT(DATE(1)), INT(DATE(2)), INT(DATE(3))
      WRITE(NW, 998) NDAYS, DAY

998   FORMAT(//18X,'SWINE BREEDING HERD SIMULATOR'//7X,'REQUEST IS FOR',I4,' DAYS,',10X,'TODAYS DATE IS ',A10/7X///17X)

In the above example, after I looked up what it did (although I probably could’ve guessed in retrospect), I re-implemented the original DATE() subroutine from CDC FORTRAN. This time using gfortran's DATE_AND_TIME built-in, and manipulated the return value so it would match what the program was originally designed to print.

There were a few other things like this, that I had to rely on reference materials, trial and error, and even a bit of ChatGPT for help with. Although I took what ChatGPT had to say with a handful of salt, but it did spit out a few useful ideas. It was definitely surreal to be using such a new piece of software to help me work with such an old piece of software!

Eventually, it all started coming together. In VS Code, errors showed up as red squiggles underneath the offending lines (much like spelling errors in Microsoft Word). I plodded away, changing as little as possible, while fixing what absolutely didn’t work.

Of particular note, I encountered a strange two-way arithmetic IF statement in a subroutine, that I learned was specific to CDC FORTRAN. I never saw something like that in any of my FORTRAN programming books, which only had three-way arithmetic if statements. And gfortran definitely didn’t know what to do with it. But I was able to simplify that part of the code, to remove it without affecting the functionality.

One last thing I had to change was any references to tapes. Yes, like tape drives. Or at least paper tape, I’m not exactly sure. I’ll touch on that in a bit, but one of the coolest things about gfortran is that it lets you use normal text files in the place of tapes. It’s just drop-in compatible - brilliant! So if the program needs to read from a tape, you can pass it a text file. If it needs to write to a tape, it’ll spit its output into a text file.

I felt like that was such a clever move on the gfortran team’s part. And I think it’s a bit of a microcosm of how Fortran became a “modern” programming language. While it has never had the reputation of being ahead of the game, Fortran has always found a way to keep up with the times.

Because honestly, what other language has survived so similar to its original form, and kept up to date, from the punch card era to the 2020’s? Even Assembly language has seen its fair share of changes, as new types of processors have come out. That’s not to say that the modern Fortran syntax is anywhere close to what it used to be. But the fact that you can still compile 50-year-old code with modern tooling and only a few changes? That’s huge.

As an aside, it should come as no surprise that the gfortran team is so interested in preserving the legacy of code from yesteryear, since it stands for “GNU Fortran”. GNU (which funny enough stands for GNU’s Not Unix) is a project spearheaded by Richard Stallman (beginning in 1983, ten years after this swine farm simulator was written). GNU’s philosophy has always been about carrying out the good ideas from the UNIX operating system (that was initially developed at Bell Labs in the late 1960s), but incorporating the idea of “freedom” into everything they release. As in, the freedom to use well-written, time-tested software however the user sees fit (more or less).

It sounds radical, and maybe a bit idealistic at first glance. But I think it’s no coincidence that the software GNU has released now underpins datacentres, Internet infrastructure, and electronic devices the world over. Most notably in the form of GNU/Linux. The way you can pretty easily trace the direct lineage of GNU’s software back to the ‘60s is kind of incredible. I can’t help but think of GNU and similar projects as ancient orders of monks and scribes, preserving sacred texts over the ages. It’s really not that different when you think about it - code is history, after all.

Interestingly enough, there’s a similar project to gfortran called “Open Watcom”, that’s still going fairly strong (although it is more niche). It carries on the legacy of a project that started with the WATFOR and WATFIV FORTRAN compilers released by the University of Waterloo back in the ‘60s and ‘70s. But that’s a story for another time. Although it’s fascinating stuff for someone like me who’s interested in Canadian computing history.

I’m getting side-tracked again, so let’s pick up with my story again, shall we?

Finally, after hours of tinkering (spread over a few weeks, because even I don’t have that much patience for this old code) I felt like I had achieved a major milestone.

I ran the whole thing through gfortran, and out popped a binary. For once I didn’t get any errors, and all seemed to have worked. Unfortunately, this was far from the end of the journey.

See, it was getting stuck in a loop. An infinite loop. Great…

So I tried going back to the drawing board. Maybe the input data wasn’t in the right format? Actually, no it wasn’t. I had originally just typed it out with tabs in between. Not realizing the annoying significance of the whitespace.

Here’s yet another way I don’t think the old days were better. See, this “Standard Control Data” was presumably originally printed onto a paper tape, which was fed into the machine when the program requested it. But because we’re in the post-tape era, I had written it all out into a text file.

But I eventually had to go back to the original page, try to make sense of the spacing (very difficult since the numbers were slightly crooked) and do my best to replicate what that would look like as a text file - inconsistent spaces and all.

Standard Control Data as of 9-17-72 - a page full of numbers with decimal points and spaces everywhere

Numbers. Numbers everywhere.

A screenshot of a code editor with 27 lines of many numbers, separated by varying numbers of spaces and decimal points

Yeah, no thanks. I'll take a CSV any day over this mess.

After all that, I think it actually worked. The program thankfully had a built-in method for outputting the control data, so you could check if it was inputted correctly.

And as far as I can tell, the control data was fed into the program successfully. So at least part of the program was legitimately working!

While I wasn’t ultimately successful at fixing the whole of the program, I don’t want to discount just how close I got. There were a lot of really fun, really interesting things involved in this process. And it was definitely worth a try, to get as far as I did.

A screenshot of several columns of numbers, outputting the control data

If only I could've formatted the control data like this in the first place...

Through the help of gdb, an incredible debugging tool (which stands for GNU Debugger, no less), and a VS Code extension that allowed me to step line-by-line through the FORTRAN code, I was able to get some insight into where exactly the issue causing the infinite loop was isolated.

While it ended up disabling most of the actual simulation, I was able to comment out a line, and that at least got the program to finish.

A VS code editor screenshot, showing a highlighted line of code, pause, play, forward, and stop buttons, and a list of variables with their values

Using gdb felt like bringing out the big guns. It found it really cool how such a powerful tool could be made to work with such old code.

I really wish I could’ve solved the problem, but I think it’s just beyond me at this point. Even line-by-line debugging doesn’t really help, because there are so many blasted GO TO statements everywhere.

For anybody who hasn’t been introduced to the joy horror that is the GOTO, basically it’s a way of moving from one part of the program to another. Now, that doesn’t sound so bad, until you realize that a significant portion of this codebase is GOTOs and similar things. Arithmetic IF statements for example, are technically three GOTOs joined together.

fortran
C     IF IAAM IS NEGATIVE, OR ZERO, GO TO 800
C     IF IAAM IS POSITIVE, GO TO 602
600   IF(IAAM) 800, 800, 602

So it ends up like a demented game of leapfrog, where you have to follow the code execution up and down the file, seemingly at random.

These days, it’s considered a poor practice, and most modern programming languages don’t have GOTO support. For good reason. But like many things, it was a product of its time.

As crusty and archaic as this code is, I can’t find it in myself to call it “bad”. It’s nearly unreadable by today’s standards, sure. But back then? That was par for the course. GOTOs were a necessary evil back then, because you were using punchcards. The rule was, at least in some ways - the fewer cards, the better. So, sometimes it made sense to reuse a portion of code in multiple places, by putting a lot of GOTOs that referred back to it. And if you were halfway into writing some code, and wanted to add a feature, you’d probably have to add a GOTO somewhere, to take you to a different line number. Or “label” as they were called back then - not every line had a label by default, and labels didn’t necessarily have to be in numeric order. They just had to be unique.

Good? Bad? It was the way things were done. Some things never change, because there are arguably still a lot of weird things we modern programmers take for granted. More than likely, we’ll look back on the way we wrote code in the 2020’s someday, and spot all the “anti-patterns” and “bad practices” that were just “the way things were done” at the time. It’s an interesting thought, indeed.

But really, what’s the point in critiquing something like this, as long as it works, and seems sensible at the time? Technology marches on, things and people change, and priorities shift. One has to wonder how much of today’s code will be able to be run in 50 years’ time?

I think in some ways, software has become more future-proof than ever before. For one, we’re not storing it on paper tape, or punch cards, or typewritten pages anymore! But with all the third-party libraries, and infrastructure, and platforms, and services today’s code relies on, it’s not as clear-cut as it seems at first glance.

Modern software development stands on the shoulders of giants. Anybody who’s been in this industry for long enough knows that. Even big tech companies know that, deep down, their empires are built on the backs of open-source projects with rich histories that span decades. In a way, that’s kind of cool. But it’s also somewhat concerning. What happens when those projects fall into disrepair? What happens when the altruistic open-source contributors giving of their time and effort can’t or won’t do it anymore? And what happens if the closed-source product or service you’ve spent the last decade building on changes their business model, or disappears entirely?

I think in some ways, there are no satisfying answers to these questions. Because there are no perfect programs. There are just varying degrees of “good enough”, and I for one don’t see anything wrong with that. But in the midst of it all, if you find yourself wrestling with these questions - you’re in good company.

Because there are always going to be people like the maintainers of gfortran, who embody the “if it ain’t broke, don’t fix it” lifestyle. Far from being stuck in the past, they think that what worked in the past should continue to work. Especially if it’s just math under the hood. They see the value in these tools, and they don’t believe that the passage of time has diminished it.

Sure, there are some pieces of software that are probably better off dead. But for every Adobe Flash, there’s a Ruffle project (https://ruffle.rs/) to keep the good parts of it alive. Well, maybe not for every Adobe Flash. Some software, for better or worse, will never have enough interest and support behind it to be resurrected. But then there are emulators, and virtual machines, and tools for decompilation and reverse-engineering. Although these efforts can only go so far, if developers and publishers of software keep it locked behind their “clouds”.

But hey, you could even get a crazy person an enthusiast like me to come along in fifty years, and try to spin up your code on their machine. If it’s out there somewhere. Stranger things have happened!


Another takeaway that I’d be remiss for not mentioning, is how this whole simulation is kind of morbid, to say the least.

I mean, the whole concept of reducing living creatures down to datapoints is inherently kind of weird. But the ways that things like culling, and breeding, and farrowing, and mortality calculations are so matter-of-factly stated is pretty macabre. Take a look at some of the comments in this section of code, for instance:

javascript
C BABY PIGS 1, AND 2-3 WKS. ADJ. WT.
C DAILY SURV. PROB. ADJ=.0049*DEVIATION BIRTHWT, SPEER REF.
4021  IF(IAGE + ISKIP - 22) 4023, 4023, 4022
4022  ISKIP = 22 - IAGE
      SKIP = ISKIP
4023  P = (PW23 + (0.0049 * (BRTHW - BWTM))) ** SKIP
      IF(IAGE-8) 4029, 4027, 4029
4027  ATRIB(2) = RNORM(GW23, SDP * GW23, -0.5, 10.0)
4029  G = ATRIB(2) * SKIP
      GO TO 4050
4007  P = (PW1 + (0.0049 * (BRTHW - BWTM))) ** SKIP
      IF(ATRIB(2)) 4019, 4008, 4019
4008  ATRIB(2) = RNORM(GW1, SDP * SW1, -5.0, 10.0)
4019  G = ATRIB(2) * SKIP
4050  IF(RANUM(0) .GT. P) GO TO 613

C IF SURVIVED, FILE.
4051  IATRIB(1) = IATRIB(1) + ISKIP
      IATRIB(9) = IATRIB(9) + ISKIP
      ATRIB(1) = ATRIB(1) + G
      GO TO 700

C SOWS OF HOUSE 4 I.E. IN LACTATION WITH BABY PIGS
4500  IF(RANUM(0) .GT. PSOWS ** SKIP) GO TO 4613

C SOW WITH 1 PIG OR LESS MOVED VIA TERMINATION TO HOUSE 6
      IF(IATRIB(8) .GT. 1) GO TO 4515
      IATRIB(6) = 6
      GO TO 6355
4515  IATRIB(4) = LTAL + ISKIP
      G = ATRIB(2) * SKIP

C SURVIVES, FILE BACK TO HOUSE 4.
      GO TO 4051

C LACTATING SOW DIES, KILL SOW, CHECK ON BABY PIGS WELFARE.
4613  NPIGS = IATRIB(8)
      NUSOW = IATRIB(5)
      MDEAD(4) = MDEAD(4) + 1

C ADJUST LITTER COUNT (KL4) IN FARROWING HOUSE.
      KL4 = KL4 - 1

C FIND PIGS, .LT. 7 DAY DIE, 50 PERCENT LIVE AFTER 7 DAYS AGE.
4623  CALL FIND(NUSOW, 5, 4, 8, KKOL, IN, VEN)
      IF(KKOL .EQ. 0) RETURN

I still don’t know exactly what to make of it all. On one hand, you could argue that this simulation represents the inherent cruelty of large-scale farming. But, as a fan of nuance, I’d rebut that this simulation is realistic, but not sadistic.

Coming from a long line of farmers (not that I’m anything close to a farmer myself) I can tell you that agriculture - especially animal husbandry - is inherently and necessarily morbid. But by and large, I wouldn’t classify farmers as a cruel lot. Modern farming equipment manufacturers like John Deere and their struggle against the right to repair, now that’s a different story. But farming is hard, risky, time-consuming, expensive, messy work - there’s no getting around it. Difficult decisions are the day-to-day, and I don’t imagine most farmers take them lightly. Because people need to eat, and there sure are a lot of us to feed.

Now, if you refuse to eat meat on moral or other grounds, I can totally respect that. It’s not unreasonable by any means. And I’m not arguing that there aren’t major issues with modern-day agriculture, especially relating to sustainability. But me personally, as the descendant of beef farmers, I love a good burger or steak. Or pork chop. Or cut of chicken, lamb, bison, turkey, quail, or venison from time to time. And I can live with myself, without feeling like a bundle of walking moral contradictions.

Although, I feel like the morbidity of such a computer program does make me think. Because programming is an inherently detached art. It’s so easy to disconnect from the aspect of reality that you’re representing with code or data. And how your code might be used by someone else, to do something you never wanted it to do. It makes me think of how a developer of a popular Node.js library ended up deliberately creating malware as a “protest”. It indiscriminately deleted all the files on computers with Russian and Belarusian IP addresses that installed it. He had become so sure of the morality of his actions, that he was willing to commit nothing short of cyber-terrorism, with just a few lines of code.

https://www.bleepingcomputer.com/news/security/big-sabotage-famous-npm-package-deletes-files-to-protest-ukraine-war/

And let’s not neglect the software that supports drone and missile strikes, facial recognition and “social credit” tracking, insurance calculations, online fingerprinting and user analytics, and loan applications. Because if it can be modelled with code, it probably will be. Even if those datapoints are human beings.

So, forgive me if I’m out of line, but I think this pig simulator feels pretty tame in comparison. Because as much as some of this did make me feel a bit uneasy to type out, I think the very fact that I considered the morbidity of such a program indicates that I still have something of a moral compass. And I never want to get so detached from the reality that my code represents, that I lose sight of my moral obligations.

Anyway, rant over.

Good question. Honestly, I don’t know. I wasn’t able to fix the infinite loop issue, so the simulator itself isn’t 100% functional. I was, however, able to get it to print out most of its reports, even if they’re mostly empty. It feels like a bit of a tease after all this work, but at least it’s something. Because I genuinely didn’t know if I could get this far. This is pretty good for 50-year-old code I typed out from an old scan of a typewritten document, I’d say.

The output of the simulator program - tables of numbers separated by headings and descriptive text

This is as close as I've gotten

Maybe someday I’ll figure out what the remaining issues are with this code. I’d imagine they have something to do with the COMMON statements, since some of them don’t exactly make sense.

While I’ve kept the vast majority of the code intact from the original (other than the things I had to tweak/retrofit to get it to compile), I had to modify a couple of the COMMON statements or the program wouldn’t compile. I haven’t been able to tell, if that was a typo in the original document (unlikely, but possible for something this long), a lack of understanding on my part (quite likely), or a quirk of CDC FORTRAN that allowed for different formats of COMMON statements (no idea, but possible).

Global/shared variables, with seemingly conflicting names and data types, are incredibly difficult to debug. So maybe that’s the issue, or at least one of them.

Maybe I tweaked/retrofitted something that broke the system, because I took it too far. Again, unlikely, since I was quite careful and experimental in my approach. I only changed one thing at a time, and tested any change to the best of my ability, before implementing it in the code.

Maybe there are still one or more typos somewhere, from the original document or my transcription of it. Definitely possible, given how many pages of code we’re talking about. Or maybe I messed up the format of the input data? Although that seems unlikely, given how the self-test seemed to confirm that the program was properly ingesting the input data.

Either way, I might never figure out what’s wrong, and get this 100% working again. Maybe with the help of AI, but good luck training an AI on something like this. I just don’t think there’s enough surviving reference material out there, for FORTRAN IV, for an AI to be any good at writing or debugging it. Kind of hope I’m wrong though, that would be cool. Maybe the secret is hidden somewhere in the paper itself. But I’m not super scientifically-literate when it comes to reading complicated papers, Although hey, maybe I could ask an AI to explain it for me!

Or, maybe someone else will come along in the future, find this project online, and fix it, like I tried to in the first place.

But in the end, does it really matter? I don’t know. Because I tried. And maybe it was a losing game anyway, something too difficult to be worth it. But either way, I don’t think it was an exercise in futility. Because, at least to me, I found this whole project to be a great experience. I got to learn a lot of history, play around with old tools in new ways, and get a feel for what it was like to be a programmer in the early ‘70s.

No, I don’t want to go back to the days of punch cards, and paper tape, and mainframe time-sharing. But I’ve gained a new-found appreciation for what it took to do anything with a computer back then. And how, despite the many differences, I couldn’t help but feel a strong sense of familiarity. Like I had forged something of a bond with the programmers of the past. A weird, anachronistic perspective of a half century of human progress, distilled into a couple of weeks of experimentation.

I think if nothing else, I’ve gotten a bit more optimistic about the future of the programming profession. And the future of the code I write today. Because sure, some things will be forgotten, or rendered completely alien and obsolete to future generations. But I think as long as there’s an attempt to preserve “what works”, and to communicate with the developers of the future - through code that’s well-documented, well-commented, and relatively easy to understand - I think we’ll be OK.

Because this is basically the “worst-case scenario of old code” - a complicated, obscure, 50-year-old agricultural simulation, written in a language that was showing its age at the time, using punch-card era conventions like GOTOs, short variable names, and very concise logic. If something like that can be almost resurrected by one self-taught programmer with the help of a code editor, compiler, and a few reference books, then the worst is probably behind us.

But, I at least wanted to preserve this project a little better. So I put it on GitHub:

https://github.com/mtpiercey/cyberpig-1973

If you’re crazy enough to check it out, be my guest. At least it’s far less likely to completely disappear into obscurity now. So I feel like I’ve done something to fight back against the forces of digital entropy, dragging the forgotten corners of our digital history into oblivion.


I’ll close with some excerpts from the paper where this program originated, which really show how far we’ve come in the last fifty years. I really think Dr. Strom was ahead of his time, for even attempting something like this in 1973. And while I wish my attempt at digital archaeology was 100% successful, it was a unique experience that I’ll never forget.

Simulation techniques have useful possibilities for application in research, but this study has shown that they can be used to the point where they tax the limits of even present day computing equipment.
It appears that the very complex nature of daily swine production cannot be represented realistically in a sufficiently abstract way to run such a model in less than, say, 100 seconds for use in a routine extension application.
Execution of the program with the standard control values for one year of simulation required 1370 seconds of Central Processing time on the CDC 6500 at Purdue University. Other problems... have used much greater amounts of execution time.
An input-output bottleneck was experienced in debugging and running test runs with the program... A means of saving a partially completed run for a rerun... would have facilitated debugging and reduced the amount of time used in debugging the program.

Funny how this still rings true, but on a much grander scale than what was possible back then. I could definitely see a modern AI researcher saying something like this.

So to all you current and aspiring programmers out there, keep your head up. Be grateful for what you have, respect the accomplishments of those who came before, and be sure to keep the future in mind, as you write any sort of code.

Who knows, it might end up being unearthed some day. Or it might become a part of something much greater that ends up standing the test of time.

Just write code that you can be proud of, and don’t take it lightly. Don’t disconnect so much from the reality of what you’re modelling with code, that you neglect its potential moral implications. Strive to always be part of the solution, never the problem. But don’t obsess over the future, or worry too much about your career, or get caught in a cycle of cynicism about the state of the software industry. Because it’s always been tricky. It’s always been messy. We’ve always faced limitations - of the tools we use to write our code, the computers we run it on, the minds we use to come up with it in the first place, and the documentation and resources available for better understanding the tasks placed in front of us by ourselves or others.

And that’s OK. Because in spite of it all, it’s worked out so far, and I really think it’s going to continue to work out. There are always going to be people dedicated to holding up the fort, and making sure our tools are fit for the task. And there’s a wealth of freely-available code that’s been shared and developed over the decades. Good ideas die hard these days, if they die at all.

But maybe you don’t consider yourself a programmer by trade. Maybe you’re just someone who uses computers as a tool to do other things. Like science, or engineering, or mechanics, or simulation, or data analysis. Or agriculture. Well, there’s a place for you here, in this crazy world of coding. There are tools out there, if you’re willing to look for them. I definitely wouldn’t recommend FORTRAN IV as a first language, but a more modern version like Fortran 2018 might be worth a try. Or R, or Julia, or more than likely Python.


So, thanks for following my journey through all of this. It was a lot of fun to document, even if the end result wasn’t what I had hoped for initially. Live and learn, I say.

Either way, learn to code, and you’ll only ever be bored, if you stop trying new (or old) things!

Tech used to make it: