Yesterday’s NeWS

Call it false nostalgia, but I find it fascinating to revisit older systems to see which parts they got right, which ones were comically short-sighted, as well as to see if they had any genuinely good but oddball ideas that fell by the wayside.

I learned programming in the early 90s, so the systems of that era defined what a computer is and how it should work for me. And while CPUs and memory were multiple orders of magnitude slower and smaller back then, things had progressed sufficiently at that point that all the major elements of modern computing had some kind of recognizable equivalent. Compare with earlier 8-bit micros for instance, which feel distinctinctly more primitive in comparison, with their single-tasking monitors and BASIC interpreters in ROM, cassette tape storage, etc.

Most interesting to me were the Unix workstations of the time, as well as the Apple Macintosh. The Microsoft platform was still a poor imitation of the state of the art — except for running old games, firing up an emulator to play with Windows 3.0 doesn’t seem nearly as interesting to me as, say, MPW on System 7, or reading about the IRIX GUI (vector icons, oh my).

My most recent foray into the world of retrocomputing was reading The NeWS Book: An Introduction to the Network/Extensible Window System, by James Gosling, et al. You may have heard of NeWS in the past — killed by the “worse is better” X11, early inspiration for Java applets which Gosling went on to design, a true PostScript interpreter for your desktop. However it seems information about NeWS is hard to come by these days — I didn’t know much about it before reading this book. If you’re curious, it is as good as any introduction to the system.

The book was published in 1989, and the first example it leads into to motivate a window system is collaborating with a colleague on another continent via video conferencing. That must’ve seemed pretty revolutionary and inspirational at the time. This quote still applies today:

“Although the hardware capability is there, the software capability is lagging behind. The process of building software that enhances productivity without introducing complexity continues to be ill-understood, especially when coupled with the variety and breadth of existing computer environments. Computer networks complicate the problem. Networking is now the rule, rather the exception, yet the development of high-performance, distributed applications across varied networks is still an art, not a science.”

Some things never change.

NeWS was in many ways a precursor of the web platform we have today, moreso than X11 which succeeded it. The NeWS “server”, which ran on your desktop, was an interpreter for an object-oriented dialect of PostScript. The server handled input events from the keyboard and mouse, and performed graphics rendering, much like a web browser would today. Remote applications, or “clients”, would upload PostScript code to the server. This server-side PostScript code performed the duties of the presentation layer for the remote application.

Unlike X11, where the graphics primitives were rather low-level and all input event handling involved round-trips to the client, NeWS was advanced enough that simple widgets, such as scroll bars and sliders, could be implemented entirely server-side, only sending high-level state changes to the client, more along the lines of “slider value is now set to 15” than “mouse button 2 released”. Similarly, the client could ask the server to render a widget in a given state, rather than repeatedly transmitting sequences of graphics primitives.

The analogy with a web browser is of course that a web browser is much like a NeWS server, with HTML/JS/CSS instead of PostScript. The web application itself is the “client”, and HTTP requests are much like the high-level events used by NeWS. Of course, mostly due to an accident of history, HTML is more of a page layout and typesetting language than PostScript; the latter is closer to what we have today in the HTML Canvas element, with simpler graphics primitives, rather than a DOM, as the building blocks. However, this is a detail which we can gloss over here.

The first thing you’ll notice while reading the book is that much of the early examples do not involve writing or running any C code at all. Instead, the user is instructed to fire up “psh”, a PostScript shell. The “psh” tool opens a socket connection to the server, allowing interactive evaluation of PostScript code. This code can create server-side objects, introspect existing objects, receive events, and perform graphics output.

In fact, it looks like it was possible to create executable shell-scripts with a “shebang” line (#!/usr/bin/psh) which behaved like executable binaries in every way. I wonder if this technique was used for any “real” NeWS applications, or if it was just for experimentation and learning. This is of course similar to how one can learn the web platform by creating an HTML file in a text editor of their choice, without having to set up a hosting platform first.

The PostScript language itself is quite fascinating. I’ve been known in the past to consider stack-based languages as a legitimate programming paradigm (and it’s great to see others have continued to experiment in this area). PostScript is a higher-order language. Evaluation in a stack language proceeds by walking an array of tokens from left to right, pushing literals on the stack, and executing word definitions as they’re encountered. So a first-class function value is just an array that has been pushed on the stack, and a named function is an association between a symbol and an array in a dictionary.

On top of the basic PostScript language, NeWS adds a light-weight object-oriented layer. Their preferred flavor of OO is a form of “message passing”, where a “send” word is used to send a message with arguments to an object reference on the stack. Normally, a message is a keyword (the PostScript equivalent of a Lisp symbol, a token that evaluates to itself). However, it is also possible to send a code block as a message, which causes the entire block to execute in the context of the object (for those of you who are PostScript nerds, this pushes the object’s class onto the dictionary stack, calls the code block, and pops the dictionary stack). This is a capability that has fallen out of fashion in modern OO languages, probably because it breaks encapsulation and introduces dynamic scoping, although JavaScript’s “with” statement seems similar (and predictably, its use is discouraged in modern JavaScript code).

Another interesting NeWS extension to the PostScript model is light-weight coroutines. In fact, it seems co-routines were used extensively in NeWS in favor of “callback hell”. Various operations exist to send and receive events as well as wait for co-routines to complete, and I imagine they all behave as if they were blocking, but in reality they schedule the current co-routine.

The book even mentions that the standard GUI toolkit shipped with NeWS spins up a co-routine every time you pull down a menu, for instance. Once again, the PostScript language shines here — a coroutine is spawned by calling a “fork” word with a code block on the stack, which spins up the new co-routine and returns to the original caller immediately. In this respect, I think the NeWS approach was more advanced than how the web platform does things today, where callbacks and code written in “manual” continuation-passing style is the norm.

On the other hand, it appears that the NeWS server scheduled co-routines co-operatively, with no real protection against rogue or incorrect code. Several examples in the book mention the need to call a “pause” word at the right point in time, which relinquishes control of the main thread, allowing other scheduled coroutines to run. Probably if we lived in an alternate universe where NeWS took off, this problem would have been solved somehow, but it is difficult to imagine this being possible without major changes to the architecture of the system, since global mutable state is prevalent.

The book does describe a simple “monitor” mechanism, which appears to behave as an exclusive mutex. It is not clear if the mutex can be locked recursively or not, maybe this problem never came up. Then they give an example of using a monitor to lock a shared counter accessed from multiple co-routines, followed by this charming quote:

“Of course, since NeWS currently has non-preemptive scheduling and runs on single-processor machines, and since increment doesn’t pause, the value would have been three without even the monitor. But in the future, we expect NeWS to implement other scheduling policies, for which the use of monitors will be essential.”

The last part is the understatement of the year. As anyone who has tried to revisit single-threaded code that relies on shared state and make it multi-thread-safe can attest, it is not simply a matter of slapping a few locks here and there and hoping for the best. Again, it is likely that the entire NeWS server, as well as large amounts of user code, would need to be re-architected to properly support concurrent execution.

Finally, near the end of the book, a case study of a port to OS/2 is discussed. After bashing Presentation Manager (the OS/2 GUI layer) as “complex to program, and [offering] little new in terms of window technology,” they go on to state that

Offering an alternative to Presentation Manager was timely, since OS/2 developers have not yet invested significant resources in Presentation Manager development. Developers are not yet dependent upon these interfaces, […] it makes business sense for Architech to bring technology like NeWS to a large market; the OS/2 market forecasts sales of 4 million units per year by 1991. The availability of NeWS on both UNIX and OS/2 is of great interest to developers trying to maximize their potential markets.

Remember, this book was published in 1989, so only 5 years later, we got Windows 95. Safe to say, very few people have heard of the “Architech” corporation today, and it is not entirely clear if those sales forecasts ever panned out.