#BabelOfCode 2024
Week 4
Language: FORTRAN

Confidence level: High

PREV WEEK: https://mastodon.social/@mcc/113867584791780280
NEXT WEEK: https://mastodon.social/@mcc/113975448813565537
RULES: https://mastodon.social/@mcc/113676228091546556

I was very excited about doing TCL this week, but I told myself the first time I get a two-dimensional array problem I'd go FORTRAN, so I guess this week is FORTRAN.

A friend of mine who did AOC2024 in December noted the early challenges this year were *very* easy. Today's definitely is. I wonder if part 2 will have any depth.

I went into this thinking: C is basically cleaned up FORTRAN, right? I know C? This should be easy, right? Right off the bat I find there will be a lot of difficulties entirely not of the kind I'm used to in programming. After a brief adventure with accidentally naming my file .f and not .f90 causing horrific and baffling errors, I run a hello world off the Internet. There's a space before the printout. Hm, how do I turn that off?

https://stackoverflow.com/a/31236043

Oh my fuck, *what*?

How to get rid of unwanted spacing in Fortran's print output?

It may look like a trivial issue, but I couldn't find any answer through googling. I have this little program : Program Test_spacing_print Integer:: N Real:: A,B N=4; A=1.0; B=100.0 prin...

Stack Overflow

I get frustrated with C all the time for being fundamentally a 70s language. It may be I'm about to learn the pain of using a *50s language*.

(Alternately, I hear modern FORTRAN has all kinds of fancy niceties like operator overloading and might not resemble traditional FORTRAN all that much. But then I have the problem if I pick up a random tutorial it's hard to guess which *decade's* standard it's teaching me from, or if it's the GNU extension, if the GNU extension is that different, etc.)

Just learned FORTRAN has an aint() function

Don't that just beat all

I am getting a weird floaty feeling from FORTRAN. I do not at any point really understand what I'm doing, but I am having little to no problems having any one particular thing. I keep doing google searches and getting which I do not understand the syntax of ( `write(error_unit, *) "String to write"`— wait, what? but which work. I do not know if I'd be able to get anywhere with this language if I didn't have either a more experienced programmer or Google+Stack Overfow.

Here is my current program. At the moment, all it does is take a command line argument (a path) and attempt to open the specified file. I build it with `gfortran src/puzzle.f90 -std=f2023 -o program`

https://github.com/mcclure/aoc2024/blob/822e460f81b944c21ca675303b868c45b22a4c2b/04-01-wordsearch/src/puzzle.f90

I'm having two problems, one serious, one unserious.

The unserious problem: I want to abort if the # of arguments is bad. If I do "error stop", it prints a backtrace, which I didn't ask for. If I do "call abort", gfortran fails to link ("undefined reference to 'abort_').

aoc2024/04-01-wordsearch/src/puzzle.f90 at 822e460f81b944c21ca675303b868c45b22a4c2b · mcclure/aoc2024

Advent of Code 2024 challenge (laid-back/"babel" version) - mcclure/aoc2024

GitHub

Here's my serious FORTRAN problem (code link in previous post):

The recommended GET_COMMAND_ARGUMENT function seems to assume you know the length of the argument ahead of time. Obviously, I don't.

https://gcc.gnu.org/onlinedocs/gfortran/GET_005fCOMMAND_005fARGUMENT.html

It allows me to pass in an `allocatable` string, but I believe it is leaving that string of length 0 if I do not ALLOCATE() it, and the fetched string is ''. Is there a way to get the length of a command-line argument before GET-ing it?

I see GET_COMMAND, but that's… awkward

GET_COMMAND_ARGUMENT (The GNU Fortran Compiler)

GET_COMMAND_ARGUMENT (The GNU Fortran Compiler)

…hm. I am concerned.

According to the FORTRAN working group

https://wg5-fortran.org/N2201-N2250/N2212.pdf

As of the 2023 standard, an un-allocated deferred-length variable may have its length set by calling intrinsic procedures; they give GET_COMMAND as an example specifically, and StackOverflow users assert GET_COMMAND_ARGUMENT is also included.

I don't get this behavior. My argument is being input as ''.

Do you think this means my code (linked above) is wrong, or that gfortran -std=f2023 is nonconformant?

Oh my hell lol, I sincerely believe I have found a bug (standard nonconformance) in GNU FORTRAN 14.2.0 and I have a repro case

https://github.com/mcclure/aoc2024/blob/b31be91adb5a0721f97e2ba8f145da4f36129753/04-01-wordsearch/src/puzzle.f90

Am I going to have to figure out how to report a bug on GNU. Geez. Is this going to be like the bureaucracy planet scene in Jupiter Rising

aoc2024/04-01-wordsearch/src/puzzle.f90 at b31be91adb5a0721f97e2ba8f145da4f36129753 · mcclure/aoc2024

Advent of Code 2024 challenge (laid-back/"babel" version) - mcclure/aoc2024

GitHub

Now that I have successfully figured out how to read an argument from the command line without knowing its length ahead of time, I am stuck on figuring out how to read a line of text from a file without knowing its length ahead of time. Apparently not an expected FORTRAN use case. I think the trick I was using before will not work, or at least, I *think*

read(10,"(a)",size=line_length,advance='NO') line_in

should read a line without advancing the filehandle and save the size. But it saves 0.

This is the second time in the longform challenge I have found myself having to implement fscanf() [the other time was Forth]. Both languages do predate C, but I was hoping both would have, at some point in the last 55 years, realized "oh… people want to be able to input line-delimited text files" and added such a feature.

Incidentally, I am very comfortable usually with reading language specifications, but I got hold of a copy of the FORTRAN 2008 spec and… this is one of the least friendly language specifications I've ever seen, when reading it to try to determine how a program should be written.

(Trivia: When the image on the right says something like "the value must be YES or NO" what they mean is "the value must be 'YES' or 'NO'.)

FORTRAN 2008 spec 9.1:
"A file is composed of either a sequence of file storage units (9.3.5) or a sequence of records… A file composed of file storage
13 units is called a stream file."

The definition of "file storage units" (9.3.5):
"A file storage unit is the basic unit of storage in a stream file or an unformatted record file."

The linked definition of "Stream file" (1.3.139)
A file composed of a sequence of le storage units (9.1)

YOU ASSHOLES, THIS DEFINITION IS CIRCULAR!

Like okay I understand what you are trying to do here is not commit to a particular byte length because you want to support 7-bit bytes, 8-bit bytes, and possibly UTF-16 characters or something, but YOU COULD HAVE *SAID SO* INSTEAD OF MAKING A LOOP OF 3 DEFINITIONS LINKING TO EACH OTHER

git discovery: you cannot check a file you do not have permissions to into a repository.

problem: my repo contains a directory of test files. this directory contains a second directory of "invalid" tests, i.e., tests that the program is *expected* to fail on (and if it doesn't fail cleanly that's an error). one of the "invalid" tests is a file the program doesn't have read permissions to.

I cannot check my "file with no read permissions" test case into the repository :(

Since automatic deferred length initialization is not working as the spec seems to require, I decided to just read the file in line by line.

This was much harder than I expected! The GNU docs do not well describe READ/WRITE, but do well describe the standard library functions. So I wrote around FGETC(), but then it turned out this is a GNU extension (or possibly was in FORTRAN 77 but not future FORTRANS?) so I had to rewrite to use normal READ in "Stream mode"… not in the GNU docs * _ *

(1/2)

I wound up slowly picking my way through the 2008 language spec, as previously mentioned not super readable. But I got it to work:

https://github.com/mcclure/aoc2024/blob/a8835dcd8ad0162268ef16708f9a7cd8b6d45958/04-01-wordsearch/src/puzzle.f90

Annoyed I had to spend all this time just doing file management, I decided to do the file management REALLY WELL. It's got unique error messages for different types of file handling errors and everything!

Now if only I could make gfortran suppress that darn `error stop` backtrace..

(2/2)

aoc2024/04-01-wordsearch/src/puzzle.f90 at a8835dcd8ad0162268ef16708f9a7cd8b6d45958 · mcclure/aoc2024

Advent of Code 2024 challenge (laid-back/"babel" version) - mcclure/aoc2024

GitHub
By the way, check out this vaguely hilarious section from the FORTRAN 2008 spec, where they state in the *most noncommital terms possible* that a byte is *probably* 8 bits (they don't say "byte"; they don't like the word "byte"; the word "byte" appears exactly twice in the 621-page spec, both times in the C interoperability section) then have this long additional note falling all over themselves to apologize for the hubris of suggesting that a byte is probably 8 bits.

A reply I got on a previous post in this thread suggested that the reason the FORTRAN spec is so strict about using the word "file storage unit" instead of the normal terminology "byte" is that FORTRAN is from 1957 and literally predates the world at large adopting the vocabulary "byte" for the minimum addressable storage in a filesystem. Well, geez. That might really be it.

(Also note FORTRAN's commitment to line numbers is so great that even the English text of the spec has line numbers.)

An interesting thing about the gfortran compiler I've never seen elsewhere… when it wants to mark the position of an error on a line, it has a little ASCII art arrow like Rust or Clang. But instead of an arrow it uses a number 1, which lets it say "blahblah wrong at (1)". It takes a moment to get used to, but it's actually really smart. If you think about it it creates the potential for sentences like "found glarg at (1), but expected blarg because of (2)". rustc struggles with such sentences.

So the reason I picked this puzzle for FORTRAN was I heard FORTRAN's builtin multidimensional array types were nice. I probably won't be truly making deep use of those in the end, but I'm at least learning one thing from the experience: FORTRAN's builtins are *not* especially nice for *growable* arrays, regardless of dimension. You can *do* it, but it's not efficient or super friendly. I realized my growable implementation would be O(n^2) on file size, just to read the file into memory.

(1/2)

Fortunately, I can make everything easy again by just scanning the file to determine the size of the multidimensional array I need to allocate, seeking back to the beginning, then actually reading the array in. It probably sounds to you like I just made a very basic statement. But something to make clear: fseek() is actually considered a very advanced feature in FORTRAN, and was only added to the language in 2003 (in other words 46 years after the language was first specified)

(2/2)

Decided to do a bit more on the FORTRAN project this morning… found myself running in circles for a decent bit trying to understand why code wasn't acting the way I expected. I eventually realized the problem was that when I wrote the expression `char_in == '\n'`, this was behaving differently than I expected because '\n' is a string containing a backslash followed by an n. Of course it is. Of course? Why would I have expected it be anything else?
On a related note, shortly after this I was in a situation it would be convenient if I could cause a particular loop iteration to abort and resume from the beginning of the loop. I experimentally typed "continue". It was accepted. I run the code. It does not behave as I expected. I go to look it up.
(So there's no confusion: I think this is a fine feature for a language to have, I think every language should have a "no-op" keyword, it's basically the same as Python "pass" and exists for the same reason [as a target for otherwise-productive flow control] [GOTO labels must point to statements, so you need a way to write a statement with no effect])

OK so

I am using the stream input mode for my file input (this freaks the fuck out of every FORTRAN programmer on this site, but)

I need to seek to the beginning of the file. A stack overflow comment suggests this is done with

read(10, "()", advance='no', pos=1)

gfortran prints

runtime error: Format present for UNFORMATTED data transfer

I remove the "()"

read(10, advance='no', pos=1)

Compiler balks

Error: the ADVANCE= specifier at (1) must appear with an explicit format expression

WDID

Man if I found a second case where GNU Fortran failed to implement the standard standardly I'm gonna be annoyed

My fuzzy read of the standard is that the "()" version above is probably inaccurate, but the version without the "()" should probably in this case compile.

I'm actually kinda stuck here, and this (the ability to seek within a file) is a banner feature of the post-2000 STREAM mode, so I think: I wonder if there's a Discord, IRC, otherwise realtime communication channel for FORTRAN programming I could tap.

https://fortranwiki.org/fortran/show/IRC

*squeaking* "No… no!!!"

IRC in Fortran Wiki

There are some ways that being stuck in 2008 are good but this is not one of them!!

I successfully worked around gfortran's apparent refusal to do a nonadvancing read by having my actual read look like

if (row_at == 1 .and. col_at == 1) then
! If we detect this is the first character of the file, reposition
read(10, iostat=file_error, pos=1) char_in
else
read(10, iostat=file_error) char_in
end if

But I really, really, *really* hate it

I am experiencing confusion about apparent disjoint between docs and behavior. Is the following correct?

! This allocates a matrix "board" of COLS columns and ROWS rows
allocate(board (cols, rows))

! This writes to the "bottom right" cell of board
board(rows, cols) = 1

Everyone agrees FORTRAN is column-major in memory but get vague about syntax (lots of examples where indices are named "i" and "j"). I get incorrect behavior if I DON'T swap rows,cols order between allocation and write/read.

Blghgafhg part 1 done. This was the longest any part 1 took me of this project so far, but I think that was mostly… external distractions, happening this week. Gonna do part 2 before I share my thoughts (part 2 is really simple but I'm going to do it a little more complicated than it has to be just so I have an excuse to do some vector math in FORTRAN)

All right.

Part 1: https://github.com/mcclure/aoc2024/blob/ca77f141f33ab494dc1bb43f3d6f13e775a36303/04-01-wordsearch/src/puzzle.f90

Part 2: https://github.com/mcclure/aoc2024/blob/ca77f141f33ab494dc1bb43f3d6f13e775a36303/04-02-wordsearch/src/puzzle.f90

Did I learn anything from this? I guess. Yeah. Okay, I guess so.

That wasn't particularly unpleasant. The ergonomics weren't great, but were not-great in forgivable ways. The fact each tutorial/doc/StackOverflow answer I found targeted a different FORTRAN std was definitely frustrating. I got to add an array to an array on two (2) lines of part 2, and other than that this was basically funny-shaped C. C with paperwork

aoc2024/04-01-wordsearch/src/puzzle.f90 at ca77f141f33ab494dc1bb43f3d6f13e775a36303 · mcclure/aoc2024

Advent of Code 2024 challenge (laid-back/"babel" version) - mcclure/aoc2024

GitHub

The v.a.s.t. bulk of the time here (and in the simpler part 2, the bulk of the code) was spent on file I/O. In the 4 weeks of this project so far, I skipped file i/o (instead embedding the data in the program) for BASIC and ASM, since those are languages with Limitations, and for Forth and FORTRAN I assumed those were Fully Featured so I could just do file i/o. But no, on both Forth and FORTRAN simple file i/o was *a nightmare*, the bulk of the work.

(1/2)

There's an awkward irony here.

For the Forth week, the input was a list of ASCII numbers. *This* kind of input FORTRAN had easy-to-use builtins for, but Forth had nothing and I had to build it myself.

FORTRAN week, the input was a grid of ASCII characters. *This* Forth could have handled pretty easy, but FORTRAN it's actually sorta impossible unless you use a modern (and, apparently, not completely tested in gfortran??) "stream" mode, which took forever and required consulting the spec. (2/2)

I got a lot of good help this week (FORTRAN) so, thank you everyone.

I guess that's one "month" of the project down. Here's my completion status.

(Note there are 43 languages on this list, and 25 puzzles in AOC, so only a little over half will get hit by the end. My "for certain" list is: TCL, Haskell, Idris, Smalltalk, Self, Ada, Factor, Mirth, Uiua, at least one of ARM and RISCV.)

I'm not doing the Babel-of-Code challenge this week but Andrzej has his writeup of his Prolog week up

https://mastodon.gamedev.place/@unjello/113935017360726890

and has started a thread for his week with Lean:

https://mastodon.social/@unjello@mastodon.gamedev.place/113935056291728976

Andrzej Lichnerowicz (@[email protected])

All right. It was a bit better than I initially expected. After a bit of fighting and mind bending, a Prolog solution is up https://andrzej.lichnerowicz.pl/en/blog/solving-aoc-in-prolog/ #BabelOfCode #BabelOfCode2024 #prolog

Gamedev Mastodon
@mcc Julia is kinda cool, though I've only played with it a bit. It's fairly new and has been rapidly improving. Worth checking out, I think. Best for the more numerically oriented problems.
@not2b I actually around 2013 auditioned Julia as my new scripting language to replace Lua. It was interesting but once I realized I couldn't embed it in an executable without embedding the 44MB entirety of LLVM I walked away. This, along with difficulties getting the Clasp compiler to run on my old laptop, was what eventually lead me to create Emily (a language that turned out unsuitable for games as the one game I wrote in it initially ran at 1 FPS)
@mcc That has changed with newer versions.
@mcc Tcl is so fun, what an odd little language
@capn_b i actually kinda need to learn that one

@mcc the tutorial on tcl.tk and the O'Reilly book are how I learned

https://www.oreilly.com/library/view/tcltk-in-a/9780596803520/

Tcl/Tk in a Nutshell

The Tcl language and Tk graphical toolkit are simple and powerful building blocks for custom applications. The Tcl/Tk combination is increasingly popular because it lets you produce sophisticated graphical interfaces … - Selection from Tcl/Tk in a Nutshell [Book]

O’Reilly Online Learning
@mcc I'm so curious to see how TCL, Haskell, and Smalltalk go 😄
@megmac this is gonna be my like third or fourth attempt at haskell, and i've somehow been reading smalltalk tutorials since the year 2000 without ever actually writing a line of it

@mcc I think all three are really great "platonic ideal" languages of their respective paradigms but that makes them kind of low key miserable to use in practice so that checks out.

(But I have also never written Smalltalk in any significant amount. The whole "image" thing makes me uncomfortable)

@megmac The whole "every program is a little VM snapshot that can be live-edited" sounds cute if you value end-users being able to customise the software they use. But from a professional software developer perspective, it sounds like a nightmare for change management, auditing, understanding *why* a particular line of code exists.

@megmac @mcc I'm looking forward to COBOL. Mainly because I've been playing around with it recently.

It's remarkably not terrible in some ways (and very annoying in others). In fact, the aplit between nice and horrible appears to be exactly opposite that of FORTRAN.

@loke @megmac I don't promise I'll do COBOL.
@mcc @loke @megmac Rumour has it that the compiler course at Lund University now has an explicit "no COBOL" clause for implementation language, after one fateful time, when a student wrote a C compiler in COBOL and handed it in.
@vatine @mcc @megmac Why not? There's a minecraft server written in COBOL. The language itself is, well, different. But if everybody is only supposed to learn ALGOL (albeit with slightly different syntax, as C, Javascript, etc) then what's the point?

@loke @mcc @megmac I think the lecturer at the time didn't know COBOL and so could not adequately rate the handed-in code (other than "works" / "doesn't work", which I would suspect is not the level of detail desired).

There's nothing I am aware of that would've blocked handing in a compiler written in Forth, Scheme, Common Lisp, or (although I would question the sanity of the student choosing to) RPG II.

@loke
Heretic.

COBOL is (very irrationally) the reason why I don't do Python these days.
@megmac @mcc
@mcc Ooh, I hope you get to one or more of Tal, Gleam, and Zig, those have all been really fun to learn!
@soxfox42 there are several reasons I should learn Zig.
@mcc I did a lot of work in Ada back in the day, so I’m keen to see what you do with it.
@mcc I was just reminded of the existence of xslt and I think you should add that to this list if you've never used it before.
@megmac I actually made a good faith effort to implement a lambda calculus evaluator in XSL/T once
@mcc The good news for when you decide to do Haskell is that it has a powerful parser library (Text.Parsec) built-in to the language.
@mcc That doesn’t seem right to me, I expect the indexing to be the same ordering in allocation and indexing.
@mcc low level libraries are made of hate
@mcc The UK research software engineering Slack has a Fortran channel, you can request to join at https://docs.google.com/forms/d/e/1FAIpQLSdqs-_QNwQFzCIUEafah91E5E00lGUEnTPC4jjYbGUqPjONwA/viewform
Request Slack Access to the RSE Space

Please fill in this short form and submit. One of the Society Membership Trustee team will action your request asap. Please note, the Society is managed by volunteers and it may take a couple of days to process your request. If access is urgent, please email [email protected] and one of the Society trustees will action your request that day. We ask for your name, organisation and job title to ensure that you are a real person with an interest in research software engineering. Once you have been added to slack, this data is deleted from this form/spreadsheet. If you are from industry please make sure that you have read our "Rules and Etiquette for Responsible Corporate Engagement on our Web Platforms" within our code of conduct on our Socity website. https://society-rse.org/about/rules-and-etiquette-for-responsible-corporate-engagement-on-our-web-platforms/

Google Docs

@h0m54r Heh, neat.

Given this still requires a roundtrip before I can post a question, I might just go ahead and finish this with workarounds and then email the GNU mailing list.

@mcc (Actually, thinking about it, UKRSE is also in the process of taking on on the Fortran standards working group from the British Computer Society, so it makes sense as a home for discussion. I know some channels on that server are bridged to Matrix, but I don’t think the Fortran one is currently unfortunately)

@mcc

Completely irrelevant to your question, but you made me smile as I recall being (what I believe to be) the first person to compile NASA GISTEMP climate index in gfortran back in 2008.

@mcc "I am using the stream input mode"
*runs away screaming before you finish the sentence*

@mcc Did you try:

read(10, pos=1)

That's what the example code for stream I/O seems to use.

@mcc I wonder if it could have also been useful as something that could have easily been replaced with a GOTO as a patch without having to redo a ton of paper tape or punch cards long ago.
@foobarsoft @mcc
paper tape would need to be repunched, but punchcards, indeed, just adding a card into the stack as a bug fix was quite convenient (no, I'm not very old, I just grew up in a backward place called USSR, and so I learned to program on a Soviet clone of IBM360/370)

@dimpase @mcc I’ve never handled either, but I thought maybe it would be possible to punch a small replacement section and splice it in, but by having the previous statement there it wouldn’t mess up the line numbers.

I don’t know if splicing paper tape was actually possible or done.

@mcc RTFM would save so much stumbling in the dark. Why do you do this to yourself?
@hyc I have no idea what you are trying to communicate here. The screenshot above is literally a screenshot of the manual.
@mcc I mean read the language text thoroughly before trying to write it. Instead of guessing and looking up your mistake after the fact.
@hyc Typing a nine-letter word, identifying that the syntax highlighter didn't bold it which is suspicious, and running the program once to see what happens is not exactly a substantial investment of time.
@mcc you see, it continues executing the code as requested