The time has come to convert all existing C code to something more modern. I have begun working on this effort in the context of the Apple ecosystem. My first stream of work is the POSIX commands that live in /usr/bin and /usr/libexec (and /bin and /sbin). I have converted much of the repository https://github.com/apple-oss-distributions/shell_cmds to Swift (here: https://github.com/r0ml/swift_shell_cmds ). Apple has numerous other similar repositories for other commands, and I'll be applying what I've learned from this first attempt to modernize more of them. But let me back up and explain what motivated me to embark on this journey.

It all started with the idea that "AI can write code". As a philosophical matter, it seemed to me that the most appropriate use of such technology would be in modernizing legacy code. As technology evolves and new software paradigms appear, organizations are faced with the challenge of adopting those new technologies and paradigms – and replacing their existing processes. The two approaches are to: a) write something new from scratch and abandon the "legacy", or b) modernize the "legacy" and then enhance it. Even the complete rewrite can be considered a modernization project, since existing business rules and existing interfaces to other systems and existing databases and existing tests must needs all be preserved – even if all the code is replaced.

I've been involved with those transitions, and there have been a never ending stream of them. From COBOL to C, C to C++, C++ to Java, Java to Javascript, Java to Python, Python to Go – and that's just the programming languages, not to mention the operating systems, databases, architectures, and paradigms.

Anyway, it seemed to me that automating code modernization had the advantage that one could automatically compare the converted code to the original code and determine if the effort had been successful, whereas if automation produced new code for a new application, determining whether the output was "successful" was a more subjective exercise. So modernization would be more amenable to automation.

Armed with this hypothesis, I selected an Apple repository of legacy code and experimented with converting it to a modern programming language (Swift) using an LLM (ChatGPT). The results were mixed. On some commands, the automatically produced Swift code was pretty good – it felt like I could fly through the code base. But on some commands, the automatically produced Swift code was so wrong, that figuring out what went wrong and correcting it was more time consuming than had I just manually converted the code.

One reason for this was if the original code had programming constructs for which no modern equivalent existed. The simplest one to explain (and one that really tied the LLM into knots) was goto. If the C code had goto statements, then what was the equivalent Swift code? The programming paradigms under which C was designed have aged to the point where modern programming languages have no corresponding features for many of the original idioms. Processing strings by using a construct like *p++ and comparing the result to 0 or to other pointers assigned along the way doesn't map well onto string handling in a modern language. (Remember how much fun the transition from bytearrays to encoded strings was in Python 3?)

Automated translation from one modern language to another modern language would probably have a higher success rate, as the existing popular programming languages have been converging on common capabilities. So, in order to get to an automated "continuous modernization" future, we have this one final lift to move off of C into the present century.

The other main idea that motivated this endeavor was my retirement. As you may have gathered from the long list of software transitions I've been involved with, I've been doing this for a long time. So long, in fact, that I retired a few years ago. Aside from the fact that this gives me more spare time to work on hobby programming projects, it underscores the fact that the people who came of age writing software in COBOL (and C) have reached (or are approaching) retirement age. I would argue that COBOL (and C) have also reached retirement age. C was released in 1972; K&R was published in 1978. (Someone who started working at 22 years of age in 1978 would now be 68 years old.)

Many C programmers are quick to argue that COBOL programs should be modernized or decommissioned because it is becoming impossible to hire or train someone to work on COBOL programs. Who would want to invest career time in COBOL when it so clearly has very little future? To those programmers, I quote Matthew 7:3.

The C programming language is about 15 years behind COBOL in the retirement timeline. The fact that C is a "portable assembly language", which made it seem like such a modern and attractive language in the 1980s, is no longer such a great draw. The modern programming landscape is converging on "platform" languages: most major platforms have settled on their preferred programming language – with Linux the last polyglot holdout. Portability between platforms is now gated by the available APIs; no longer the CPU instruction set.

Swift is not yet a candidate for replacing the Darwin kernel – but it is certainly capable enough to replace many (if not all) of the shell commands. Additionally, if all of that code were available as a Swift library or package, many tasks which are currently implemented as shell scripts could be implemented as Swift commands. (My implementation provides a Swift package for all the executables, and will one day package the functionality as a library.) Many of the commands merely provide human readable interfaces to libc or other library functions. Those libraries are still mostly written in C, and once the shell commands have been moved to Swift, the libraries will be the next project.

Anyway, I'll be chronicling my adventures in replacing macOS commands and libraries written in C with Swift translations. I'll be talking about which constructs in C seem to cause confusion with LLMs, what features of the Swift ecosystem are helpful (or cumbersome) in this process, other side projects which might be inspired by this endeavor, and any other learnings I stumble upon along the way. If you have any ideas about which libraries or commands you would like to see converted to a Swift package, let me know.

Retiring C