Advent^2 of Code continued

In the earlier post about a spiced up Advent of Code challenge, I wrote about interfacing with the Apple Newton MessagePads as a nice all around task for learning and test driving programming languages.

Back in the days, Apple provided the Desktop Integration Libraries for Classic MacOS and Windows to synchronize data between desktop and MessagePad computers.

After the Newton’s cancellation, Paul Guyot, Michael Vacík and Nicolas Zinovieff set out to implement a full replacement, and adding more functionality, as well as covering also POSIX platforms in the form of the DCL.

Ruby

The DCL unfortunately does not support Windows natively, so I set out to see how something similar can be created using Ruby, resulting in the RDCL. Ruby turned out to be quite pleasant to work with, but one challenge back then was how to install a Ruby-based application, I never found the time to improve the user experience to a simple “step 1: download the app, step 2: sync with the Newton, … there is no step 3”.

I revisited the RDCL recently to check out how Ruby has progressed, and was very impressed with the Async capabilities added in Ruby 3.0.

Go

One programming language which early on got the distribution problem right is Go. Applications are single files, and can be very easily cross compiled. I implemented the most interesting parts of interfacing with a Newton in the GDCL: Encoding and decoding of NSOF data, and the Dante protocol with package installation.

Go is a very pragmatic language, not overly clever or elegant, almost boring, but it does get the job done. The module system is a bit confusing, and generics are something I would still like to explore. Overall, Go looks like a solid choice for implementing at least a command line utility to interface with the Newton.

Zig

I came across the Zig programming language looking for an improved C with cross compilation capabilities, and it fully delivered on that. Having worked for a while on more high level languages like TypeScript, Scala or OCaml, it took a bit to get back to a more low level approach (e.g. manual memory management or no asynchronous support, at least yet), but it feels just right in many ways. For me, the most compelling feature is comptime, specifically the ability to work with types at compile time, which makes generic programming really easy. In some cases, this can lead to excessive duck typing, but I definitely miss the compile time capabilities in other languages (Forth is a notable exception :) ).

I got quite far with a tool to interface with the Newton, aptly called zdcl. The development experience was very nice, and I think Zig has a bright future ahead. The 1.0 release for Zig is still a while out, and there frequent changes to the language, the standard library and the build system, thus I put zdcl on hold for now, but I’ll be happy to get back to it soon.

Another change which will definitely have an impact is the switch away from LLVM. This is not so much a problem for zdcl as macOS, Linux and Windows are tier 1 platforms, but beyond that, I found Zig also a great fit for embedded targets, and developing for them will require some changes.

Clojure

In the area of cross-platform programming languages, the JVM and Node are two very interesting foundations, as both are designed from the beginning to support multiple platforms. With Clojure, it is possible to target both (either as Clojure or ClojureScript), and I started the lower level Dante protocol implementation in both Clojure and ClojureScript. REPL based development in Clojure is a really interesting experience, where code and test are iteratively implemented, and development switches back and forth between bottom up and top down. And the focus on getting your data right and letting functions transform it fits the problem space very well.

JVM and Node based implementations still have the same issue as Ruby has, the runtime environment needs to be installed, or packaged with the application. The single executable approach of Go or Zig remains simpler for distribution and installation.

Other Candidates

I experimented with OCaml, which I really like as a general purpose functional programming language. It seems to fit the problem well, but unfortunately, targetting Windows is not yet completely straightforward.

I also started to look into C++ again, which has gone through some very fundamental changes since the original DCL was implemented. It does not direcly solve the cross platform issue, but has gotten otherwise much better in incorporating more modern programming styles. It is probably nowadays one of the more straightforward candidates for a DCL upgrade or replacement, and might be worth a second look, same as Go.

2023-08-14