The techy post, part 2 of 4

Thursday, November 18, 2010

Tagged: glulx, zarf, z-machine, interactive fiction, history, if

Sorry, we've experienced a bit of post bloat. This series will be four parts, not three. (Just four, though.)

Zarf and Modularity

I wanted to design a new 32-bit VM to carry Inform into the Century of the Fruitbat. With (potentially) four gigabytes of memory, and without a host of trivial Z-machine limitations, we'd have room for some serious interactive fiction design. But I wanted to start on a solid foundation.

I was impressed by the generality of the Z-machine design; so I planned a design that went farther. I would completely separate the display layer -- text layout and text input -- from the virtual machine's "CPU" and memory layer.

That sounds wrongheaded, but it grew directly out of my experience in implementing IF interpreters. By 1998 I had released a Z-machine interpreter for X windows, and then ported it to the Mac, and then released a TADS interpreter for the Mac. Comparing the three, it was clear that each application could be divided into a portable VM engine (Z-machine or TADS), and a display library (Mac or X). It really should be possible to create a new VM, and combine it with all the existing display libraries to get instant ports -- or write a new display library, and combine it with all the existing engines.

Moreover, it should be possible to improve the display layer and the VM layer separately. We wouldn't be locked into upgrading the entire thing as a unit. Infocom had done that, near the end of their tenure, producing the "version-6 Z-machine" -- which abandoned much of the portability in order to get a graphical UI out the door. Infocom got a couple of good games that way (Zork Zero, Journey) but they are much harder to play in the modern era than their earlier, cleaner games. I wanted to avoid that mistake. So, modularity it was.

To make this dream work, all I needed to do was specify the API -- the docking port between VM and display library. So I wrote this spec up, and I named it "Glk". To get the ball rolling, I wrote Glk display libraries for Mac (OS8, at the time) and for Linux (both X windows and terminal windows).

(I won't translate "Glk", because it doesn't mean anything.)

I hoped that Glk would change the IF landscape, but it didn't turn out that way. My API did a great job with the basics of text windows and status lines. But IF engines were pushing into the realms of sound, graphics, and mouse input. (Really, that had started in Infocom's day.) Every system handled these things slightly differently, and Glk was slightly different from all of them. Rather than a universal display system, I'd created an adequate common denominator.

Of course, that was a good thing. But the true power of the Glk API wouldn't be realized until I'd created a virtual machine that had no display model of its own -- a VM that relied solely on Glk for input and output.

I worked out that design in 1999; I called it "Glulx". (For translation, see above.) I implemented the VM engine -- in portable C, as promised. Then I turned my attention to the harder problem: adapting the Inform 6 compiler to generate Glulx game files. With that done, people could compile their existing Inform games to Glulx, with only minimal code changes. I didn't expect everybody to jump in and do that with every game -- indeed, I continued to build Z-code games myself. But it provided a smooth transition path.

(I'm glossing over all sorts of details here, you understand. For example, the Glk library doesn't fit perfectly with Glulx game code: one is a C library on the real machine, the other is Inform code on a virtual machine. I needed a shim to translate data structures back and forth. There was also a whole pile of work in translating the Inform 6 library -- the standard parser and so on -- which had a lot of fixed assumptions about the Z-machine's architecture. But this all got done.)

It's worth noting that while I am proud of Glulx, it is not the end-all of IF virtual machines. It was constrained in some ways by the design assumptions of Inform 6 (which was constrained by the design assumptions of the Z-machine). I don't mean that Glulx had to be backwards-compatible with Z-code; it's not. But I6 semantics revolve around pointers, byte arrays, and byte structures (very much like C semantics). So Glulx offers a flat space of bytes for storage. In contrast, modern languages (Perl, Python, Java, Javascript, etc) live in a world of run-time-typed, dynamic, garbage-collected objects -- and Glulx has only the most superficial support for that sort of thing.

This makes life difficult for Inform, which is evolving more modern features with every release. But that's for the next post.