Programming Paradigms

Michael examines how the British microcomputer revolution in the early 1980s led to the object-oriented model Apple's Newton uses today.


April 01, 1994
URL:http://www.drdobbs.com/programming-paradigms/184409223

APR94: PROGRAMMING PARADIGMS

A Little RISC Lands Apple in the Soup

In the early 1980s, the British microcomputer market was dominated by British companies, primarily Sinclair and Acorn.

It was an unlikely scenario.

The microcomputer revolution was by this time becoming institutionalized. What, only a few years before, had been a marginal market of electronics hobbyists selling to other electronics hobbyists had become a venture-capital-attracting international industry. IBM had come in and legitimized the industry, was the commonly heard--and true, even if incomplete--explanation.

All the early shots in this revolution had been fired in the United States, and all the big companies--no surprise--were U.S. companies, some of which had established manufacturing facilities in Europe. The European market, taken as a whole, was only a fraction of the U.S. market. The British market was a fraction of that fraction, and, unlike some European countries, Britain didn't have high tariffs to keep out American computers. By all logic, American computer companies should have been able to walk all over the homegrown brands.

But that's not what happened. British computer companies were bucking the odds and winning. What was going on?

Who Were These Guys?

One of the things that stands out when you look at the British microcomputer scene in those days is the Cambridge connection. Sinclair and Acorn had Cambridge University connections in common, and Acorn in particular maintained close ties with the university, drawing on it for personnel, ideas, and support. Cambridge may have been one strength of these companies.

But Sinclair and Acorn differed in many ways. For one thing, Clive Sinclair went for the high-concept products: The World's Cheapest Computer, The First Practical Electric Car. The Acorn crew were less flamboyant. They just built a computer.

The Sinclair computer was one of the first users of the Zilog Z80, arguably the first microprocessor created specifically to be the CPU of a personal computer. Arguably. The Acorn used a chip originally intended for controller use: the Rockwell 6502. The Acorn developers got to be experts in the 6502, just as Apple cofounder Steve Wozniak did.

Clive Sinclair, like Nolan Bushnell in the United States, founded several companies, explored diverse industries, and had flashes of high visibility; Sinclair, though, has been off American radar for years. The Acorn team prospered with less abrupt ups and downs and has significant visibility today. It was the BBC deal that made their fortune.

The British Broadcasting Company had decided to launch a computer-education television show that would run throughout the UK, and it wanted a BBC microcomputer to sell to viewers of the show. It was a savvy plan, and when Acorn got the BBC contract, both Acorn and the BBC thought that they could sell over ten thousand computers despite the small size of the nascent British market.

To date, Acorn has sold nearly two million BBC Micro-compatibles, and the company has grown from a typical microcomputer company of the early '80s with a staff of a couple dozen to a multimillion-pound company with hundreds of employees.

When it came time, in the mid-1980s, to admit that the 6502 had had its day, the Acorn guys did something telling. Rather than accept the conventional wisdom about the "right" microprocessor for the next generation of computers, they fell back on their expertise, or perhaps just their old habits. They designed their own.

What they came up with was the kind of chip you might expect old 6502 hackers to design: a small instruction set, low power consumption, small die size, potentially low cost. It may have been of only academic interest to them that these are now the characteristics of low-end RISC chips. They weren't trying to develop the first commercial RISC processor. They just wanted a better 6502.

What they came up with was the Acorn RISC Machine, or ARM. The first ARM chip was shown fully functional in April of 1985. It operated reliably at 8 MHz, although designed to operated with a 4-MHz clock. It was a 3-micron device of about 25,000 transistors. Initially, the ARM1 was offered as a coprocessor in the BBC computer. The second generation ARM2 was used by Radius in one of its first graphics accelerator cards for the Macintosh. The ARM2 also saw service in the movies, being used in the robotic controller from MicroRobotics of Cambridge, England, that controlled the robot turtles in the movie Teenage Mutant Ninja Turtles.

Meanwhile, Back in the Colonies_

Apple formed its Advanced Technology Group (ATG) in 1986. At that time Acorn, facing competitive pressures from clones, had just been acquired by Olivetti and was soon to release its first ARM-based computer, the Archimedes, to a lukewarm response. Apple's ATG was chartered to explore new technologies that could be of use to Apple in the '90s. One technology that ATG evaluated and took note of for possible inclusion in Apple products was Acorn's ARM processor, but nothing was done with the ARM at the time.

Somewhat later, a skunkworks within ATG called the Advanced Products Group (APG) took on the mission of developing a new system architecture that they were calling Newton. The trip to Newton had a lot of side trips and blind alleys. It was apparently Michael Chao's Knowledge Navigator pitch to John Sculley that tipped the balance from a tablet form factor to the hand-held device that Apple eventually released.

One of the other alleys explored involved the microprocessor. For some time the AT&T Hobbit chip was considered. What they were looking for was a processor with characteristics that sounded like those of a microcontroller rather than a computer CPU: small die size, low cost, low power consumption, instruction set efficiency, ease of embedding in ASIC designs. In 1990, RISC looked promising, and ARM looked particularly good.

To ensure that future ARM processors would fit Apple's evolving needs, Apple made a deal. It was an early example of the joint ventures that Apple continues to pursue today. Apple UK joined forces with Acorn and VLSI Technology, with whom Acorn had worked in producing the first ARM chips, to form ARM Ltd.

ARM Ltd.'s ARM 610 became the processor for the first Newton devices, the Apple MessagePad and Sharp ExpertPad. (ARM6 devices like the ARM 610 really represent the fourth generation of ARM devices; apparently the numbering skipped 4 and 5.)

ARM was on a roll. In 1992, 3DO announced that the ARM60 would be used in its Interactive Multiplayer. ARM6 devices are also seeing use in controller applications, such as fuzzy-logic controllers.

The ARM6 family embodies full 32-bit addressing and support for both Big-endianness and Little-endianness, a requirement imposed by Apple. The ARM610 includes a 4-Kbyte cache, a write buffer, and a MMU, all in a package smaller than a 386. The MMU implements memory domains and permissions designed to provide hardware support for modern operating-system memory-management strategies like multilevel memory protection, memory paging, demand-paged virtual memory, and object-oriented memory with background garbage collection. The last of these turns out to be crucial to the Newton model for object storage.

The rest of this column looks at some of the characteristics of that model.

A Little Selfishness

Newton's model of object-oriented technology is reported to be related to SELF, an object-oriented dynamic language developed by Smith and Unger at Stanford University about the time the ARM1 chip was seeing first silicon. NewtonScript is not SELF, though, or Dylan, or any other language. It has some unique characteristics.

One characteristic that NewtonScript does share with SELF is the "everything is an object" approach. The SELF model is unusual among object-oriented languages in that it isn't built around classes. The slogan "everything is an object" means that objects inherit directly from other "prototype" objects, as distinct from the more familiar class-based inheritance.

Newton's object-oriented language, NewtonScript, diverges from SELF in many ways, but has much the same spirit. It has prototype inheritance, as well as "parent" inheritance. But not everything is an object to NewtonScript. Chunks of data that can fit into 32 bits (integers, characters, Boolean values) are addressed via immediate reference, while everything else is a pointer reference. All these pointer-referenced data are stored in the heap as, yes, objects. Some object-data types are: symbols, reals, arrays, strings, and frames. The most important type of object in the Newton object-storage model is the frame.

A frame is a data structure containing named references to objects of arbitrary data type. It's much like a struct or record in other languages. A frame can also contain functions.

Example 1 is a typical NewtonScript frame. Frames in NewtonScript are delimited by braces ({}). The named data items within a frame are called "slots." Each slot is specified by its name, a colon, and its value. The slots are separated from one another by commas. Example 1 shows a _proto slot (more about this shortly), an integer constant slot, a Boolean constant slot, a string constant slot, a function slot (this is how methods are implemented in NewtonScript), and a slot that is itself a frame.

The _proto slot indicates one of the modes of inheritance, prototype inheritance. To establish that frame 2 inherits in this way from frame 1, you give frame 2 a _proto slot and give that slot a reference to frame 1 as its value. Frame 1 is then frame 2's prototype. Frame 2 can use (inherit) slots of frame 1, can override them with its own slot declarations, and can have additional slots that frame 1 doesn't have. Since functions can appear in frame slots, functions can also be overridden and inherited in this same way.

By the way, to send that method exampleFunction as a message to the frame exampleFrame, the syntax is exampleFrame : exampleFunction.

A couple of points will indicate how you work with this kind of inheritance: Inheritance is by reference, and prototypes can be in ROM. The implication is that if there is any chance that a reference to a certain slot may be a reference to ROM, you should declare that slot in frame 2, even though it is declared in frame 1 and inherited from it.

In fact, the whole Newton user interface essentially resides in prototypes in ROM, and you can use them as the prototypes for components of your applications. Simple Newton applications can be developed without any actual coding by using visual programming tools in the Newton Toolkit (NTK). These tools mainly facilitate this process of using ROM prototypes as the prototypes for components of your application. More complex applications will require some actual coding, of course, and it should be noted that only the user-

interface elements can be used in this way. The rest of your app has to be built the hard way.

Look for the Union Label

To understand how Newton stores object data, you need to know about stores, soups, and entries.

Newton objects can, at least for the current devices, reside in one of two places: in memory (ROM or RAM) or on a PCMCIA card. The memory and the card are called "stores." Other stores may be available on future Newton devices.

Stores contain collections of data called "soups." All the data in a store are in soups, and a store can hold many soups. If a store is like a volume, a soup is like a database on the volume.

Soups are made up of "entries." An entry is a frame. If a soup is like a database, an entry is like a record.

This model--physical stores containing soups made up of entries, and entries that are struct-like frames of object data--shows that Newton objects basically reside on Newton's physical storage devices, but it creates a false impression.

Because it isn't the simple soups that matter most in Newton software development, but cross-store collections called "union soups." Union soups seamlessly merge data from soups of different stores. If programmers use union soups rather than soups, then users can always decide where they want their data stored. In a machine with less than 200K of user-available RAM, you can be sure that's an issue. The moral for Newton developers: Use union soups.

Naturally, there's an exception to this rule. Preferences are stored in the System soup in ROM only. Every application adds at least one entry to this soup, which is not a union soup.

All existing soups (the "names" soup used by the bundled Names application, for example) are available to your application, and you are encouraged to use them. You can add your own data to these existing soups by adding a slot. To avoid conflicts, Apple encourages you to add just one slot, using your appSymbol as the name entry for the slot.

Note the distinction: Adding an entry to a soup is like adding a record to a database. Adding a slot is like adding a field.

Soup Management

Besides automatic garbage collection, Newton provides a lot of built-in data management. Soups automatically maintain indexes of their entries. You specify these indexes when you create a soup, but indexes can be added and removed dynamically. Currently, the only kind of index supported is "slot," but future versions of NewtonScript may support others. Using a slot index means that the index key is the value of a particular slot that appears in each entry.

The function theStore : createSoup

( soupNameString, indexArray ) creates a soup of the specified name in the store named theStore. IndexArray is a frame describing the initial index(es) you are creating for the store. You don't have to create any, since indexes can be added later. Soups can contain any mishmash of entries, but unless all entries have at least one slot in common, it won't be possible to specify an index that lets you search the whole soup. Some points on managing soup entries: When you add an entry to a soup, you actually add the transitive closure of the entry. Altering an entry doesn't update the store; you need to call EntryChange. The Newton operating system calls EntryChange every so often when idle, but applications will typically have to know when to call EntryChange themselves. The only way to get at the entries in a soup is via a "query." A query can use an index, or some other kind of search, like searching all string slots in all entries for a specified search string. A query returns a set of entries, and these entries are then accessed through an object called a "cursor."

A cursor is a pointer to one of the entries in this returned set. The cursor is advanced to the next entry in the set or otherwise repositioned by sending it messages.

The Newton approach to handling persistent-object data has some distinctive and, I think, interesting characteristics. I suspect I'll have more to say about it in future columns.


Example 1: A NewtonScript frame.

exampleFrame := {
      _proto: protoFrame,
      index: 1,
      active: TRUE,
      name: "Name of Frame",
      exampleFunction:
            func(param)
            begin
                  return param * 10;
            end
      otherFrame:
            {     owner: "Mike Swaine",
                  ownerAddress: "72511,172" }
      } ;

Copyright © 1994, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.