(navigation image)
Home American Libraries | Canadian Libraries | Universal Library | Community Texts | Project Gutenberg | Biodiversity Heritage Library | Children's Library | Additional Collections
Search: Advanced Search
Anonymous User (login or join us)
Upload
See other formats

Full text of "Lisp lore : a guide to programming the Lisp machine"

LISP 

LORE: 

A GUIDE TO 
PROGRAMMING 
THE LISP 
MACHINE 



Hank Bromley ^g. 



LISP LORE: A GUIDE TO 
PROGRAMMING THE LISP MACHINE 



AT&T 

LISP LORE: A GUIDE TO 
PROGRAMMING THE LISP MACHINE 



by 



Hank Bromley 

AT&T Bell Laboratories 



W 



KLUWER ACADEMIC PUBLISHERS 

Boston/ Dordrecht/ Lancaster 



Distributors for North America: 

Kluwer Academic Publishers 

101 Philip Drive 

Assinippi Park 

Norwell, Massachusetts 02061, USA 

Distributors for the UK and Ireland: 

Kluwer Academic Publishers 

MTP Press Limited 

Falcon House, Queen Square 

Lancaster LAI 1RN, UNITED KINGDOM 

Distributors for all other countries: 

Kluwer Academic Publishers Group 

Distribution Centre 

Post Office Box 322 

3300 AH Dordrecht, THE NETHERLANDS 



Library of Congress Cataloging-in-Publication Data 

Bromley, Hank. 
Lisp lore. 

Includes index. 

1. LISP (Computer program language) I. Title. 
QA76.73.L23B75 1986 005.133 86-7377 

ISBN 0-89838-220-3 



Copyright © 1986 by Bell Telephone Laboratories, Incorporated. Portions of this book are copyrighted 
by Symbolics, Inc. 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or 
transmitted in any form or by any means, mechanical, photocopying, recording, or otherwise, without 
the prior written permission of the publisher, Kluwer Academic Publishers, 101 Philip Drive, Assinippi 
Park, Norwell, Massachusetts 02061. 

Printed in the United States of America 



TABLE OF CONTENTS 



LIST OF FIGURES 


ix 


PREFACE 


xi 


INTRODUCTION 


1 


GETTING STARTED ON THE LISP MACHINE 


5 


1.1 The Keyboard 


5 


1.2 Typing to a Lisp Listener 


8 


1.3 Logging In 


9 


1.4 The FEP 


10 


1.5 Random Leftovers: the mouse, the monitor, the editor 


12 


1.6 Problem Set #1 


14 


WHAT'S A FLAVOR? 


17 


2.1 Basic Usage 


18 


2.2 Initial Values for Instance Variables 


20 


2.3 Mixing Flavors 


22 


2.4 Combined Methods 


23 


2.5 Other Ways of Combining Methods 


28 


2.6 Vanilla-flavor 


30 


2.7 Fun and Games 


31 


2.8 Problem Set #2 


32 


MORE ON NAVIGATING THE LISP MACHINE 


43 


3.1 The scheduler and processes 


43 


3.2 Windows 


46 


3.3 Debugging 


50 


3.4 Who Does What 


52 


3.5 The Input Editor and Histories 


53 


3.6 Fun and Games 


54 


3.7 Problem Set #3 


57 


FLOW OF CONTROL 


61 


4.1 Conditionals 


61 


4.2 Blocks and Exits 


63 


4.3 Nonlocal Exits 


64 


4.4 Iteration 


64 



5.1 


The Nodes and Arcs 


5.2 


Managing Multiple Windows and Processes 


5.3 


The Windows and the Mouse 


5.4 


Fun and Games 


5.5 


The Program 


5.6 


Problem Set #5 


STREAMS AND FILES 


6.1 


Streams 


6.2 


Accessing Files and Directories 


6.3 


Pathnames 


6.4 


Fun and Games 


6.5 


Problem Set #6 



TABLE OF CONTENTS 



4.5 A Bit More on Working with Macros 71 

4.6 Fun and Games 71 

4.7 Problem Set #4 73 

THE GRAPH EXAMPLE 83 

84 
85 
87 
91 
91 
101 

119 

119 
125 
129 
135 
137 

7 THE TREE EXAMPLE 139 

7.1 The Nodes and Arcs 139 

7.2 The Windows and the Mouse 141 

7.3 Fun and Games 143 

7.4 The Program 144 

7.5 Problem Set #7 155 

8 RANDOM USEFUL TOPICS: RESOURCES & SYSTEMS 161 

8.1 Resources 161 

8.2 Systems 165 

8.3 Problem Set #8 170 

9 SIGNALING AND HANDLING CONDITIONS 173 

9.1 Overview 173 

9.2 A Few Examples 174 

9.3 More on Handlers 176 

9.4 Restart Handlers 178 

9.5 More on Proceeding 179 

10 THE MOVING ICONS EXAMPLE 183 

10.1 General 183 

10.2 moving-icons-frame 185 

10.3 moving-icons-main-pane 185 



TABLE OF CONTENTS 



10.4 Messing with the mouse blinker 186 

10.5 The :drop-icon method 187 

10.6 Setting up the comtab 188 

10.7 Getting in the System Menu 188 

10.8 The Program 189 

10.9 Problem Set #9 194 

1 1 MORE ADVANCED USE OF THE EDITOR 199 

11.1 Keyboard Macros 199 

11.2 Writing New Commands 201 

1 1.3 Buffers and Streams 201 

1 1.4 Reading from the Mini-buffer 204 

11.5 A Real Example 206 

11.6 Problem Set #10 207 

12 A QUICK LOOK AT "THE NETWORK" 211 

12.1 The "Gee- Whiz" Overview 211 

12.2 The Beginning of the Real Explanation 213 

12.3 The Ethernet 214 
12.4Chaosnet 215 

12.5 A Bit More on Serial Streams 217 

12.6 The Role of the Namespace 2 1 7 

12.7 Troubleshooting 219 

APPENDIX: BASIC ZMACS COMMANDS 221 

INDEX 225 



LIST OF FIGURES 

1 Flavor tree for lisp-listener 24 

2 Structure of combined method 28 

3 Transitions among window states 48 



PREFACE 



This book had its genesis in the following piece of computer mail: 

From allegra!joan-b Tue Dec 18 09:15:54 1984 
To: solalhjb 
Subject: lispm 

Hank, I've been talking with Mark Plotnik and Bill Gale about 
asking you to conduct a basic course on using the lisp machine. 
Mark, for instance, would really like to cover basics like the flavor 
system, etc., so he could start doing his own programming without 
a lot of trial and error, and Bill and I would be interested in this, 
too. I'm quite sure that Mark Jones, Bruce, Eric and Van would 
also be really interested. Would you like to do it? Bill has let me 
know that if you'd care to set something up, he's free to meet with 
us anytime this week or next (although I'll only be here on Wed. 
next week) so we can come up with a plan. What do you think? 
Joan. 

(All the people and computers mentioned above work at AT&T Bell Laboratories, 
in Murray Hill, New Jersey.) I agreed, with some trepidation, to try teaching such 
a course. It wasn't clear how I was going to explain the lisp machine environment 



Xii PREFACE 



to a few dozen beginners when at the time I felt I was scarcely able to keep myself 
afloat. Particularly since many of the "beginners" had PhD's in computer science 
and a decade or two of programming experience. But the need was apparent, and 
it sounded like fun to try, so we had a few planning sessions and began class the 
next month. 

From early January through late March we met once a week, about a dozen times 
in all, generally choosing the topic for each session at the conclusion of the previous 
one. I spent the last few days before each meeting throwing together lecture notes 
and a problem set (typically finishing shortly after the announced class time). By 
the end of the course, the students had attained varying levels of expertise. In all 
likelihood, the person who learned the most was the instructor; nothing provides 
motivation to figure something out like having committed oneself to talking about 



After it was over, another co-worker saw the sizable pile of handouts I had gen- 
erated and proposed that it would make a good book. He offered to contact a pub- 
lisher he had recently deaft with. I was at first skeptical that the informal notes I 
had hurriedly concocted would interest a reputable academic publisher, but after 
taking another look at the materials that had sprouted, and discussing the matter, 
we agreed that quite a few people would find them valuable. I've spent the last few 
months filling out and cleaning up the pile, and Presto, change-o. My "set of hand- 
outs" is "a book." 

There are a number of people who have, in one way or another, consciously or oth- 
erwise, helped create this book. Ken Church was instrumental in arranging my 
first experience using the lisp machine, and later was responsible for bringing me to 
Bell Labs. He also taught a course here, before I came, which laid some of the 
groundwork for my own course. Eva Ejerhed, in a rare act of faith, hired me to 
work on a lisp machine thousands of miles from the nearest expert assistance, 
without my having ever touched one. Joan Bachenko and Bill Gale first suggested I 
teach a course at the Labs. Many of my colleagues who served as experimental 
subjects by participating in one of the three trials of the course provided useful 
comments on the class handouts; among those whose contributions I particularly 
recall are Mark Liberman, Jeff Gelbard and Doug Stumberger. Ted Kowalski first 
broached the idea of making a book from the handouts, and also — with Sharon 
Murrel — supplied lots of assistance with the use of their Monk text formatting 
system. Wayne Wolf suggested improvements to my coverage of managing multi- 
ple processes. Jon Balgley, of Symbolics, Inc.,* wrote a helpful review of one 



Symbolics, Symbolics 3600, Symbolics 3640, Symbolics 3670, and Document Examiner are trade- 
marks of Symbolics, Inc. 
Zetalisp® is a registered trademark of Symbolics, Inc. 



PREFACE 



Xlll 



version of the manuscript. Valerie Barr introduced herself to the lisp machine by 
actually working through an entire draft, making a great many valuable observa- 
tions along the way. Mitch Marcus and Osamu Fujimura, my supervision at the 
Labs, were most understanding about the amount of time I put into this project. 
Carl Harris was an obliging and patient Publisher. Finally, Symbolics, Inc. gra- 
ciously allowed me to quote extensively from their copyrighted materials, and 
Sheryl Avruch of Symbolics made possible the distribution of a tape to accompany 
this book. 

I would like to hear about any problems readers have while working their way 
through the text. Please don't hesitate to mail me any of your comments or sugges- 
tions. 



Hank Bromley 
December, 1985 



computer mail: 



US mail: 



hjb@mit-mc (arpa) 

AT&T Bell Laboratories, room 2D-410 
alice 600 Mountain Avenue 

research } !sola!hjb (uucp) Murray Hill, NJ 07974 
allegra 



LISP LORE: A GUIDE TO 
PROGRAMMING THE LISP MACHINE 



INTRODUCTION 



The full 1 1 -volume set of documentation that comes with a Symbolics lisp machine 
is understandably intimidating to the novice. "Where do I start?" is an oft-heard 
question, and one without a good answer. The eleven volumes provide an excellent 
reference medium, but are largely lacking in tutorial material suitable for a 
beginner. This book is intended to fill that gap. No claim is made for complete- 
ness of coverage — the eleven volumes fulfill that need. My goal is rather to 
present a readily grasped introduction to several representative areas of interest, 
including enough information to show how easy it is to build useful programs on 
the lisp machine. At the end of this course, the student should have a clear enough 
picture of what facilities exist on the machine to make effective use of the complete 
documentation, instead of being overwhelmed by it. 

The desire to cover a broad range of topics, coupled with the necessity of limiting 
the amount of text, caused many items to be mentioned or referred to with little or 
no explanation. It's always appropriate to look up in the full documentation any- 
thing that's confusing. The manuals are perfectly adequate reference materials, as 
long as you know what you want to look up. The point in this text is rarely to 
explain what some specific function does in isolation — that's what the manuals are 
good for. The focus here is on how to integrate the isolated pieces into real appli- 
cations, how to find your way around the landscape, how to use the multitudinous 
features described in such splendid detail in the 1 1 volumes. The manuals provide 



INTRODUCTION 



a wonderfully thorough, but static, view of what's in the lisp machine environment; 
I've tried to provide a dynamic view of what that environment looks like in action, 
or rather in interaction with a human. 

The book assumes some background in lisp; the reader is expected to have experi- 
ence with some dialect of the language. If you lack such experience, you may want 
to do a bit of preparatory study.* This course concentrates on those aspects of lisp 
machine lisp ("Zetalisp") which are not found in most dialects, and on the unique 
overall programming environment offered by the lisp machine. No experience with 
the lisp machine itself is assumed. 

Finding an ideal order of presentation for the various topics would be difficult. 
Many topics are interdependent, such that knowing either would help in figuring 
out the other. Presenting them simultaneously would only confuse matters, so I've 
had to settle on one particular linear sequence of topics. It may seem natural to 
some readers and bizarre to others. I've tried to identify places where it might be 
helpful to look ahead at sections further on in the text, but I'm sure I haven't found 
them all, so don't hesitate to engage in a little creative re-ordering if you feel the 
urge. One chapter whose position is problematic is that on flavors. Conceptually, it 
is probably more difficult than both of the two subsequent chapters {More on Navi- 
gating the Lisp Machine and Flow of Control). But I've chosen to put it first 
because the flavor system is extremely characteristic of lisp machine programming, 
making it important to discuss as soon as possible. The main barrier to mastering 
the lisp machine is absorbing its gestalt, much of which is implicit in the flavor sys- 
tem; covering that right at the beginning helps to set the tone for what follows. But 
if you find flavors a bit much, feel free to look through Navigating and maybe Flow 
of Control and come back to it. 

I've adopted a rather informal tone for most of the text: people learn better if 
they're relaxed. Just let me caution you that "informal" doesn't mean "sloppy." 
There are few extra words. Lots of information is present in only one place, and 
apparent only if you read carefully. If you get fooled by the informality into think- 
ing you can scan half-attentively, you'll miss things. 

It must be emphasized that learning to use the lisp machine is more a matter of 
learning a way of thinking than of learning a set of specific programming con- 
structs. No amount of time spent studiously poring over documentation can yield 
the benefits gained from sitting at a console and exploring the environment directly. 



Two widely available sources you may find well worth your time are Lisp (2nd edition), Winston and 
Horn, Addison- Wesley, 1984, and Structure and Interpretation of Computer Programs, Abelson and 
Sussman, MIT Press, 1984. 



INTRODUCTION 



Time spent examining various parts of the system software with no particular goal 
in mind is anything but wasted. Once one has a feel for how things are done, an 
overview of how things fit together, the rest will follow easily enough. Most lisp 
machine wizards are self-taught; the integrated nature of the environment, and 
ready access to the system code, favors those who treat learning the machine as an 
interactive game to play. 

With that in mind, a word or two of advice on the problem sets. Don't get too 
wrapped up in finding the "right answer." Many of the problems are, shall we say, 
"challenging;" they require knowledge not found in the text (and in some cases not 
even found in the manuals). You will need to investigate, often without knowing 
exactly what you're looking for. If the investigation fails to yield immediate results, 
I strongly recommend that rather than head straight for my solutions, you continue 
to investigate. Stick it out for a while, even if you don't seem to be getting much 
closer. You can't learn to speak a foreign language by consulting a dictionary 
every time you need a word you don't know — forcing yourself to improvise from 
what you do know is the only way. Floundering is an unpleasant but absolutely 
necessary part of the process, arguably the only part during which you're really 
learning. Similarly, you can't become a lisp wiz just by assiduously studying some- 
one else's code. Although seeing how an experienced programmer handles a prob- 
lem is certainly useful, it's no substitute for struggling through it yourself. The 
problem sets are largely a ruse to get you mucking around on the machine. I don't 
really care if you solve them, as long as you come up with some ideas and try them 
out with an open mind. 

The examples in the text (barring typos) are known to work in Release 6.1 of the 
Symbolics software for the 3600 family of machines. Only the "moving icons" 
example requires additional support software not included in the text. That 
software is available on a cartridge tape, which also contains all the code for the 
"graph," "tree," and "moving icons" examples, as it appears here, and all problem 
solutions which are too long to reasonably be manually copied from the text. 

To order a copy of the tape, write to the following address (you may wish to use 
the order form at the back of this book) and include a check for $40 made out to 
Symbolics, Inc. Instructions for loading the tape will accompany it. 

Software Release 
Symbolics, Inc. 
1 1 Cambridge Center 
Cambridge, MA 02142 



Chapter 1 

GETTING STARTED ON THE LISP MACHINE 



1.1 The Keyboard 

Note that there are many keys which don't appear on a standard keyboard. Much 
of what you need to know to start using a Lisp Machine boils down to knowing 
what the various funny keys do. 

Apart from the keys for the standard printing characters (white labels on grey 
keys), there are two kinds of special keys. The beige keys with grey labels (shift, 
control, meta, super, hyper, and symbol) are all used like the shift key — you hold 
them down while striking some other key. These modifier keys may be used singly 
or in combination. So "control-meta-K" means type K while holding down control 
and meta. There is a standard set of abbreviations for the various modifier keys. 
They're all just what you'd expect except that the abbreviation s stands for super 
rather than shift. Shift is abbreviated sh. 

The beige keys with white labels are special function keys, and are typed like stan- 
dard printing characters. That is, "Select-E" means to strike Select and then strike 
E. And "Select c-L" means to strike Select and then hold down control and strike 
L. 



GETTING STARTED ON THE LISP MACHINE 



Chapter 1 



Use the Help key a lot. The information it supplies depends on the context, but it 
usually tells you what sort of input is wanted by the program you're typing to. 

You can think of the Lisp Machine as a collection of processes, analogous to the 
different users on a time-sharing system. Each process is a program written in lisp 
and running in a common environment which all the processes share. A process 
typically (but not necessarily) has a window for user interaction. The Select key is 
the easiest way to switch among processes. To find out what your options are, type 
Select-Help. The display shows you that, among other programs that may be 
reached in this way, you can get a lisp listener by typing Select-L, and an editor by 
typing Select-E. This list is by no means fixed. Users may add their own programs 
to the list quite easily. Here are brief descriptions of the programs that are already 
in the select list on a freshly booted lisp machine: 



X Common Lisp 
C Converse 



D Document Examiner 

E Editor 

F File System Maintenance 

I Inspector 

L Lisp 

M Zmail 

N Notifications 

P Peek 

T Terminal 

X Flavor Examiner 



a (Common Lisp) lisp listener [X = symbol-sh-L] 
convenient way to send and receive messages 
from users currently logged-in on other machines 
(lisp or otherwise) 

a utility for finding and reading online documen- 
tation; everything in the 11 -volume manual is 
available here 

the powerful Zmacs editor, like Emacs plus 
much more 

various display and maintenance operations on 
the file system of the lisp machine or of other 
machines 

structure editor for displaying and modifying lisp 
objects 

a (Zetalisp) lisp listener 

a comprehensive mail-reading and sending pro- 
gram, using many pieces of the Zmacs editor 
displays a list of all "notifications" (messages 
from running programs) you've received 
displays the status of various aspects of the lisp 
machine 

use the lisp machine as a terminal to log in to 
other computers 

convenient way to find out about different flavors 
(active objects), their message-handlers, and 
their state variables. 



The Function key, like Select, dispatches off the following keystroke. Function- 



Section 1.1 The Keyboard 



Help displays a list of the options. The most commonly used are Function-F 
("finger"), to find out who's logged in on the various machines, Function-H ("hos- 
tat"), for a quick look at the status of all the hosts on the local Chaosnet, and 
Function-S to select a different window. The exact behavior of many of the Func- 
tion options is controlled by an optional numeric argument; you pass the argument 
by pressing one of the number keys after the Function key and before the chosen 
letter, e.g., Function-O-S. 

The Suspend key generally causes the process you are typing to to enter a "break 
loop", that is, the state of its computation is suspended and a fresh read-eval-print 
loop is pushed on top of the current control stack. The Resume key will continue 
the interrupted computation. Suspend takes effect when it is read, not when it is 
typed. If the program isn't bothering to check for keyboard input, pressing 
Suspend will do nothing. 

c -Suspend does the same thing as Suspend, but always takes effect immediately, 
regardless of whether the program is looking for keyboard input. 

m-Suspend, when read, forces the process at which you type it into the debugger. 
The debugger is another story (see below), but when you're done looking around 
you can continue the interrupted computation with Resume. 

c-m-Suspend is a combination of c-Suspend and m-Suspend. It immediately forces 
the current process into the debugger. 

The Abort key is used to tell a program to stop what it's doing. The exact behavior 
depends on what program you're typing to. A lisp listener, for instance, will 
respond by throwing back to the nearest read-eval-print loop (the top level or an 
intervening break loop). Like Suspend, Abort only takes effect when read. If the 
program isn't waiting for keyboard input, you need to use c- Abort instead. 

m- Abort, when read, throws out of all levels and restarts the top level of the pro- 
cess, c-m- Abort has this effect immediately. 

The debugger prompt is a small right-pointing arrow. Once you have that, all 
kinds of commands are available for moving up and down the stack, getting infor- 
mation about the different frames on the stack, restarting execution with or without 
modifying arguments and variable values, etc. Try the Help key and see what you 
can find out. Besides all the special commands, any normal text you type will be 
evaluated by the lisp interpreter. 



GETTING STARTED ON THE LISP MACHINE Chapter 1 



1.2 Typing to a Lisp Listener 

A lisp listener is a window with a lisp interpreter running in it. It reads a lisp 
expression from the keyboard, evaluates it, prints the returned value (s), and waits 
for another expression. Booting a machine leaves you in a lisp listener. Whenever 
you're not in a lisp listener you can get to one by typing Select-L. 

While waiting for input, lisp listeners usually display "Command:" as a prompt. 
The presence of this prompt indicates that the Command Processor (CP) is active; 
it provides a convenient interface to many frequently called lisp functions. (The 
name of a CP command won't necessarily be the same as the name of the 
corresponding lisp function.) CP commands don't use the same parentheses syntax 
as lisp expressions do. You simply type the name of the command (one or more 
words) followed by any arguments to the command, and finish with the Return key. 
But you needn't type the name of the command in its entirety — all that's required 
is enough to uniquely identify which command you mean. The CP command 
Help (i.e., type out the letters h, e, 1, p, and hit Return) lists all the defined com- 
mands. Pressing the Help key while partway through a command will display a list 
of only those commands which match your input thus far. Section 3.2 in volume 1 
of the documentation describes all the CP commands present in the software distri- 
buted by Symbolics. You can define more of your own. One command which may 
be particularly valuable to new users is Show Documentation. You specify 
some topic you want looked up in the manuals and it displays a facsimile of that 
portion of the documentation on your screen. 

You may be wondering how the command processor knows whether you intend 
your typein to be interpreted as a CP command or as a lisp expression. If you 
begin with a letter, it assumes you're starting a CP command; with a non- 
alphabetic initial character it tries to parse your input as a lisp expression. Since 
lisp expressions usually begin with a left paren, it guesses correctly most of the 
time. But what if you want to evaluate a lisp symbol — if the symbol's name 
begins with a letter, the command processor will guess wrong and look for a com- 
mand with that name. The solution here is to type a comma before the symbol's 
name. The comma has special meaning for the command processor: it forces 
whatever follows to be interpreted as a lisp expression, regardless of what the initial 
character is. 

If you'd like to know about some other features that are available whenever you're 
typing to a lisp listener and you don't already feel as though you've seen more than 
you can possibly remember, I suggest looking ahead at the section "The Input Edi- 
tor and Histories" in chapter 3. It'll make life much easier as you take on the first 
few problem sets. 



Section 1.2 Typing to a Lisp Listener 



1.3 Logging In 

To login, you simply use the CP command Login with an argument of your user- 
id. In my case, it looks like Login hjb. Alternatively, you could apply the lisp 
function "login" to your user-id: (login 'hjb). The effect is the same, but the 
former requires less typing (because of the automatic command completion). The 
only reason I sometimes use lisp functions when there is an equivalent CP com- 
mand is force of habit: the command processor is a fairly new feature, while my 
fingers have been typing the lisp functions for years. 

It's important to keep in mind the difference between a local login to the lisp 
machine, and remote logins to other machines being used as file servers. Local 
logins are controlled by a database called the namespace. To login locally with a 
certain user-id requires that there be an entry in the namespace for that user-id. It 
does not require a password, as there is no internal security on the lisp machine. 

Many things on the lisp machine can be done with no one logged in. Some opera- 
tions, however, do require that someone be logged in. Modifying the namespace, 
for instance, is one of these operations. How, then, you may ask, do you create a 
namespace entry for yourself if you can't modify the namespace unless you're 
logged in, and you can't log in unless you're in the namespace? One option would 
be to log in as someone else so you can create a namespace entry for yourself, and 
then log in as yourself. But nothing so underhanded is really necessary. All lisp 
machines have a dummy user in the namespace which the system itself uses when it 
needs to do something which requires having someone logged in. (This situation 
arises most notably while the machine is being booted — no one can log in until it's 
finished booting, but it can't finish booting until it does a bunch of things that 
require someone being logged in.) The dummy user is typically named "Lisp 
Machine", with user-id "Lispm" or "NIL". Whatever it's called on your machine, 
you can always use it by typing ( si: login-to-sys-host). This is often a 
handy trick to know about. You can now edit the namespace — use the CP com- 
mand Edit Namespace Object — and create a user object for yourself. There 
is introductory documentation on the namespace and the namespace editor in 
chapter 11 of volume 1. 

Whenever you log in to a lisp machine, unless you explicitly specify otherwise, it 
tries to find your personal initialization file and load it into the lisp environment. 
This is a file containing any number of lisp forms which customize the machine for 
you. They will typically set some variable values and load some other files. Where 
the machine looks for your init file depends on what you specified for your home 
host in your namespace entry. If you specified a host running the UNIX* 



10 GETTING STARTED ON THE LISP MACHINE Chapter 1 



operating system, it will first look for a file named lispm-init .bn in your direc- 
tory on that machine. If your home host is a lisp machine, it'll look for the newest 
version of a file named lispm-init.bin. 

The issue of remote logins arises whenever you try to do something from the lisp 
machine on another computer across a network, like read or write a file. If the 
remote host is a lisp machine, it won't ask for a password, and your local machine 
can take care of establishing the connection with no intervention on your part. But 
if the remote host is the sort that believes in security, say a UNIX system, it'll stop 
your local machine from doing anything until you provide an appropriate login id 
and password. Your local machine will pass the request right along to you. But 
it's essentially a matter between you and the remote host — the local machine 
doesn't care what username you use on the remote machine, or whether it's one 
that exists in the namespace. The local machine is just a messenger in this case. It 
will, however, try to be helpful. If you specify in your namespace entry what user- 
names you want to use on the various remote hosts, the local machine will try those 
first, even if those names are arbitrary nonsense as far as the local machine can tell. 
And you can always override the default usernames. 

And while we're on remote file systems, there's the question of whether you should 
keep your files on a lisp machine or some other sort of file server. It depends on 
what sort of set-up you have — how much disk space in what places, how many 
users, etc. It's often the case that you'll want to keep as few files as possible on the 
lisp machine disks, because the available space would be better utilized by virtual 
memory and saved lisp worlds. Files can be kept on any machine you have an eth- 
ernet connection to, with little loss of efficiency, so large file systems are effectively 
dead weight on a lisp machine. If at all practical it makes more sense to convert 
every available megabyte to virtual memory or room for saved worlds, which have 
to be on the local disk. 



1.4 The FEP 

Having looked at the disk label brings up the Front-End Processor, or FEP. The 
Fep is a 68000-based computer which handles starting up the main processor of the 
lisp machine, and may also become active if the lisp machine enters an illegal state, 
whether because of a hardware malfunction or system-software bug. You can tell 
if your lisp machine is in the Fep if there's a prompt that looks like this: "Fep>", 
and the clock at the lower left of the screen has stopped. For now, there are just 
three Fep commands you should know. Continue, which may be shortened to 



UNIX is a trademark of AT&T Bell Laboratories. 



Section 1.4 The FEP 11 



"con", tells the Fep to try having the lisp machine resume exactly where it left off. 
If you were thrown into the Fep because of some serious system error, this is not 
likely to work — you will probably be thrown right back into the Fep. But not 
always. Start, which may be shortened to "st", does a warm boot. It tries to re- 
start all of the machine's active processes while preserving the state of the lisp 
environment (i.e., function and variable bindings). This is a something of a 
kludge.* It can put things into an inconsistent state, and is something of a last 
resort, but it is sometimes the only way to get a wedged machine going again, short 
of wiping the environment clean, and losing whatever work was in progress. That is 
the effect of the Fep command Boot, which may be shortened to "b". Boot does a 
cold boot. It clears the machine's memory, reloads the microcode, restores one of 
the saved worlds into the virtual memory, and does a start. This is how you get a 
fresh machine. 

There are times when you may want to get into the Fep so you can do a warm or 
cold boot. Perhaps your machine has been used by someone else who has 
significantly changed the lisp environment in unfamiliar ways, or who has used up 
nearly all your virtual memory. Then you will likely want to do a cold boot. Or 
perhaps, as often happens to me, you were playing with some critical part of the 
system code (after all, it's written in lisp and is completely accessible), did some- 
thing unwise, and now your machine is wedged, responding neither to keyboard 
input nor mouse clicks. Then you may wish to resort to a warm boot, and salvage 
what you can. So to get into the Fep, the preferred method is to use the CP com- 
mand Halt Machine [or evaluate (si: halt)]. That'll do it. But if your 
machine isn't responding to the keyboard, typing a command isn't an option. Then 
you'll have to use hyper-control- Function. Yes, if you hold down hyper and control 
and type Function, your lisp machine will enter the Fep under any conditions other 
than hardware failure. This is not the preferred method because the lisp processor 
will be rather rudely interrupted and may leave things in an inconsistent state. But 
if all else fails, it is the appropriate action. 



KLUGE, KLUDGE (Jclooj) noun. 

1 . A Rube Goldberg device in hardware or software. 

2. A clever programming trick intended to solve a particularly nasty case in an efficient, if not 
clear, manner. Often used to repair BUGS. Often verges on being a CROCK. 

3. Something that works for the wrong reason. 

4. verb. To insert a kluge into a program. "I've kluged this routine to get around that weird bug, 
but there's probably a better way." Also "kluge up." 

5. A feature that is implemented in a RUDE manner. 

(The Hacker's Dictionary, Guy L. Steele, Jr., et at. Harper & Row, Publishers, New York, 1983.) 



12 GETTING STARTED ON THE LISP MACHINE Chapter 1 



1.5 Random Leftovers: the mouse, the monitor, the editor 

A few observations on the mouse. The functions associated with clicking the mouse 
buttons are completely context-dependent. It's up to the window the mouse is over 
when you click. It is generally the case, though, that the current binding of the 
buttons will be documented in the reverse video line near the bottom of the screen. 
And it is also generally the case that clicking once on the left button will select the 
window the mouse is pointing to, and clicking twice on the right button will get you 
to the system menu. The system menu offers many useful operations, such as 
creating windows, moving and reshaping existing windows, selecting some of the 
programs which are accessible via the Select key, and some which are not, etc. 
Play with it. It's a very good habit to keep an eye on the mouse documentation 
line. 

There is also a lot of other useful information available at the bottom of the screen. 
From left to right, we have the date and time; the user-id of the currently logged in 
user, if any; the current package (the set of all symbols is partitioned into pack- 
ages, to minimize name conflicts — a cold-booted machine starts out in the "user" 
package, which is where you'll probably do most of your work at the beginning); 
the state of the current process ("Tyi" means awaiting keyboard input); and all 
the way on the right, the names of any files that are open for reading or writing, or 
a notice of what services have been invoked locally by some other machine. And 
underneath the line of text you can sometimes see a few thin horizontal lines. 
These are the run bars. The one immediately under the process state goes on when 
some process is actively running. The one a bit to the left of that, midway between 
the process state and the current package, indicates that you are paging, waiting 
for something to be brought in from disk. The other two run bars, which appear 
under the current package, you will see less often. They are related to garbage col- 
lection. 

One last bit of information on the monitor. We have some lisp machines which are 
3600 models, and some which are newer 3670s. The two models are quite close in 
most respects. One way in which they differ is how the brightness of the display is 
controlled. The 3600 monitors have a knob on the bottom side of the console 
cabinet, in the front right corner. To adjust the brightness of a 3670, hold down 
the Local key and press "B" for brighter or "D" for dimmer. (3640s are like 
3670s in this respect.) 

The Zmacs editor. The built-in editor commands are multitudinous, and the total 
number of available commands is continually growing because it's fairly easy and 
very tempting to add new ones. The Appendix lists the most basic commands, but 
by far the best way to find out what's around is to get used to using the online 



Section 1.5 Random Leftovers: the mouse, the monitor, the editor 13 



documentation. Some aspects of the lisp machine can be mastered by reading the 
manuals, but the editor is not one of them. Type Help to an editor window, and 
type Help again. Start exploring. The most commonly helpful of the help options 
are A (Apropos), C (Command), and D (Describe). To get started, use Help -C on 
c-X c-F and on c-X c-S. You should also try Help-A on "compile." And one of 
the best sources of information on the lisp machine is the m-. command (meta- 
period). It prompts for the name of something, then finds the file where whatever 
you typed is defined. The something is often a function, but it can also be many 
other kinds of lisp objects: a global variable, a flavor, a resource... Two other very 
useful features of the editor that you might not run into right away are these: if 
you type Suspend, you get a lisp listener which starts at the top of the screen and 
grows as you need it. This funny window is called the typeout-window. Resume 
returns to the editor. And m-X Dired, which is also invoked by c-X D, is a utility 
for editing directories. Call it on some directory and type Help. (Keep in mind 
that if it's a lisp machine directory, there's no security to keep you from deleting 
absolutely anything.) 



14 GETTING STARTED ON THE LISP MACHINE Chapter 1 



1.6 Problem Set #1 

Questions 

This "problem set" is really just a sample programming session, to familiarize you 
with basic operations on the lisp machine. 

1 . Create a namespace entry for yourself. 

2. Log in. 

3. Switch to the editor and create an empty buffer for a file in your home direc- 
tory named "fact.lisp" (if your home directory is on a lisp machine) or 
"fact.l" (if your home directory is on a UNIX machine with a 14 character 
limit on file names). 

4. Enter the text for a function named "fact" which returns the factorial of its 
argument. 

5. Compile the function from the editor with c-sh-C, and test it from the 
typeout window. 

6. When you're satisfied with the function's performance, save the buffer and 
compile the resulting file. 

7. Cold boot the machine. 

8. Log in, and note that the function "fact" is now undefined. 

9. Load the compiled version of your file. 
10. Run your function successfully. 



Section 1.6 Problem Set #1 15 



Solutions 

1. (si:login-to-sys-host), then Edit Namespace Object. Click on 
"create," click on "user," enter your chosen login-id, fill in the required fields 
(marked with *), if you wish fill in the optional fields, click on "save," click 
on "quit." 

2. Login yourid 

3. Select-E, c-X c-F fact, lisp (or fact.l) 

4. (defun fact (n) 

(if (zerop n) 
1 
(* n (fact (1- n)))) ) 

5. Type c-sh-C while anywhere inside the text of the function to compile it. 
Then hit the Suspend key to get to the typeout window, and evaluate ( fact 
5 ). The Resume key returns to the editor window. 

6. c-X c-S, Meta-X Compile File (Actually, if you skip the c-X c-S, Compile 
File will ask if you want the buffer saved first.) 

7. Suspend or Select-L, then Halt Machine. Type b (then Return) to the 
Fep prompt. 

8. Login yourid, then (fact 5) 

9. (load "host : >dir>subdir>f act" ) for a lisp machine, 
( load "host : //dir//subdir//f act" ) for a UNIX host. 

10. (fact 5) 



Chapter 2 

WHAT'S A FLAVOR? 



(For a more detailed presentation of this material, see Part X, Flavors, in volume 2 
of the Symbolics documentation. I have skipped many features of flavors which 
you may find useful, and which are fully described there.) 

The flavor system is the lisp machine's mechanism for denning and creating active 
objects, that is, objects which can receive messages and act on on them. A flavor is 
a class of active objects. One such object is called an instance of that flavor. 

There are two primary characteristics of a flavor: the set of messages an instance 
of that flavor can receive, and the set of state variables an instance of that flavor 
has. The state variables are called instance variables. Every object of a given 
flavor has the same set of instance variables, but the values of those instance vari- 
ables are likely to vary from object to object. And for each message a flavor can 
receive, it has a corresponding function to invoke. The function which gets called 
to handle a particular message is called the flavor's method for that message. That 
method is shared by all instances of the flavor. 

So, for instance, the window you see on a freshly booted machine is an instance of 
the flavor tv:lisp-listener Like any instance of lisp-listener, it can handle 286 



18 WHAT'S A FLAVOR? Chapter 2 



different messages (as of the current software). One of the messages it handles is 
: expose. Its expose method is a function which makes the lisp-listener visible on 
your screen, if it is not already. All lisp-listeners have the same expose method. 
One of the instance variables of flavor lisp-listener is exposed-p. All lisp- 
listeners have an exposed-p instance variable. If a given lisp-listener happens to be 
exposed, perhaps because you just sent it the :expose message, the value of its 
exposed-p instance variable will be t. Otherwise it will be nil. 



2.1 Basic Usage 

Flavors are defined with the defflavor special form. Here is a simple definition of a 
flavor named "ship," which might be used in a program for a space wars game. 

(defflavor ship 

(x-position y-position 
x-velocity y-velocity mass) 
()) 

It states that all instances of flavor ship will have five instance variables, as listed. 
(The empty list following the instance variables is related to a feature we'll consider 
in the section "Mixing Flavors.") Here are two methods for the ship flavor, to han- 
dle the messages : speed and : direction. 

(def method (ship : speed) () 

( sqrt (+ (expt x-velocity 2) 

(expt y-velocity 2)))) 

(def method (ship : direction) () 
(atan y-velocity x-velocity)) 

A defmethod looks very much like a defun. It has a function-spec, an argument 
list, and a body. The body will be executed in an environment in which the names 
of ship's instance variables will refer to the instance variables of the specific ship 
object which received the message. 

We might also wish to have methods which allow one to examine the values of 
ship's instance variables. Like: 

(defmethod (ship : x-position) () 
x-position) 



Section 2.1 Basic Usage 19 



Writing one of these methods for every instance variable would be tedious. For- 
tunately there is an option to defflavor that automatically generates such methods 
for all the instance variables. There is also an option which causes defflavor to 
automatically generate methods for setting the values of all the instance variables. 
Their definitions are as though one had done: 

(def method (ship : set-x-position) (new-position) 
(setq x-position new-position)) 

To get both of these options, our updated call to defflavor would look like: 

(defflavor ship 

(x-position y-position 
x-velocity y-velocity mass) 
() 
: gettable-instance-variables 
: settable-instance-variables ) 

To make an instance of flavor ship, we use the make-instance function:* 

(setq my-ship (make-instance 'ship)) 

This will return an object whose printed representation looks like #<SHIP 
25564553>. (The funny number will be the virtual memory address, in octal, of 
the instance.) 

To send a message to an instance, you use the send function. (The effect of send is 
in fact identical to that of funcall, but when funcalling an instance send is preferred 
for reasons of clarity.) We can now do things like: 

(send my-ship : set-x-velocity 1000) 

(send my-ship : set-y-velocity 500) 

(send my-ship : speed) - 1118.0339 

In addition to the instance variables, another very important variable is bound dur- 
ing the execution of a method. The value of the variable self will be the instance 
object itself. It's often used to send the object another message: 

(def method (ship : check-speed) () 



in the special case where the object is a window, you should instead use tv:make-window, which will 
perform some necessary bookkeeping operations in addition to calling make-instance for you. 



20 WHAT'S A FLAVOR? Chapter 2 



(when (> (send self : speed) 3.0e8) 

(f error "travel at rates greater than the - 
speed of light is not permitted" ) ) ) 



2.2 Initial Values for Instance Variables 

Instances of our ship flavor start out with all their instance variables unbound. 
Sending a newly constructed ship the :x-velocity message, for instance, would 
result in an unbound-variable error. But there are two ways to arrange for initial 
values to be assigned to an instance when it is made. If you have used the 
: initable-instance-variables option to defflavor, then you may specify 
the initial values in the call to make-instance. So with this defflavor: 

(defflavor ship 

(x-position y-position 
x-velocity y-velocity mass) 
() 
: gettable-instance-variables 
: settable-instance-variables 
: initable-instance-variables ) 

you could use this call to make-instance: 

(make-instance 'ship : x-position 30 : y-position -150 
:mass 10) 

The instance variables mentioned in the call will have the specified initial values. 
Instance variables not mentioned will be unbound, as before. Now suppose you 
want all instances to have certain initial values for certain instance variables. 
Perhaps you want the x-velocity and y-velocity of all new ships to be 0. You could 
specify so in every call to make-instance. But there is an easier way. You can 
specify in the defflavor what initial value you wish the instance variables to have. 
Here's our next version of the defflavor for ship: 

(defflavor ship (x-position 
y-position 
(x-velocity 0) 
(y-velocity 0) 
mass) 



() 
: gettable-instance-variables 



Section 2.2 Initial Values for Instance Variables 21 



: settable-instance-variables 
: initable-instance-variables ) 

Now all ships will start out with x- and y- velocities of — unless you specify oth- 
erwise in the make-instance. An initial value specified in make-instance will over- 
ride any default initial values given in the defflavor. 

Here is a slightly more complex example, taken from p. 427 of the flavor documen- 
tation: 

(defvar *def ault-x-velocity* 2.0) 
(defvar *default-y-velocity* 3.0) 

(defflavor ship ( (x-position 0.0) 
( y-position 0.0) 

(x-velocity *def ault-x-velocity* ) 
(y-velocity *def ault-y-velocity* ) 
mass ) 
() 
: gettable-instance-variables 
: settable-instance-variables 
: initable-instance-variables ) 

(setq another-ship 

(make-instance "ship :x-position 3.4)) 

The values of the new ship's instance variables will be 3.4 for x-position (the 
make-instance specification overrides the default of 0.0), 0.0 for y-position (the 
default), 2.0 for x-velocity and 3.0 for y-velocity (the values of the two global vari- 
ables), and mass will be unbound. 

It's useful to know that describe, a function which tries to print helpful information 
about its argument, no matter what it is, lists the values of all the instance vari- 
ables when applied to an instance: 

(describe another-ship) would print 

#<SHIP 40113625>, an object of flavor SHIP, 
has instance variable values : 
X-POSITION: 3.4 

Y-POSITION: 0.0 

X-VELOCITY: 2.0 



22 WHAT'S A FLAVOR? Chapter 2 



Y-VELOCITY: 3.0 

MASS : unbound 



2.3 Mixing Flavors 

The real power of the flavor system lies in its facility for producing new flavors by 
combining existing ones. Suppose we wished to define an "asteroid" object. It 
would need much of the same functionality as the ship flavor. In fact, all of ship's 
instance variables and methods would be appropriate. But we do want to have two 
distinct kinds of object, because we might wish to add more functionality to ship 
and asteroid which would not be shared. Ship, for instance, could use an instance 
variable for its engine power, or we might want to give each ship a name. And for 
each asteroid we might want to characterize its composition (perhaps part of the 
game requires replenishing resources by mining asteroids). 

One way to handle the situation would be to duplicate the lisp code for the common 
functionality in both flavors. Such duplication would clearly be wasteful, and the 
program would become far more difficult to maintain — any modifications would 
have to be repeated in both places. A better approach would be to isolate the com- 
mon functionality and make it a flavor in itself. We can call it "moving-object." 
Now the ship and asteroid flavors can be built on moving-object. We just need to 
specify the added functionality each has beyond that provided by moving-object. 
The defflavor for moving-object can be exactly like our existing defflavor for ship. 
The new ship defflavor will have moving-object specified in its list of component 
flavors, which up until now has been an empty list. 

(defflavor ship (engine-power name) 
(moving-object) 
: gettable-instance-variables 
: initable-instance-variables ) 

And asteroid: 

(defflavor asteroid (percent-iron) 
(moving-object) 
: gettable-instance-variables 
: initable-instance-variables ) 

Ship and asteroid both inherit all of moving-object's instance variables (including 
their default values) and all of its methods. They are each specializations of the 
abstract type moving-object. And the specialization could continue. We could 



Section 2.3 Mixing Flavors 23 



define a "ship-with-passengers" flavor, built on ship, with an added instance vari- 
able passengers, and added methods for :add-passenger and : remove- 
passenger. 

A flavor is not limited to having only one component flavor — it may have any 
number. So the set of components for a given flavor is actually a tree, consisting of 
all the flavor's direct components, and all of their direct components, and so on. 
Figure 1 shows the tree for the flavor tv:lisp-listener. (All are in the tv package, 
unless otherwise noted.) As you can see, it can get quite elaborate. tv:lisp-listener 
has 26 component flavors in all. Of the 287 handlers I mentioned earlier that 
tv:lisp-listener has, only one of them is locally defined in tv:lisp-listener. The rest 
are all inherited, about 150 from tvrsheet alone, and another 50 or so from 
tv:stream-mixin. 



2.4 Combined Methods 

Saying simply that a flavor inherits all the methods of its components sweeps an 
important issue under the rug. What happens if more than one of its components 
define methods for the same message? Which gets used? It depends on the order- 
ing of the component flavors. As it says on p. 432 of the documentation, "The tree 
of flavors is turned into an ordered list by performing a top-down, depth-first walk 
of the tree, including nonterminal nodes before the subtrees they head, and elim- 
inating duplicates." So the for tv:lisp-listener, the ordered list starts with: lisp- 
listener, listener-mixin, listener-mixin-internal, process-mixin, window... 

If more than one component flavor defines a method for a given message, with the 
kind of methods we have seen so far, the one which appears first on the list is taken 
as the combined flavor's method for that message. In particular, this means that 
any methods (again, of the type we have seen so far) defined locally in the new 
flavor will supersede all methods (for the same message) defined in any of the com- 
ponent flavors, since the new flavor is first on the ordered list. For example, the 
flavors tv.lisp-listener and tv:essential-window both define methods for the message 
: lisp-listener-p. The one in tv:essential-window always returns nil. The 
one in tv:lisp-listener always returns t. So a window without tv:lisp-listener mixed 
in will answer the : lisp-listener-p message with nil. But a lisp-listener 
will answer t, because its local method overrides tv:essential-window's. 

[There is an exception to the top-down depth-first rule. If you're 
already confused, skip these two paragraphs for now and come 
back later. If not, it's time to learn about the : included- 
flavors option to defflavor. Suppose you're defining a flavor 



24 



WHAT'S A FLAVOR? 



Chapter 2 



LISP-LISTENER 



LISTENER-MIXIN 



LISTENER- 

MIXIN- 
INTERNAL 
/ 
PROCESS STREAM 



BORDERS 
MIXIN 



MIXIN- 



MIXIN 



WINDOW 



SELECT- 

MIXIN 



MINIMUM- 
WINDOW 



LABEL- 
MIXIN 



GRAPHICS- 
MIXIN 



ESSENTIAL- 
EXPOSE 



ESSENTIAL- 
SET-EDGES 



ESSENTIAL- 
WINDOW 



ESSENTIAL- 
LABEL- 
MIXIN 



ESSENTIAL- 
ACTIVATE 



ESSENTIAL- 
MOUSE 



MARGIN-HACKER-MIXIN 
Sh INTERACTIVE -STREAM 



ShLINE-OUTPUT 
STREAM-MIXIN 



ST.BIDIRECTION- 
STREAM 



ShCHARACTER 
STREAM 



SHEET 



ShOUTPUT- 
STREAM 



ShSTREAM 



SL-INPUT-STREAM 



Figure 1. Flavor tree for lisp-listener 



Section 2.4 Combined Methods 25 



(call it my-flavor) which is intended to be used as a component for 
other flavors (call one of them user-flavor). And suppose that for 
the methods defined in my-flavor to work properly, it's necessary 
that some other flavor (call it needed-flavor) also be mixed into the 
user-flavor. And suppose further that needed-flavor is a rather 
basic flavor, and so should appear towards the end of user-flavor's 
ordered list. You could guarantee that needed-flavor always be 
present whenever my-flavor is present by making it a component of 
my-flavor. But then it would appear just behind my-flavor in 
user-flavor's ordered list of components. (Possibly closer to the 
front if some other component flavor uses it, but certainly no 
further back.) And some of needed-flavor's methods might over- 
ride methods of other flavors which were really intended to over- 
ride needed-flavor's methods, expecting to find needed-flavor near 
the end of the list. The solution here is the rincluded- 
flavors option. My-flavor lists needed-flavor as an included 
flavor. The effect is that when user-flavor uses my-flavor, needed- 
flavor will appear in the ordered list immediately after my-flavor 
only if no other flavors in user-flavor have needed-flavor as a com- 
ponent. If some other flavor does — and the expected case is that 
somebody near the end of the list will — then needed-flavor will 
appear there, as though my-flavor never mentioned it. 

An example: look back at the lisp-listener tree, and note the posi- 
tion of process-mixin. It will be the fourth flavor in lisp-listener's 
ordered list. The defflavor for process-mixin specifies that 
essential-window is an "included-flavor," because for process-mixin 
to work properly, any flavor which uses it must also use essential- 
window. But if process-mixin specified essential- window as a nor- 
mal component, essential-window would be brought all the way 
from its current position near the end of the list to fifth position, 
just behind process-mixin. Worse yet, sheet would be pulled from 
last to sixth, because it is a component (normal) of essential- 
window. But many of sheet's methods are supposed to be overrid- 
den by the other flavors, e.g., select-mixin. If sheet were pulled in 
front of select-mixin, the lisp-listener would never see many of the 
select-mixin methods, and it wouldn't behave properly at all. J 

As I've hinted, there are more kinds of methods than we have so far seen. All our 
methods have been what are called "primary" methods, and by default, when there 
is more than one primary method for the same message in the ordered list of com- 
ponent flavors, the one which appears first overrides all others. But sometimes you 



26 WHAT'S A FLAVOR? Chapter 2 



don't want to completely override the inherited primary method; sometimes you 
would like to specify something to be done in addition to the action of the inherited 
method rather than instead of. Then you would define a : before or an rafter 
method, often called before and after daemons. 

Here's how it works. Suppose I did the following defmethod: 

(def method (asteroid rafter : speed) () 
(do-something-or-other ) ) 

Asteroid already has a primary : speed method, inherited from moving-object. 
Once this new rafter : speed method is defined, asteroid will have a "com- 
bined method" for r speed, consisting of a call to the moving-object primary 
method followed by a call to the asteroid r after method. Any number of flavors 
in the ordered list of components may provide daemons. They will all be included 
in the resulting combined method. To quote from the documentation again, 
"Before-daemons are called in the order that flavors are combined, while after- 
daemons are called in the reverse order. In other words, if you build bar on top of 
foo, then bar's before-daemons will run before any of those in foo, and bar's after- 
daemons will run after any of those in foo." The primary method which appears 
first in the list will be called after all the before daemons (even if some of the 
before daemons appear later in the list than the primary method) and before all the 
after daemons. 

The value returned by a combined method is exactly the value returned by the pri- 
mary method — before and after daemons are executed only for side effect, i.e., 
their return values are ignored. It is allowable to have before and after daemons 
for a message which has no primary method; in such a case the combined method 
will return nil. 

Before and after daemons provide a lot of flexibility (perhaps more than you'd like 
to have just yet), but sometimes not enough. Fairly frequently a situation demands 
altering the context in which a primary method runs. A typical case would be 
binding a special variable to some value around the execution of the primary 
method, or putting the primary method into an unwind-protect or inside a catch.* 
Or deciding in some cases to skip the primary method altogether. Before and after 
daemons are unable to do any of these. The kind of method which can is called a 
whopper. 

Whoppers are best explained by example. Here are three which handle the cases I 



* If unwind-protect or catch are unfamiliar, you might want to look them up in volume 2. 



Section 2.4 Combined Methods 27 



just listed. To understand them you'll need to know that continues hopper is a 
system-provided function which calls the regular (non-whopper) methods for this 
message. 

(def whopper (some-flavor : some-message ) (argl arg2 ) 
(let ((some-special-variable temporary-value)) 
(continue-whopper argl arg2 ) ) ) 

(def whopper (some-flavor : some-message ) (argl arg2 ) 
( unwind-protect 
(progn (setup) 

(continue-whopper argl arg2 ) ) 
(cleanup) ) ) 

(def whopper (some-flavor : some-message ) (argl arg2 ) 
(unless (some-special-test argl) 
(continue-whopper argl arg2 ) ) ) 

Unlike before and after daemons, whoppers have control over the value returned by 
the combined method. They most commonly just pass up the value returned by 
continue-whopper (which will be whatever the primary method returns, as before), 
but they needn't. I could, for instance, do this: 

(def whopper (doubling-mixin : calculate) (argl arg2) 
(* 2 (continue-whopper argl arg2))) 

And since continue-whopper is just a function like any other, there's no reason you 
couldn't do something like this: 

(def whopper (doubling-mixin-of-another-sort : some-message) 
(argl arg2 ) 
(continue-whopper argl arg2 ) 
(continue-whopper argl arg2 ) ) 

(def whopper (yet-another-doubling-mixin : some-message) 
(argl arg2 ) 
(continue-whopper argl (continue-whopper argl arg2 ) ) ) 

One point about ordering needs to be clarified. A whopper surrounds not just the 
primary method, but all the before and after daemons, too. So suppose flavor "out" 
is built on top of "in," and both out and in have a whopper, a before daemon, an 
after daemon, and a primary method for message : mumble. Out's combined 



28 WHAT'S A FLAVOR? Chapter 2 



method for : mumble would look like Figure 2. 



out-before 
in-before 
out-whopper in-whopper out-primary 

in-after 
out-after 



Figure 2. Structure of combined method 

There is another kind of construct called a wrapper. This was the predecessor of the 
whopper, but now that the whopper exists, which is easier to use, there is seldom 
any need to use wrappers. 



2.5 Other Ways of Combining Methods 

All that I said in the previous section applied only to the default style of combining 
methods, called the : daemon type. There are actually about a dozen different 
types of method combination. Moreover, users can define additional types (with 
some effort). Before despairing, though, note that at least 90% of the time the 
: daemon type of method combination is used. All of the built-in types are dis- 
cussed in chapter 53 of Symbolics volume 2, "Method Combination." I will 
describe one of them, the : or type, both because it is a relatively simple example 
of what can be done, and because I've actually seen it used. 

First, in order to specify that you wish to use a type of method combination other 
than daemon, you use the : method-combination option to defflavor. Here is a 



Section 2.5 Other Ways of Combining Methods 29 



defflavor pulled from the source code for the window system: 

(DEFFLAVOR ESSENTIAL-MOUSE () () 

( : INCLUDED-FLAVORS ESSENTIAL-WINDOW) 

(: METHOD-COMBINATION ( :OR : BASE-FLAVOR-LAST : MOUSE-CLICK) ) ) 



essential-mouse is one of the flavors that appears in the lisp-listener tree given 
above. It's the mixin that enables a window to interact properly with the mouse. 
As you can see, this flavor has no instance variables and no component flavors. It 
has essential-window as an : included-f lavor, though that has no bearing on 
the immediate issue of non-standard method combination. The : method- 
combination option is what concerns us. It says that the : mouse-click 
methods for all flavors built on this flavor should use :or style combination, and 
that the order of combination should be base flavor (essential-mouse) last. 

So what's :or combination, and what does base-flavor-last mean? In :or combi- 
nation, all the methods appearing in the ordered list of component flavors are col- 
lected, and each is called in turn. If a particular method returns a non-nil value, 
the remaining methods are skipped. Otherwise (the method returned nil), the 
next one is called. We just step through all the methods, stopping as soon as one 
returns a non-nil value. Base-flavor-last means that the essential-mouse method for 
: mouse-click will be the last one to be tried, i.e., the methods will be collected 
and tried in the exact same order as their flavors appear in the ordered list of com- 
ponents. The opposite ordering may be specified with :base-f lavor-f irst. 

Suppose I define a flavor built (directly or indirectly) on essential-mouse, and give 
my flavor a : mouse-click method. Then whenever the : mouse-click mes- 
sage is sent to an instance of my flavor, my : mouse-click method will be called. 
If my method returns anything other than nil, no other : mouse-click 
methods will be called. If my method returns nil, then any .-mouse -click 
methods defined by flavors which are components of my flavor will get a chance. If 
the only other : mouse-click method is essential-mouse's, or if all the others 
return nil, then the essential-mouse method for : mouse-click will be called. 

The : mouse-click message is sent to the window under the mouse blinker 
whenever you press one of the mouse buttons. (The mouse process takes care of 
sending the message — you don't need to worry about it.) If you want to do some- 
thing special when the buttons are pressed, you simply need to define an appropri- 
ate : mouse-click method. Now there are six different kinds of button presses 
(three different buttons, and single or double clicks on each button). Maybe you 
have something you want to do if there is a single click on the left button, but not 



30 WHAT'S A FLAVOR? Chapter 2 



if there is a double click on the middle button. One of the arguments to the 
method will tell which kind of button press there was, so your method should test 
the argument, and if it's the kind of button press you want to handle (single left), 
do whatever you had in mind, and return something non-nil, so that the other 
: mouse-click methods won't be called and possibly do something else with the 
single left click, interfering with your action. If it's some button press that you 
don't care about (double middle), return nil so that the other methods will have a 
chance to handle it. 

Here's essential-mouse's method for : mouse-click, which is called if no one else 
handles the button press: 

(DEFMETHOD (ESSENTIAL-MOUSE : MOUSE-CLICK) (BUTTONS X Y) 
(COND ((AND (= BUTTONS #\MOUSE-L-1) 

(NEQ SELF SELECTED-WINDOW) 
(GET-HANDLER-FOR SELF ': SELECT)) 
(MOUSE-SELECT SELF) 
(SEND-IF-HANDLES SELF : FORCE-KBD- INPUT 

x ( : MOUSE- BUTTON , BUTTONS , SELF ,X ,Y) 
T)) 
( (OPERATION-HANDLED-P SELF : FORCE-KBD- INPUT) 
(SEND SELF : FORCE-KBD-INPUT 

*( : MOUSE-BUTTON , BUTTONS , SELF ,X ,Y) 
T)) 
((= BUTTONS #\MOUSE-R-1) 

(MOUSE-CALL- SYSTEM-MENU) ) 
(T 
(BEEP) ) ) 
T) 



You don't need to understand all the details to write your own : mouse-click 
methods. All you need to understand is the general format of testing the "buttons" 
argument and choosing some action accordingly. 



2.6 Vanilla-flavor 

shvanilla-flavor is the generic flavor on which all other flavors are built. Even if 
your defflavor specifies no components, your flavor will still have vanilla-flavor 
mixed in because the flavor system does it automatically (unless you explicitly 
instruct otherwise with the :no-vanilla-f lavor option to defflavor). But 



Section 2.6 Vanilla-flavor 31 



don't complain, because vanilla-flavor is very handy. It provides several extremely 
important methods. The : print-self method is called whenever an instance is 
to be printed. (The representation of the first ship instance we made, #<SHIP 
25564553>, was actually printed on my monitor by ship's : print-self 
method, inherited from vanilla-flavor.) The : describe method is used by the 
describe function. (The example shown earlier, where the describe function listed 
all of a particular ship's instance variables, was printed by ship's : describe 
method, also inherited from vanilla-flavor.) The :which-operations method 
returns a list of all the messages handled by the object. The :get-handler- 
f or method takes one argument, the name of a message, and returns the function 
object which is the instance's handler for that message. 

See chapter 52 in the flavor documentation for the remaining vanilla-flavor 
methods. 



2.7 Fun and Games 

And from The Hacker's Dictionary, Guy L. Steele, Jr., et ah 

FLAVOR noun. 

1. Variety, type, kind. "Emacs commands come in two flavors: single-character 
and named." "These lights come in two flavors: big red ones and small green 
ones." See VANILLA. 

2. The attribute that causes something to be FLAVORFUL. Usually used in the 
phrase "yields additional flavor." Example: "This feature yields additional 
flavor by allowing one to print text either right-side-up or upside down." 

VANILLA adjective. 

Standard, usual, of ordinary FLAVOR. "It's just a vanilla terminal; it 
doesn't have any interesting FEATURES." When used of food, this term 
very often does not mean that the food is flavored with vanilla extract! For 
example, "vanilla-flavored wonton soup" (or simply "vanilla wonton soup") 
means ordinary wonton soup, as opposed to hot-and-sour wonton soup. 

This word differs from CANONICAL in that the latter means "the thing you 
always use (or the way you always do it) unless you have some strong reason 
to do otherwise," whereas "vanilla" simply means "ordinary." For example, 
when MIT hackers go to Colleen's Chinese Cuisine, hot-and-sour wonton 
soup is the canonical wonton soup to get (because that is what most of them 
usually order) even though it isn't the vanilla wonton soup. 



32 WHAT'S A FLAVOR? Chapter 2 



2.8 Problem Set #2 

Questions 

Part I 

1. Define a function of four arguments that draws a square. The args are the 
window, the x and y coords of the square's center, and the size (length of 
each side). 

2. Define a flavor of window which handles a : draw- square message by call- 
ing your draw-square function. Then create a window of that flavor, being 
sure to keep a pointer to it, and verify that the : draw-square message 
works. 

3. Make the size argument to the method optional, defaulting to the value of a 
global variable *square-size*. Make the default size 100 pixels. 

4. Arrange it so that clicking left on the mouse while over your window draws a 
square centered on the mouse position, using the default size. 

5. A. Try these out — they temporarily bind the default size to 50 instead of 

100, and then draw a square using the default size. 



(let ( (*square-size* 50)) 

(send w : draw-square 150 150)) 



(let ( (*square-size* 50)) 

( process-sleep 300 ) ) click left over my-window during the sleep 

Why doesn't the second work? Why isn't the binding of *square-size* 
to 50 being seen? 

B. There is special form called let-globally which will get around this 
problem. Look it up in the manual and use it with a process-sleep so 
that clicking left over the window will make a square whose size is con- 
trolled by the let-globally. 

Making the default size an instance variable will get around the problem 
addressed in (5), and has several other advantages. We no longer clutter 
things up with an extra global variable. More important, with the default 
size an instance variable, it's possible for each instance of my-window to 
simultaneously have a different value for default-square-size. 

Redefine your flavor of window (and make a new instance) so the following 
works: 



Section 2.8 Problem Set #2 33 



(let ((old-size (send w :def ault-square-size) ) ) 
(send w : set-default-square-size 50) 
(process-sleep 300) 
(send w : set-default-square-size old-size)) 

7. What would happen if, during the process-sleep in the let in problem (6), I 
typed c-Abort? The reset of default-square-size back to its previ- 
ous value would never happen. The let, which is intended to be without 
side-effect, would have permanently changed the value of the instance vari- 
able. 

Add something to the let in problem (6) so that it will be guaranteed to reset 
default-square-size to its previous value. 

8. Without duplicating any code, define a new flavor of window, doubling- 
window, which behaves just like the window you've already defined, except 
that the squares it draws are twice as big as you ask for. That is, if you click 
left the square will be twice the size specified by the window's default- 
square-size instance variable, and if you explicitly send the : draw- 
square message the square will be twice the size specified by the third argu- 
ment to the message. 

Part II 

Not too long ago, I had to track down some bugs in the speech editor I was work- 
ing on, related to the ordering of the components of one of my flavors. I had 
switched the order of two components to fix one bug, and apparently introduced 
some new ones. At least, the program was misbehaving in a way it previously 
hadn't, and the only relevant change I'd made was the component reordering. It 
was a sort of misbehavior that would have been difficult to debug by interrupting 
the program while it was doing the wrong thing, examining the state of the world, 
and working back to see which message-handler was responsible for the new 
behavior. So I instead decided to find out what messages would be handled 
differently with the new component ordering, and work forward to see which of 
those changed handlers could be causing the odd behavior. 

The Flavor Examiner (Select-X) has a facility for listing all the message-handlers 
of a given flavor, together with the name of the flavor the handler was inherited 
from. So all I had to do was list all the handlers for my two flavors, and compare 
them. If only one of the two handled a particular message, it wouldn't matter in 
which order the flavors were mixed in, since I would get the same handler either 
way. And if they both handled a message, but handled it with the same inherited 
method from a common component, the order of combination still wouldn't matter. 
Any messages, however, which were handled by both flavors but with different 



34 WHAT'S A FLAVOR? Chapter 2 



methods, would be likely suspects. Which handler my combined flavor had would 
indeed depend on the order of combination. 

It would have been a simple task, except that the two flavors involved each had 
between 190 and 200 handlers. Both included the flavor tv: window, which has 194 
handlers. Nearly all of the handlers I had to wade through were internal to 
tvrwindow (mainly from the flavors tvrsheet and tv:stream-mixin) , and shared by my 
two flavors. There were only a handful of suspects, and once I found them it did 
not take too long to realize that my mistake had been in using tv:window-pane 
where I should have used tv:pane-mixin. The bugs went away. But it was a far 
more painful experience than it would have been if we had a few simple utilities for 
filtering the lists of handlers. This portion of the problem set asks you to write a 
few such facilities. 

1 . Write a function of two arguments, to be called on two instantiated objects of 
different flavors. It should return a list with four sublists: a list of handlers 
in flavor- 1 and not in flavor-2, a list of handlers in flavor-2 and not in flavor- 
1, a list of handlers in both flavors, and a list of pairs of corresponding 
handlers, for messages handled by both flavors but with different handlers. 

2. That's already enough to be useful, but often a flavor is not instantiated, and 
sometimes may not even be instantiable without further mixins. The function 
you've defined won't work on such flavors. Write a similar function which 
will take as arguments the names of two flavors. 

3. The answer to (1), and depending on how you did it, quite possibly the 
answer to (2), are subject to a bug of sorts. They may decide under certain 
conditions that two handlers are different, when for all practical purposes 
they are not. Consider the following:* 



FOO (foo) 

1. interjection. Term of disgust. For greater emphasis, one says MOBY FOO (see MOBY). 

2. noun. The first metasyntactic variable. When you have to invent an arbitrary temporary 
name for something for the sake of exposition, FOO is usually used. If you need a second one, 
BAR or BAZ is usually used; there is a slight preference at MIT for bar and at Stanford for 
baz. (It was probably at Stanford that bar was corrupted to baz. Clearly, bar was the origi- 
nal, for the concatenation FOOBAR is widely used also, and this in turn can be traced to the 
obscene acronym "FUBAR" that arose in the armed forces during World War II.) 

Words such as "foo" are called "metasyntactic variables" because, just as a mathematical 
variable stands for some number, so "foo" always stands for the real name of the thing under 
discussion. A hacker avoids using "foo" as the real name of anything. Indeed, a standard 
convention is that any file with "foo" in its name is temporary and can be deleted on sight. 



BAR 



The second metasyntactic variable, after FOO. If a hacker needs to invent exactly two names 



Section 2.8 Problem Set #2 35 



(def flavor foo ( ) ( ) ) 
(def flavor bar ( ) ( ) ) 

(def method (foo : silly-message ) () nil) 

(def method (bar : before : silly-message) () nil) 

(def flavor flav-1 ( ) 

(foo bar) ) 
(def flavor flav-2 ( ) 

( foo bar ) ) 

Flav-1 and flav-2 each have a combined method for the message : silly- 
message, and they use the same components for their respective combined 
methods. I would like these two combined methods to be considered the 
same, and fall into the third of our four sublists. But your functions may be 
putting such pairs of methods into the fourth sublist. If so, modify one or 
both of your answers to (1) and (2) to re-classify these methods accordingly. 

Of all your answers to questions (l)-(3), select the one that seems to be the 
most useful, and merge it into the Flavor Examiner. 



for things, he almost always picks the names "foo" and "bar." 
(The Hacker's Dictionary, Guy L. Steele, Jr., et al) 



36 WHAT'S A FLAVOR? Chapter 2 



Hints 

Part I 

1. Your function should either send the window the : draw- line message four 
times, or the : draw- lines message once. You can find out about the 
arguments to the : draw-line and : draw-lines messages by looking 
them up in the index to volume 7. 

2. Your flavor of window should be built on tv.window. The : draw- square 
method will need to use the self variable. 

Using the window brings up a somewhat subtle issue. At times you'll need 
the lisp listener exposed so you can type commands. And at times you'll need 
your new window exposed so it can display the squares being drawn. You 
could, then, alternate between the two windows, but that becomes awkward. 
Far better is to position and shape the two windows such that they can both 
be exposed simultaneously. One procedure would be to first narrow the lisp 
listener down to the left half of the screen (choose Edit Screen from the sys- 
tem menu, then Move Single), then make your window with the following 
form, choosing an area with the mouse that doesn't overlap the narrowed lisp 
listener: 

(setq w (tv: make -window 'my-window :edges-from : mouse 

:expose-p t ) ) 

Now you're ready to try drawing squares, with (send w : draw-square 
... ). 

3. The global variable should be defined with defvar or def const, and initialized 
to 100 in the call to defvar/const. The redefined method should include in its 
arglist "^optional (size *square-size* )". 

4. The window needs a : mouse-click method. Recall that :mouse-click 
methods use : or combination, so your method should return t if it handles 
the click, and nil otherwise. 

5. A. Think about processes. 

B. let-globally looks just like a let. 

6. The flavor will have an instance variable named default-square-size, 
and you'll need to use the rsettable-instance-variables option. 
The new : draw- square method will have to access the instance variable. 

7. Use unwind -protect 



Section 2.8 Problem Set #2 37 



8. Your new flavor should be built on the old one, and should have a whopper 
for : draw- square. 

Part II 

1. You can get a list of all the messages an object handles with :which- 
operations. And given a specific message, you can get the handler for it 
with :get-handler-for. 

2. The Flavor Examiner finds the methods from the flavor name, without having 
an instantiated object. Find out how. As a simpler and nearly as useful 
alternative, note that the editor command M-x List Combined Methods 
(among others) can do the same thing as long as the flavor has been instan- 
tiated at least once, and track down what it does. (Try meta-. on com-list- 
combined-methods.) This won't help for uninstantiated flavors, but does 
remove the need to have a pointer to an actual instance in cases where the 
flavor has been instantiated. 

3. If you're modifying your answer to (1), you're probably dealing with com- 
piled function objects. Notice that the describe function, when applied to the 
compiled function object for a combined method, prints the necessary infor- 
mation under the title extra info, after :f definition-location- 
hints. Find out how. 

If you're modifying your answer to (2) you probably already have a data 
structure containing the necessary information, and you just need to make 
use of that information to re-classify the handlers. 

4. The source code for the Flavor Examiner is in the file "sys: window; flavex." 



38 



WHAT'S A FLAVOR? 



Chapter 2 



Solutions 



Part I 



x half-size) ) 
y half-size) ) ) 



1. (defun draw-square (window x y size) 

(let* ((half-size (// size 2)) 

(xO (- x half-size)) (x1 (+ 

(yO (- y half-size) ) (y1 (+ 

(send window :draw-line xO yO xO y1 ) 

(send window : draw- line xO y1 x1 y1 ) 

(send window : draw-line x1 y1 x1 yO ) 

(send window :draw-line x1 yO xO yO ) ) ) 

(defun draw-square (window x y size) 
(let* ((half-size ( // size 2)) 

(xO (- x half-size)) (x1 (+ x half-size)) 
(yO (- y half-size)) (y1 (+ y half-size))) 
(send window : draw-lines tv:alu-ior 

xO yO xO y1 x1 y1 x1 yO xO yO ) ) ) 

2. (def flavor my-window ( ) 

(tv: window) ) 

(def method (my-window : draw-square) (x y size) 
(draw-square self x y size)) 

3. (defvar *square-size* 100) 



(def method (my-window : draw- square) 

(x y &.optional (size *square-size* 
(draw-square self x y size)) 



4. (def method (my-window : mouse-click 
(cond ((= buttons #\mouse-l-1) 

(send self : draw-square ( 



(buttons x y, 



5. A. 



t) 



(t nil))) 



x tv: lef t-margin-size ) 
(- y tv: top-margin-size) ) 
prevent other .mouse-click methods 

from being called (:or combination) 
allow other kinds of clicks to fall through 



It doesn't work because the : mouse-click method is called from 
the mouse process, and different processes each have their own variable 
binding stacks. The mouse process can see the global value of 
*square-size* (100) which was set by the defvar, but not the let bind- 
ing (50) which is in the binding stack of your lisp listener. (There is 



Section 2.8 Problem Set #2 39 



more information on processes in the next chapter.) 

B. (let-globally ( ( *square-size* 50)) 
(process-sleep 300)) 

6. (def flavor my-window 

( (default-square-size 100 ) ) 
(tv: window) 
: settable-instance-variables ) 

(def method (my-window : draw-square ) (x y ^optional size) 
; ; can't default the optional arg because environment 
; ; isn't set up yet - use "or" in body 
(draw-square self x y (or size default-square-size))) 

7. (let ((old-size (send w :def ault-square-size) ) ) 

( unwind-protect 

(progn (send w : set-default-square-size 50) 
(process-sleep 300)) 
(send w : set-default-square-size old-size))) 

kwc-letf, a macro written by Ken Church, does just this sort of thing, and 
looks a lot nicer. (Its name was chosen to distinguish it from letf, a special 
form provided by Symbolics which has similar, but slightly different, effects.) 
The syntax is like that of let, except in place of the names of local variables 
to be bound, kwc-letf accepts any reference which can be understood by setf. 
It arranges for that reference to return the specified value if called within the 
kwc-letf, and for the old value to be restored upon exiting. In our case, it 
would be used like this: 

(kwc-letf (((send w :def ault-square-size ) 50)) 
(process-sleep 300)) 

This produces identical compiled code, but makes the intent much clearer — 
you can see that I just want to evaluate the process-sleep in a context where 
(send w :def ault-square-size) would return 50. The call to kwc- 
letf macroexpands into: 

(LET ((#:G0531 (SEND W : DEFAULT-SQUARE-SIZE) ) ) 
(UNWIND-PROTECT 

(PROGN (SEND W ': SET-DEFAULT-SQUARE-SIZE 50) 
(PROCESS-SLEEP 300)) 
(PROGN (SEND W ': SET-DEFAULT-SQUARE-SIZE #:G0531)))) 



40 WHAT'S A FLAVOR? Chapter 2 



8. (def flavor doubling -window () 
(my-window) ) 

(defwhopper (doubling-window : draw-square) (x y ^optional size) 
(continue -whopper x y (if size (* 2 size) 

(* 2 default-square-size)))) 

An alternative whopper would be: 

(defwhopper (doubling-window :draw-square) (x y &.optional size) 
(let ((default-square-size (* 2 default-square-size))) 
(continue-whopper x y (and size (* 2 size))))) 

Part II 

1 . Here is a simple-minded implementation: 

(defun sort-handlers ( object- 1 object-2) 
(loop 

for message in (union (send object- 1 :which-operations) 

(send object-2 :which-operations) ) 
for handler- 1 = (send object- 1 :get-handler-for message) 
for handler-2 = (send object-2 :get-handler-for message) 
when (not handler-2) collect handler- 1 into only-1 
else when (not handler-1) collect handler-2 into only-2 
else when (eq handler-1 handler-2) collect handler-1 

into both-and-same 
else collect (cons handler-1 handler-2) 

into both-and-dif f erent 
finally (return (list only-1 only-2 

both-and-same both-and-dif f erent) ) ) ) 

2. A partial answer: everything you need to know about a flavor is in the list 
returned by (si: examiner-compute-magic-list (get flavor -name 
'si : flavor) ). The extraction of the info is done by the method 
:compute-all-handlers-once of the flavor flavex:flavor. As for M-x 
List Combined Methods, the crucial function is zwei:find-combined-methods 

3. To follow up the describe hint, this is what describe uses: 

(cdr (assq :fdef inition-location-hints 
( si : cca-extra-inf o 

(si:compiled-function-cca function-obj) ) ) ) 



Section 2.8 Problem Set #2 41 



So we might replace this line in my answer for (1): 

else when ( eq handler- 1 handler-2) collect handler- 1 

into both-and-same 

with: 

else when (or (eq handler- 1 handler-2) 

(equal ( f oo handler- 1) ( f oo handler-2))) 
collect handler- 1 into both-and-same 

where ( f oo handler) is: 

(cdr (assq : f definition-location-hints 
( si : cca-extra-inf o 

( si : compiled-f unction-cca handler ) ) ) ) 

And if you used my partial answer for (2), the list returned by shexaminer- 
compute-magic-list still contains everything you need to know, although it's 
possible your answer to (2) threw away some of the information needed for 
(3). 

4. At the moment, this is an open problem — I don't know exactly what's 
required to make such an addition. But it sure would be nice to have... 



Chapter 3 

MORE ON NAVIGATING THE LISP MACHINE 



The last chapter discussed an aspect of programming with the lisp language, as 
implemented on the lisp machine. This one is about some aspects of using the lisp 
machine which are more or less independent of programming on it, i.e., what you 
might call the operating system of the lisp machine. 



3.1 The scheduler and processes 

Switching back and forth among the different processes can be explicitly controlled 
by the lisp machine programmer (read the documentation on Stack Groups), but 
almost never is. A special module called the scheduler generally handles this 
responsibility. Every l/60th second the scheduler wakes up and decides whether 
the current process should be allowed to continue running, and if not, which other 
process should get a chance. 

If the current process has been running continuously for less than a second, and 
wishes to continue, it is allowed to. (Note that a full second is a long time for this 
sort of thing, compared to other timesharing arrangements.) Or if it's been running 
for a second but no other process wishes to run, it is still allowed to continue. But 



44 MORE ON NAVIGATING THE LISP MACHINE Chapter 3 



if it's been monopolizing the machine for more than a second, and one or more 
other processes want to run, it's forced to take a rest while the scheduler gives the 
others a chance. The process chosen by the scheduler is now treated as the previ- 
ous current process was: it will be allowed to run until some other process (es) wish 
to run and the current process either volunteers to give the others a chance, or 
passes the one second mark. 

The way a process "volunteers to give the others a chance," or, in less emotionally- 
laden terms, informs the scheduler that it doesn't need to run, is with the process- 
wait function. Process-wait specifies a condition the process is waiting for. When 
the condition becomes true, the process is ready to run. When the scheduler 
decides to resume the process, the call to process-wait returns and the computation 
continues from there. The first argument to process-wait is a string to appear in 
the wholine (at the bottom of the screen) while the process is waiting. The second 
arg is a function and any remaining args are arguments to the function. To see 
whether the process is ready to continue, the scheduler applies the specified func- 
tion to the specified arguments. The return value of the function is what the 
scheduler uses for the "condition" mentioned above. This function is often called 
the process' wait -function. Here is the process- wait which is responsible for "Tyi" 
appearing in the wholine most of the time: 

(PROCESS-WAIT "Tyi" SELF ':LISTEN) 

This call is buried somewhere in the code windows (or anything with tv:stream- 
mixin) use for reading from the keyboard. It says that the process will be ready to 
continue when application of SELF to the argument : LISTEN returns non-nil. 
Since funcall is equivalent to send when dealing with instances (see the previous 
chapter), this process-wait will return when (send self : listen) is true. 
The handler for .listen just checks to see if anything is in the io-buffer, so the pro- 
cess which calls this process-wait will forfeit its turns in the scheduler until it has 
something in its io-buffer. 

Now a question for the bold: what happens if an error occurs in the scheduler? It 
is, after all, just another piece of lisp code. And even if the scheduler code itself is 
bug-free, all the wait-functions are called in the scheduler, and any loser* can 
write a buggy wait-function. It's also the case that blinking of flashing blinkers 
gets done from the scheduler. (There's a clock function list of things to be done 
every time the scheduler runs, and by default the only thing on the list is blinking 
the blinkers.) And any loser can also write a buggy :blink method for his/her 
blinkers — I've certainly done it. So what happens when the scheduler runs into an 



See hacker's definition at end of chapter. 



Section 3.1 The scheduler and processes 45 



error? The scheduler has no window to use. How can the debugger communicate 
with you? 

What happens is that the scheduler enters the debugger and uses what is called the 
cold-load stream. This is a very basic stream which completely bypasses the win- 
dow system. It uses the screen as it would a dumb terminal, with no regard for the 
previous display contents, ignoring even window boundaries. There will be no 
blinker (which makes typing somewhat disconcerting) and none of the input editor 
commands will be active, apart from the rubout key. But you will be in a legiti- 
mate debugger, from which you can attempt to set things right. So don't panic. 

Our view of scheduling is now fairly complete. The current process owns the lisp 
machine until it either does a process-wait, or uses up its second. When either of 
these occurs, the scheduler calls the wait-functions of the other processes. The first 
process whose wait-function returns a non-nil value gets to become the current- 
process. If none of them do, the old current process remains the current process. 
And if any errors occur while in the scheduler, the debugger uses the cold-load 
stream. 

Fine. Now it's time to complicate things again. At any given time a process is 
either active or inactive. Inactive processes are not even considered by the scheduler 
when it looks for an alternative to the current process. Their wait-functions aren't 
called at all until they become active. And what makes a process active or inac- 
tive? Two of the instance variables of a process are its run-reasons and its 
arrest -reasons. An active process is one with no arrest reasons and at least one run 
reason. Otherwise (at least one arrest reason or no run reasons) the process is inac- 
tive. There are messages for looking at a process' run and arrest reasons, and for 
adding to or deleting from them. A program might use those messages, but an 
interactive user is more likely to arrest or un-arrest a process in one of the follow- 
ing ways (all of which end up passing those same messages, but are easier to use) : 

1. The system menu has options for arresting or un-arresting the process in the 
window the mouse is over. 

2. If you click on the name of a process in Peek's display of processes, you get a 
menu of useful things to do to that process. Two of them are arresting and 
un-arresting. 

3. Typing Function- A arrests the process the wholine is watching. (This is usu- 
ally the selected window's process. But you can change which process the 
wholine watches with Function-W.) Function-minus-A un-arrests it. 

Another common operation to perform on a process is to reset it. This is very 
much like typing c-m-Abort to it. It flushes everything on the process' stack and 



46 MORE ON NAVIGATING THE LISP MACHINE Chapter 3 



restarts it. (More exactly, it reapplies the process' initial function to its initial 
arguments, but you needn't understand that just yet.) You can only type c-m- 
Abort to a process when you can select its window, which isn't always possible, but 
you can reset a process anytime. The options for how to reset a process are similar 
to those for un-/arresting one. You can send a process the :reset message; you can 
use the reset option in the system menu to reset the process in the window under 
the mouse; you can use the menu in Peek's display of processes. 

Note that all these ways of resetting, except for explicitly sending the :reset mes- 
sage, depend on being able to use the mouse. So if the mouse process is the one 
which is in trouble, they won't work. The only way out is to get a handle on the 
mouse process and send it the :reset message. An extremely useful fact to 
remember is that the value of the symbol tv:mouse-process is always the mouse pro- 
cess itself (an instance of flavor si:process). So typing this will often unwedge the 
mouse process: (send tv: mouse-process :reset). 

One final note on resetting: (send current-process : reset) doesn't work. 
(It just returns nil.) The usual method for unwinding a stack doesn't work from 
within that stack. To reset the current process, you need to either spawn a new 
process for the sole purpose of resetting your process (use process-run-function) , or 
use an optional argument to the reset message: (send current-process 
: reset : always ) will work. 

Before long you will probably have cause to create your own processes. Take a 
look at Part III of Volume 8 of the Symbolics documentation when the need arises. 



3.2 Windows 

The entire set of existing windows is organized into several trees. The root of each 
tree is a screen. (Screens are built on tv:sheet but don't have all the other mixins 
that make a window.) Each window has a superior (towards the root of the tree) 
and any number (possibly 0) of inferiors (towards the leaves) . The windows option 
in Peek displays all the trees (subject to a restriction mentioned below). 

The state of a window may be characterized in any of several ways. The window 
may be selected or deselected, it may be exposed or deexposed, and it may be 
activated or deactivated. The terminology is confusing and unfortunate. Selection, 
exposure, and activation are not independent factors. In fact, they are closely tied. 
Before a window may be selected, it must be exposed. And before it may be 
exposed, it must be activated. So there are four possible states for a window: 
deactivated; activated but not exposed (usually called deexposed); activated and 



Section 3.2 Windows 47 



exposed but not selected (usually called exposed); and activated, exposed, and 
selected (usually called selected). 

If a window is deactivated, the system will not keep track of it. More precisely, the 
window will not appear in the array which is the value of tv:previously-selected- 
windows. Many parts of the system software, including Peek, use that array when 
they are expected to produce a list of all windows. And a deactivated window will 
not appear in the inferiors list of its superior. The system will not keep any 
pointers to such a window, so unless you have one, the window will be garbage- 
collectible. (Ignore this point for now if you don't understand garbage collection.) 

Once activated, a window may become exposed. Being exposed means roughly that 
the window has somewhere for its typeout to go. Any window which is completely 
visible on the screen, not even partly covered by some other window, is exposed. (It 
is also possible for windows to be exposed without being visible. Such a window 
must have somewhere for its typeout to go other than your screen — that place 
would be a bit-array which could later be mapped onto the screen. See sections 
11.4 and 11.5, Pixels and Bit-save Arrays, and Screen Arrays and Exposure, in 
Volume 7. For now let's just assume that only visible windows are exposed.) 

If a window which is not exposed is asked to type something out (perhaps with the 
:tyo or :string-out messages), it won't be able to do it, since it has no place to send 
the typeout. How it reacts is controlled by its deexposed -typeout -action, which is 
an instance variable of tv:sheet. It may specify, for instance, that the window 
should try to expose itself, or that an error should be signaled. The default value of 
deexposed-typeout-action, : normal, specifies that the process doing the typeout 
should enter an output hold state. That means it will do a process-wait (remember 
those?) with a wholine state of "Output Hold" and a wait-function which essen- 
tially waits for the window to become exposed: 

(PROCESS-WAIT "Output Hold" 

#' (LAMBDA (SHEET) 

(NOT (SHEET-OUTPUT-HELD-P SHEET))) 
SELF) 

In addition to the usual ways of exposing the window (mentioned below), when an 
output hold occurs there is one extra way which becomes available. That is to type 
Function-Escape. 

Now for selection. Although any number of windows may be simultaneously 
exposed, as long as they can all fit on your screen without overlapping, only one 
window at a time may be selected. The currently selected window is always the 



48 MORE ON NAVIGATING THE LISP MACHINE Chapter 3 



value of the symbol tv:selected-window. The selected window is the one to which 
keyboard input is directed. It usually has a blinking rectangular cursor in it. 
There must, of course, be a process running in the selected window for it to do any- 
thing with the keyboard input. If the selected window has no process, typing on the 
keyboard has no effect, except for special keys like Function and Select. 

If we imagine the four possible window states (deactivated, deexposed, exposed, 
selected) occupying a spectrum, the various messages for changing the state of a 
window may be pictured as follows: 



ACTIVATION EXPOSURE SELECTION 



DEACTIVATED 



DEEXPOSEO 



EXPOSED 



SELECTED 



ACTIVATE 

EXPOSE 

SELECT 



DEACTIVATE 

DEEXPOSE 

DESELECT 



Figure 3. Transitions among window states 



The meaning of the arrows is that a window sent the given message will be pushed 
all the way from its current state to the head of the arrow. So, for instance, if an 
exposed window is sent the :deactivate message, it will be both deexposed and deac- 
tivated. A selected window would be deselected, deexposed, and deactivated. The 
messages only push in the direction of the arrows, they don't pull. That is, if the 
window is already at or beyond the arrowhead nothing happens. If a selected win- 
dow is sent the :activate message, there is no effect. It is not pulled back to the 
deexposed state. 

A freshly instantiated window, as is returned by tv:make-window, will be deac- 
tivated, unless you specify otherwise. This is also the state of a window which has 
been sent the deactivate or :kill messages. (Killing a window deactivates all of its 
inferiors as well as itself.) 

You can always change the state of a window by sending it an appropriate mes- 
sage, but there are several ways to make these messages be sent without explicitly 
sending them yourself. The system menu has an option for killing the window 



Section 3.2 Windows 49 



under the mouse, and one for selecting a window from the list in tv:previously- 
selected-windows. The Edit Screen option in the system menu pops up another 
menu with options for killing or exposing any partially visible window, and for 
exposing any window in tv:previously-selected-windows. (The Edit Screen menu 
also has options for creating, moving, or reshaping windows.) And if you click on 
the name of a window while in the windows display of Peek, you get a menu with 
options for selecting, deselecting, exposing, deexposing, deactivating or killing the 
window. 

There's another way to select a window which you are already familiar with: use 
the Select key. For the kinds of windows accessible via the Select key (Select-Help 
displays a list), the effect of the Select key depends on how many instances of that 
flavor of window exist. Let's take Select-E (for the Zmacs Editor) as an example. 
If there are no existing Zmacs windows, typing Select-E will create one and select 
it. If there is exactly one Zmacs window, Select-E will select it (unless it is already 
the selected window, in which case the screen will flash and it will remain the 
selected window) . If there are more than one existing Zmacs windows, and none of 
them are the selected window, Select-E will select the one which had most recently 
been the selected window. Typing Select-E repeatedly will rotate through all the 
existing Zmacs windows. 

Typing Select-c-E (hold down the control key while striking E) will always create 
and select a new Zmacs window, regardless of whether there are already some. 

Windows can also be selected with the Function key. Function-S selects the previ- 
ously selected window. Providing a numeric argument between the Function key 
and S allows rotation of the selected windows in various arcane ways. Type 
Function-Help and read about S for a full description. 

Changing the state of a window will often cause the state of other windows to 
change. For instance, if I select one window, the window which had been selected 
necessarily becomes deselected. And if I deselect a window, some other window 
(the previously selected one) becomes selected. Similarly, exposing a window may 
partially or entirely cover some other window which had been exposed; the latter 
window is forced to become deexposed. And deexposing a window may uncover 
some other window, thereby exposing it. (A subtler point arises here. Simply send- 
ing the :deexpose message usually does not have the intended effect. Since no other 
windows will be covering the one which has just been deexposed, it will immedi- 
ately be automatically re-exposed. It will look like nothing happened. What you 
probably meant to do was either expose some other window [which will automati- 
cally deexpose the first window], or send the first window the :bury message, which 
in addition to deexposing it, puts the window underneath all the other windows, so 



50 MORE ON NA VIGA TING THE LISP MACHINE Chapter 3 



that the window that ends up being auto-exposed is some other one.) 

The interactions among windows can become terribly convoluted. There are several 
kinds of locks intended to keep everything straight. If something goes wrong and 
an error occurs while the window system is locked, the debugger won't be able to 
expose a window to use. So it uses the cold-load stream, just as when an error 
occurs inside the scheduler. 

If you've been messing with the window system in unwise ways, it's possible to get 
it locked up so that you can't do anything (I do it all the time). If the window 
which appears to be selected isn't responding to typein, and c-m-Abort doesn't help, 
and the mouse is dead, and you can't select some other window with the Select or 
Function keys, it may be that you're hung up in a locked window system. Your 
last resort in such a case (short of h-c-Function and a warm or cold boot) is to type 
Function-control-Clear Input. This clears all the locks in the window system. It's 
a sledgehammer, and can easily break some things, but it may revive your machine 
without having to boot. 

One last note about windows. When a window is sent more than one screenful of 
typeout at a time, it may pause at the end of each screenful, type **MORE**, and 
wait for you to press any key before continuing. This behavior is called more pro- 
cessing. Whether more processing occurs (as opposed to continuous output) is con- 
trolled by Function-M and Function-c-M. Type Function-Help for details. For 
more processing to occur it must be turned on both globally and for the individual 
window. 



3.3 Debugging 

The trace feature can be invaluable in finding out why your code isn't doing what 
you expected. You can read all about it in chapter 4 of volume 4. The basic form 
works like this: you turn on tracing for a function named foo by evaluating 
(trace foo). From then on, every time foo is called, a line will be printed on 
your screen announcing that foo has been entered and listing its arguments. And 
when foo finishes another line will be printed, announcing the exit from foo and 
listing the return value(s). You turn off tracing of foo with (untrace foo). 
Some of the fancier features allow you to print the values of arbitrary expressions 
upon function entry or exit, or to make tracing conditional on some predicate, or to 
enter a break loop or the debugger upon entry. The syntax for these features can 
be difficult to remember, so I'd suggest using the trace menu to select them. (You 
get the trace menu by clicking on trace in the system menu or by doing Meta-X 
Trace in the editor.) 



Section 3.3 Debugging 51 



Trace can be used on anything you can describe with a function spec (see chapter 
27 of volume 3). Function specs are most often symbols, but can also be something 
like (: method tv: sheet : expose), referring to the :expose method for flavor 
tv:sheet. 

One note of caution: you can instantaneously make your machine unusable by 
tracing the wrong function. If, for instance, you'd traced some function that gets 
called every time a character is read from the keyboard, with the feature that 
throws you into the debugger upon function entry, you'd have a real tough time 
typing "untrace." (On the other hand, the kinds of functions that can break every- 
thing when traced are not ones the new user is likely to be interested in anyway, so 
don't feel inhibited by this warning. Go ahead and play. You can always boot. I 
just thought I should mention that I've screwed myself this way more than once.) 

Advising is a more general facility similar to tracing. Here you supply an arbitrary 
piece of code to be executed upon function entry or exit. Advice comes in three 
varieties: before, after and around. The three kinds are very much like before 
daemons, after daemons, and whoppers. Advising is explained in detail in chapter 
4, volume 4. 

The debugger itself is the main tool for discovering what went wrong. You should 
remember a few things about the debugger from Chapter 1 : it is entered whenever 
an error occurs, and may be entered manually with the function ( dbg ) or by typ- 
ing m-Suspend. Once in the debugger, you can move up and down the stack with 
c-P and c-N (for previous and next), and see the whole stack with c-B (for back- 
trace). There are generally a series of restart handlers bound to the super keys, 
and to Resume and Abort. 

Now some debugger facilities that may be new. The arguments of the function in 
the current frame are accessible via the function dbg:arg. It takes one argument, 
specifying which of the current function's arguments you want (you may specify 
either by name or by number). Suppose the current function has an argument 
named "array," and I want to know what element #5 in the array is. I could type 
(aref (dbg:arg 'array) 5). The best part about dbg:arg is that it can be 
used with setf to change the argument. So if the first argument to the current 
function were the string "now" and I wanted to change it to the string "then", I 
would type ( setf (dbg:arg ) "then" ). (Note that the numbering of argu- 
ments begins at 0, not 1 .) The function dbg:loc is analogous to dbg:arg, but works 
on local variables instead of arguments. 

You can also use the debugger commands c-m-A and c-m-L to get the values of 
arguments and local variables. Returning to the case where I wanted to see 



52 MORE ON NAVIGATING THE LISP MACHINE Chapter 3 



element #5 of an array which was an argument in the current frame, I could type 
(assuming the array were the third argument) c-2 c-m-A, which would return the 
array object and give me a fresh debugger prompt, then (aref * 5), using * to 
access the previously returned value. 

Once you've re-arranged the arguments to your liking, you may use c-m-R to rein- 
voke the current frame with the new arguments. Another useful command is c-R, 
for returning a specified value from the current frame (the value is prompted for 
after you type c-R). 

Another handy command is c-E. It finds the definition of the function in the 
current frame and reads it into the editor. (Of course, it reads the whole file the 
function is defined in. You will be positioned in the buffer at the place where the 
function is defined.) Finally, c-M (for mail) will set you up for sending a bug 
report. You'll be switched to a mail window, with both a complete stack backtrace 
and information on what version of the system software is running on your machine 
inserted as the initial contents of your message. Add whatever text is necessary to 
describe the situation. Check the top line of the buffer to make sure the "To:" field 
contains the name of an appropriate recipient, and edit it if necessary. Then just 
hit the End key. (c-End if you have the Bell Labs/Murray Hill standard utilities 
— we use End for another editing function.) Off goes your mail, you get returned 
to the debugger, and you may continue as you please. The inclusion of the back- 
trace makes life much easier for your system maintainer. 



3.4 Who Does What 

Here are a hodge-podge of lisp functions for finding out about functions and sym- 
bols (see "Poking Around in the Lisp World," section 17.1 in volume 1, for some 
more): who-calls takes one argument, usually a symbol. It searches all defined 
functions and collects those which call the symbol as a function or use it as a vari- 
able or constant. This takes a long time. You can limit the search to certain pack- 
ages by using the optional arguments to who-calls. Apropos takes one argument, a 
string, and finds all symbols whose print-names include the string as a substring. 
This also takes a long time, and also can be limited to certain packages by using 
the optional arguments. Disassemble takes one argument, the name of a compiled 
function or the function object itself. It prints a human-readable version of the 
compiled instructions. Grindef pretty-prints the definition of a non-compiled (inter- 
preted) function. 

See also the Zmacs Meta-X commands List Callers, Edit Callers, Function Apro- 
pos, List Combined Methods, Edit Combined Methods, List Methods, and Edit 



Section 3.4 Who Does What 53 



Methods. 

Section 17.1.1 of volume 1 also describes some variables whose values are automati- 
cally maintained by the lisp command loop. *, for instance, is always bound to the 
value returned by the last form you typed in, and can be extraordinarily helpful. 



3.5 The Input Editor and Histories 

The input editor is active in most contexts outside of the editor. Most notably, it is 
active when you're typing to a lisp listener. c-Help lists all the input editor com- 
mands. Most of them are similar to the Zmacs commands, so you can do all sorts 
of editing of the input before it gets to the lisp reader. Two of the more helpful 
features of the input editor are the histories it keeps, the input history and the kill 
history. Every time you send a form off to be evaluated by a lisp listener, the form 
is added to that lisp listener's input history. (Each lisp listener keeps its own input 
history, even the editor's typeout window.) Pressing the Escape key will display the 
input history of the window you are typing to. Every time you delete more than 
one character of text with a single command (with, for example, m-D, m-Rubout, 
Clear Input, c-W, c-K), the deleted text is added to the kill history. There is only 
one kill history; it is shared by all the windows which use the input editor, and also 
the Zmacs window (s). c-Escape displays the kill history. 

In both the input editor and in Zmacs, c-Y yanks the most recent item off the kill 
history and inserts it at the current cursor position. You can select an earlier ele- 
ment from the history by giving c-Y a numeric argument. Typing m-Y immedi- 
ately after a c-Y does a yank pop; it replaces the text which has just been yanked 
with the previous element from the history. Repeatedly typing m-Y will rotate all 
the way through the history. Giving m-Y a numeric argument will jump that many 
items in the history. 

Note that since all windows share the same kill history, it provides a simple way of 
transferring text from the editor into a lisp listener: just push the text onto the kill 
history while in the editor, perhaps with c-W or m-W or a mouse command. Then 
switch to a lisp listener, type c-Y, and presto! There's your text. 

In the input editor, c-m-Y yanks from the input history. (c-C also has this effect. 
It is an older command which some people still prefer to use. I find c-m-Y easier 
to remember.) m-Y again has the effect of rotating through the history. (m-C is 
the corresponding older command — you used to need different commands for 
rotating through the kill history and the input histories, but now m-Y does both.) 



54 MORE ON NAVIGATING THE LISP MACHINE Chapter 3 



In Zmacs, c-m-Y has the effect of yanking from what's called the command his- 
tory, which is a history of all editing commands which use the mini-buffer. 
Immediately after a c-m-Y, m-Y has the usual effect. 

The ability to yank previous inputs into a lisp listener raises an interesting question: 
how does the input editor know when you're finished editing and ready for the input 
to be sent off to lisp? Normally, if you just type your input without any yanking, 
the input editor knows you're done when you type some sort of delimiter at the end 
of the input string, like a close paren, to complete a well-formed lisp expression. 
But if you've yanked an already well-formed expression, how can you complete it? 
The answer is that there is a special activation character. It is the End key. Press- 
ing End while anywhere within a well-formed expression tells the input editor 
you're done, and it sends your input off to lisp. So if you've yanked a previous 
input with c-m-Y, you can type End immediately to re-evaluate the same expres- 
sion, or you can edit it some and type End when finished, to evaluate the modified 
expression. 

There's one other input editor command of special interest. That's c-sh-A, which 
displays the argument list of the function whose name you have typed. So if I type 
"(with-open-f ile " to a lisp listener, and then type c-sh-A, the following will 
appear on my screen: 

WITH-OPEN-FILE (MACRO): ((STREAM-VARIABLE FILENAME . OPTIONS) &BODY BODY) 

c-sh-A also works in Zmacs. 



3.6 Fun and Games 

More definitions from The Hacker's Dictionary (Guy L. Steele Jr., et at), 
prompted by my spontaneous use of the term loser. 

LOSE verb. 

1. To fail. A program loses when it encounters an exceptional condition or fails 
to work in the expected manner. 

2. To be exceptionally unaesthetic. 

3. Of people, to be obnoxious or unusually stupid (as opposed to ignorant). See 
LOSER. 

DESERVE TO LOSE verb. Said of someone who willfully does THE 
WRONG THING, or uses a feature known to be MARGINAL. What is 



Section 3.6 Fun and Games 55 



meant is that one deserves the consequences of one's losing actions. "Boy, 
anyone who tries to use UNIX deserves to lose!" 

LOSE, LOSE interjection. A reply or comment on an undesirable situation. 
Example: "I accidentally deleted all my files!" "Lose, lose." 

LOSER noun. An unexpectedly bad situation, program, programmer, or 
person. Someone who habitually loses (even winners can lose occasionally). 
Someone who knows not and knows not that he knows not. Emphatic forms 
are "real loser," "total loser," and "complete loser." 

LOSS noun. Something (but not a person) that loses: a situation in which 
something is losing. 

WHAT A LOSS! interjection. A remark to the effect that a situation is bad. 
Example: Suppose someone said, "Fred decided to write his program in 
ADA instead of LISP." The reply "What a loss!" comments that the choice 
was bad, or that it will result in an undesirable situation — but may also 
implicitly recognize that Fred was forced to make that decision because of 
outside influences. On the other hand, the reply "What a loser!" is a more 
general remark about Fred himself, and implies that bad consequences will 
be entirely his fault. 

LOSSAGE (lawss'.j) noun. The stuff of which losses are made. This is a 
collective noun. "What a loss!" and "What lossage!" are nearly synonymous 
remarks. 



WIN 



1. verb. To succeed. A program wins if no unexpected conditions arise. Anto- 
nym: LOSE. 

2. noun. Success, or a specific instance thereof. A pleasing outcome. A 
FEATURE. Emphatic forms: MOBY win, super-win, hyper-win. For some 
reason "suitable win" is also common at MIT, usually in reference to a satis- 
factory solution to a problem. Antonym: LOSS. 

BIG WIN noun. The results of serendipity. 

WIN BIG verb. To experience serendipity. "I went shopping and won big; 
there was a two-for-one sale." 

WINNER noun. An unexpectedly good situation, program, programmer, or 
person. Albert Einstein was a winner. Antonym: LOSER. 

REAL WINNER noun. This term is often used sarcastically, but is also 
used as high praise. 



56 MORE ON NAVIGATING THE LISP MACHINE Chapter 3 



WINN AGE (win'.j) noun. The situation when a LOSS AGE is corrected or 
when something is winning. Quite rare. Usage: also quite rare. 

WINNITUDE (win':-tood) noun. The quality of winning (as opposed to 
WINNAGE, which is the result of winning) . 



Section 3.6 Fun and Games 57 



3.7 Problem Set #3 

Questions 

Evaluate (make-system 'funny-window rnoconfirm : silent). This 
will load some code, and create and select a window of flavor funny-window, mak- 
ing it the value of the symbol * funny -window*. 

The funny-window flavor is built on tvrlisp-listener, so you can type forms to this 
window and it will evaluate them just as a lisp listener would. 

This window has two behavioral quirks, one which occurs just before it types out 
the return value of whatever it evaluates, and one which occurs whenever you move 
the mouse. 

The assignment is to find out what's responsible for the odd behavior. You win the 
game if you can get the code causing the behavior into a Zmacs buffer. Use what- 
ever you know about looking into the state of the lisp machine. Several good tech- 
niques are buried in the text of this chapter. 

There's one restriction on what you may do: you should read the code into the edi- 
tor by using some system-provided operation which finds the definition of a given 
function. So you have to first figure out what function is responsible. It's cheating 
to randomly read in files and scan them. 

I would suggest starting on the typeout quirk — it should be a little easier to track 
down than the mouse behavior. 



58 MORE ON NAVIGATING THE LISP MACHINE Chapter 3 



Hints 

Note that there's a delay partway through the funny typeout. To find out what's 
going on, you can simply do c-m-Suspend during the delay and look at what's on 
the stack. (At this point you might want to (setq *funny-typeout- 
delay* ) for the duration.) Use c-E on the appropriate frame to pull the 
offender into the editor. 



Finding the mouse funniness isn't as easy. c-m-Suspend doesn't work — and not 
only because there's no time for it. Try setting *funny-mouse-delay* to 1 (sec). 
Now there's time to type c-m-Suspend during the funniness, but the stack shows 
nothing revealing, because the action is in a different process. (When convinced, 
you should probably set *funny-mouse-delay* back to 0.) 

One possible way to proceed would be to put a trace (with :error) on the : draw- 
circle method, which you can see is being called. [To get the method do 
(get-handler-for * funny- window* : draw-circle), which you will see 
turns out to be (: method tv:graphics-mixin : draw-circle) J. That 
would force the process which is calling : draw-circle into the debugger. 
Unfortunately everything gets fouled up when the mouse process, which turns out 
to be the culprit, goes into the debugger. (The trouble starts because the mouse 
process doesn't have a window to use, so it has to come up with one and expose it. 
That in itself is okay [processes which run in the background generally have that 
capability], but the real killer is that the mouse process has to be running in order 
for most ways of switching windows to work. With the mouse process halted for 
debugging, most window system operations are impossible, and the lisp machine is 
suddenly in a terribly wedged* state! (It usually isn't necessary to re-boot if this 
happens — try resetting the mouse process, with (send tv: mouse-process 



WEDGED adjective. 

1 . To be stuck, incapable of proceeding without help. This is different from having CRASHED. 
If the system has crashed, then it has become totally nonfunctioning. If the system is 
"wedged," it is trying to do something but cannot make progress. It may be capable of doing 
a few things, but not be fully operational. For example, the system may become wedged if the 
disk controller FRIES; there are some things you can do without using the disks, but not many. 
Being wedged is slightly milder then being "hung." This term is sometimes used as a synonym 
for DEADLOCKED. See also HANG, LOSING, CATATONIA, and BUZZ. 

2. Of a person, suffering severely from misconceptions. Examples: "He's totally wedged — he's 
convinced that he can levitate through meditation." "I'm sorry. I had a BIT set that you were 
responsible for TECO, but I was wedged." 

(The Hacker's Dictionary, Guy L. Steele, Jr., et at) 



Section 3.7 Problem Set #3 59 



: reset). If you can't get to a window that will accept typein, do Function- 
Suspend first.) 

If you really want to make this approach work, here's something a little more 
advanced (that's understated — it took two of us quite a while to come upon it) 
that will produce the desired effect: 

(advise (: method tv:graphics-mixin : draw-circle) : before nil nil 
(send (send * funny-window* : process) 

: interrupt #'dbg current-process) 
(process-sleep 60.)) 



The basic idea is to force the process calling : draw-circle into the debugger by 
calling the dbg function on it, but to do the call to the dbg function from the funny 
window, using its process and its already exposed and selected window. Now you 
can examine the stack and quickly find the : before : mouse-moves method 
which is responsible. 

But there's a much more sensible approach. You could think of the above force-it- 
into-the-debugger approach as finding the set of functions which are being called 
and filtering that set for functions which seem related to the funny-window flavor. 
Turning that around is far more effective in this case. That is, first collect the 
functions related to the funny-window flavor, which is much easier in this case than 
getting access to the control stack, and then filter that set for ones likely to be caus- 
ing the funny effects. So one idea is to do a :which-operations on the win- 
dow and search for messages with suggestive names. You could, for instance, try 

(loop for msg in (send * funny- window* rwhich-operations) 
when (string-search "mouse" msg) collect msg) 

[If you have the Murray Hill standard utilities, you could simply do (grep-msgs 
"mouse" * funny- window*).! This will be a small enough set that they could 
all be investigated. A more direct approach, and the clear winner for this problem, 
is based on the observation that although the funny-window flavor has many 
methods defined, the bulk of them are inherited from other flavors, and whatever is 
responsible for its peculiar behavior must be somewhere in the relatively small 
number of methods defined locally for funny- window. So all you have to do is enter 
the Flavor Examiner (Select-X), and get the list of local methods for funny- 
window. How about that. Two methods, one for each peculiarity. Now you can 
edit them either by clicking mouse-right while pointing to one, and choosing "edit" 
from the menu, or by clicking where it says "edit" on the extreme right. 



60 MORE ON NAVIGATING THE LISP MACHINE Chapter 3 



Solutions 

Here's what causes the typeout funniness: 

(defvar *funny-typeout-delay* 1) 

; ; ; You found the funny typeout stuff ! 
(def whopper (funny-window : input-editor ) (krest args ) 
(let ((thing ( lexpr-continue-whopper args))) 

(format self "-&You entered something of type ") 

(process-sleep (* 60 *funny-typeout-delay* ) ) 

(princ (typep thing) self) 

thing)) 



And this causes the mouse funniness: 

(defvar *funny-mouse-delay* 0) 

; ; ; You found the funny mouse stuff I 

(def method (funny-window : before : mouse-moves ) (x y) 

(format self "-&The mouse is moving . . . ") 

(process-sleep (* 60 * funny-mouse -de lay* ) ) 

(send self : draw-circle 

(- x tv: left-margin-size) (- y tv: top-margin-size ) 8 

(send self :tyo #\ ! ) ) 



Chapter 4 

FLOW OF CONTROL 



In this chapter we leave behind the "operating system" of the lisp machine and 
return to aspects of the lisp language itself. In particular, we'll look at the various 
constructs for determining the flow of control. The notes are a little sketchier than 
usual, because this material is covered reasonably well in Part V of volume 2 of the 
Symbolics documentation. 



4.1 Conditionals 

The cond special form is the basic conditional. The arguments to cond are any 
number of clauses, where each clause is a list containing a predicate (the 
antecedent) and zero or more consequents. The clauses are handled one at a time, 
in order of appearance. If a clause's antecedent returns nil, its consequents are 
skipped and the next clause is considered. When a clause is found whose 
antecedent returns a non-nil value, that clause's consequents, if any, are all 
evaluated. The value of the last consequent in that clause (or of the antecedent, if 
there are no consequents) is the value returned by the cond, and the rest of the 
clauses are skipped. If every clause's antecedent returns nil, the cond returns nil. 



62 FLOW OF CONTROL Chapter 4 



Beyond their value as logical operators, and and or can also be used as conditionals. 
If one of the subforms of an and returns nil, the rest will be skipped. And if one of 
the subforms of an or returns non-nil, the rest will be skipped. Here are two exam- 
ples taken from the manual: 

(and bright-day 

glorious-day 

(print "It is a bright and glorious day.")) 

(or it-is-f ish 
it-is-fowl 
(print "It is neither fish nor fowl.")) 

Almost all of the remaining conditionals are really macros which expand into calls 
to cond. when and unless take a predicate and any number of consequent forms. If 
the predicate for a when returns non-nil, all of the consequent forms are evaluated 
and the value returned by the last one is returned by the when. Otherwise (a nil 
predicate value) the consequent forms are all skipped, unless works similarly: if 
the predicate returns nil the consequents are evaluated, otherwise they're skipped. 
Here are the definitions of the when and unless macros: 

(DEFMACRO WHEN (TEST &BODY BODY) 
N ( COND ( , TEST ( PROGN , @>BODY ) ) ) ) 

(DEFMACRO UNLESS (TEST &BODY BODY) 

"(COND ((NOT ,TEST) (PROGN ,@BODY) ) ) ) 

[Actually, I lied a bit in the previous paragraph. Although they could, and in fact 
used to, have the given macro definitions, when and unless are now special forms 
instead. I used the old macro definitions because they're easier to read, while for 
our immediate purposes, any differences in behavior aren't important.] 

Defining suitable macros is an extremely common (and effective) method for 
extending the syntax of lisp. There are no extra levels of function calling at run- 
time, and no modifications to the compiler are involved. 

if is somewhat similar to when, and also macroexpands to a call to cond. If the test 
evaluates to non-nil, the first body form is evaluated. Otherwise (test returns nil), 
if there are any body forms following the first, they are all evaluated. 

Three more macros based on cond are select, selector, and selectq. Selectq is used 
most frequently. Here is its structure: 



Section 4.1 Conditionals 63 



( selectq key-form 

(test consequent consequent . . . ) 
( test consequent consequent . . . ) 
( test consequent consequent . . . ) 
...) 

The key-form is evaluated and checked against the tests. The tests are not 
evaluated. Each test must be either a symbol, a fixnum, or a list of symbols and 
fixnums. If the test (or one of its elements, if it's a list) is eq to the evaluated key- 
form, then it matches. The symbols t and otherwise are special: a test consisting 
of one of those two symbols always matches. As with cond, the consequents to the 
first test which matches are evaluated, and the rest of the clauses are skipped. 

Select is the same as selectq, except that the symbols in the tests are evaluated 
before being compared to the (evaluated) key-form. Selector is like select except 
that there is an additional argument (following the key-form) which is the name of 
a function to use for the comparison in place of eq. 

See also typecase, dispatch, cond-every, and selectq-every. 



4.2 Blocks and Exits 

block is the primitive for defining a piece of code which may be exited from the 
middle. The first argument to block must be a symbol. It is not evaluated, and 
becomes the name of the block. The rest of the arguments are forms to be 
evaluated. If a call to return-from occurs within the block, with a first argument of 
the block's name, the block is immediately exited. The rest of the arguments to 
return-from are evaluated and become the return values for the block. (Beginning 
with release 6.0, the preferred way of returning multiple values is with (return- 
from name (values form... ) ), for compatibility with Common Lisp.) 

The scope of the block is lexical, so the corresponding call to return-from must 
occur textually within the block; it will not work to call return-from inside a func- 
tion which is called within the block. The next section discusses that sort of nonlo- 
cal exit. 

Blocks may be nested; that's the whole point of naming them. A return-from 
causes an immediate exit from the innermost block with a matching name. 

Some other constructs (including do and prog) create implicit blocks. These blocks 



64 FLOW OF CONTROL Chapter 4 



have nil for a name, and so they may be prematurely exited with (return- 
from nil (values value...) ). They may also be exited with the return special 
form, which always exits the innermost block named nil. 



4.3 Nonlocal Exits 

catch and throw are analogous to block and return-from, but are scoped dynami- 
cally rather than lexically. This means that a throw may cause an exit from any 
catch on the control stack at the time the throw is reached (unless an inner catch is 
shadowing an outer catch with the same tag) . catch's equivalent to the name of a 
block is its tag. The tag is the first argument to catch; it is evaluated, and may 
return any lisp object. The first argument to throw is its tag. It is also evaluated, 
and the throw causes the exit of the innermost catch whose evaluated tag is eq to 
the throw's evaluated tag. 

If a throw occurs, its second argument is evaluated and the value (s) returned will 
be returned by the corresponding catch. If no throw occurs, the values returned by 
the catch are the values returned by its last subform. 

There are obsolete forms of catch and throw, called *catch and *throw. They differ 
from the newer version mainly in what values are returned. *catch and *throw 
should not be used in new code. 



4.4 Iteration 

There are three styles of built-in facilities for iteration. A group of operators are 
available for mapping a function through one or more lists; the do special form 
allows more general forms of iteration; and the loop macro provides even more 
flexibility. (I should also point out that functions which make use of tail recursion 
are compiled into iterative structures.) This set, of course, could easily be extended 
by writing more macros. 

When more than one of the iteration facilities is applicable to a particular task, the 
choice is mainly a matter of personal taste.* All three are comparably efficient. 
The key issue is readability, and on this score opinions differ. My own view is that 
the mapping functions are succinct and to the point, and therefore desirable, within 
the limited set of applications that are easily expressed as mapping operations. For 
all other kinds of iteration, do is often concise but I find it somewhat obscure. 1 I 



See hacker's definition at end of chapter. 



Section 4.4 Iteration 65 



think loop is much easier to read, but there are those who consider it wordy and 
nebulous. 

"Loop forms are intended to look like stylized English rather than 
Lisp code. There is a notably low density of parentheses, and 
many of the keywords are accepted in several synonymous forms to 
allow writing of more euphonious and grammatical English. Some 
find this notation verbose and distasteful, while others find it flexi- 
ble and convenient. The former are invited to stick to do." 

[The preceding, as well as parts of the discussion of loop below, is 
taken from the loop documentation written by Glenn S. Burke: 
MIT Laboratory for Computer Science TM-169.] 

For the sake of comparison, here are four ways to print the elements of a list: 

(defun print-eltsl (list) ; mapc 
(mapc #'print list)) 

(defun print-elts2 (list) ; do 
(do ( (1 list (cdr 1) ) ) 
((null 1)) 
(print (car 1) ) ) ) 

(defun print-elts3 (list) ; loop 
(loop for elt in list 
do (print elt) ) ) 

(defun print-elts4 (list) ; tail recursion 
(unless (null list) 
(print (car list)) 
(print-elts4 (cdr list)))) 

4.4.1 Mapping 

The mapping operators come in six varieties. They all take as arguments a func- 
tion followed by any number of lists, and step through all the lists in parallel, 
applying the function as they go. They vary along two dimensions: whether they 
operate on successive elements of the lists or on successive sublists, and which of 

t ditto. 



66 FLOW OF CONTROL Chapter 4 



three kinds of values they return. (Two x three = six.) The return value can be 
simply the second argument to the mapping operator (implying that the mapping 
was done for side effect only), or a list of the results of function application, or a 
list formed by nconcing (destructive appending) the results of function application. 
Here are a few examples: 

Applied to successive elements, lists results 

(mapcar #' + '(1 2 3 4) '(2 4 6 8)) 
-(369 12) 

(mapcar #'list '(1 2 3 4) '(2 4 6 8)) 

- ((1 2) (2 4) (3 6) (4 8)) 

Successive elements, nconcs results 

(mapcan #'list '(1 2 3 4) '(2 4 6 8)) 

- (1224364 8) 

Successive sublists, lists results 

(maplist #'( lambda (1) (and (second 1) 

(+ (first 1) (second 1)))) 
'(1 2 3 4)) 
-(357 NIL) 

(maplist #'( lambda (1) (list (first 1) (second 1))) 
'(1 2 3 4)) 

- ((1 2) (2 3) (3 4) (4 NIL)) 

Successive sublists, nconcs results 

(mapcon #'( lambda (1) (list (first 1) (second 1))) 
'(1 2 3 4)) 
-(1223344 NIL) 



4.4.2 Do 

A do looks like this: 
(do ( ( var init repeat ) 



Section 4.4 Iteration 67 



( var init repeat ) . . . ) 
{end-test exit-form exit-form . . . ) 
body -form body -form . . . ) 

The first subform is a list of index variable specifiers. Upon entering the do, each 
var is bound to the corresponding init. And before each subsequent iteration, var is 
set to repeat. The variables are all changed in parallel. The end-test is evaluated 
at the beginning of each iteration. If it returns a non-nil value, the exit -forms are 
all evaluated, and the value of the last one is returned as the value of the do. Oth- 
erwise the body -forms are all evaluated. Here's an example which fills an array 
with zeroes: 

(do ((i (1+ i)) 

(n (array- length foo-array) ) ) 
((= i n)) 
(setf (aref foo-array i) 0)) 

Upon entry, i is bound to and n is bound to the size of the anay. On each itera- 
tion, i is incremented, (n stays constant because it has no repeat form.) When i 
reaches n, the do is exited. On each iteration, the ith element of foo-array is set to 
0. 

And another, which is equivalent to (maplist #'f x y): 

(do ((x x (cdr x)) 
(y y (cdr y) ) 
(z nil (cons (f x y) z))) 
((or (null x) (null y) ) 
(nreverse z) ) ) 

Note that the preceding example has no body. It's actually fairly common for all 
the action in a do to be in the variable stepping. 

There are macros named dotimes and delist which expand into common do con- 
structs. For instance, the following macroexpands into the first example above: 

(dotimes (i (array-length foo-array)) 
(setf (aref foo-array i) 0)) 



68 FLOW OF CONTROL Chapter 4 



4.4.3 Loop 

loop is a macro which expands into a prog with explicit go statements, and often 
with several lambda bindings. A typical call looks like this: 

( loop clause 
clause 
clause . . . ) 

Each clause begins with a keyword, and the contents of the rest of the clause 
depend on which keyword it is. Some clauses specify variable bindings and how the 
variables should be stepped on each iteration. Some specify actions to be taken on 
each iteration. Some specify exit conditions. Some control the accumulation of 
return values. Some are conditionals which affect other clauses. And so on. A full 
discussion of all the clauses would be lengthy and not particularly useful, as they're 
all described coherently enough in the documentation. We'll just look at some 
representative examples. 

The repeat clause specifies how many times the iteration should occur. The key- 
word is followed by a single lisp expression, which should evaluate to a fixnum. 
And the do keyword is followed by any number of lisp expressions, all of which are 
evaluated on each iteration. So putting the two together, 

( loop repeat 5 

do (print "hi there")) 

prints "hi there" five times. The most commonly used (and complicated) of the 
iteration-driving clauses is the for clause. The keyword is followed by the name of 
a variable which is to be stepped on each iteration, then some other stuff which 
somehow specifies the initial and subsequent values of the variable. Here are some 
examples: 

( loop for elt in expr expr is evaluated (it better return a list), elt is bound in 

do (print elt) ) turn to each element of the list, and then the loop is exited 

( loop for elt on expr similar, but elt is bound to each sublist 
do (print elt) ) 

. . . for x = expr . . . expr is re-evaluated on each iteration and x 

is bound to the result (no exit specified here) 

. . . for x = exprl then expr2 ... x is bound to exprl on the first iteration 



Section 4.4 Iteration 69 



and expr2 on all succeeding iterations 

. for x from expr ... x is bound to expr (it better return a fixnum) on the first 
iteration and incremented on each succeeding iteration 

. for x from exprl to expr2 . . . like above, but the loop is exited 

after x reaches expr2 

. for x from exprl below expr 2 . . . like above, but the loop is exited 

just before x reaches expr2 

. for x from exprl to expr2 by expr3 . . . incremented by exprS 

on each iteration 

. for x being path . . . user definable iteration paths 



When there are multiple for clauses, the variable assignments occur sequentially by 
default (parallel assignment may be specified), so one for clause may make use of 
variables bound in previous ones: 

(loop for i below 10 i starts at when from isn't specified 

for j = ( * i i ) . . . ) 

The with clause allows you to establish temporary local variable bindings, much like 
the let special form. It's used like this: 

( loop with f oo = expr expr is evaluated only once, upon entering the loop 
... ) 

A number of clauses have the effect of accumulating some sort of return value. 
The form 

(loop for item in some-list 
collect ( f oo item)) 

applies foo to each element of some-list, and returns a list of all the results, just like 
(mapcar #'foo some-list). The keywords nconc and append are similar, but 
the results are nconc-ed or appended together. Keywords for accumulating numeri- 
cal results are count, sum, maximize, and minimize. All of these clauses may option- 
ally specify a variable into which the values should be accumulated, so that it may 
be referenced. For instance, 



70 FLOW OF CONTROL Chapter 4 



(loop for x in list-of-frobs 

count t into count-var "t" means always count 

sum x into sum-var 

finally (return (// sum-var count-var))) 



computes the average of the entries in the list. 



The while and until clauses specify explicit end-tests for terminating the loop 
(beyond those which may be implicit in for clauses). Either is followed by an arbi- 
trary expression which is evaluated on each iteration. The loop is exited immedi- 
ately if the expression returns the appropriate value (nil for while, non-nil for until). 

(loop for char = (send standard- input :tyi) 
until (char-equal char #\end) 
do (process-char char)) 

The when and unless clauses conditionalize the execution of the following clause, 
which will often be a do clause or one of the value accumulating clauses. Multiple 
clauses may be conditionalized together with the and keyword, and if -then-else 
constructs may be created with the else keyword. 

( loop for i from a to b 
when (oddp i) 

collect i into odd-numbers and do (print i) 
else collect i into even-numbers) 

The return clause causes immediate termination of the loop, with a return value as 
specified: 

(loop for char = (send standard- input :tyi) 
when (char-equal char #\end) 

return "end of input" 
do (process-char char)) 

Please refer to the documentation for a more complete discussion of loop features. 
Of particular importance are prologue and epilogue code (the initially and finally 
keywords), the distinction between ways of terminating the loop which execute the 
epilogue code and those which skip it, aggregated boolean tests (the always, never, 
and thereis keywords), the destructuring facility, and iteration paths (user-definable 
iteration-driving clauses) . 



Section 4.4 Iteration 71 



4.5 A Bit More on Working with Macros 

Since so many of the control structure constructs are macros, you'll probably find it 
helpful in working with them to be able to see what forms they macroexpand into. 
The most basic of the tools for expanding macros is the macroexpand function. It 
takes a list as an argument and returns its expanded version: 

(macroexpand '(if (test) (do-this) (do-that)))) 
-» (COND ((TEST) (DO-THIS)) (T (DO-THAT))) 

The grind-top-level function, for pretty-printing, is also useful in conjunction with 
macroexpand. 

Rather than type (grind-top-level (macroexpand ... ) ) repeatedly, an 
easier way to expand forms in a lisp listener is with mexp. Evaluating (mexp) 
puts you into a macro reading and expanding loop. You type a form, and it 
pretty-prints the expansion and waits for another input form. Exit by pressing the 
End key. 

But by far the easiest way to see what something expands into is the c-sh-M com- 
mand in the editor. When you place the cursor at the beginning of a lisp expres- 
sion and type c-sh-M, the macro-expansion of the form is shown in the typeout win- 
dow. If you give c-sh-M a numeric argument, it inserts the expanded form into the 
buffer. c-sh-M only expands the top-level form, not any of its subforms which are 
themselves macros. m-sh-M expands subforms as well. 

Of course, you can also use Meta-. on a macro to edit its definition, but it's often 
more useful to see what a macro expands into than to see how it does it. 



4.6 Fun and Games 

From The Hacker's Dictionary, Guy L. Steele, Jr., et at 

TASTE noun. 

Aesthetic pleasance; the quality in programs which tends to be inversely pro- 
portional to the number of FEATURES, HACKS, CROCKS, and KLUGES 
programmed into it. 

OBSCURE adjective. 

Little-known; incomprehensible; undocumented. This word is used, in an 
exaggeration of its normal meaning, to imply a total lack of 



72 FLOW OF CONTROL Chapter 4 



comprehensibility. "The reason for that last CRASH is obscure." "That 
program has a very obscure command syntax." "This KLUDGE works by 
taking advantage of an obscure FEATURE in TECO." The phrase 
"moderately obscure" implies that it could be figured out but probably isn't 
worth the trouble. 



Fun and Games 73 



4.7 Problem Set #4 

Questions 

1. A. Write a function called do-word which takes one required argument, a 
symbol, and two optional arguments, both fixnums. If the symbol is 
one of : point, : rectangle, : triangle, or : circle, the func- 
tion should draw the specified kind of object on standard-output, at the 
coordinates specified by the fixnum arguments (choose any size you like 
for the figures). If the symbol is : reverse, the function should tog- 
gle the state of reverse-video-p for standard-output. If the sym- 
bol is : erase, the function should clear standard-output. If the sym- 
bol is anything else, it should call the function beep. 

B. Write another function, called read-chars, which reads a series of char- 
acters from the keyboard. When the Return key is pressed, it makes a 
string out of all the characters read (before Return), and returns a 
symbol in the keyword package whose print-name is that string. That 
is, if the characters "s," "a," "m," "p," "1," "e" and "<cr>" were 
typed, the symbol : sample would be generated. (Normally, you 
wouldn't write such a function because there are already several built- 
in functions which do the same sort of thing and with more features. 
But for the sake of demonstrating a point or two...) 

C. Write a third function, called main-loop, which repeatedly calls read- 
chars and then do-word on the result. It should provide the optional 
arguments to do-word, and increment one or both each time so that the 
figures are drawn across the top of the screen, and then in a second 
row below the first, and so on, with each position 200 pixels from the 
previous one. That is, if standard-output is a window whose dimensions 
are 1088 by 749, the optional arguments should be (0,0), then (200,0), 
(400,0), (600,0), (800,0), (0,200), (200,200) ... (400,800). (Don't 
worry about resetting the coordinates after an : erase, or not step- 
ping after a : reverse — just allow blank spots.) This version of 
main-loop should iterate until it reaches the bottom right corner of the 
window. You'll probably want to touch up do-word so that it draws 
the figures centered in the 200 x 200 area whose upper left corner it is 
given. 

D. Alter main-loop and (read-chars) so that if at any point you press the 
End key, even in the middle of typing a word, main-loop will return 
immediately. 

E. Make similar alterations so that the Line key will have the effect of 



74 FLOW OF CONTROL Chapter 4 



skipping any remaining positions in the current row and continuing at 
the beginning of the next row. 

2. Write three functions which meet the following spec, one using a mapping 
operator, one using do, and one using loop: f takes one argument, a list of 
fixnums, and returns a list containing only the even numbers from its argu- 
ment. That is, 

(evens '(12345)) -» (2 4) 

3. Like (2), but this time the list which f returns includes only those elements of 
the argument which are less than the succeeding element. That is, 
(less-thans '(36725435)) - (3623) 

4. Write a function which takes two arguments, a fixnum "n" and a list "1," 
and uses a mapping operator to return a list consisting of the elements of 1 
incremented by n. Try to do this two ways, one using a lambda expression as 
the function argument to the mapping operator, and one just using # ' +. 

5. Write a function which takes one argument, a fixnum n, and returns the nth 
fibonacci number, subject to the restriction that the time it takes should 
increase linearly with n. I suggest using loop. 

6. Write a function of no arguments which finds all prime numbers between 2 
and 50000. (You might find it easier to have the function stop at the first 
prime greater than 50000.) I suggest using loop again. 

7. The function mexp only expands the initial operator in an expression. If one 
of the arguments to that operator itself uses a macro, that doesn't get 
expanded. That is, 

(if test (do-this) 

(if another-test (do-that) 
(do-the-other) ) ) 

expands into 

(COND (TEST 

(DO-THIS) ) 
(T (IF ANOTHER-TEST (DO-THAT) (DO-THE-OTHER)))) 

instead of 

(COND (TEST 

(DO-THIS) ) 
(T (COND (ANOTHER-TEST 



Section 4.7 Problem Set #4 75 



(DO-THAT) ) 
(T (DO-THE-OTHER) ) ) ) ) 

Write mexp-all, which behaves just like mexp except that it macroexpands 
subexpressions and thus would produce the second of the expansions shown 
above. 



76 FLOW OF CONTROL Chapter 4 



Hints 



A. The body of do-word should consist of a selectq (or a defselect, which 
is a macro that expands into a selectq). The messages you'll need to 
send standard-output are : draw-point, : draw-rectangle, 
: draw-triangle, : draw-circle, :reverse-video-p, 
:set-reverse-video-p, and : clear-window. 

B. To read each character, send :tyi to standard-input or terminal-io 
(usually the same thing). Collect the characters into a list, and use 
string-append to combine the characters into a string, and intern to 
make the string into a symbol. Make sure the characters are converted 
to upper case, either before or after they're collected into the string. 

C. The : inside-size message to a window returns two values, the 
width and height of the interior, in pixels. (The difference between 
inside-size and size is the margin area, which the usual output mes- 
sages can't draw in.) Use these (actually, 200 less than these) as the 
upper bounds on your iteration. You probably want two nested loops, 
an outer one for the y coordinate and an inner one for the x coordinate. 

D. Wrap the body of main-loop in a catch, and have read-chars do a throw 

at the appropriate point. 

E. Same technique. This time the catch goes around the inner loop. 

The mapping operator should be mapcan. The do would need a structure 
very much like that produced by the dolist macro (which you might even 
want to use), combined with some parts of the do example in the notes which 
was equivalent to maplist. The loop would use collect, conditionalized 
with when. 

This time the mapping operator should be mapcon. The do and loop can be 
done in any of several ways. There could be one iteration variable which 
took on the value of successive sublists, and then you could take its first and 
second elements and do the comparison. But better (because it requires 
fewer redundant cdr's and exits more cleanly) would be to have the value of 
the "first" variable be directly set to the previous value of the "second" vari- 
able. 

The lambda expression adds n to its argument. A very nice way to do this 
without a lambda expression is to use a circular list. (You can make one 
yourself with rplacd, but the circular-list function is more convenient.) 

Lots of choices here. You probably want to use a repeat clause to control 
the loop termination. But the tricky part is that you need to have a value 



Section 4.7 Problem Set #4 77 



from one iteration hang around through the next one. So you might want 
something like the loop answer to (3), where one variable always takes on the 
previous value of another one. And you'll probably want to use a finally 
clause with an explicit call to return. 

You probably want a subroutine which tests whether a number "n" is factor- 
able by any of a list "1" of potential factors. The loop keyword thereis 
may be helpful in writing this part. Then you'll want to use this in another 
loop which tests each number from 2 up for factorability. When it finds a 
prime, it should add it to the list of potential factors. 

The editor commands Macro Expand Expression (c-sh-M) and Macro 
Expand Expression All (m-sh-M) display exactly the same difference in 
behavior we wish to see between mexp and mexp-all. So you should be able 
to pull some code out of Macro Expand Expression All, and use it as a black 
box to help you create mexp-all. 



78 FLOW OF CONTROL Chapter 4 



Solutions 

A. (defun do-word (message ^optional x y) 
(selectq message 

(: point (send standard-output : draw-point x y) ) 
(: rectangle (send standard-output : draw-rectangle 

100 100 x y) ) 
(: triangle (send standard-output : draw-triangle 

x y (+ x 100) y (+ x 50) (- y 87))) 
(: circle (send standard-output : draw-circle x y 50)) 
(: reverse (send standard-output : set-reverse-video-p 
(not (send standard-output 

:reverse-video-p) ) ) ) 
(: erase (send standard-output : clear-window) ) 
(otherwise (beep)))) 

B. (defun read-chars () 

(loop for char = (send terminal-io :tyi) 
until (char-equal char Areturn) 
collect (char-upcase char) into char-list 
finally (return (intern (apply #' string-append 

char-list) 
"keyword" ) ) ) ) 

C. (defun main-loop ( ) 

(multiple-value-bind (width height) 

(send standard-output : inside-size ) 
(loop for y below (- height 200) by 200 

do (loop for x below (- width 200) by 200 
do (do-word (read-chars) x y) ) ) ) ) 

and in do-word 

(: point (send standard-output : draw-point 

(+ x 100) (+ y 100))) 
(: rectangle (send standard-output : draw-rectangle 

100 100 (+ x 50) (+ y 50))) 
(: triangle (send standard-output : draw- triangle 

(+ x 100) (+ y 57) (+ x 50) (+ y 143) 
(+ x 150) (+ y 143))) 
(: circle (send standard-output : draw-circle 
(+ x 100) (+ y 100) 50)) 



Section 4.7 Problem Set #4 79 



D. (defun main-loop ( ) 

(catch 'end-key 

(multiple-value-bind (width height) 

(send standard-output : inside-size ) 
(loop for y below (- height 200) by 200 

do (loop for x below (- width 200) by 200 

do (do-word (read-chars) x y) ) ) ) ) ) 

(defun read-chars ( ) 

(loop for char = (send terminal -io :tyi) 
until (char-equal char Areturn) 
when (char-equal char #\end) 

do (throw 'end-key nil) 
collect (char-upcase char) into char-list 
finally (return (intern (apply #' string-append 

char-list) 
"keyword" ) ) ) ) 

E. (defun main- loop ( ) 

(catch 'end-key 

(multiple-value-bind (width height) 

(send standard-output : inside-size ) 
(loop for y below (- height 200) by 200 
do (catch 'line-key 

(loop for x below (- width 200) by 200 
do (do-word (read-chars) 
x y))))))) 

(defun read-chars ( ) 

(loop for char = (send terminal -io :tyi) 
until (char-equal char Areturn) 
when (char-equal char #\end) 

do (throw 'end-key nil) 
when (char-equal char #\line) 

do (throw 'line-key nil) 
collect (char-upcase char) into char-list 
finally (return (intern (apply #' string-append 

char-list) 
"keyword")))) 



(defun evens (list) 

(mapcan #' (lambda (n) (and (evenp n) (list n))) list)) 



80 FLOW OF CONTROL Chapter 4 



(defun evens (list) 

(do ((sublist list (cdr sublist)) 
( item) 

(evens -found) ) 
( (null sublist) 
(nreverse evens-found) ) 
( setq item (car sublist)) 
(if (evenp item) (push item evens-found)))) 

(defun evens (list) 
(let (evens-found) 
(dolist (item list) 

(if (evenp item) (push item evens-found))) 
(nreverse evens - f ound) ) ) 

(defun evens (list) 

(loop for item in list 

when (evenp item) collect item)) 

3. (defun less-thans (list) 

(mapcon #' (lambda (1) 

( and ( cdr 1 ) to avoid doing (< n nil) at the end 

(< (first 1) (second 1) ) 
(list (first 1))) ) 
list)) 

(defun less-thans (list) 

(do ((sublist list (cdr sublist)) 
(item) (good-ones)) 
( (= 1 (length sublist) ) 
(nreverse good-ones)) 
(setq item (car sublist)) 
(if (< item (second sublist)) 
(push item good-ones)))) 

(defun less-thans (list) 

(loop for a = (car list) then b 
for b in (cdr list) 
when (< a b) collect a)) 

4. (defun add-to-list (n list) 

(mapcar #' (lambda (elt) (+ elt n) ) list)) 



Section 4.7 Problem Set #4 81 



(defun add-to-list (n list) 

(mapcar #' + (circular-list n) list)) 

5. I've fudged the repeat counts of these three so that they'll agree on which is 
the nth fibonacci number. 

(defun linear-fib (n) 
( loop repeat n 

for a = then b 
for b = 1 then partial-sum 
for partial-sum = (+ a b) 
finally (return partial-sum))) 

(defun linear-fib (n) 
( loop repeat ( + n 2 ) 

for a = then b 
for b = 1 then partial-sum 
sum a into partial-sum 
finally (return partial-sum))) 

(defun linear-fib (n) 
(loop repeat (1+ n) 
with a = 1 
sum (progl a ( setq a partial-sum)) 

into partial-sum 
finally (return partial-sum))) 

6. This takes about 10 seconds to find all primes up to 50021 ("5100 of them). 

(defsubst factorable? (n factors) 
( loop for f in factors 

while (< (* f f) n) 

thereis (zerop (remainder n f)))) 

(defun primes ( ) 
(loop for n from 2 

unless (factorable? n found) 
collect n into found 
and when (> n 50000) return (length found)))) 

7. The editor command Meta-X Macro Expand Expression All calls a function 
named macro-expand-all to do the actual expansion. It's kind of messy, but 
it basically does a recursive tree walk of the input form, expanding each part. 
Understanding how it works, however, is not really necessary. All we need to 



82 FLOW OF CONTROL Chapter 4 



know is what it does; we can treat it as a black box. Here is the original 
definition of mexp, and one for mexp-all, which modifies mexp to use macro- 
expand -all. 

( DEFUN MEXP ( ) 

(LOOP WITH (FORM FLAG) 

DOING (FORMAT T "~2L") 

(MULTIPLE -VALUE (FORM FLAG) 

( PROMPT-AND-READ ' : EXPRESSION-OR-END 
"Macro form -♦ " ) ) 
UNTIL (EQ FLAG ':END) 
DO (LOOP AS NFORM = FORM 

DO (SETQ FORM (MACROEXPAND- 1 NFORM)) 
UNTIL (EQ FORM NFORM) 
DO (PRINC " -» ") 

(GRIND-TOP-LEVEL FORM)))) 

(DEFUN MEXP-all ( ) 

(LOOP WITH (FORM FLAG) 

DOING (FORMAT T "~2&") 

(MULTIPLE -VALUE (FORM FLAG) 

(PROMPT-AND-READ ' : EXPRESSION-OR-END 
"Macro form -» " ) ) 
UNTIL ( EQ FLAG ' : END ) 
DO (PRINC " ■+ ") 

(GRIND-TOP-LEVEL ( zwei : macro-expand-all FORM)))) 



Chapter 5 

THE GRAPH EXAMPLE 



This chapter, rather than present some abstracted features of the lisp language or 
of the lisp machine operating environment, will cover a programming example 
which puts to use many of the features we have previously discussed. The piece of 
code in question allows one to display and manipulate simple undirected graphs, 
that is sets of nodes connected by arcs. 

If your site has loaded the tape which accompanies this book, you can load the code 
by using the CP command Load System graph [or evaluating (make- 
system 'graph)]. Once the code has been read, start the program by evaluat- 
ing (send (tv: make -window 'graph-frame) : select). 

Please refer to section 5.5, which contains a picture of the program in operation 
and a listing of the code. The first three sections will point out and briefly discuss 
the interesting features of the code. The basic mechanism is contained in the first 
half of the file. All the graph manipulation functionality is there, provided you're 
willing to type in awkward forms to a lisp listener. The rest of the file provides a 
more convenient user interface. 



84 THE GRAPH EXAMPLE Chapter 5 



5.1 The Nodes and Arcs 

The four defvar's 

These four declarations are for global variables that will be needed at various 
places throughout the code. A defvar must precede the first appearance of the vari- 
able so that the compiler knows the symbol refers to a special variable. Another 
good reason for putting them at the beginning is so anyone reading the code can 
quickly find out what hooks are available for modifying the program's behavior. 

The node defflavor 

All five instance variables are sellable (you may recall that settable implies get- 
table and initable). The : required- init-keywords option specifies that 
every call to make-instance must include initial values for xpos and ypos. 

defun-method 

This facility is sort of a cross between defun and defmethod. It's used for defining 
functions to be called from inside methods, which need access to the instance vari- 
ables. For defun-methods to be compiled optimally, they should be defined before 
they are used. 

The : init method 

The last thing make-instance always does is call the flavor's : init method, if it 
has one. Here you can specify operations to be performed on every instance of your 
flavor, upon being instantiated. I use this one to set the radius of the new node 
according to the size of its label, and to add the node to the list of all nodes. Note 
that many of the window mixins already have : init methods, so if your flavor is 
built on some of them you'd better use a before or after daemon rather than a pri- 
mary method so you don't override the other one. 



ignore as an argument 

Use of ignore in a lambda-list for an argument which isn't going to be used 
saves you from getting a compiler warning about an unused variable. 



: send-if-handles 

This method comes with si:vani!la-flavor. The specified message is sent only if the 
object has a handler for it. This avoids unclaimed message errors in cases when 
you can't be sure of the exact flavor of the object you're dealing with. The 



Section 5.1 The Nodes and Arcs 85 



: primitive-item message has to do with mouse-sensitive items. We'll get to 
that a little later. 



map-over-arcs 

I wrote this macro to have a handy way to iterate over all the arcs. For each node 
it runs through all its arcs. If it has already seen that arc it goes on. If it hasn't, it 
executes the body forms with the specified variable bound to the arc, and marks the 
arc as visited. Note the use of gensym to make sure the mark-var and node-var 
don't shadow any variable bindings. 



5.2 Managing Multiple Windows and Processes 

We now have everything needed to make and alter graphs, but it would be very 
awkward to do it by typing forms like 

(make-instance 'arc 

model (make-instance 'node :xpos 135 :ypos 251) 
:node2 (make-instance 'node :xpos 338 :ypos 92)) 



The rest of the file is concerned with making it easy to do this sort of thing. First 
we define a frame (an object composed of several windows). Our frame has two 
panes, one for display of the graph, and one for typing lisp forms. Then we set up 
a process in the graph pane which just watches for mouse clicks on the mouse- 
sensitive items (the nodes) and dispatches appropriately. The lisp pane, by virtue 
of being built on tvtlisp-Iistener, will automatically have its own process for reading 
lisp forms, evaluating them, and printing the results. 

Managing multiple processes is something people often find confusing, at least the 
first few times. Windows, processes, and i/o buffers are all independent objects on 
the lisp machine, so you can have nearly any number of each. A window can have 
zero or one processes running in it, and any number of processes can exist indepen- 
dently of windows; windows can each have their own i/o buffers, or any number of 
them can share a single i/o buffer; any process can read from (or stuff characters 
into) any i/o buffer. How do you decide how many you want? I'm not sure how 
generally applicable they are, but here are some guidelines you can try out. 

First decide on the windows: the number of windows is your number of distinct 
output channels to the user, so you'll need as many as you have things you want to 
display simultaneously. In this example we want to see the graph and our 



86 THE GRAPH EXAMPLE Chapter 5 



interaction with a lisp listener, thus we have two windows. 

Next think about your input channels from the user. You'll probably want to use 
one i/o buffer for each. In our case we need one for keyboard typein (lisp forms) 
and one for mouse clicks on the mouse-sensitive items. Hopefully it will be obvious 
how the i/o buffers and windows match up. For this example it is: we'll use the i/o 
buffer of the window displaying the graph for mouse clicks, and the i/o buffer of 
the window displaying lisp interaction for keyboard typein. (See chapter 7 for a 
situation that calls for having two windows share an i/o buffer so that the process 
running in one can see input from both.) 

Now processes. For each i/o buffer there will have to be a process, generally one 
running in the window to which the i/o buffer belongs. (Having several processes 
read from a single i/o buffer would lead to undesirable "race conditions," where the 
program's behavior randomly* depends on which of the processes happens to get to 
a particular input first.) If there are leftover things to do which don't involve direct 
communication with the user, you can create extra processes running without win- 
dows. 

In deciding how many i/o buffers and processes you need, keep in mind that some 
tasks will be handled by the mouse process, for free. Think back to problem set 
#2, problem 4, when you defined a : mouse-click method which drew a square 
where the mouse was clicked. That window didn't have a process in it, and you 
made no use of its i/o buffer. It was the mouse process that watched for user input 
via the mouse and called your method when appropriate. Similarly, in this graph 
example, we'll define a : mouse-click method to create new nodes at the mouse 
position (see below), and this will happen independently of our own processes and 
i/o buffers. The mouse process does it all. There are other tasks, however, for 
which the mouse process only does some of the work. It turns out that handling 
clicks on mouse-sensitive items fall into this category. The details are covered later, 
but what's relevant here is that when a mouse-sensitive item is clicked on, the 
mouse process simply stuffs something into the i/o buffer of the window under the 
mouse, and does no more. Somebody else has to notice what's in the i/o buffer and 
do something about it. That's why the window displaying the graph needs a pro- 



See hacker's definition at end of chapter. 



Section 5.2 Managing Multiple Windows and Processes 87 



5.3 The Windows and the Mouse 

The graph-frame defflavor 

This defflavor uses the :def ault-init-plist option, which lists alternating 
keywords and values. The effect is as though the keywords and values were present 
in every make-instance for this flavor (unless explicitly overridden). The 
: selected-pane init keyword means that whenever the graph frame receives a 
: select message, it will pass it on to the the lisp pane. The : panes keyword 
says that this frame has two panes, named "graph" and "lisp," and that they are 
instances of the flavors graph-pane and tv:lisp-listener-pane, respectively. The 
: configurations keyword specifies the layout of the frame. Configuration 
specs are often very messy, and you should try to read up about them. This simple 
spec states that the graph and lisp panes are stacked vertically, with the graph pane 
occupying the top 60% of the frame's area, and the lisp pane occupying the rest. 



Selection 

The next two methods, :alias-for-selected-windows and 

: selectable-windows, are ones which applications programmers don't usually 
mess with. Although what these particular methods do is easy to see, the manner 
in which they affect the behavior of the Select key and system menus is extremely 
obscure. The only reason they're here is because I thought it would be nice if we 
could use the lisp pane to make our frame accessible via Select L. Take a look at 
the comments in the code, and don't worry about it too much if you don't com- 
pletely understand. (Incidentally, the bug in the speech editor which I mentioned 
in the introduction to Part II of the second problem set had to do with these mes- 
sages.) 

The graph-pane defflavor 

This flavor is based on graph-window (defined below), with tv:pane-no-mouse- 
select-mixin added. tv:pane-no-mouse-select-mixin itself is just a combination of the 
flavors tv:pane-mixin and tv:dont-select-with-mouse-mixin. The former provides the 
functionality a window needs to be a part of a frame. The latter fixes it so that a 
pane won't show up in various system menus. Otherwise those menus would con- 
tain separate entries for every pane in every frame, which is most inelegant. All 
you really want is one entry for each frame. (As to exactly what that one entry 
should be, see the previous paragraph.) 

The graph-window defflavor 

This is the definition of the window in which the graphs are to be displayed. It 



88 THE GRAPH EXAMPLE Chapter 5 



includes tv:process-mixin so that there will be a process running in the window, and 
tvtbasic-mouse-sensitive-items, so the window can display items which will be mouse 
sensitive. We use :default-init-plist again here. The : process key- 
word gives the name of a function which will be called on one argument (the win- 
dow) the first time the window is exposed. Such functions are typically written as 
loops which never return. The : item-type-alist is an instance variable con- 
trolling the behavior of the mouse-sensitive items. The contents of this list are 
described below. The :blinker-p keyword specifies that this window is to have 
no blinkers, and the : font-map keyword is a list of fonts this window is to start 
out knowing about. In this case, the window's sole font will be Helvetica, 12 point 
italic. (The default font we're all so familiar with is called "cptfont," so the font 
object may be found as the value of the symbol fonts : cptfont.) 

The : init method for graph-window 

This is where the variable *graph-window* gets set. Note that this setup assumes 
there is only one active graph-window around at a time. Whenever one is created 
the old binding of *graph-window* is lost, and anybody trying to use the old win- 
dow is likely to get confused. (If you wished to have several graph-windows around 
simultaneously, you'd have to think of something more clever than a single global 
variable to keep track of them. Similarly, the global variable *a!l-the-nodes* would 
have to go if you wanted different graphs in the different windows.) Note also that 
this is an after daemon, to avoid clobbering the important : init method defined 
for tvrsheet. 

The main-loop for graph-window's process 

This loop simply reads blips from the window's i/o buffer and dispatches. The only 
blips it's expecting are ones with a first element of : typeout-execute. These 
blips are generated in the mouse process when someone clicks on a mouse-sensitive 
item. The remainder of the blip will be a function name, dependent on the type of 
item and type of click, and the item itself. This loop simply calls the function with 
two arguments, the item and the graph-window. As we'll soon see, the items will 
be nodes, and the functions will be ones like delete-node, rename-node. etc., all 
defined below. 

The : refresh method 

This generates the picture. It sends each node and each arc the : draw- self 
message. (Note the use of map-over-arcs.) This is an after daemon so we don't 
override the : refresh method of tv:sheet. 



Section 5.3 The Windows and the Mouse 89 



The :who-line-documentation-string method 

The response a window gives to this message is the string which is displayed in the 
mouse documentation line at the bottom of the screen whenever the mouse is over 
the window. : override is a kind of method combination we haven't discussed 
before. It is similar to : or combination in that if it returns nil other methods get 
a chance to run and if it returns anything else they don't. It's different from : or 
combination in that some of the remaining methods may be before or after dae- 
mons, which isn't allowed with :or combination. In this case, the intent is that if 
the mouse is not over a mouse-sensitive item, the string supplied in this method 
should be displayed. But if it is over a mouse-sensitive item, some other method (in 
particular, the one on flavor tv:basic-mouse-sensitive-items) should be allowed to 
specify the documentation string. 

The : mouse-click method 

If the mouse is not over a mouse-sensitive item, and if the click was a single one on 
the left button, make a node at the mouse position and display it. Otherwise let the 
other : mouse-click methods have a chance. (Recall that : mouse-click 
methods have :or type combination.) The new node will have no label. 

The guts of the mouse-sensitive items 

For each type of mouse-sensitive item a window knows about, there is a set of pos- 
sible operations. (Graph-window currently knows about only one type of item, the 
:node type.) The item-type-alist (recall that this is an instance variable of 
tvrbasic -mouse-sensitive-items) tells what the possible operations are for each type, 
and also indicates that one of them is the default operation. The : mouse-click 
method for tv:basic-mouse-sensitive-items is set up so that if you click left over an 
item, a : typeout-execute blip is forced into the window's i/o buffer, listing 
the default operation and the item itself. If you click right, it pops up a menu with 
all the operations for that type of item, and when you choose one a : typeout- 
execute blip is sent containing the chosen operation and the item. It's up to the 
process running in the window to read these blips from the i/o buffer and do some- 
thing with them. As we've just seen, the process in the graph window calls the 
operation as a function, with arguments of the item and the window. 

The internal structure of the alist is a bit of a mess, and it usually is not built by 
hand. Instead, it is generally constructed with the macro tv:add-typeout-item-type, 
which is called once for each operation defined for an item. The first argument is 
the alist to be modified, the second is the type of item, the third is a string to name 
the operation (this appears in the menu you get from clicking right while over an 
item) and the fourth is the symbol which actually ends up in the blip if this 



90 THE GRAPH EXAMPLE Chapter 5 



operation is chosen. The fifth and sixth arguments are optional. If the fifth arg is 
t, the operation becomes the default operation for this type of item. If the sixth 
arg is present, it is a documentation string to appear in the who line while the 
mouse is over this option in the click-right menu. 

You can see that for the graph window the default operation (which you get if you 
click left over a node) is the function mouse-new-arc. If you click right you get a 
menu listing four other operations in addition to "New Arc," for deleting an arc, 
moving a node, renaming a node (new label), or deleting a node. 

The function definitions for the operations 

All that remains are the definitions of the five functions which implement these 
operations. The first two (mouse-new-arc and mouse-delete-arc) use a function 
from the Edit Screen menu to choose an arbitrary point in the window, then see if 
there's a node under that point, and if so, act accordingly. The delete-node function 
is very simple. The rename-node function uses a built-in function named tv:get- 
line-from-keyboard which pops up a small window and prompts the user to type in 
a line of text. The function for moving a node uses the same piece of Edit Screen 
as the earlier two. 



: item and : primitive-item 

The only thing I haven't explained is how the window knows that some portion of 
its display is supposed to be a mouse-sensitive item, and of what type. The : item 
and : primitive-item messages take care of that. If you look back at the 
: draw-self method for node, you'll see the : primitive-item message we 
glossed over before. What this one does is tell the window that there is an item of 
type mode, with left, top, right and bottom edges as given. The window has an 
instance variable which is a list of all the current mouse-sensitive items. The effect 
of the : primitive-item method is just to push the given item on the list. The 
: item method (which isn't used by graph-window) is an alternative to 
: primitive-item for mouse-sensitive items which are text. The method will 
take care of printing the item and figuring out its edges. With graphical objects 
like our nodes it can't do that, so we display them ourselves, calculate the edges, 
and send the : primitive-item message. To see whether there is anything on 
the list at a given position, send the : mouse-sensitive-item message with 
args of the x and y coords. If there's an item on the list matching those coords, 
some information about it will be returned, including the item itself, its type, and 
its edges. This method is primarily for internal use by the : mouse-click and 
: mouse-moves methods of tv:basic-mouse-sensitive-items, so the window knows to 
highlight the appropriate region when the mouse is over an item, and what to do if 
there's a mouse click. 



Section 5.3 The Windows and the Mouse 91 



5.4 Fun and Games 

From The Hacker's Dictionary, Guy L. Steele, Jr., et al: 

RANDOM 

1. adjective. Unpredictable (closest to mathematical definition); weird. "The 
SYSTEM'S been behaving pretty randomly." 

2. Assorted; various; undistinguished; uninteresting. "Who was at the confer- 
ence?" "Just a bunch of random business types." 

3. Frivolous; unproductive; undirected. "He's just a random LOSER." 

4. Incoherent or inelegant; not well organized. "The program has a random set 
of MISFEATURES." "That's a random name for that function." "Well, all 
the names were chosen pretty randomly." 

5. Gratuitously wrong; poorly done and for no good apparent reason. "This 
subroutine randomly uses six registers where two would have sufficed." 

6. In no particular order, though deterministic. "The I/O channels are in a 
pool, and when a file is opened one is chosen randomly." 

7. noun. A random hacker. This is used particularly of high school students 
who soak up computer time and generally get in the way. The term "high 
school random" is frequently heard. 

8. One who lives at Random Hall at MIT. 

J. RANDOM is often prefixed to a noun to make a "name" out of it (by 
analogy to common names such as "J. Fred Muggs"). It means roughly 
"some particular" or "any specific one." The most common uses are "J. 
Random Loser" and "J. Random Nerd." Example: "Should J. Random 
Loser be allowed to delete system files without warning?" 



5.5 The Program 



92 



THE GRAPH EXAMPLE 



Chapter 5 




Section 5.5 The Program 93 







a> 


-0 


0) 0) 






























•0 


a> 


A tj 

































!* 


id 








^» 






















Pi 


id 


rH C 








rH 
























rH 

ft 


4H 








0) 
A 0) 






















P 


CO 


Pi 








m TJ 

























•H 








CO 


rH 






















> 


T> 


A U 






H 


Pi 






















Id 




P 0) 






0) 


4H 






















rH 


CO 


•H P 




u 


X 


0) 






















4-1 


•H 


> 0) 

5 




rl 

ITJ 


■H 
ft 


43 
43 -P 






















4-1 


43 


CO -H 








P 

























Id 


01 P 

tj o) 




u 


■H 


tn Pi 






















CO 


P 


O ft 









0) 






















a> 


Cn 


a 




> 


X 


rH TJ 






















CJ 




TJ 




ITJ 


CD 


0) 






















fi 


a> 


4H Pi 




rH 


n 


Pi * 






















id 


A 


id 




4H 





id 






















•p 


P 








a 


rH 






















CO 




«-» rH 




4H 




P ft 






















c 


.ci 


CO 0) 







4H 


Pi CO 
















«-~ 






•H 


o 

•H 


rH £1 
0) Id 




to 





0) -H 
TJ TJ 
















CM 






^^ 


XJ 


X rH 




ID 


P 


Pi 
















^-> 


1 




0) 


* 


•H 







<v 


0) 0> 
















rH 


1 




> 

•H 

-P 


■H 


ft Pi 

o> 

PS 0) 




(TJ 
P 


p 
C 

0) 


ft A 
0> 
TJ 
















0) 
A 
id 


o 




CJ 




•H S 




CO 


o 


— P 
















rH 


*~ 


CO 


id 


8 


— V 
0) 




rt 
•rl 


4H 


CO - 
















1 


• • 


£ 




•a 


0) J3 









rH CT> 
















0> 


a 


4-1 


p: 


N 




4H 




0) Pi 
















CO 


id 





•rl 


•rl CO 







CO 


X -H 
















Pi 


3 


P 




» 


CO rH 






TJ 


•H P. 
















0) 


b> 


-p 




0) 




p 


P 


ftp 
















rH 






CO 


01 


0) X 




CO 





CO 
















1 


• » 


•a 


•H 


.C 


J3 -H 




•H 





Pi 
















&> 


a 



■p 


rH 


-P 


•P ft 




rH 





•rl Id 
















•H 


co 


o 






























P 


o 


0) 

P 
•H 






























P 
CO 


V 


TJ 
































o» 


§ 






























* 


•d 






























S 


* 



































o 


4-1 






























TJ 


fl 





















^x 












Pi 


& 


>, 














* 




CO 








* 


„ 


•H 


• •> 


<« 














CO 













CO 


ID 


1 


ft 


rH 














n 




R 











N 


43 — 


CO 


a 














•rl 










•H 


•H 


ft — 


H 


CO 














TJ 






«-» 






TJ 


CO 


id — 


J 


■H 

tj 






O 








id 

rl 




CO 


w 






id 
rl 


P! 


P * 

C^ CO 


• • 








T- 








1 




a 


CD 






1 


•H 


* Pi 


01 


•0 














0) 


CO 


T) 






ID 


tn 


•H 


* 


c 






* «■» 








TJ 


0) 


X 









TJ 


p 


TJ TJ 


* 






CO CO 











<-i 




C 









m 


Pi id 


s 


c 


rH 

•rl 


rH 


3 

•H * 








Pi 
1 


A 

id 


CO 


CO 






c 

1 


a 
i 


01 U 
CO 1 


• •> 





CI 


•H 


TJ 0) 








1 


■rl 


Tl 


PI 






1 


CD 


^ 0) 


A 


•rl 




Pi 


(0 N 








rl 


p 


•rl 






TJ 


TJ 


en 


p 


* 




P -H 








a 


id 





T) 






s 


\ 


•H 


id 


CO 


* 


1 CO 








•H 


> 


K 


id 






■H 


Pi \ Pi 


rH 


0) 


0) 


s 


0) 1 








Pi -» 


i 


rl 






c 


* 




(0 


P 


•d 





T> Pi 








•H — » 


0) 


0) 








•H 




~s 


P 


O 





•a 


-H 




*-* 




B rH 


O M 


P 






a 


+ 


01 




a 


a 


Pi &> 




rH 




* -H 


Pi 


1 


CD 






* 


*_- 


a 


N 


P 


i 


•H 


1 rl 




•rl 




Pi 


id 


p 


CO 




r-i 






•H 




(0 


0) 


> 


e (0 




c 




CO 


p 


•H 


<D 




CD 


X 




Pi 






■C 


1 


3 e 


0) 






P> rH 


CO 


PI 


rl 




X3 


id 




•H 


k 


CO 


■p 


43 


6 i 


■0 


CO 




•rl 0) 


a 


•H 




CO 


id 


a 




a 


id 


ca 




ft 


•H 0) 





u 


CO 


CO T) A 


■H 




T) 


P) 


rH 






* 


P 


ft 


rH 


(0 


Pi tj 


C 


P 





Id Id 


| 


T) 





•H 










g. 


rH 


rl 


■H 




aJ 


ft 


ft P. rH 


0) 


<D 


* 


TJ 


4H 










Id 


0> 


e p! 


rl 




X 


>i~ ~ - 


• i-\ 


P 


P 


m 


•H 








CO 

1 


4J 

CO 

P 


* 

rl 


p 


rl rl 




> 

id 


~ 






■ A 

ITJ 
P 


•H 


0) 

e 
i 


u 


^ 








* 


•H 


ITJ 


Id 


•0 id 


rH 








P 


0) 




p 










1 


4-1 


> 
4H 


> 

4H 


> > 

4H 4H 


4-1 
4-1 








0) 
CO 


P 


4H 


CD 
CO 














0) 


0) 


0) 0) 


0) 












ID 












1* 


1* 


•0 


■0 


TJ -0 


n 












TJ 













94 



THE GRAPH EXAMPLE 



Chapter 5 











■rl 
































+J 




















"O 
































45 




















(0 
































0> 




















h 
































■H 




















































CD 












P 








••» 
































45 












G 








> 
































1 






















































CD 












«w 








■0 

c 
































C 
•H 












P 








•H 
































rH 












a 








> 
































•• 












0) 

u 








A 
































S 












u 








ft 













































a 








id 
































73 




-^ 








o 








P 
d> 
































•H 




CO to 








CD 








































s 




3 3 








43 













































•H -H 








P 








C 
































-d 

C 




■d -d 

<d id 








a 








CO 
































CD 




u u 








•rl 








•rH 
































(0 












"" 








Q> 
































*^ 




to to 

















P 












ft 






_» 


















££ 








£» 








A 












1 






fc 


























10 








P 












>> 






w 


















1 + 








rH 





















4H 
•H 






CM 














CO 




»-- "^ 








(V 








rH 












£ 






EH 












r-\ 


ft 




^ -^ 








A 








•H 












CO 


















CD 






CO CO 








p 








A 
» 












0) 
rH 






i 












42 
03 


, 




•H -H 








>4-l 




















CO 


















■ — • 




-d -d 

















-d 








^ 




CD 














CO 




Oi 


^^ 




id id 

u u 








43 








p 








CD 




P 






E-< 








fJ 




C 


CO 












P 








<d 








P 











Cfl 








■H 




•H 


3 




to to 








0> 








0) 

U 








I 




C^ 






h 








0! 




P 
P 


•H 

■d 




aa 








(V 








o 










•H 






J 








P 




CO 


03 




X X 








-» rH 
















-H 










w 












1 


rl 












V 








CO 








^^ 


.-» 


a 






w 






<-^ 


CO 




■d 






1 + 








P CD 








i 












03 












> 







CD 


CO 












O A 
















»-» 


CO 


<D 


.— - 













ft 




M 













*~. 


&* 








CD 








rH 


3 


P 


.-» 




Eh 






■d 


s 




CD 


ft 




<4H 






o 








■o 




CO 




CD 


•H 


P 






(J 






c 






P 


X 




t-i 






p 


•H 








o 




0) 




a 


■a 


CO 


XS 




W 






•H 


CO 




C 






CD 


.-^ 




id 


P 








c 




-0 




id 


<d 




CD 




b 






5 







CD 


+ 


CO 


to 


U 






■P 















^ 


rH 


p 




6 




m 


^^ 


^^ 




ft 




O 


— 


CD 




P 




*^ 


10 (J> 












c 










03 




o 








X 








rH 


CD 


03 






<l) C 




* 




&» 






* 


P 


p 


*+H 


C 




i 


e 


^-~ 


^-« 






>, 


-^ 


■d 


■d 






O "~ 


P -rl 




s 




c 


^ 


rH 


CO 


CD 


CD 


rH 


g 




2 


03 


-^ 


4H 


CD 




03 


CO 


a 


O 






P to 


cd T> 









•rl ~ 




rH 


CD 


CO 


CO 


CD 




I 


CD 


E 


rH 


r-{ 




r-i 


s 


03 


a 






id u 


~ P 




•d 




c — 


-— 


Id "O 




CD 


CO 


r 




P 


03 


CD 


O 




ft 


■H 


45 




O 




1 U 


O 




c 




P *4H 


CO 









P 


I 








P 


CD 


CO 


P 




CO 


■d 


i 




P 




CD 03 


*->• o 




■H 


rn 


fd rH 


rJ 


4H 


a 


P 




P 


rH 






CO 


U 


1 


•H 




•H 


<d 


4H 


a 


03 




> 


P o 




» 


•H 


S CD 


•H 


o 


1 


CD 




C 


CD 




p2 




P 


* 


O 




Tl 


P 


•H 


« 






O 


•h id 




1 


C 


= to 


■d 




CD 


P 


* 


•H 


45 




i 


CD 


CO 


03 


1 








1 


p 


■d 




a p 


C 


^ 


43 






<d 


p 


A 


<4H 


* 


P 


03 




CD 


^ 




rl 


S 






CO T3 


•H 


T) 




oi id 


•H 10 


rH 


ft :* 




p 


CO 


P 


<d 





ftrH 




2 


CD 


T3 


03 




? 


a 


(5 




03 




p 


•• 3 


(1) 


id 


IW 






•H 


1 




T! 






ft H 


C 


a 




rl 







CD 


CD 




<^ 


.. o* 


•H 


JQ 


P 


•H 




p 


rH 


rH 




C 




P 


1 


Eh 




03 




T3 




-d 


x 


CO 


> 




»-» 


rH 


<U T3 


0) 


d> P 




CD 




rH 


CD 


•H 


CD 





>» 2 


u 


a 


CD 






c 






■H 


CD 


CO 


CD CD 


■d (0 


rH 


* 







CO 


CD 


<d 


-0 


* 


T3 




m 


H 


C 




■d 






•H 


i 




P 


■d 


u 


-d -d 


P 






c 




«D 


A 


* 





1 







•H 


Pi 


■H 


o 





s 




s 




» 


•H 





rl 


— 


G 


-P 


P 






P 


P 




c 


A 


C 


CD 


45 


Cu 


P 


C 


c 














a 


(5 


03 


C 


*- <u 


o 





> 








4H 




ft 




e 


CO 




ft 


■H 




T3 


rH 


T3 




T3 


•H 






— CO 


A 


c 


Pi- 


p 









rH 




05 




0) 


03 


H 




u 




P, 


CD 


fi 




C 


P 




CJ 


O 


•g^ 










P 


p 


CD 


■d 


P 


•0 


c 


rH 


W 




ft 


X) 


•H 


J3 


CD 




H 


ft 


>d 


U 


T3 P 














CO 





tn 







CO 











S 


03 


CO 




£ 







03 


id 


A -p 












Tl 




43 




45 


^ 










45 




rH 


■~^ 








45 




45 


-P tt) -0 










TJ A 


p 




P 




4H 








p 


■d 








T3 




P 


45 


p tr 


0) CO 


c 










<d 


CO 


CD 


13 


CD 


p 


•H 








CD 


c -d 






C 




CD 


CO 


Q) +J 


B 















3 


e 


£5 


6 


CD 


^ 








e 


CD 


C 






CD 




e 


El 


a oi 


<w •► 


o 










.- 


a 


MH 


03 


14H 


r-i 










14H 


CO 


01 






CO 




4H 


ft 


MH CO 


0) .- 
















CD 




(1) 












CD 














CD 




0) ^ 


■0 
















T) 




T) 












T3 














13 




■d 



Section 5.5 



The Program 



95 



•H P 

a a) 

(V 

— .c 
v m 
p •• 

0) > 

rH P 

a) 

■?.§ 

M 

•d 
o -d 

£§! 
o 
■d u 
o n 
.£ o 
p .Q 

0) «^ 

e 

4-1 •♦ 
0) .- 
T3 



a> in 

> ~ a; 
0) to *d 
M ~ O --' 
ft CO u 

O (0 * 

O fc o 

** «3.g 

^ J u o 

(0 J — c 

> p I 

Z P a) 
w ~ Z .£ 

•H W P 

,C J W I 

Eh H 

o cu a* 

q o -P 

o a> 



0) <D 

■d -d 
o o 



fc TJ -d 

moo 
e c c 



S-l V4 

fl Hi 

O ~ 

> 

id 



a> a) 
•d -d 
o o 



0) OJ 0) 

H rH rH rH 

■H .Q jQ £1 

C <TJ it} rtj 

-p +J p 

P -H P 

Q) (5 0) 

Ill-ri (Jl 




96 



THE GRAPH EXAMPLE 



Chapter 5 





































^ 




^ 


CO -H 




































^-^ 




^ 


P) tn 




































ft 




^ 


•H £3 




































CO 






J3 -H 




































•H 




c 


■P "0 




































rH 




0) 

> 


■H 

3 P 




































.C 




0) 


U 




































ft 






C CO 




































<fl 






> 




































P 




ft 


>» 




































tnvo 


CO 


CO 








































•H 


>! CO 




































§ 


o 


rH 


p 
■p id 




































3 


£ 




o 




































rH 


ft 


C 


CO CO 







































id 


0) 


-H > 








■>-» 




























O 


rl 


^1 


CO 






































tn -P 


w -o 




p 




»■» 


































o 




$ 




»»» 


























—~ 


c 






co A 




> 

1 




P 


























0) 




c 

•H 




JCJ -M — 

■P CO • 




<-» M 




id 


*-» 
























c 


l 




e 4h 




CO P 




> 


CN 
























m 






CO rH 




Sg 




i 


CO 
























ft 








CQ CO CO 






« 



























i 


P 






3 .C to — 




(0 •> 




p 


& 
























p 
cu 


C! 


CO 
0) 




Id en -P — 
O >- -H 




-— 




e^ 


























c 


* N 




Q) -» 




P * 






CM 
























0> 


id -h 




A CO CO 




(0 u 






CO 
























p 


rH 


CO 




• e 3 




^ 




M 


a 






, — i 
















0) 


CO 








- co id 






p 






--^ 
















C 


■H 


>— 


— 




J S P -0 




Q> .. 




? 


X 






















« 


rH 








i id <m a 


*-. 


■0 










-^ 








-^ 








ft 


1 


c 






•P P 1 -H 


* 


u 






CN 






►, 








^ 








1 


ft 


•H 






O 4H A > 


I 


G <d 




-p 


P 






-a 
















^ 


CO 


<fl 






CO 1 ft 1 


* - > 




a> 










'— 


-~- 


.— » 


^~ 






& 


ft 


■H 


e 






rH J3 Id TJ 


to 1 




co 








>. 














CO 


* 


rH 








CO ft P CO 




CO TJ O 






CO 






-o 


A 


A 


*S 


X! 




-— 


■H 


P 




^.^ 






co id tn -P 


* 


•o a u 
o oi (« 















P 


P 


P 


+J 




(D 


rH 


tn 


> 


«. 






P u 






p 


ft 






* 


tn 


tn 


tn 


0> 




e 


* 




P 








id tn co co 




a co - 




03 










a 


c 


C 


C 




nj 




A 




CO 






•H JC rH 


ja 


i ^ 




> 










OJ 


0) 


cu 


CO 




n 


CU 


ft 


ft 


C 






> id -p co 




CO T3 




1 










rH 


rH 


rH 


rH 




4H 


C 


rtJ 


CO 









CO 


~ R 


5 a c 




o 


CO 






s 












| 


(0 


P 


■H 


•H 






CO 4H (3 1 


■P -H CO 




M 



















-P 


ft 


tn rH 


P 






rH P P 


P CO 


1 CO 




a) 


ft 








T— 


T— 


<N 


CN 




c 


1 


^^ 


^— 


rfl 






43 3 


to a 


rH P ~ 






X 






3 


M 


P 


P 


U 




•H 


TJ 






P 






•H -O -P 4H 


> V 


rH Id 


>, 




















m 


0) 


% 




g. 






to id co i 


1 tn 


m > O"0 


t— 








3 


>> 


3 


>. 




p 


P 










CO CO P CO 


o •— 


* 1 CO 





C 


u 






* 


13 


■o 




p 


U 


CO 




•H 






co p» «d 


p "» 


o *- 


a 


9 




^-* 


—^ 


-^ 












CO 


d) 


<D 




4H 






O tO -0 -H 


03 - — - — It 


G P 


© 


co 




T— 


T— 




* 


* 


* 


* 




C 


rH 


c 




c 






O CHH 




•H Id CO 






CO 


CO 


CO 


+ 















0) 


rfl 











id -h 3 id 


"* & £. * 


« CO 
P CO 







CO 


a 




— ' 


N, 


N. 


s 


\ 


3 


o 


CO 


a 




u 






•• 


CO (0 CO > 


id M h 


■d 







X 




p 


V 


\ 


s 


\ 




T3 














e co co 


U C C I 


> c 

I 4-i 3 






c 






p 










0) 


<1) 


P 












id C TJ 6 


P 0) 0> X 






1 


CN 


(N 


V 










6 


P 


CO 












p co c id 


id tn tn P 


CO 






4-1 


to 


CO 


CO 


r— 


T— 


CN 


CN 


s 


CU 


•H 












4H -P Id P 


rl~~§ 


-0 ft 














■H 


CO 


CO 


CO 


to 


u 


T3 


rH 












0) 4-1 — 









1 


ft 




«— 


a 











<u 


P 


a 












P -H CO 1 CO 


11 h VI • 


£5 






CO 


X 






s 


ft 


a 


i 


a 














r-t e xi g 


> id id 


- rH 






CO 






,C 


X 


X 


A 


-p 












i id ft id 


O > > A 


- 






tn 


I 


1 


•P 










ft 




•H 












ft P id ft 


1 1 I +3 


u 






-0 






tn 


+ 


+ 






id 


> 


c 












tO tO 4H P 1 


ft * <u -h 









CO 






C 


^ 


^ 


^ 


w 


u 


p 


■H 












co -h i tn "0 


A p tj s 

S ISa 


4-1 >0 






1 


4 


>1 


CD 










Cn 




1 












XH O- 4) 








TJ 


T3 


rH 


CO 












P 












Id -rl -P 








Pi 






• — ■ 


a> 








M 




rH 












B id to no o 


o «- — 








•H 








3 













3 












id co 


P — 








4-1 








rH 








> 




<fl 












tO tO XX A rH 


O rH 










* 






(fl 








(0 




4-< 












•H <■ +J CO 


IS r 








S 


+j 






> 








rH 




CO 












a v a co to 








<u 














4H 




T3 












£-1 -rl S •• 


4H H 








4-1 


rH 














4-1 
















4H > 


(U — 








CO 
















CO 
















•- •' •* CO -P 


•0 








•o 
















•o 
















n 



Section 5.5 The Program 97 



ft 
o 
p 

TJ 0) 
+» <M 0) > 

(OOP 

CO TJ 
CD P -H O 

(0 -H +J 

AH « « 

c s 
ft « s 

m^ ft (I 

•HP 43 

rH ft £< 

CD CO ^ 

CD ^ -H 

43 0J rH 
P 6 

0) 4J 

CD CD 43 -H 

CO M -P — 

03 -H tO «-«■ 

h mi — 

>> > x v 

CD CO <0 -H C 

>! &>43 >M <0 

C ft 

P -H Tj CO I 

O 43 rH -rl TJ 

CD P C 43 CD U 

H O tn P 

a; co £ u 

CO 0) CD 4-1 it! 

O P • rH II 

CD TJ H — CD — HO) 

43 a» co — a> ft 

p 43 e •• * > £ 

O • 10 > O 0) P <— 

c; 'H h ^ +j nj. i — i i 4» 

>! 43 C «H - C Ig ri 

<tj>a>i -h ft cd o — 

S 6 43 — * OP — 2 -H 

S ft C I +» -H — & >, 

O Jl g fl -O 43 II— -H — P 

+j +j CD P -- •* ft J43-H > I 

COP&lp (0 OftCNP O r^ 

-O >n co — o P tjifl'-co ■d C 

•rl CO >> CD — CO CD t? C P rH CD «3 <0 

>C CO 43 •> rH CO -rl fr 43 P -rl 

>p?ocd i3 e>*--us > 

POCDOTJCO -H CD I CO -^ ^ ri IH^ 

CO TJ 43 P -d C I X +J43+JP -rl rH CD 

C C P O C -H P -H -H ft CO C — C C CD P 

•|-| -rl <M -rl > O 6 I (0 -rl rH O P O CO — 

S <M > I »4H I CD P rH -H 4H -rl -H —»0 — 

CD O 111 I 91 I P > &> <0 C >- C P ft T> CD — 

S CD O rH rH CD O -H •— I » -H O O C X 4H 

43 C C <0 43 6 CD P * CD ft •• £3 OCDCDrH 

&HJ O O -H fl fl rH -H ftlft C rHCOICD 

C -rl p p C a, CO CO >, p <0 P 4H I >- P CO 

•HM-tP-OCO" co C copcdB CD i (3 3 _ 

43 O ft C CD CD I CD CD I ,!«! I -P — • rH -HMOS 

■p o id n h ai cd (3co o g c p mh— <d <o cdcd 



SrH 



CQCDC3 CO -HI O CD -rl C <0 4H > 

p p <W CD CO <0 S *-»XCD h+JrHO •• H CD 



• e .-££.t 



4*1 <0 O rH •• ft O -'■H « ft -H 43 4-1 CD rrift CDP 

<0 ft CD CD C I ~ 6 S C >C0 10 * P •• ft 

CD rH CO O CD TJ «- I » I O O ftOO'HO 

C CD CD P BCD O O CO B — P TJ* Ori T3 TJ 

CO 43 CO -rl CO (0 P CD C >0 CO I ? CO C ? PI G ft 5 rH 

+J -H p O CI C3CDOO-H -HO I C -HOSrH 

CD CDP *M CD 03 (D •HU-H'OrH ? T3 5 -H > 0) n3 

43 CO 43 O C* I rH ft C £ O CO C ft IC O <0 1-0*0 

En CD P <4H C 43 CD 1(0 I P <fl -rl I 43 -ri TJ 6 43* C 

co -Hftco co, 43ft4a*p ft> a •■ ftScrB 

C P CD -d «J •• ft •• ft H <fl I -H fl CD CD <W 

•»wOO-HP> rfl> «>>>C P43 >S P >J ^ — 

>!CMHCP&)P PP U *J *J *J -r^ &>ft 10 C7> — 

CQOOP^ tp^tji^ I ^(0 43"O^CO 

id O 10^ 0) TJ P pftC PCDTJ 

>>'OCP P r-i 'O&i<0-HTJO43 

prHOCDOOCD O O C O* P» Oiw? 

x CD-OO43c0> > id 43 tj>43 

C>C-HCDP^m nJ *w PC -OPft 

OCD-H^PCD-rH rH CD CDPCCCDO 

QrH^plCB— <W IH T3 BCDSCDBO 

4-|x_,l4H IW •• IMCO^HCOM-lrH 

.-.».».» .^ CD ' CD CD •-' CD — ' D w D — 

. ^ . ^ .«-.«-.*- rrj f rl irt trj irj tr) 



98 



THE GRAPH EXAMPLE 



Chapter 5 













P 
■H 






















o 
u 

0) 














to 




















rH 
•H 


0) 


p 












e 












rH 
•H 




rH 
•H 




(3 


p 
a) 


o 












u 












c 




c 




CI) 


rH 


p 

































■d 


tt) 


03 












> 












0) 




0) 




o 


■d 














o 












-d 
o 




-d 






13 


i ■»■» 

B 


0) 












c 












(3 




c 




0) 


(0 • 


(3 












V 












1 




i 




> 


rj rjj 


I 












43 




CD 


~~- 






d) 




0) 




o 


4) 


tt) 








rH 




» 




N 


0) 






p 




g 




e 


e p 


to 








■H 








•H 


N 






0) 








tt> 


3 








C ~ 




d> 




to 


•H 






rH 




c 




0) 


= rH 















13 




1 


(0 






0) 




0) 




to 


O 0) 


a 








~* 




•H 




c 


1 






■d 




p. 




3 ~ 


p -d 










d> i 




43 




•H 


c 














= 


< 










13 a> 




■P 




Cn 


•H 














e • 





o ^ 








•H 10 









p 


tJ> 






0) 


*-» 


0) 


--~ 


« 


4) 43 


r. 








P 3 




C 




03 


M 






p 


s 


S 


= 


= d 


P 








P o 








e 


03 






v 




03 




cu o 


tt) 


o 








to E 









i 


e 






rH 


43 


(3 


0) 


> C 


rH P 


» p 








i •• 




•d 




■p 


i 






d) 


ft 


CU 


d 








tt) 03 








C > 








4H 


ft 






o 


03 


Pi 





S to 


Q O 


21 








O P 








0) 











P. 




c 


= -rl 


= u 


= > 








■H 








rH 


p 








Cn 






43 


0) 





9) 






P X 
















0) 




0) 


CO 


0) jj 





tt) 13 


u 






(0 1 








> 


> 






T3 


d) 


d 


•H 


d 


-d c 


•d 


O 






P tt) 








P 


p 






43 





43 


P 


O 03 


O 03 


g> 






a to 


--n 


-■* 












(3 


p 


c 


P 


c 


{3 


13 






0) 3 


= 


>»~ 




X 


>^ 














•• 4H 


.. m 


.. m 


•H 






IS 


3 
















4-1 




P. 
















c 


X P 




1 


i 






* 





* 





* a 




* 


■P 






O •• 


0) 






w 


_- 






P 




p 


4-1 


P 


p p 


p p 


CO 






> 


E 


to X 












to 


p 


to 




tO -H 


to c 


to fi 









*d P 




C 




to 


to 






•H 


3 


•H 


rH 


•H P 


•H -H 


•H -H 


U 






1 


e 


O S 




a 


o 






rH 





rH 


CD 


rH -H 


rH O 


rH O 


<4 






oj e 


CD 


P W 




ft 






03 




03 


42 


o) to 


03 ft 


03 ft 








c a> 


p 


P E* 




X 








1 


0) 


1 


03 


1 O 


1 










•H P 


(0 


3 H 












tt) T3 


0) 


rH 


V ft 


tt) -d 


tt) -d 








rH -H 


:* 


43 I 












ft 


ft 




ft 


ft (3 


&s 


45 






I | 


en 


~ W 




cu 








>> «3 


^ 


IS 


>^ > 


>, tt) 


CO -> 






o a) 




> 




xs 








P 




P 


<1> 


P tt) 


P 


+i 


0) ~ 






43 > 




^ H 













I 


to 




£3 


1 c 


1 


1 


u <m 






> -H 




-X Eh 




c 








6 


•H 


e 




e 


e c 


e c 


«H rH 






.. +J 


CN 


O H 












0) 43 


0) 


03 


tt) 03 


tt) 





tt) * tt) 






•H 


« 


•H CO 








>4H 


r-i 


P 


P 


p 




p 


p 


p 


h to n 






a> to 




rH 55 




0) 




rH 


•H 


•H 




•H 


0) 


•H >, 


•H >, 


•H >, 


.. o> 






■d (3 




u w 




o 




0) 


fi 


1 


0) 


1 


d 


1 4-1 


1 4-1 


1 4-1 


•d mh 






•H 0) 




1 CO 




c 




to 




43 


U 


43 


•H 


43 -H 


43 -H 


43 -H 


P O rH 




—. 


P tQ 




0) 1 




03 






* 


ft 


•H 


ft 


> 


ft o 


ft o 


ft o 


tt) J3 tt) 




^~- 


P 1 




to w 


-^ 


-p 




l« 


+J 


03 


rH 


05 





03 d) 


0) d) 


03 tt) 


P 1 (0 




4H 


a) a> 




3 10 




to 




t-t 


m 


U 


ft 


U 


u 


U ft 


P ft 


P ft 


<U 1 




rH 


> to 


*> 


D 


I 


c 




0) 


■H 


& CO 


d>o< 


0>CO 


0> to 


CP (0 


03 43 * 




0) 





<d 


e o 


<H 


•H 




n 


rH 


* 


: 


* 


= 


* s 


* = 


* = 


•• -P «d 




CO 


•• o -d 


" ? 


1 


1 




i 


(0 
















^ ' n 






6 


o 




0) 


CI) 




> 


1 


0) 




0) 







tt) 


tt) 


>HT5 




4H 


? •• 


c 


> " 


(0 


M 




03 


Q> 


& 




ft 




& 


ft 


ft 


OH •• 




rH 










3 


03 




H 


^ 




>> 




>> 


>» 


■d «J 




0) 


■0 »tH 


? 


•d fa 





6 




•d 


+» 




p 




P 


P 


P 


£ * 0) 


o 


(0 


13 rH 


0) 


C J 


3 








P 






1 




1 






•H TJ 


p 




•H d) 


c 


•rl W 








1 


a 




a 




6 


e 


g 


> f3 O 


a) 


> 


* to 




» to * 


■d 






s 


0) 




0) 













i -h a 




03 




03 


1 




13 






V 


4J 




p 




P 


p 


P 


43 




P 


43 -d 




43 -d 


CO 


0) 






p 


•H 




•rl 




•H 


•H 


•H 


ft tt) -O 


to 


■a 


ft c 


a> 


ft c 


C 


to 




^ 


•H 


| 




1 




1 


| 


1 


Kflfl 


o 




o3 a) 


^ 


03 V 


O 


^ 




p 


1 


+J 




P 




P 


P 


P 


MOO) 


p 




P to 


03 


P 10 


-P 








43 


S 




3 




n 


S 


S 


d> 33 to 


03 


u 


tn — 


2 


d>~ 


P 


C 






ft 


















o 




1 


u 








3 


&i 






03 


0) 




cu 










d) 


P 

■coo 


P 



03 


P 
■d o 




w p 

<d 


43 









U 

d> 


£ 




& 




& 


ft 


& 


O <H TJ 


> -0 


o c 


J 


C 


M 


ft 






* 


p 




p 




p 


P 


p 


43 


o 


C 


43 — 


E 


43 ~ 






















1 




P ft 


1 


0) 


P 




P 










u 


■d 




d 




•d 


d 


d 


a) o 


ft 


to 


a» -d 




<u >d 










(0 


-d 




T) 




T3 


d 


■d 


6 O 


03 


^ 


e c 




6 C 










> 


03 




03 




os 


03 


03 


<W rH 


e 




4H 03 




>W 03 










MH 
















0) ^ 






0) ^, 




0) — 










0) 


> 




> 




> 


"> 


> 


■d 






■d 




■d 










•d 


p 




P 




p 


p 


P 



Section 5.5 The Program 99 



o CO I 

u xi = n 

<t» co o 

o -o i 

S +j o co 

CO -H 

u «h 

CO (0 43 13 

45 +J 0} 

+J CU 

H — -P o * 

o g <w * 

4-1 CO M 

-P O -H +J 

<D -H 4-1 0) CO 

o "d o> «^ ^ <o 43 

C C <0 to — — h ra 

O O O ~ <-* I 

ViO CVht-csi cC CO 

id cu <tf co co co 

43 ~ CO h — « •• •O •O" ^ 3 

+j ^ _ CO ~ O O co o 

O ~ fl- - C C -P E 

>. <N B 4J >, g -. •• C •• 

•P CO CO -P O CO W> 

pi 43 * -d cx-p«j«j = -p 

•H V O -H a) -H 

oec o^e-o-o tj 

o« co co •• h*j « t) B t! ^ 

to p -P C co co <0 

>! O -h a> >JS-HOwcn O 

O O I TJ U O I O — — 43 

•H 43 CO O -H 43 CO CO >, 

puu>C Pn m > co co a> ~ co 

= = -H =s-H— ■dT) — .* 

£ 4-» <- S-POO — I 

OiH-HCU OrH-HTJCC — 6 

TJ-HCOTJ -d-HCOC! «— O 

CCCO fifl fi IID'D' — H 

■H CUC'- -H CO CO CO CO ~ *- *W 

S+jcq-^^>+jco— — ^^ 43 i 

C I ~ ? fl I — w v 

rH-HCUO-— OrH-HCPCHOj CU C! 

— iHOCOW— -OrHOCO-HO ^M -H 

>njaDnj>C(Oft0 — c a) iw m 

OOI O^O-HOI O<0 h ^ -P <U -^ •— I 

•Ol-dE -d » I *d g $3 ft CO H S >-P 

C £3 £3 •• COG £3 G •• H d) +J 0) H •• O O <D 

•HCU-H O -rl CO CO -H O 43 <U CO 01 TJ TJ CJ> 

s ~ 43 4-1 > c> -o — g <w s <«> na-o? c a • • 

>,4JI O ~ <d O >, -P I O ~ — •• O -H -H > 

aii^'dft-PM-iCiU'Ofta «os S-p 

■d X -P O £3 CO to rH ^-X+JO (30)0 — O £3 — — -» 

O — CO -P -H CU C <D — CO .p -H CO O O fc -rl CO « CO ~ 

£3 CO -rl £ 43 -H 10 O CO -rl £ 43 rH >H flj £ Tj 43 Tj rH 43 

^■o x -d «-ii ^■043'0 »-*- <a o co o co co 

ficoco TJ co? nJCcoco -O "O -O £3~<U C43 co 

O-HII £3— >J(fl l-HII C'-O 4JC3C —con — «J n 

nxi+jfi coemn coxiP£3 coen ococo -p«w rH iw 

it I CU 01 CO CD g T3 -PIC0CO CO CU (fl (3C0C0 CU CU CU CU I CO 

i ai co cu —..p«_-.. cu cu co cu ^-+j^- ^«_-^ t) h ^ tJ-P ^ 

>SIM -H rH^I^ -rl— O «» •• O <D •• 

COrHCOOg-d COrHCOOg <W flTJ J3C0 

{3k)coco co-PC tj k) co n copp -h !••> I •• * 

i > s •• +j o iii i > d •• 4J o « — cooco o 

QJIO>-H(3C0 (0IO>-HC3rH -PCOTJgaj'O 

cocogp ^.w.^ cocog+J — «-' — cotJC (OtJ (3 

■3 rH •• - — pj H .. k w ,H Q -H £3 O -H 

oft>=* <« o a > % M-i coj3>co(3> 

g -H -p +> -H g -H +J P -H TJ M 

+)^- d)^ 4J— CO— "OTJ "OTJ 

(3iH rH J3i-i rH C3CJ3CJ3C 

j30 ^ 00 ~ 0COCO0COCO 

lUg <4-|g lw tfl CO 4-1 CO CO 

<p^ cu_- co^^co— — 



100 



THE GRAPH EXAMPLE Chapter 5 



0) ~ *- 

to — "» 
o 4> >— 

ONI) 
.C -rl N 
O W -H 

= I to 

C i 
= -H $3 

•H Ifl H 

o e <o 

eu i e 
•^ I 

M<H ft 

O 0) o 

•HH+J 
pn .. .. 



O H o o 

•O -rl T) "O 

c c n c 

•rl -H -H 

> -P 5 5 

> H -ri T) fl 

O rH O C C 

c o I to w 

■H I >0 -' -' 

* g -S X * 
0) -- ^! M-i 

•d :*p i " ' 

i u «-* «- 

a x p o ~ 

^«- « |J 91 01'- 

4) -H O O .C 

0> T3 ,C TS ft 0< CO 

•O G to 4> X >^ 4> 

O -rl I I I IH 

a a -p c +j +j M-i 

1 | <D 4> CD <U 4> 
0) CD 10 4> tQ 10 U 

> 3 i n 

OH d) o 

g id oi to 4i u ^ 

i > a •• *o tj o 
a) i o > o o -o 

to <u 6 -P C C fi 

fl H ••' -H 

O ft > % -o -o s 

g -H +J C C _ 

+J ^ 4) 4) T3 

C pH to CO C 

g jj >_^ a) 

WE « 

■d 



Section 5.5 The Program 101 



5.6 Problem Set #5 

Questions 



1 . Assure yourself that you understand the graph code. 

2. Write a function that finds any nodes with no connections to other nodes and 
removes them from the graph. Write another which clears the graph-window 
then uses map-over-arcs to display only those nodes which are "nodel" for 
some arc. 

3. Extend the program to be able to deal with a larger area than will fit on the 
window at one time. You'll need some mechanism for moving the graph win- 
dow around within the entire space. 

4. A. Write a : highlight method for nodes, which puts an already 

displayed node in reverse-video. Now modify the functions mouse- 
new-arc and mouse-delete-arc to highlight the first node that was 
moused while the program is waiting for you to choose the second, and 
un-highlight it when you've chosen. Fix up mouse-move-node similarly. 

B. Write a new mouse-sensitive operation which has you pick two nodes 
and then highlights all the nodes in the shortest path between the two 
chosen ones (where "shortest" simply means containing the fewest 
nodes — don't worry about ties). 

5. {Hard.) Make the arcs mouse-sensitive too, but modify the mechanism so 
that the area considered part of the item is not an entire rectangle, because 
that would include too much area. Allow specification of parallelograms, or 
something like that, so you can tighten the mouse-sensitive area to be just 
around the arc. 

6. There are a number of problems with the code as it stands. Here's your 
chance to improve on the teacher's work. 

A. Any operation which requires that some part of the display be erased 
currently causes a complete redisplay. This is really unnecessary, and 
quite unattractive, especially if there's a lot of stuff on the screen. Fix 
the deletion commands to do minimal redisplay. 

B. Currently, if two nodes are connected by an arc which cuts across 
another node, the line for the arc just runs right through the node. Fix 
the : draw- self method for arcs to be smart enough to go around 
obstacles. 

7. Write a new program, borrowing whatever portions of this one are 



102 THE GRAPH EXAMPLE Chapter 5 



appropriate, for displaying trees. One important difference should be that 
instead of having the user specify the location of each node, your program 
will determine their locations. That is, the root will appear at the top with its 
inferiors spread out in some tasteful fashion below it. 



Section 5.6 Problem Set #5 103 



Hints 



1. Play. 

2. The first function should loop through all the nodes, sending the : delete 
message to any which have no arcs, and then refresh the graph window. The 
second should clear the graph window, then use map-over-arcs to loop 
through all the arcs, sending "nodel" of each arc the : draw-self mes- 
sage. 

3. Give the graph-window flavor two new instance variables to indicate the x 
and y position of the window relative to the graph area. Now the functions 
concerned with node positions need to convert between a node's apparent 
position and its real position by adjusting for the window position. Four of 
graph-window's methods (: draw-circle, : draw-line, rdisplay- 
centered-string, : primitive-item) will have to convert from real 
node positions to apparent positions, while the : mouse-click method and 
the function mouse-move-node will have to convert from apparent to real. 
The former four are all inherited from some other flavor, so for them the 
easiest thing is probably to define whoppers which adjust the arguments. For 
the latter two, on the other hand, we did the relevant definitions ourselves, so 
we can change them. 

The whoppers converting from real positions to apparent positions should be 
prepared for the apparent position being off the screen entirely. The 
: draw-circle and : draw-line methods "clip" (they'll even do the right 
thing if the circle or line should be partially visible), so you can just pass 
along any bogus arguments without worry. The :display-centered- 
string method, however, wraps around when given off-screen coordinates, 
so in this case you should check the apparent position and possibly skip the 
whopper continuation. 

(You'll have to make a new instance of the graph-frame, because the new 
graph-window defflavor, with two extra instance variables, is incompatible 
with the existing graph-window.) 

4. A. The : highlight method should draw a filled-in circle in xor mode. 

The basic idea for the mouse-!...] functions is to use the : highlight 
method once to highlight a node and again to turn it off, but there are 
two kinds of complications to watch out for that could leave you with a 
node turned on: the : refresh method clears the screen, thus remov- 
ing any highlighting that may be present; the new-arc and delete-arc 
functions have several failure modes (the parts with the beeps) that 
skip portions of the code. 



104 THE GRAPH EXAMPLE Chapter 5 



B. Add a new type of typeout item to call the function mouse-find-path. 
The control structure of mouse-find-path should look roughly like that 
of mouse-delete-arc, and you'll probably want an auxiliary recursive 
function, say find-path-to. A breadth-first search will be the easiest 
way to find the shortest path (because the first path you find will be 
the shortest); you can use the mark instance variable of arcs to 
prevent looping in the search. 

The key issue here, and the reason I call this a hard problem, is compatibil- 
ity. We want to use the bulk of the existing mouse-sensitive-item code to 
save us the trouble of duplicating its functionality, and we want to modify it 
to provide the new features. But at the same time, other programs will be 
using the ms-item code and counting on it to behave the way it used to. 

My approach is to first replace the hollow-rectangular-blinker that is provided 
by the basic-mouse-sensitive-items mixin with a polygonal-blinker, a new 
flavor of blinker which can draw itself as any closed polygon (imitating 
hollow-rectangular-blinkers as a special case). Then I define a line-item 
object, and arrange for the polygonal-blinker to draw itself as a squashed 
hexagon around ms items which are of type line-item (and as a rectangle 
around all other ms items). A number of basic-mouse-sensitive-items 
methods have to be modified, but most of the changes are of one very simple 
kind: references to individual ms items are replaced with calls to a macro 
which just returns the item if it's the normal type, and extracts the appropri- 
ate information out of it if it's a line-item. The only substantive changes are 
to the : mouse-moves method, because there's a new way for specifying the 
shape of the blinker, and the typeout-mouse-item defun-method, because 
there are new rules for determining whether the mouse is over a particular 
item. 

Now all I have to do is change the : draw- self method for arcs to provide 
a line-item as an argument to the : primitive-item message, and define 
the "Delete" operation on mouse-sensitive arcs. 

(You'll have to make a new graph-frame to put all the changes into effect.) 

A. The deletion commands should surgically erase exactly the nodes 
and/or arcs being deleted, and leave the rest alone. You can erase the 
nodes by drawing a filled-in circle in andca mode, and the arcs by 
drawing over them in xor or andca mode. 

B. Open problem. I haven't thought of a good way to do this. 
Done as "The Tree Example," chapter 7. 



Section 5.6 



Problem Set #5 



105 



p 


















? 


n 





















1-\ 


















■0 





















c 


1 
1 

in 


















•H 

1 

ft 


* 


















U 

CT> 


P 


















* 


CO 




















W 






^ 








^ 




4H 

rH 


g 






^-~ 








:s 




CO 


(V 




* 


0) 













CO 


rH 




03 











13 






A 




CO 


P 


--. 


»-. 




C 




5 


O 




T3 


(0 


^-~ 


«-* 




■H 




Hi 


M 









CO 


^ 




> 




rl 


h 




l 


CO 


P 

CO 


co 

CO 




m 




<a 






co 


T) 


rH 


h 




« 










A 





CO 


4H 




CO 




■— 






-p 
1 


C 


■a 


CO 
in 




rH 

o 




CO 






iH 


T3 






•— ~ 






T3 






H 


C 


CO 















- 


* 


CO 


T3 


* 




* 


»-• 


c 






* 


to 





» 


CO 


» 









CO 






n 










u 






u 


C 






TS 


CO 


73 


<c 


o 




0) 


•H 


r-\ 


n 


G 


T3 


a 




rl 




c 




rH 


a 


•iH 





•H 




rfl 







0) 





CO 


5 


fi 


s 


CO 






rH 


■0 


a 


co 




1 


1 





-d 




| 







■~^ 


k 


s-,43 


rl 


c 




CO 


c 






ft 


(0 


ft 


ro 


CO 




> 




c 





(0 


rH 


<0 


1 


CO 







M 


0) 


T3 


5h 


a 


H 


rl 


^< 




g 





A 




Cr> 


CO 


Cr> 


co 






(V 


4-1 


» 




* 


•H 


* 


> •« 




M 


a 






■0 


T3 


T> 




1 


c 

CO 




a 









c 


c 


a 


ft 


CO 














CO 


9 


CO 





— ' 




<u 


H 






CO 


4H 


CO 


e 






CD 










1) 










•o 










-a 









££ 

0) rl 

43 tn O 

P P 

a> Pi 

•0 43 -n 
P! P 

«D * 

co M 

CO o 

3 > rH 

o o 

>> o 

-O P 

P c 

(0 pi p 

43 O P! 

P U <0 

-0 > 

CO 

co P P 

U -H 43 

•H tJ> 

3 CO -rl 

tr > g 

CO o 

Hg- 

o • 

P O rH C 

2 P -rl 

A X 

CO • -H 

- co co e 

>, &> CO I 

P <0 2 &> 

•h co o a 

rH CO g -H 

(0 CO rH 

a g CO rH 

O 43 O 

•H CO P U 

P O O 

O ft 43 CO 

PJ I p I 

3 >>-H £ 
4-1 I > 43 

43 co 

■O ft rH (0 

CO 10 rH rH 

■O rl O <4H 

co tn u •• 

co i cj > 

P! P to P 

co 

co co o *0 

43 •• -P P! 

P (0 

TJ P 

rH C P! H 

rH <0 CO <0 

«5 -H 43 

CO C I 

CO O CO rH 

CO ft > rH 

■d I P! O 

■H X O rl 

> I O U 

O 43 to 

rl ft CO I 

ft «0 rl O 

rl O 'H 

tj> &1 g CO 

Pi I 03 

•H P CO 43 

> CO 43 •• 
O CO > 

rH •• 13 P 

r-i t-\ 

O ? P» CO 

4H O O P! 

T3 » -H 

CO Pi X 

rl "H +J 'H 

e > H g 



— P! to 



> P 



> O O X CO 

O -H CO 

TJ co co g 3 

P! O O I O tu -H 

•H ftftCO g^ OH 

> I i co i S C ft 

i X >,I1H) O id i 

43 I I O -H T3 P P 
ft4343OC0P!C0-H 

irJftftum-HCC 

}H * 10 ft 43 > -H -H 

0> rl rl I I 

Cn tr> > > > co P 

M— — PPPrHrH 

O >- «- 43 P> 

> (0 (0 

10 +J IH 

rH P CO 

Uj CO -O 



S * to 

i P 

•S +• 6 

ft co O 

It! -H rH 4-1 

»H rH -H - 

01 10 C — 

^ I ' 

» CO ft 

ft I ft 

to >, U i0 

CO CO P CO g 

CO CO I 4* I 

rH O g P! P 

43 O CO -H G 

(0 U P rH O 

•H ft-H 43 <4H 

u 

Rl 



CO 

CO I 
•H I 

TJ 43 
>0 ft 

rl (0 

rl 

>> C7> 

X >, 



u co 

-^ a 

O I 

^? 

<0 43 

rl ft 

■O <0 

•• U 

&> 

Bx 

T3 

Pi I 
•H — 

I U 

43 CO 

ft ft 

(0 ft 

rl O 

&>43 

I 

rl CO 

CO p) 

ft Pi 

ft-H 
O P 
43 Pi 
> O 

4H O 

Q) ^ 

T3 



106 



THE GRAPH EXAMPLE 



Chapter 5 



















a 
i 

X 


to 

a 

1 




































1 

(0 


1 

* 












r 
























ft 


Ifl 

rl 












cu 


























Cn 












T3 








CO 






e — 










.-~ 























H 






o — 










cu 














Pi 












P CO 










N 


cu 
























ft 










•H N 
CO -H 












cu 

,£3 








p 1 






£1 — I 










1 


CO 












P 








A >> 






CO >, 










c 


1 




















CT> 1 






P i 










•H 


c 












kl 








•H A 






A <XA 










tn-H 





















u a 






0> i ft 










M 


Cn 












4-1 








10 






•H >, « 










§ 


M 














— - 






p u 






P I P 










1 












c 








4H 0> 




^ 


43 &> 










i 















cu 




^-^ 


V 




^-» 


ft ft 










P 


i 












•H 


N 




cu 


rH 01 




P 


it) 6 










4-1 


ft 












P 


•H 




N 


&> ft 




-C 


P P 










CD 















■rH 


CO 




•H 




tn 


tnP 










rH 


P 












CO 


1 




CO 


c >. 




•H 


-P -P 




<-» 























PI 




1 


•rl 




01 


4h ft 
d) A 


^ 


*-» 






> 


> 












a 


■H 




Pi — 


P. <W 




A 


CO 


CO 






P 


P 














CJ> 




•H -^ 


P O 




1 


rH P 


a 























s 


tH 


^~- 


tn — 


CO CD 




V 


I 


ft 






X 


►, 










r 


cu 


ifl 


—■ 


U — 


— -0 




Pi 


6 i — 


i 




















P 


Pi 


e 


co 


(fl CO 






•H 


0) ^ 


>> 


>1 


^- 




1 


1 










c 









a o 


--» 




rH 


p — 






>>~ 




— 


- — 










•H 


Ifl 


p 


ft 


i a 


t7» — 






•H — CO 


CN A 


A 























4-1 




ft i 


C co 




> — 


CO 

cu ft 


>> ft 


ft 


X * 




+ 


+ 










cm 


cu 


CU 


X 


o >, 


•H 




P — 


•0 


« 




















CO 


rH 




p i 


U ft 




CO 


ft?A 


CN U 


(H 


co X 
















X 







A 


•• A 


p 1 




*~* 


X c^ 


Cn 


Pi 




00 


CO 










o 







a 


ft 


co X 




p ft 


P X 1 






o s 







a 










•H 


A 


3 


id 


S ifl 


1 1 




A £ 


— I A 


T— T— 


(N 


P w 




ft 










0. 


u 





n 


P. 


T> A 




tn 


A ft 


►«>»>» 


p H 




X 


s 










r 


= 


-0 


CT> "O 


CU ft 




— -H +J 


— ft «J 






PI H 














•e 






C 




Pi •• 


P. lit 




.-. q, # 


e m p 


T— | 


1 


A 1 

















rH 




•H 




■H 


CU U 




^5 ^3 Cn 


cu p tn 


X — 


~— 


~« 




cu 










T3 


■H 




* 


> 


> > 


P tj> 




P 1 -H 


p tn 








T3 










Pi 


C 












ps 




■o (u h 


•H P 


«-~ 


*-> 


— H 















•H 






"0 


T3 


TJ X) 


CU P 




•H T3 


i p A 


«-^ CO 


CO 


>! t>i 




C 










s 


P 




Pi 


c 


Pi Pi 


O A 




» -rt P 


a» m &> 


CU o 





O H 
















c 




CU 


■H 


CU -H 


I 0> 




1 CO (M 


> CD -H 


Pi ft 


ft 


•H W 








4H 


» 




rH 


■H 




10 


:* 


W > 


>*-H 




D fi D 


•H rH P 


•H 1 


1 


rH 2! 




CU 




rH 







rH 













<o p 




-H tH 


P 


rH X 


X 


U W 




CJ 




CU 


■o 




Ifl 


ft 






■d 


^ T3 


rH 




•H •• 


■H 1 1 


1 1 


I 


1 CO 




Pi 




CO 


Pi 











X 


Pi 


>> Pi 


ft M-t 




CO tn 


e — — 


? A A 


CU 1 




(0 






■H 




1 


T3 






cu 


0) 


co o 




Pi 4-1 Pi 


•H 


tO ft 


ft 


CO U 


— ~ 


p 




4-1 


> 




Pi 


a 




1 


to 


I CO 


•H CD 




•H iH -H 


p e 


H <0 


<fl 


pl CO 




CO 




rH 






cu 


•H 










? 2 




.. CD P 


ft CU 


■o n 


u 


C3 


1 


c 




CU 


CU 


^^ 


A 


4-1 














CO p 


.. p 


.. tn tn 


a o 


rH 


•H 




CO 


■o 


>>-P 


1 




+ 




+ 






4-1 CO 


•H 






•• as 








1 









M 










* — 




rH -0 


s 


> r- 


OJ 




CU 


CU 




» 


Pi 


X 


P 











^^ 


CO 




<D C U 


O cu 


X 


X 


* " 


CO 


,X 




(0 






<D 


p 




CO 




CO -» 


■S& 




CO cu cu 

CO ft 


SS 


■o 

C 1 


1 



•0 fe 





1 




u 
n 


cu 


■0 


CO 

A 






a 




A 

ft CO 


•H 1 




•O ~ ft 


•H P 


•H ~- 




Pi J 


B 








-0 


c 


CO 


CU 




X 




>\ cu 


* X 




Pi o 


> 


* 




•H W 


P 











•H 


1 


1 




1 




1 Vl 


1 1 




0> 1 .c 


1 P 


1 u 




* w 


* 


-d 






Pi 


X3 


p 


C 




p 




P 4-1 


.c a 


P 


co ~ » 


A cu 


A CU 




1 




c 




— . 


1 




<D 


0) 




CU 




cu cu 


ft ft (M 


»-» i 


ft ft 


ft ft 




A TJ 


to 


0) 




^ 


cu 


CU 


CO 


cu 




CO 




CO u 


(fl <0 


a) 


co a> 


a) ft 


<0 ft 




ft Pi 


C 


CO 






> 


P) 




M 










P P 


rH 


P 3 


u o 


U 




(0 CU 





^- 




p 





rH 


CU 


u 










tn 0> 




.G ft C 


Cn .C 


&A 




U CO 


p 








e 


id 


to 


CO 




cu 




01 ? 




ft 


CU S-H 


~ * 


— > 




&) — 


p 


& 






i 


> 









■d 




T3 


W P 


CO 


■H P 










PI 






0) 


i 





> 









T3 


P <W 


3 


ho c; 


p cu 


M CU 




^ P 


J3 









CO 


CU 


a p 




c 




Pi Pi 


a> cu 


rH 





CU 3 


CU 3 




•O 




M 






pi 


rH 












■H 


ftrH 


ft 


V v o 


ft a 


ft Pi 




Pi 


II 


ft 









ft > 




t) 




-0 * 


ft 






ft-H 


ft-H 




A ~ 










a 


•rl 


p 






PI 




Pi 


M-t 






P 


P 




P 












P 








cu 




CU -0 


J3 O <0 




^ Pi 


A Pi 




CU T3 










§ 


H 








CO 




CO Pi 


> a) 


fi 




> 


> 




6 Pi 










i 








— - 




_ o> 


<W 


« 




4-1 O 


>H U 




4H tO 










<4H 












CO 


0) w- 






0) .-. 


0) «- 




01 _- 










CU 
















•0 






>0 


•o 




■o 










•o 

















Section 5.6 Problem Set #5 107 



tJ> 4H g 

a in -h 

id en P 

43 0) 43 

o o en 

— O -H 

— - SH 

— » to A 

— 6 O Cn 

— o> >d oi -h 
H -P — C > 43 
O -H — -H 

X > S 0> 0) 

1 X> O — — H 43 

2 (3 fl M-'- p 01 P 
rH O CO— — 43 43 

Id O -H M x- (N tn > to 

iv ? <t3 a* a> -h w 

> — 0) -- ••'dt) H (D«) 

P -»_- = — POO43t00) 

— • — 43 — (3 C 0> *h 

10 = >, (N =T3>>t7>e H O O 

2 "O P 0> -d X) P 0) -H 01 43 

•H 0) 13 X Xl 0) 0) C4J«H+)ldfl •• (DIM 

•O" &1 -H OCn &1 -H 0) 43 -H 43 rH 

•d J3 06CJ3 a O h 6 d> x« xi o> P oi 

w ro o< — o> •• id id o*o>o>-hxii3i3xi to 

43 = P 43 43 x» P 43 13 01 0) O (3 P 

t0 O M • -H 0) O O 4* -H •• O 01 t0 fi -ri -H 

o o o i xj o o> i o «— -- 

ft •- -H w 0) O — -H 43 0) <u <u -a ID 43 

>, Pn 10 > G 0. > XI to 01 0) C too 

= -H rO-HO---XlXlO>— 3-H 

to SS+jt- SPPGOOto — <d43 

O O H J) -ri IV OrH-H-Ofifi^— OS 

ft •d-ncio'O xi -h o to >o (3 — ~a> 

X CC C O fl fl H C fl Hi ffO 1 -- -fl - 

•h iv u c -h <d o> oi to oi o> — ft — 43 

— o> s p 43 to ••— — s p toto^-^^njiu 43<vto 
>ih J3-PI — > j3Q)i— ajtowiu 

OO rH-H a) O — O rH -H 43 0> (3w (343 0> 0> fc 

•K3 U — rH O H 10 H— XI rH O -P tO — -HO H — — W 43 «W 

(3 -h > id ft o 3 id* G (dft 3 ft--- rJ v <h o> 

•HO O OliwO % O — -H O I M O 0) id +JCPIV+JW 

»i -o— 1-d 6 -d— >— i flO Em C o> d> o> n 43 •• 

— C fi> C C 01 •• <VC» S B B ih •• fl H« H O H •• tJi 
■ri -ho oi -h xl o -h o o> o o> -h — o 43 u 01 -h id 

— I > -d — 43 <« O S C > Xl Xl Xl — 43 «H tt) > <wS ft-dSH 

■p-d i3 >. p i c o — id a ocj^Pi-doc — •• o 43 x> 

430) 0> -H I U Xl ft -P <4H -H J3 -H I Vl CO tJ>ft Xl d> -H 

0> rH T3»XPOMC0)t0rH> -'SXPOCCOO — OCI-HTJ 

•Hi-I O ^<UP0)-Hll)l3a) ---01-P -HMO OM-H43 

rH-H CP 0)-H43>43-Hl0+J OP <V-Hrl*ftrH U * & " Q> 

43<w — 43 "d 43 T3 -P — I I 43 H43-d43 , da> — — id > 

tj>i d»i3tna)0'd 0)>o> ^011310(1)43^ ■d'dnJ 

•H ^ O -H -H I I C — M Id -H I H -H I I +J C — O P C C 

43ld VlrH43-P(3a>a>aidiHrH 11 H ,Q (J B O 11 g tl O 0) 0) P o 

••>h <d43ia)a>43toa>E'd43 P43i<va> toaiid i3tatorJ>H 

■d i&i<D(oa>4J»--4J«-'"&i a)di<vtoa)tt)^-P»— ^^^ftm 

0) •• > -H r> I H -H -H rH -H ^ I U 43 -H ^ 

XI 0)43rHil)Oa)e "d 43 0)43rH0)O-PE MH P13 

OS (3"idtototoaiPi3 •• ■d"idioto iv+ip -h toid 

co i >0-oPoa> i >0-*Poo) — s 

^■d Q)a)lO>O-Hflt0 0) 0)<VlO>O-Hj3rH -nul 

a io-da>eP43~ — — -d mfl m B+)^ a> 

•d-H B O H •• * O ^ O 3 O H •• « W ^- P+J 

0> OCft>*= im 13 OCft>%= iw ^0) 

43 6 -H -P +J -H g -H P P -H BH 

■p*d "dP^- o)^- >o xi-p^- <v <~- <oo) 

0)CCC!rH rH CCfirH rH OT3 

g tl B V B w O);30>rj w 

MH 10 I4H W g 10 IM 111 E ••> •» 

•d *d *d 



THE GRAPH EXAMPLE Chapter 5 



a - 

z I U 

"2 £ ~ 

0) G XI ~ 

O <w O > 

0) fl *« 

0) to — C 

5 3 3 - ~* 

O sO) X\ &•* 

u~t j5 tj +J to tr — 

o — — * £ D, &~ 

•H ~ — 03 +JO—&> — 

jj ^ ^ -Q -H MT>-H~ 

•ho>— c^ £ 5 ~ ^ ~ 

"58 Z* u «"* 

•> C I 0)0) 01 ^ ^ C T) C 

tr -H flj <tf H "A -H +J _ ,G ' ~ -M 
G 

5 



a 



a ji i 1 * xi fc " "" 'd "P 5 ? 



£ u • • • • « -p * ^ > "2 h tJ '2 

R_,00 ft P O H 01 'H O 

■rt £ -O T3 K £ -O-H-H03T3OH0) 



El* So c2 cfiiflfl 

.5 -H I ^ -H 0> 4> 01 O O 

S+J 55 e ™_ ? c o ? ™~~ 

"* jj irtfl +J0) S H 'H >, 41 OC"0 

n 2 O C C -H .2 O rHO 01 — P-Hfi 

.2— it) ~ ~ ft *o -h— i>d-HE<up ^ 

n.rliiu -^ ^ O-H i n +j tj tn G ft «> 

5 ? .2 « +j oioi-> ft " ^<U+J0)-HV4>wO — 

ti 0>g>t!)« a a m -n .G&>o>oia>.P~P~ft~ 

oSh i 3 tr> -P -H^iHttfOttig t »w 

i » * w £ <u<i)* c g ^ " IS S " S ?! ^, i 

i > 2 •• T5T30 -H O I >3l'8^2^ 

a .j jj C C I I S "H +■> 4J •" 

B T3 -m i- §§A a 2 ^ "9 ii w iS w 

fiflH 0101CP-O gCH rH 

ih a § tod*- "S 016 

5 . +J t3 



Section 5.6 Problem Set #5 109 



u •- a) 

o -P 73 
>w CO 

o o 

— o> 03 +j •• o <« 03 

~— +J .C -H M W 4-1 .C 

---X -h .p ,c p 73 oi -p 

.C P >, O -P -H O •- ,C 

+J (0 I-H-H73 4-I.C-P-P'' 

me -p r-\ c <w i p w tn 

«-• a -Hamo-paj-Hy-iaj 

0) 1^ OX 01 BHIH 01 

73 > p -hoj-ojo) o* 

aim rHg&i^aajojo 

C C E ft C 03 fl 3 3 E 

1 I gfl+J+J >0J0J0JH 
73 03 -P -H -rl fi 4-» 3 3 ,C <H 
C 0303 03 (0 03 O* O* -P « 
0) P 03 ffl > +J > fc 

0) •• ,£(CK73-H.p0)ftp 

03 > +J^!03(0>wXX!OO 

73 — 03 O (0 C I 03 -P ft fe 

O £! P P ft fi 03 .C C 

c+j g ~ to m n c+3 i iH-o 

— 1(0 — M rHOXiO-O-POC' 

0) P ft P 73 « 4-> (0 03 (0 E 

O03 CJiflfi -HO) 0) tT> -P 03 

p x: oj ceo3 4->sp'P"C--p 

(O+j-o-hos vio-pxjo-p-h 

• •00 73 ~ •— (0 ► M-l X 73 P M 

••CC^ ftl) 1) -fiW-H+J 

03 I « 'ri ^ O P 03 fi -P (0 rH X • 

-oos+jihatj u-iss « 03 a»i-i 

P 03 03 I E O-P0373PE.C03fi(C 
fi ill C tJlX "fl O 3 03 -H 03 -P ,C O 

1 M-PC 033D'3'«-P-P03-H 
73-003(0(00(0 S ^ 0) I -H ► .C .p 

C C C 4-> ft P 03+J03J-l£!l'4-l<4-(.PC 

0303O (OX ^OI^SVOIWO 03 

03 O 0) E -P C -P ft ft 73 O t* 73 

73 ~ ~ 73 O 73 (0 rH 0)(0AJC-H 

— C O P C ft 03O.X0373--EO-H 

M 9 I I fX «H 03 I ^hlllfl- OJUflOl 

P 03 I I 03 S P -P 03 <U £ X) P -H 

(0 — 03 X > C — 03 fi 73 03 ,C -P 3 

E 73 -P 03 P G Jl O >iri 1I4J 11+)^ 

03—co(0C3O' >ofhsx! axojo 

03 XX5-HCO,+J03+J (0 03OO(T>O-PP-P 

45 +j+j 110*03^0 A 03 > A P C ft I 

•P (0(OOSS03P03 > -H 03 (0 -rl O 03 ,fl 

(0 ftftPO30)«-'-'O3rH C-H-P 0) >* 73 -P P -P 

ft I 75 C C 03 iH (003(0^!03(OCCOlO 

I rH P CO03O ,CPP-P03(0OMHft 

rH <0(0PPP0373rHO — -P 3 03 (0 MH S 031 

(0 -hoooox fi 03 o+jfto-p'Ojxi'O 

■ H +J ~ 4H 4H <4H ? 3 73 H03-H CEC 

P P O 03prH03>,O0)4J-H 

P * ii ft C-- Xfim-o^+Jtniw 

(0 ftO ~ 03 4-> 03 03 -rl fi 0} -rl -H — 

ft 030 73 (flXX+J-H+JErH 

CO H ~ O Jh+J+JP^0103S03 

P -HO— 03CMC (0 3 -P 03 03 3 

03&1 C 7303 >,73ft-PT-l-HCXJa3 

fr C X!lO> O 73 ~ •• ,Q rH C +J 3 

P-H -P73C fi O <N OlSX0373»03O < 

(073 lOC-H ICO) 3..XOOP0303O-P 

4J CO ft03O P73 -H O > -H 03 -P C -H p 03 

— -H+J fi 0) -* O 73(OX*4-lCiHOX3 
03 <4H I PPO X'-C C+JOS<4-l03Xft03.p 

,C I £ OOO ~4->03 •H00+J-HEO3W 
+J+JX+J 4h 4H G <— O7303 *4H 10373033 3 M-l 

l(0P(0-P ~ •• O 73 l03,C73rHft3OO 

£! ft (0 ft 0) ft — CO— .CX-P-rl-Pft 0>! 

•P I ft I t7> ^ O C~ -P-P(0O(0EC>i 03 

(0rH73PO P P 03 ~ (0 ft 03 ,C -H O -P 03 

ftfllX C UH (0 flfl tTH ftCiT3-P >,+J 01 3 

1 -H O -H +J — E^OOJ-H -H73 03 03 H 

73 -P O <« C^C03C73O3£l+Jp-HO3 

CPrH>- 73 > 73 -H rH -H 03 -H <4H 03 

•H(0.Q OCW •H03l«CCP , PI^ 

"Wft— ,C 03 -rl +JCOX(0-HI+J(0 

+J ^ ^ fl.H SOO4-I4503E 

C73 03 G(0'(0I-P03 

CC EM-i H-PO)0)0^4373XIX 

y-iio <«-h 03fiS3P--p(0O 

03— 03— +J-H0303ftOft03P-H 

73 73 rH(0C3ft-P03POX 

— — <EO , O , (00373XJ<«» 



1 10 THE GRAPH EXAMPLE Chapter 5 















-^ 




«-. 
















ft 














ft 




"" 












^ 




> 














to 
















0> 




0* 














G 




I 












T) 




(3 














0) 

































Cr 




to 












13 




Oi 














*"' 




o> 












0) 




to -» 

r) « 


















Cn 












•0 




0> 43 








<-~ 






<-^ 
















43 


> -P 














01 
















C P 


oi — id 








.-» 






•0 




0) 












1 


ft 


U X ft 














o 




3 












n 


G U I 








- s 






c 




0) 












0) 




— id — £ 








~ 0) 










3 












43 


0) 


e -v o» 








— > P 






43 ~ 




cr 












P 


T3 


•O rl C 








e -h 






•p ~ 














to 





O 


$3 — id 








0) 






Id ' 




*-» 










o 




J3 ^ 


v x e b 








P to 






ft 




e 










u 






U 01 








•H fi 






1 ~ 




0> 






«-» 




id 


O 


> P 


4H id M P 















■o e 




p 






P 






rl 


0> Oi 


1 S rl -h 








to u 






c 0> 




•H 






X 






« 


C &>43 •• id 








a g 






•H P 


^ 




* 




01 




43 0) 




u 


+» g *d 








o — 






«4-l -H 


«»s 


T3 


n 




c 




P TJ 


T3 


to id 


id o i -0 








o 






1 


<u 


G 


Id 




1 




id 


(3 


a p 


ft u P id 








g u 






o> -o 


3 


— O 


B 




p 




ft C 








id oi •• 




g 




- p 






to c 


0) 


<-» O 






Oi 






to 


U 01 


B to 




01 




ft 






3 


3 


Oi 0> 


01 




Cn 




U TJ 


•-^ 


— -0 


O TJ •• 01 




•p 




U 1 






o o 


cr "O to 











id C 







rl C 




•H 




■p -p 






6 0) 




o ~ 


0) 








O 0> 


II 


II (3 


MH 01 O 0) 




> 




ft s 


«_» 




to 




G 


3 




01 




— to 






1 to U 3 








I 






J3 — 


a* 


- o 


cr 




n 




< — 


0) 


43 i 


c — id cr 








p 






•H 


o 


— +J 






0) 




II 


T3 


P Oi 


rl 




e 




3 0- 


■P 




o 


(3 


' 1 


p 




3 




a 





ft C 


3 cr tj "O 




a> 




O P 


X 




0) P 


03 


„ A 


<D 




cr 




0) -H 


C 


P Oi C (3 




■P 




01 


0> 




C 1 


P 


b p 


tP 








X) 


1 


i cr oi — oi oi 




■rl 




cr to 


c 




•H 43 


to 


0> 0) 


rl 


■O TJ 




o o 


S 


> o> 


rl 01 tQ 




1 




p «- 


1 




rH P 


a 


p a 


id 


(3 


(3 




13 U 


0) 


Oi — 


^- to «^ ^ 


— » 


■0 




0* 


•p 




Itf 


■H 


•H 1 


p 


3 


<D 




id 


(3 


{3 


(0 


<-» rH 


•0 




to U 


a> 




Cr ft 


1 


1 T3 




o 


W 




43 




(3 


o oi o 


rH -H 


n) 




>— -p 


Cx> 




C 1 


01 T3 C 




4H 


~_- 




P n 


rl 


rl 01 


•O rH -0 


•H a 




-— . 


ft 






•H -O 


M -0 -H 





1 






•H O 





43 


G 


a 




n 


M 1 






> C 


1 


0) 4-1 


p 


43 


ii 


43 


> »w 


4-1 


4H » 





u 


a> 


p 


-p p 


o> 




-H 


.. — 


1 


■P 




P 










o> n P 


3 


a 


ft 







rH <W 






43 


id 43 


<d 


ft 








d P ft 


a> 




I 


0> 


»■"« 


rH «-' 




0> 43 


P 


ftp 


ft 


O 








V ft 1 





c 


g 





»-» 


O 


0) 


n p 


m 




■d 













3 i -P 


cr 


■rl 


■H -0 


cr 


rl 


<W 43 


d 


0> 10 


ftT3 


ft 


<D 


rH 








trc s 






o 




p 


■P 


0) 


3 ft 




0) 




rH 










■H O ~ 




rH 


cr as 




ft 


0) id 


3 


cr — 


■a 


e 


u 


•H 










n ~ «--* 


T> 


rH 


P rH 


■o 


1 


43 ft 


cr 




(3 


<d 


43 











O ~ ~ 





fJ 


0> ft 





c 


P «- 




•o w 


•H 


C 


4-1 


> TJ 








> 


43 


J3 


to u 


43 


•H 




~_^ 


C P 


4H 
















Id 


p 






p 




01 




0) o> 




ft 














1-1 


o> 




B 


0) 


ft 


O P 


p 


tO rH 


C 

















«w 


s 


4-1 


o> 


a 


a 


id 0) 


0) 


^^ ^-» 


3 

















<H 


4H 


•H 


p 


4-1 


rH rH 43 


rH 




4H 


r-t 














a> 


01 




■H 


0) 




ft — P 






<U 
















TJ 


•0 






•o 




01 -rl 






TJ 
















w 


*■* 






w 




U IS 






"■* 

















Section 5.6 



Problem Set #5 













<T3 
















Xi 






•O 






























U 




^«, 












Cn 






o 

o 
























«-» 






o 




^~ 












C 































(0 






x; 




W 












•H 






u 
























T3 






s 




CO 












> 






o 
























U 

8 






d) 

p 




1 












i 






•H 

6 
























o 






3 

co 


UH 


w 








H 




rH 






fe 
























0) 











CO 








2 




rH 






























•d 






p 




i 












03 






xs 
























■H 









B 








>« 











0) 
























CO 






c 


0» 


CU 








P 




P 






X 
























■p 








A 










•H 




CJ 






CJ 
























3 






a 


•H 


Q 








rH 




(fl 






«3 
























O 








a 


J 








■H 










U • 






























H 


01 

ft 


o 








■H 




UH 
■H 






■P >, 

rH 


















^ 






CO 






1 


o 










CO 










CT> 0) 


















p 






P 








B 


1 








•H 




M 






C3 P 


















0> >, 






•H 






s 










> 




c 






■H flj 


















0> 1 






id 






CD 


3 












•H 






CU -H 


















X3 P 






ft 






XI 


rH 




— 




UH 




rH 






X> T3 


















(0 CQ 












p 


T3 










•H 




X3 






0> 


















P 






>> 






CU 


C 


CO 




^~ 














Si 


















rH 'H 












e 


<TJ 


p 


co 


>^ 




G 




>l 






















•H UH 






X* 






n 


X! 


•H 


p 

■H 


X 




0) 
ft 




rH 






C5 -H 


















CJ 
X 






UH 






CD 





ft 


m 


■H 









o 






10 G 


















P 1 ~ 


<-» 




O 






p 


■p 




ft UH 






-^ 








•H O 


















O P ~ 












•H 




Uh 


1 






p 




























X CO ~ 


-^ 




P 

CO 






3 


■o 





UH 




_^ 




c 


H 






H 


p >J 

•H O 


















1 P P 


"> 




•H 






CU 





■p 


1 


X 




a 


2 






2 


03 


















rH UH 0) 


+J 




rH 






P 


A 


0) 


p 














T3 a 


















03 X! 














•P 


•rl 


CO 


X 






cu 






cu 


a 










CO 








^ >» CO 














0) 


rH 


■H 


•H 






1 








03 P 










p 








>> 1 


0) 












s 




rH 


UH 






3 






S 


•H 










C 








> rH 


Cn 


















-_^ 






O 


CO 




o 


•> 










•H 








X 0) -H 


fl 












to 


^» 


CJ 








J 


P 




J 


u c 



















P CJ 












a 


CO 


■H 


CO 






J 


•H 




J 


0> P 








rH 


ft 








:* ft 


u 








rH 




•P 




CJ 






o 


03 




o 


AS CJ 


^-~ 






•H 










1 u 


(0 








•H 




p 


CJ 


— 









Cu 


ft 




fe 


C P 


^ 






c 


p 








> x o 


a 








C 




o 


•H 



^ 


u 






CO 


UH 




CO 


•H 
rH O 


H 








03 
O 








o> i x 
p > i 


TJ 








^» 




p 


ft 










P 







p 


XI -P 


J 






S 


~-- 








ft 0) C3 


c 








CD 




C3 






p 






•H 


1 




■H 




CQ 






2 




X 


►< 




P rH 


■H 








N 




o 


Eh 


X 


o 






n3 


p 




03 


0> P 








■H 


II 






CO 


X ft 03 


UH 








•H 






W 




(D 






ft 


CO 




ft 


co a 








rH 




c 


CJ 


p 




1 








CO 




p 


CO 




rH 








•H 






C3 01 






<-» 


XI 


--- 


CD 


o> 


CJ 


> 0) 


tP 






*~. 






cu 




u 


rH 






UH 


rH 




UH 


O P 


>n 




*-» 




>.XJ 


■H 


0) CJ 


* 






co 






(0 



















^-~ 





6 P 


E-i 




'-. 






P 


p 





P -H 


a 






01 


P 






g 


UH 


o 








CO 


fc 







H 






P 


P 






ft 


ftrH 




PJ 




rH 


ID 












^~ 


P 


p 


J 


P 


0) ft PI 




^^ 


0) 


CO 


X 


>, 








w 




XI 


* 




CO 


g 


ft 






>H 


CO 


C 


w 


CO 


xi e 


H 




&4 


X 


p 


1 


1 


P 


01 S 


a) 


tt 




05 


CJ 




^ 









E- 


■H 


•H 


CO 


■H 


P -H 


CQ 




J 


a 


■H 


p 


P TJ 


CJ 03 


Cn 


2 




•H 


•H 




p 


H 









H 


rH 


a 




rH 




H 


w 


w 


•H 


UH 


co 


CO 


U 


•H P 


ifl 


H 




P 


rH 




0) 


PI 


r-\ 






J 




« 




CO CO 


CO 


CO 


CO 


rH 




P 


p 




rH -O 


>J 


J 




03 


£1 




M 


CO 


-^ 




Ei 


H 


CO 




w 


CO 


•H -H 


H 


i 




XI 




■H 


•H 






o 


CQ 




> 


1 




a 










CQ 


P 


rH 


I 


P 




> 


1 






UH 


UH 


CJ 


> P 


(0 








rH 




•H 


rH 


CO 




>H 


H 


C 


id 


fi 


CO P 




Cu 


rH 


X 






■H 


03 0) 


ft 


rH 




cu 


10 




rH 


Jr, <0 


P 




9 


CO 


•H 


3 


H 


•H 


•H -H 


o 


1 


H 


03 




II 


II 




P 0) 




05 




o 


c 




X) 


rH CJ 


•H 




H 


a 


cr pi 


a 


X5 


w 


Q 


J 


C 


P 








•O X! 


—' 


CJ 




a 









P 


n) 




w 


> 


0) 


PQ 


P C 


2 


J 


CQ 


O 


CO 


X 


>1 


>. 


1 CO 









03 


Cn 




P 


0) tP 


ft 




£ 








1 




0> 




O 




Cn 


p 




1 




■p — 


p 


Cn 


— « 


P 


>. 




0) 


ft * 






i 


J 


o 




2 


g 


UH ^) 








>i 


■H 


> 


> 




0) 


a) 


>, 


(0 W 


CO 


r-\ 




■P 


rH 


UH 




c< 


J 


Eh 


p 


W 


H P 


Q 






rH 


UH 


cu 


CU 




0) >, 


rH 


rH 


P * 


C 


a 


^— 


<H 


aa 


c 




H 




W 





CU 


w 




9 






O 


w* 


p 


p 


X 


J3 rH 


1 


a 


cj a 


•H 


o 


nj 






* 


2 


CO 


c 


o 


CO 


.» ••> 






ft 




ft 


ft 


— ' 


CO rH 


p 


•H H 












p 




2 






















■C 








<— 03 


<D 




O J 


ID 




o 


T5 


p 


CO 




H 






















P 


p 


p 


p 


CJ 


M 


* 


ft CQ 


r-i 


T3 




0) 


0) Q 


•H 




J 




















X) 


•H 











O -rt 


•H 


o 




XI 


O 


n 


rH 


* o 


r— | 




CQ 


Q 





















S 


UH 


UH 


UH 


T3 UH 


ft 


> 




05 


.£ 


cu 


0) 


CJ X 






1 


2 


















.£ 












S 


< 




p 


P 


3 


T3 


•H H 


tr 




K O 


















p 


ft 













J 




p 


(1) 


rH 


O 


rH W 


p 




Eh 


U 


















01 


8 










U 


fc 




a; 


e 


(0 


B A 


0) 




H 




















e 










~^ 






co 


UH 
d) 


> 




Pu 

- w 


CO 




3 




















UH 
01 


rH 










> 


D 






-d 




»•> 


- Q 


























■d 












P 


' — 






^^ 




•• 


•- *-• 


























— ' 













1 12 THE GRAPH EXAMPLE Chapter 5 











^ 




? 






















c 


















»-» 


j 


•rl 


CO 
















4-1 


H 


X 


a 
















0) 

P 

1 


2 


0) 

c 


i 
















a 


H 


•H 


Eh 
















0) 


H 










e 










•p 


ij 


p 


2 






s 










■H 


H 











o 










* 


0) 

H 


<4H 


O 

fa 






H 

w 










*-» 


CO 


-o 








X 










4-1 


H 


0) 


Eh 
















a> 


— > 


to 


CO 






a 










P 

1 


a os * ~ 


3 


W 
1 


to 




z 

H 










a 


0) o ~ 


to 


O 




J 










0) 


e z os ~ 


•H 




% 














p 


O W fa 




§ 




>H 










•H 


a h * j 


w 


i 














* 


rJ — z w 

1 H (0 


Oh 

E 


Eh 

H 


Eh 




PS 

o 










a 


ft— J 




2 




CO 










0) 

■p 


o e m « 

ft H 1 o 




w 

04 


O 




B 










•H 


Z rH H 
0) H rtj PS 

.c •• c w 


CO 


Eh 


fa 




u 










a 


o 




fa 




+ 










0) 


P 04 


S 




J 




^» 










■p 


ps c* d 


—* 


w 














•H 

1 


•o w >> CO 


I 
Eh 


2 
W 


CO 




X 










01 


«J fa » 




Eh 


Eh 




PS 










c 


2 


H 






o 










■H 


10 •• » p 










CO 


*-* 








rH 


6 Z 


o 




2 


^-~ 


B 


0) 










0) to fa w 


fa 


CO 


o 


fa 


B 










P 2 J 2 




2 


fa 


J 


u 


rt 










•H W W I 


P 


w 




w 




i 








6 
0) 


ype 
E-IT 
ER S 
TARY 





Eh 

H 


=tt 


CO 


1 


o 








•p 


4H 




j 


--~ 


PS 


a 




-— 




•H 


rH 


B 


j 


2 


o 







4-1 




I 


P > K Z 
H Z W 


0> 


< 


w 


CO 


o 




d) 




0) 


CO 


H 


O 


Eh 


B 






M 




c 


=1 En H 2 


p 


Eh 




H 






1 




•H 


C H J O 


•H 


H 






o 


■o 




a 




rH 


0) to ffl 2 




CO 


fa 


5 




0) 




0) 




x 


a S5 1 » 


to 


z 


1 


<D 


X 


e 




p 






w w 


<fl 


w 


OS 


P 




m 




•H 




4-1 


<D to ^ S 




CO 


fa 


■H 


2 


a 




-^ 




0) 


P W 2 Q 


p 




X 


1 


u 








-^ 


P 


0) 


Eh W 


w 


P 


Eh 






a 


4-1 


1 


CO — Z 


£ 


CO CO 


J 


U 


H 


s 




0) 


0) 


a 


P D H 


P 


H D — 




(0 




01 




p 


U 


0) 


O PS £ 


•H 


•J O — 




p 


w -» — 


+J 




■H 


1 


•p 


4-1 2 W 1 


o) <: 


to 


p 


04 Eh — 


•H 




| 


e 


•H 


1 « W 




I I 1 


o 


X 


>H CO — 


1 




P 


0) 




P. U Z ^ 




W U PS 


sg 


<u 


E<HO, 


0) 







p 




0) H H <jj 


a 


04 H O 




■.?§ 


c 




03 


•H 


0. 


.* co iJ 2 


0) 


>H CO CO 


1 




•H 
rH 


c 


P 
P 


*"' 


0) 

ft 


■h m i 


p 

•H 


^alg 


Eh 


y 


CO 2 t^ 

H W ^ 


«-» 





X 


>, 


ri-2g 




2 — U 


2 


H 


JtHS 




•H 


0) 


rH 


•p 


X) HZ 


P 


w 




PS 


— H 1 


P 


p 




C 


■ — 


Q Eh W 





Eh Q X 


O 


fa 


W 


O 


«J 










(0 O H 2 





HO — 


fa 




K CO 


3 


0) P 


u 




4H 


« 




K ~ 






CO CD 


u 


3 C 


o 


0) 


■H 


0) Eh O 
* W Eh 


0> 


Eh 


fa 




D O 


P B 


•H 0» 


<T5 


u 


«_» 


ft P W Eh 


H 




fa 2 


(0 0) 


•0 -H 


e 


c 


* 


«J 2 W 


& 


C 2 W 


w 






4-1 P 


« >H 


4-1 







2 fa CO 


•H fa J 








0) -H 


u o 


<D 






•• H — 




•- w ~ 








■o 




73 






- Q 


•- 


— Q 









Section 5.6 



Problem Set #5 



13 

























P 






—» 




> Eh 


























,« 










fa 


























&» 






^-» 




■d w 


























— -H 






>, 




PI J 


























-. 4» 






-0 




■H 1 


























e x; 










* fa 


























tt) X) 






— e 




Q 


























■p 






e o 




C7> H 


























■H * 






O P 




PI CO 




as 






















_» 






p -p 




•H Z 




w 






















c -» — 






P — 




P H 




Eh 






















o — ~ ~ 






2&* 




— CO 1 




H 






















•H ,C 4J -» 








— -H Eh — 








^-> 


















-4J+J^^ 






« -p i 




— X fa — 




g 






















<-» Ifl T) t* P 










-^ 0) W — 






>H *- 


















g P -H -H T3 






. •> 




e i » fa 


«-"> 


3 






















tt) Pi £ tt) -H 










O 4) CO O 






X Eh 


















P tt) X) A » 






^. . 




■P P -^ Eh 


EH 






CO 


















■ri -H Xt XI 






X P 




•P ft 1 


K 


JH 




£ H 


















P 4S 






■O X! -P 




O Eh W O 






£3 


















CO O P -» *■» 






tn«w 




X) tt) fa Q 


H 


X 




















3 1 -0 X! X! 






+J -H tt) 


ft 


'6MH 


fa 






H 1 

1 W 














_^ 




•h e -h +j p 

X3 4) ? &> C7> 






4H P rH 
0) ► « 




p 


O J co 
• co Z 




,-» 




g£ 














u 




(0 +J Xt C C 






rH —* w 


• 


1 H 


<"^ 


co 
















tt) 




W -H tt) 4) 










•P X! >- I 


x — — 


I 
















X 




1 1 * H H 


/ 








*u V E-i 


S-rH 




Eh I 














c 




e o) — 






— —ft 




tt) -H fa fa 




CO W 






.-» 








•H 




tt) Pi CO CO 






- >, O P 


rH » W W 


H Eh Z 


g 








-«= 








rH 




p -H + 3 pi 


S3 




— TJ P^X! 


* as is 


i 




2 Eh 












A 


e 


•H iH —' -H -H 


O 


— 




0i 


— PI Z CO 


PS fa fa 
fa fa 


w 




W H 






£ Eh -* 








1 


01 


1 — T3 T3 


■H 


e 


— — ft 


•H 


tt) H — 


CO 




CO 






W H — 








r-f CO 


p 


tt> P (0 nj 


P 





— e o • 


P 


— ft J 


fa « « 


o 






g 


.-^ 


Eh 6 








Ifl P 


•H 


S3 S3 P U U 


<fl 


p 


— OP 


» 


6 ft n fa 


fa z z 


o 




W £ 


,— 


H £ 0) 








S3 S3 


| 


■h o cr 


P 


p 


>*** c 


w 


OK I o 


« H H 


s 




CO w 


E-i 


g 


O P 








O -H 


0) 


rH -H CO * * 


S3 





TJ P + X 

o — -o 




V A T. fr 


Z J J 






H> Eh 


H 


Eh Eh -H 








sa 


S3 


^ jj ^, ^, »_, 


4) 


XI 


-— 


P fa 


m cq m 






O H 




Eh 


SB Eh 








•H 


<d 


•H 




1 XI - 


ft 


O rH En 1 


J i i 


10 




£ 


E-t 


H 


O o e 






^~. 


rH 1 


rH 


co P X! \ \ 


P 


ft 


^ ► +J 


^3 rH H — 


m £ £ 
i w u 


s 




.. pq 


fa 




h m id 






fa 


ft 0) 




3 C P s. \ 








• A 


■P 


- -H 


w 




» fa 


fa 


fa 


fa i p 




Eh 


B 




•H tt) tx> — ^ 




p 


rS • C7> 


» 


? 55 


£ Eh Eh 


P Eh 




>H 


J 


O 


1 £ -H 




fa 


» CO 


e 


•O -h P! 


cr 




■O V ■* 




. — o 


W H H 


H 




fa Eh 


1 


Eh 


2 fa I 




fa 






0) 


« P tt) X >, 


4) 


4-1 


P X! P 




fa 


** ^ ^ 


(0 1 




J 1 


s 




w eh e 




J 


£ 


P 


P 


P O rH TJ TJ 


■— 


ft 


O" 4h Cn 




P 4) fa 


H Eh|h 


4-> W 




W £ 


u 


i 


Eh H 0) 






8 


0) p 


•H 






Ifl 


p 4) -H 1 


P 


45 ft O 


C > 




CO fa 


Eh 


H 1 P 




Eh 


* 0) 




»_* 


S3 


* 


tt) rH P «- 


4-1 


tn >,CO 


W H H 


•H H 


— 


Z i 


H 


Eh 


1 Eh -H 

s§p 




X 

o 

H 


Eh 
O 

m 


•rl C 


ft 

tt) * 
ftp 


4) 

9 


CO 


(Q . ► ^ 


41 




N J J 
H t-i H 


as 


CO 

2 


1 

Eh 


H 


Eh* 




W ^ " *"" 


- 


CO fa fa 


CO 


fa Eh 


D Eh O fa S 


33 


fa 




XI rH 


^ tt) 


—* 




' 


—■ 


«— rH 1 


1 H H 


co w 


fa 


CO O O 


a 


fa fa o 




1 


1 XI 


P 


rH 










O Eh 


Eh CO CO 


o 


— o 


fa O 


fa >H 4) 

Jm Eh ft 


H 


1 


^ 


s i 


^ 


-^ 








* 


fa 


W H H 


3 CO 


CO 


fa 


fa 


w 


fa- 


-^ 




tt) s 














CO CO 


CO > > 


ii 


gg 


>* 

Eh 


fa 


Eh — >,SC 


as 


Eh 

as 


p tt> 

•H +J 


4-1 
•H 












•H 1 
fa 


VC ^> b* 


CO 


u 


fr> tr> 




Eh 


2 « 




fr> 


•H 














tt) fa 


www 


V ID 


1 


H -~ 






ElSa 


te 


Q 


H 


ft 














CO it 


U, CO CO 


J3 O 


fa 




Eh 




8 


H 


w 


tt) Ti- 














r4 Z 


Z 1 1 


P £ 


w 


a O 

b* CO 
fa CO 


fa 


fa 


O Eh tt) 


IS 


as 


ft S3 














tt) H 


(BLI 
NKEF 
NKEF 


1 
6 U 




fa 


8 


H O -P 
fa fa -H 


H 

3 


pq 


m 


>, tt) 

P CO 














•« fa 


0) H 


H 


CO < 








n 


o 




















P CO 


J 




_ 








Eh 




















M M 


• ri S 


PQ 

1 


Q 


Eh 








fa 
CO 




4H 
•H 
















fa fa 


>1~ 
Pi 


W 


% 


fa 








*■"' 




*"' 
















Eh 


flj Q 


CO 




^ 




























M% 


w 


*■"" 
































C Eh 


CO 


p 
































•H W 


D z 
































rH £ 


o 


O 
































m fa 


2 


o 

































14 THE GRAPH EXAMPLE Chapter 5 



,-» 










o — 


■p £ 










O ft 


•H W 






^^ 




» J 


Eh 






^-» 




o w 


V< H 










i to 


id 












S| 






i 




2 £ 

w w 


*s 






Eh 




£ Eh 
1 H 


c — 






W 




g~ 


<D }H Eh 






S§ 




B (0 








o w 


X H 






Eh Eh 




W ft 


% 3 






1 H 

£ 1 




££ 


a o i 

3 Eh ~ W 






£§ 




Eh I 


Eh — 0. 






H Eh 




01 D JH Jh 

an Eh 






H 




Eh 






ft 1 




= H 


O — X I 






SB 




0) 
to ft 






o o 




8§ 


•P « W ~ Eh 






— w 




«UH-H 






ft 




^ Q 


D>HH« 






W X 




U U 


•rl J 1 2 W 

M O W W ft 
1 1 > Eh >i 




Eh 


Eh Eh 








E3 D 




3 W 




ft 


U 




0) 2 


4) W H H Eh 




2 


w a 




(0 (0 Eh 1 




H 


X 0) 




£ W 


O H w s 
OOIOP<H 




1 


W P 




b £ 




Q 


1 -H 






B £ SS £ Eh 
•• W Eh H 




SB 




2 
O 


to 1 




1 


o o 




H 


a to i s o 

<l) £ w w to 




W 


w (d 




Eh 




U 


ft Jh 




O 


P W 10 Eh 10 




ft 


X +J 




§ 


•H Eh D H < 




o 


Eh X 




H O 1 — 




ft 


.. 0) 




ft 


<7> 1 S Eh 










I 


a w •• & w 


2 








B 


•H > * O A 


gT 




Eh 


T— 


.X H W {m 


ft 


to 




ft 


G Eh ft ft Eh 


ST 


J 


H 


n 




•H H iJ >H 1 


ft 


J 




to 


rH tO W Eh S 
£) 2 tO -' W 


ft W 


to 




W 


to 


to 






to 


w 


W Eh O 


p 




D O 


01 to Q W H 


Eh O 


2 




O 


o 


A l 2 ft 


U £ 


w 




£ 


ft 


P w w x o w 


to 




7 


ft 


to tO Eh Eh 


•J % 




Eh 


% 




m D- i W 


W — 










•P O S3 to 


to 










o s £ w — 

0> 1 W Eh — 






















rH U Eh H 












0) H H «- Q 












to to «- Z 












■P ft Eh Eh O 












<W >- W W — 












0) to J 












HQ-- 












I O — 












0) K 












to Eh Q 

3 W 2 












O SS o 












S ft o 













Section 5.6 



Problem Set #5 



15 















w 


















B 




0) 


^^ 


























e 


















cu 




■p 


-— 


























1 
















<-» 


P 




•H 


B 








































E 
cu 


•H 




B 


cu 
p 






,_, 


































P 


E 







•H 


























S 

o* 










— - 




^ 


■H 


/ 


p 








<N 




























-— 




/ 




+» 




p 


ft 






>J 




























*-% 






ft -P 










































B 












c 


43 


p 






CN 




















3 










0) 




c 


p 


J2 







1 






X 




















5 










P 







1 


1 


•H 


E 


B 






— 






























■H 




•H 


E 


E 


•p 


0) 


<D 






1 








X 


















S 




<D 




-p 


cu 
P 


01 

•P 


(0 

p 


p 

•H 


P 
•H 






p 








X 












£ 











c 




•p 


■H 


•H 


c 


1 


1 






t^. 
























■P 




•rl 




G 


1 


I 


0) 


P 


P 


























g 

CO 

g 






•H 




<-{ 




a> 


P 


P 


■H 


ES 


13 














en 
















1 — 


^ 






•H 








M 












^x 








S 
















0, ~ 


B 


c 




M 











0) 


cu 














w 
















p: e 


cu 







O 


cu 


<D 




ft 


ft 














Eh 
















•H CO 


-p 


•H 






a 


e 


cy 


fh 


K 














H 
















rH -P 


•H 


p 




0* 


K 


CU 


p 


p 






0) 








I 
















» -H 


1 


id 




0) 


p 


p 


•— 


^ 


^ 






a 








t 












— 






— e 


P. 


p 




""' 


w 


*■* 


t» 










•H 
rH 








H 












Eh 

H 






B CO 


■rl 


0) 




'4-1 






•H 


















Eh 
















0) -P 


iH 


•H 




■H 






~^ 










(0 








H 
















+J -H 




u 




«^ 
























10 
















•H 1 


CO 























■0 








2 
















E 


d 






^» 






B 










C 








W 












Oh 






6 co 


•H 


E 




e 






0) 










10 








(0 
















CO -P 


■o 


0) 




a> 






p 


















1 
















— +J -H 


« 


p 




-p 






■H 










^^ 








w 
















— ^ — > -H 1 


h 


•H 




•rl 
















>. 








o en 
■p D 












as 
w 

Eh 






M ITEM 
ITEM) 
ITEM) 
-item- 
ypeout 


i 

B 


1 

0) 




■p 






P 










ft 








O 








«-» 








<D 


c 




4H 






Cn 










X* 






^~ 


tn 2 




^ 




-— 








P 


■H 




a> 






•H 










ft — 






--» 


C 1 


















■H 


rH 




i-t 






P 










— CM 








•H O 




p 




CO 




i 

w 

Oh 

>H 

Eh 




























>. 








■P H 


^ 


i 




g 








TEM-BOTTO 
[TEM-LEFT 
TEM-RIGHT 
( typeout 
e-item (t 


CU 


a 


0) 


s 
a> 






E 
0) 










-P 






^ ^ 


•H < 


.— ~ 


o 




Eh 








•H 





+J 






P 










■H X 






^ c? 


o m 


to 


? 




H 








■H 


■H 




•H 























ft >^ 


a 


s 












^ 


-P 


1 


I 






I 






-— . 




ft<" 








s 


w 






9 










IT3 


o 
-p 


•P 






P 






— 




>. 






<N CN 


<*H W 


Eh 


Q 




■<■» 






CO 


-P 


r> 






3 






^« 




ifl 






X >^ 


•H Eh 


H 


w 




u 


Eh 








3 


a 
















CO 












H 




Oh 








X 






•H 


0) 


p 
c 

•H 



ft 


a> 






<u 






n 


^~ 


C X 






* * 


0) 1 


05 


& 






Q 






h v h a c 


T3 


•H 


ft 






ft 






•H 




0) 








CO W 


o 






2 


i 


s 

w 

Eh 
H 






TYPEOUT - 
[ TYPEOUT - 
TYPEOUT - 
ot ( type 
et* ((li 


* 


U 


>> >. 






>! 






-d 




0) >, 








3 CO 


CJ 


pj 




W 


^ 




M 





•p 






-p 






<ti 


--^ 


> ft 


t— 


T— 


— ft — 


D 




§ 




Eh 


o 


-— 


>H 






X — 












p 


s 


■p 


>, 


>>CN 


E O 








H 


s 


J 




















w 


0) X 






>> CO X 


2 


Eh 








H 


s 

W 

Eh 

H 






















Eh 


a ft >, 


■p 


0) 1 


CO 






O 


i 


W 
CO 


2 






















H 




ft 


>. 


X <N 


£ Eh 


H 


>H 




Eh 


Q 








v/ 


















0) 






ft ft X 


+J&J 


1 




W 


W 


























O 0) 


4H 


4-1 


E 


O 


1 


§ 


^— 


CO 


Oh 


s 


- - CH 






















s 


c c 


U 


CJ 


* 0) * 


B W 


s 


CO 




Oh 




* 


X * X "" 
























d -rl 


0) 


CU 


^ +J ^ 


0) Oh 


w 


Eh 


S 






*-' 


Eh 






















Eh 


+J rH 


■d T3 




•P X 


Eh 


H 


w 


Oh 






W 




A\ rl 






















W 


CO 1 






1 * + 


•H Eh 


H 




Eh 

H 


O 


5 


V/ 


Oh 


A\ 


v A v 






















0, 


•H 

•0 -P 


^, 


^, 


^ -" *^ 


q) a 


CO 


-^ 




^ 


o 
































1 


t— 


T— 


ft\ 


A o 


g 


s 


J 


Eh 


Q 




Q 


























0) +J 


X 


X 


E \ 


+J x 


w 


J 


X 


W 


| 




I 


























X3 C 






0) ^ 


Eh 


Eh 


Eh 


§ 


CO 


CO 




























■P -H 


X 


CN 


■p 


S^ 


H 


H 







































ft X 


— +J 










































T3 ft 






-- p 


3 1 


~^ 




v^ 


h 


































C 


4H 


iw 


cr 


•P z 








H 


































•H C 


o 


u 


+J CO 


0) 5 


8 








































<« d 


CU 


cu 


0) ^ 


OS fe 








































m 


•O -0 


rH 


••> w 










































.► 0) 








•- Q 










































.-TJ 









116 



THE GRAPH EXAMPLE 



Chapter 5 



11 



IS 

U W 




o> < 
p 

o p 

<i) 2 

rH W 



fl w 0> 

•p m & 

•rtODJ 
SO 3 W 0, +J w 

K rH - 

x> i j a -- 

p 0) I < 

ozhehHO 

S OJ W 2 W 
0> I N •• H W 

Pi En -H * «- ~ 

•rl P P 

43 O H 
p W O) 

04 > 

4J 5m -d 
(V c 

rH ZP 
01 P 

CO fa •• 



«- CM 
0) 0) 

01 0) 






*- cn 
0> 0) 

"8S 

a ps 

0) 0) 



T3 TJ 

H M 



cn e 

r- CN >,-H 
Oi 0) M 

^ -^ -o tj cn a 

> CN O O X •• 
o >, Pi Pi 

•o «- to e 

a cn -o •o >> o> oi 

•H X Pi Pi rj +J 

S a> a> r- -o -h 

— r- (0 CO X Pi I <w 
>,^ _ rfl 0) rH 



CN 



CN 
CN 



— CN 

a* 

(0 r- 
3 X 

rH 

a x 

-1 



§* 



rH X 0) 

0) «- TJ 

CO O 

I -O Pi 

5 Pi I 

Id'ri m 

MAO 

TJ i I 

•• 01 CO 

rj ft) 

OH t)i 

H nJ «0 

«j > 0) 

^ i i 

0> T) 

•O rH Pi 

O ft-H 

J3 -rl <M 

+J -P «-' 

ID rH 

6 a 



p >* 

0) A Pi oi <d 

Pi i -h to to P Pi 

■HIHH a -H 

rH >H I S -H 0) 6 

I I 0) 0» T3 -H ^ 

J TJ * P <fl H 

* fi < 'H H O - 

H 0) 6 CN 

•O to •• > > > X 

.. .. > +j +j +j 

o o 

•O -O O Pi 

Pi Pi U -H 

•H -H (0 6 

> * •• w 

Pi Pi 
0) 0* 



Q £ 



01 o 

&s 

p 

I CO 

B -H 

0) 43 

P P 
•H 

I 0> 

II 

U 0) 



Section 5.6 Problem Set #5 117 



o 
u 
«} 

to -> 

"d ** 

.C to 

■p d) 

i -» n 

■p -p a> 

0) (U M 

rH i-H •• 

■O -O > 

I •• O 

a» -o 
woe 

9 * * 

■a -o 

C C fi 

3 0) a» 



Chapter 6 

STREAMS AND FILES 



6.1 Streams 

Since the mechanics of interacting with different kinds of peripheral devices vary 
widely, and are often quite messy, it is desirable to shield programmers from having 
to know the details of such operations. This shielding is accomplished by routing 
all input and output operations through streams. A stream is a message-receiving 
object (some use the flavor system and some do not). There are different kinds of 
streams for the different kinds of peripherals. All streams accept generic com- 
mands to perform some operation, and take care themselves of the details of per- 
forming that operation on their particular sort of device. This way, knowledge 
about how to perform I/O operations is segregated into the streams themselves, 
freeing programs (and programmers) from the need to understand the details of 
these operations. All a program needs to know is how to deal with streams; the 
streams know how to deal with everything else. 

6.1.1 General Purpose Stream Operations (3.2, Volume 5) 

Some streams only handle input; some only handle output; some do both. There is 
a small set of basic operations that all output streams are required to handle. 



120 STREAMS AND FILES Chapter 6 



Similarly, there is another set that all input streams are required to handle. Addi- 
tionally, there is a somewhat larger set that all streams are guaranteed to accept, 
even though they themselves may not handle them. This bit of magic works 
through the default handler. Whenever a stream receives a message it has no 
handler for, it passes the message on to the default handler. The default handler 
then tries to use some combination of messages the stream does handle to produce 
the desired effect. For instance, the :tyo operation is required of all output streams. 
It outputs a single character. The :string-out operation, which outputs a string of 
characters, is in the set that is guaranteed via the default handler. Some streams 
handle this operation directly; for the ones that don't and pass it on to the default 
handler, it achieves the same effect (albeit more slowly) by repeatedly sending the 
stream the :tyo message. 

Among the messages all streams handle is :which-operations. The list returned 
includes only those messages handled directly by the stream. Messages handled by 
the default-handler on behalf of the stream will not appear in the list. 

Here are some of the more commonly used messages which are accepted by all 
streams of the appropriate type (input or output), possibly via the default handler. 

:tyo char 

The stream will output the character char. For example, if s is bound to a 
stream, then (send s :tyo #\B) outputs a "B" on the stream. (Recall 
that "#\" is a reader macro that expands into the fixnum representation of 
the character code for the given character.) 

:tyi &optional eof 

The stream will input one character and return it (as a fixnum). On an 
interactive device this is likely to mean first waiting for input to become 
available. The optional eof argument tells the stream what to do if it gets to 
the end of the file (however end-of-file is defined for that kind of stream) . If 
the argument is not provided, or is nil, the stream will return nil at the end 
of file. Otherwise it will signal an error, and print out the argument as the 
error message. (This is not the same as the eof optional argument to read, 
tyi, and related functions.) 

:untyi char 

The stream will remember the character char, and the next time an input 
character is requested (presumably via :tyi), the stream will return char. 
Some restrictions: you are only allowed to runtyi one character before doing 
a :tyi, and you aren't allowed to :untyi a different character than the last 
character you read from the stream. Some streams implement :untyi by 



Section 6.1 Streams 121 



saving the character, while others back up the pointer into a buffer. 

characters 

Returns t if the stream is a character stream, nil if it is a binary stream. 

direction 

Returns one of the keyword symbols : input, : output, or : bidirec- 
tional. 

:listen 

This is a test to see whether there is any input waiting to be read. On an 
interactive device, :listen returns non-nil if there are any input characters 
immediately available, or nil if there is no immediately available input. On 
a non-interactive device, the operation always returns non-nil except at end- 
of-file. 

:tyipeek &optional eof 

Returns the next character that is about to be read (without removing it 
from the input buffer), or nil if the stream is at end-of-file. The eof argu- 
ment is interpreted as for :tyi. :tyipeek is defined to have the same effect as 
a :tyi followed by an runty i (if end-of-file was not reached), meaning that 
you may not read some character, do a :tyipeek to look at the next charac- 
ter, and then :untyi the original character. 

:string-out string &optional start end 

The characters of the string are successively output to the stream. Many 
streams can perform this operation much more efficiently than the equivalent 
sequence of :tyo operations. If start and end are not supplied, the whole 
string is output. Otherwise a substring is output; start is the index of the 
first character to be output (defaulting to 0), and end is one greater than the 
index of the last character to be output (defaulting to the length of the 
string) . 

:string-in eof-option string &optional start end 

The stream inputs a number of characters, reading them into string, string 
may be any kind of array, not necessarily a string, which can be very handy 
for reading from binary files, start and end specify the substring to use, 
defaulting to the entire string, eof specifies what to do if end-of-file is 
encountered before reading the intended number of characters. If nil, 
:string-in returns normally and sets the fill-pointer of string (if it has one) to 
point just beyond the last character read. If non-nil, the condition sys:end- 
of-file is signaled, with the value of eof&s the report string. 



122 STREAMS AND FILES Chapter 6 



:clear-input 

The stream clears any buffered input, i.e., input sitting in its buffer, waiting 
to be read. 

rclear-output 

The stream clears any buffered output. 

:force-output 

This is for output streams to buffered asynchronous devices, such as the 
Chaosnet. Any buffered output is sent to the device, rforce-output returns 
immediately, without waiting for the output to be completed. For that, use 
rfinish. If a stream supports :force-output, then usage of :tyo, :string-out, 
and the like, may have no visible effect until a :force-output is done. 



: finish 



The stream does a rforce-output then waits for the output to complete before 
returning. 



:close &optional mode 

The stream is "closed" and no further operations should be performed on it. 
If mode is : abort, and the stream is outputting to a file, and it has not 
been closed already, the stream's newly-created file will be deleted, as 
though it had never been opened. 

6.1.2 Special Purpose Operations (3.3, Volume 5) 

There are a wide variety of operations particular to streams for one or another of 
the peripherals (files, Chaosnet, windows, etc). Most of these are not handled by 
the default handler, and so would result in an error if sent to a stream which does 
not itself handle them. The bulk of the special-purpose operations are documented 
along with the type of device they're intended to be used with. Here are a few of 
the more commonly-used of these operations. 

:tyi-no-hang &optional eof 

Just like :tyi except that if it would be necessary to wait in order to get the 
character, returns nil instead. 

:read-cursorpos &optional (units : pixel) 

This operation is supported by windows. It returns two values: the current 
x and y coordinates of the cursor. The optional argument is a symbol indi- 
cating in what units x and y should be expressed; the symbols : pixel and 
: character are understood. 



Section 6.1 Streams 123 



:set-cursorpos x y &optional (units : pixel) 

This operation is supported by the same streams that support :read- 
cursorpos. It sets the position of the cursor, x and y are like the values of 
:read-cursorpos and units is the same as the units argument to tread- 
cursorpos. 

:clear-window ( : clear-screen in older code) 

Erases the screen area on which this stream displays. 

tread-pointer 

This operation, and the next, are supported by streams to random-access 
devices, principally files. :read-pointer returns the current position within the 
file, expressed in either 8-bit or 16-bit bytes, depending on the type of the 
stream. 

:set- pointer new -pointer 

Sets the reading position within the file to new-pointer, where the units are 
as with :read-pointer. This operation is for input streams only. 

6.1.3 Standard Streams (3.4, Volume 5) 

There are about half a dozen special variables whose values are streams widely 
used by many system (as well as user) functions. Here are some of them. 

standard-input 

In the normal Lisp top-level loop, input is read from standard-input (i.e., 
whatever stream is the value of standard-input). Many input functions, 
including tyi and read, take a stream argument which defaults to standard- 
input. 

standard -output 

Analogous to standard-input; in the Lisp top-level loop, output is sent to the 
stream which is the value of standard-output, and many output functions, 
including tyo and print, take a stream argument which defaults to standard- 
output. 

terminal-io 

The value of terminal-io is the stream which connects to the user's console. 
In a process which is running in a window (keep in mind that each process 
has its own binding stack, and thus can have its own value for a given spe- 
cial variable), the value of terminal-io is likely to be that window. For 
processes without windows, which don't normally communicate directly with 



124 STREAMS AND FILES Chapter 6 



the user (like the mouse process), terminal-io defaults to a stream which 
does not expect to ever be used. If it is used, perhaps by an error printout, 
it turns into a "background" window and requests the user's attention. 

error-output 

The value of error-output is a stream to which error messages should be 
sent. Normally this is the same as standard-output, but standard-output 
might be bound to a file and error-output left pointing to the terminal. 

standard-input, standard-output and error-output are initially bound to synonym 
streams which pass all operations on to the stream which is the value of terminal- 
io. That is, they are bound to an uninterned symbol whose function definition is 
forwarded to the value cell of terminal-io. So if terminal-io is re-bound {i.e., the 
contents of its value cell change) the synonym streams see the new value. 

User programs generally don't change the value of terminal-io. A program which 
wants, for example, to divert output to a file should do so by temporarily binding 
standard-output; that way error messages sent to error-output can still get to the 
user by going through terminal-io, which is usually what is desired. 

6.1.4 Making Your Own Streams (3.5, Volume 5) 

While most streams are actually instances of some flavor, and handle their mes- 
sages through the usual message-handling mechanism of calling the appropriate 
method, all that's really needed for a simple stream is a function which dispatches 
off its first argument (the operation) and calls the default handler if it doesn't 
recognize the operation. Here's a simple output stream, which accepts characters 
and conses them onto a list: 

(defvar the-list nil) 

(defun list-output-stream (op ^optional argl &rest rest) 
(selectq op 

(:tyo (push argl the-list)) 
( :which-operations ' ( :tyo) ) 
( otherwise ( stream-default-handler 

#' list-output-stream op argl rest)))) 

As an output stream, the stream is required to support :tyo directly, and to support 
the other standard output operations (like :string-out) via the default handler. The 
default handler is invoked by calling the function stream-default-handler, with argu- 
ments of the stream, the operation, the first argument, and the rest arg. 



Section 6.1 Streams 125 



Here's a complementary input stream, which reads its characters from a list. 

(defvar the-list) 

(defvar untyied-char nil) 

(defun list-input-stream (op ^optional argl &rest rest) 
(selectq op 

( :tyi (cond (untyied-char (progl untyied-char 

(setq untyied-char nil))) 
((null the-list) (and argl (error argl))) 
(t (pop the-list)))) 
( :untyi (setq untyied-char argD) 
( :which-operations ' ( :tyi runtyi) ) 
( otherwise ( stream-default-handler 

#' list-input-stream op argl rest)))) 

Note that :untyi must be supported, and that the stream must check for having 
reached the end of the information, and do the right thing with the argument to the 
: tyi operation. 



6.2 Accessing Files and Directories 

Some of the information in this section will make more sense after reading section 
3, Pathnames. 

6.2.1 Open, and Other Functions for Operating on Files (10, 10.1, Volume 5) 

All reading from and writing to files is done through streams. To access a file you 
must have an open stream to that file. The fundamental way to obtain an open 
stream to a file, whether for reading or writing, is with the open function. 

open pathname &rest options 

Returns a stream connected to the specified file, pathname may be anything 
acceptable to fs:parse-pathname, generally either a string or an actual path- 
name object, options is a set of alternating keywords and values, controlling 
such attributes of the stream as whether it is for input or output, and how 
many bits there are per "character." Here are some of the more frequently 
used option keywords: 

direction 



126 STREAMS AND FILES Chapter 6 



usually either :input, to read from an existing file, or :output, to write 
a new file. 

:byte-size 

the number of bits per byte; each :tyo or :tyi operation will deal with 
this many bits of the file. Note that this need not agree with what 
the host computer thinks the byte-size for the file is. 

:if -exists ( Warning: not fully supported by Version 8 UNIX.) 

specifies what to do if the : direction is : output and a file with 
the desired name already exists. Some of the possibilities are to sig- 
nal an error, overwrite the old file, append to the end of the old file, 
or write a file with a unique version number. 

Most programs do not call open directly. They more commonly use the with-open- 
file macro, which makes use of an unwind-protect to guarantee that the stream will 
be closed when you're done with it. If you call open directly, you should also use 
an unwind-protect to make sure the stream gets closed, because leaving around lots 
of open streams can create problems. 

with-open-file (stream pathname options...) body... 

Evaluates the body forms with the variable stream bound to a stream open 
for reading or writing to the file specified by pathname, pathname and 
options are interpreted as in open. When control leaves the body, either nor- 
mally or abnormally, the file is closed. If a new output file is being written, 
and control leaves abnormally (i.e., because of an error or a throw), the file 
is aborted. 

So if I wanted to write a new text file in my directory on the UNIX host sola, which 
contained only the string "Wow. I'm on a disk!" (without the double quotes), I 
would evaluate: 

(with-open-file (str "s : //usr//hjb//yippee" rdirection routput) 
(send str :string-out "Wow. I'm on a disk")) 

Or if I wanted to see how many characters into a certain file the first "a" occurred, 

(with-open-file (str "s : //usr//hjb//.prof ile" :direction :input) 
( loop for i from 1 

for char = (send str :tyi) 

when (char-equal char #\a) return i)) 



Section 6.2 Accessing Files and Directories 127 



Here are some more functions for operating on files. They generally accept either a 
string or a pathname object, and some of them also accept a stream open to the 
appropriate file. 

renamef file new-name &optional (error-p t) 

Changes the name of the file. Meta-X Rename File in the editor uses this 
function. If an error occurs and error-p is non-nil, the error is signaled. If 
there's an error and error-p is nil, the error object is returned. See the 
documentation for details on what happens with wildcard names and links. 

deletef file &optional (error-p t) 

The specified file is deleted, error-p is as in renamef. 

fsrfile-properties pathname &optional (error-p t) 

Returns a disembodied property list describing the file. The car of the list is 
a pathname for the file's truename, the rest is alternating indicators and 
values. See the documentation for fs:directory-Iist for a list of the possible 
indicators. 

fs: change-file -properties pathname error-p &rest properties 

The properties arguments are alternating keywords and values. fs:change- 
file-properties alters the attributes of the file accordingly, if possible. (Some 
properties are not alterable. Which ones are is a property of the host file 
system.) 

viewf pathname &optional (stream standard-output) leader 

Prints the file on stream. (Use this just for looking at a file, not for copying 
it. Its output is not exactly the same as the contents of the file.) 

copy f from-path to-path &key (characters :default> (byte-size niU 

(copy -creation-date t) (copy -author t) 
(report -stream niU (create -directories :query>) 

Copies one file to another. M-x Copy File in the editor uses this function. 

See the documentation for the details of merging, wildcard names, and links, 

and for the meanings of the keyword arguments. 

probef pathname 

If the specified file exists, returns a pathname for its truename. Returns nil 
if the file does not exist. 

load pathname &optional pkg nonexistent -ok -flag dont -set -default -p no-msg-p 

Loads the specified file into the Lisp environment. (If it's a text file, load 



128 STREAMS AND FILES Chapter 6 



calls readfile; if it's a binary (compiled) file, load calls fasload.) 

6.2.2 Special Messages for File Streams (10.3, Volume 5) 

These are some of the operations handled by streams connected to files, in addition 
to the general operations described earlier. 

:pathname 

Returns the pathname that was opened to get this stream. This may differ 
from the original argument to open because parts of the pathname may have 
been filled in with defaults. 

:truename 

Returns the pathname of the file actually open on this stream. This may 
differ from what :pathname returns because of links, logical devices, mapping 
of the "newest" version onto a specific version number, and so on. 

:length 

Returns the length of the file, in bytes. The number of bits in each byte 
depends on how the file was opened. (See the :byte-size option to open.) 

:creation-date 

Returns the creation-date of the file, expressed in lisp machine "universal 
time" units (see "Dates and Times," Part VI of Volume 7). 

6.2.3 Directories (11.1, Volume 5) 

fs:directory-list pathname &rest options 

pathname may be either a string or a pathname object. fs:directory-list 
finds all files matching pathname and for each one gets the information that 
would be returned by fs:file-properties for that file. It collects all of these 
into a list, and adds one element to the beginning of the list with information 
about the file system as a whole. So the returned list has one more element 
than the number of files. See the documentation for a description of the 
options and more details on what information is provided for each file. 

fs:complete-pathname defaults string type version &rest options 

string is a partially specified file name. fs:complete-pathname looks in the 
file system on the appropriate host and returns a new, possibly more specific, 
string. Any unambiguous abbreviations are expanded out in a host- 
dependent fashion. There are four full pages of documentation attempting 
to explain how this happens (repeated in 12.7). Help yourself. 



Section 6.2 Accessing Files and Directories 129 



6.3 Pathnames 

6.3.1 General (12.1, Volume 5) 

Just as streams are intended to provide a uniform, device-independent interface 
between programs and the different kinds of peripherals, pathnames are intended to 
provide a uniform interface between programs and remote file systems. The idea is 
to free the programmer from having to keep in mind the format for file names on 
the various remote hosts. With pathnames, you should be able to manipulate files 
on a file server without knowing anything about that server's syntax for file names. 

All pathnames are instances of some flavor, and all the pathname flavors are built 
on the flavor fs:pathname. Each pathname has six components which correspond to 
different parts of a file name. The mapping of the components into the parts of the 
file names is done by the pathname software, and is specific to each kind of host the 
software knows about. 

The six components of a pathname are the host, the device, the directory, the 
name, the type, and the version. So, for example, the pathname corresponding to 
the file /usr/hjb/mbox on the UNIX host sola is an instance of flavor fs:unix- 
pathname which prints as #<UNIX-PATHNAME "S: //usr//hjb//mbox">. It 
has a host of sola, a directory of /usr/hjb, a name of mbox, and a value of 
:unspecific for device, type and version. The pathname corresponding to the 
file >sys>site>notice.text.8 on the lisp machine glengarioch has a host of glen- 
garioch, a directory of >sys>site>, a name of notice, a type of text, a version of 
8, and :unspecific again for device. 

A pathname need not refer to a specific file. #<UNIX-PATHNAME "S: "> is a 
perfectly legitimate pathname, even though it specifies only a host and nothing else. 

The conversion of a string into a pathname is usually done by the function 
fs:parse-pathname The first thing it has to do is determine the host, since the 
method for parsing the rest of the components depends on which host it is. If there 
are any colons in the input string, everything appearing before the first colon is con- 
sidered to be the name of the host. Parsing of the remainder proceeds according to 
the type of the host, and its own syntax for file names. (If there are no colons, 
some default value is used for the host — every pathname must have a host.) 

Of course, there's no need to go through strings (and worry about the remote host's 
file name syntax) at all. One of the selling points of pathnames is precisely that 
you shouldn't need to do so. Accordingly, one may construct pathnames in this 
manner: 



130 STREAMS AND FILES Chapter 6 



(f s :make- pathname :host "s" : directory ' ( "USR" "HJB" ) 
:name "MBOX" :type runspecific) 

which returns the same pathname whose printed representation was shown above. 

Pathnames are interned, just like symbols, meaning that there is never more than 
one pathname with the same set of component values. The main reason for main- 
taining uniqueness among pathnames is that they have property lists, and it's desir- 
able for two pathnames that look the same to have the same property lists. 

6.3.2 Component Values (12.1.4, 12.1.5, Volume 5) 

The host component is always a host object (an instance of some flavor built on 
net:basic-host) . The permissible values for the other components depends to some 
extent on the type of the host, but there are some general conventions. 

The type is always either a string, or one of the symbols nil, :unspecific or 
:wild. Both nil and :unspecific denote a missing component. The 
difference is in what happens during merging (see below); nil generally means to 
use the default, and runspecific generally means to keep that component 
empty. The symbol :wild is sometimes used in pathnames given to fsrdirectory- 
list, and matches all possible values. 

The type field gives an indication of what sort of stuff is in the file. Lisp source 
files, for instance, usually have a type component of "lisp," and compiled lisp code 
a type component of "bin." Since there are some system-dependent restrictions on 
how many characters may appear in this field, a canonical type mechanism exists to 
allow processing of file types in a system-independent fashion. I quote: "A canoni- 
cal type is a system-independent keyword symbol representing the conceptual type 
of a file. For instance, a Lisp source file on a VMS* system will have a file type of 
'LSP,' and one on a UNIX system will have a file type of '1.' When we ask path- 
names of either of these natures for their canonical type, we receive the keyword 
symbol :lisp." 

The version is either a number or one of the symbols nil, runspecific, 
:wild, : newest or : oldest. The first three have the same meaning as for 
type. : newest refers to the largest version number that exists when reading a 
file, or one greater than that number when writing a new file. : oldest refers to 
the smallest version number that exists. 



VMS is a trademark of Digital Equipment Corporation. 



Section 6.3 Pathnames 131 



The device component may be either nil or runspecif ic, or a string designat- 
ing some device, for those file systems that support such a notion (VMS, TOPS-20, 
ITS). 

The name component may be nil , :wild or a string. 

The directory component may be nil or :wild for any type of host. On non- 
hierarchical file systems, a string is used to specify a particular directory. On 
hierarchical systems, the directory component (when not nil or :wild) is a list 
of directory level components. These are themselves usually strings. So the path- 
name #<UNIX-PATHNAME "S: //usr//h jb//mbox"> has for its directory 
component the list ( "USR" "HJB" ). The directory level components can also be 
special symbols, as well as strings. :root, for instance, refers to the root direc- 
tory on the given host. And : relative followed by one or more occurrences of 
:up refers to a relative pathname. So the UNIX pathname #<UNIX-PATHNAME 
"S: . .//foo//bar"> has a directory component of (:relative :up 
"FOO"). And the lisp machine pathname #<LMFS- PATHNAME 
"G:<<x>y>z. lisp"> has a directory component of (: RELATIVE :UP :UP 
"X" "Y" ). Other possibilities for directory level components are :wild (for any 
single directory), : wild-inferiors (for any number of directory levels), and 
partially wild strings, like "FOO*". 

6.3.3 Case in Pathnames (12.1.7, Volume 5) 

Since the various host systems have different conventions as to upper and lower 
case characters in file names, most pathname functions perform some standardiza- 
tion of case to facilitate manipulating pathnames in a host-independent manner. 
There are two representations for any given component value, one in raw case and 
one in interchange case. Raw case representation, which is used internally for the 
instance variables of pathnames, corresponds exactly to what would be sent to the 
remote machine to find the file corresponding to the pathname. Interchange case is 
the standardized form, and is what you get if you ask a pathname for its com- 
ponent values. It's also what functions like fs:make-pathname expect (unless you 
specify that you mean raw case). 

The standardization is simple. Each host is classified as to whether its preferred 
case, or system default case, is upper or lower. Any raw component which is in the 
preferred case for its host has an upper case interchange form. A raw component 
which is in the non-preferred case has a lower case interchange form. A raw com- 
ponent in mixed case has an identical (mixed case) interchange form. Since UNIX 
hosts are classified as having lower case for the system default, this means that the 
raw forms are case-inverted to get the interchange forms, and vice versa. 



132 STREAMS AND FILES Chapter 6 



The messages for accessing and setting the component values of pathnames assume 
that you want to see or set the interchange form, unless you explicitly specify raw 
case. 

6.3.4 Defaults and Merging (12.2, Volume 5) 

In most situations where the user is expected to type in a pathname, some default 
pathname is displayed, from which the values of components not specified by the 
user may be taken. Most programs maintain their own default pathnames, contain- 
ing component values that would be reasonable in the particular context. For pro- 
grams which really have no idea of what sort of pathname to expect, there is a set 
of default defaults. 

The pathname provided by the user (actually, the pathname constructed by 
fs:parse-pathname from the string provided by the user) and the default pathname 
are then merged by the function fs:merge-pathnames. The details are a little 
messy, but the basic idea is that components which aren't specified in the user's 
pathname are taken from the default. 

6.3.5 Pathname Functions and Messages (12.7, 12.8, Volume 5) 

We've already seen three of the most important pathname functions: fsrparse- 
pathname, fs:merge-pathnames, and fs:complete-pathname. Here are some more. 

fs: make-pathname &rest options 

The options are alternating keywords and values, specifying the components 
of the pathname. Missing components default to nil, except the host, 
which is required. Options allowed are :host, : device, : direc- 
tory, :name, :type, : version, : raw-device, : raw- 
directory, : raw-name, : raw- type and : canonical-type. So 
the device, directory, name and type may be given in either interchange case 
or raw case, and the type may also be given in canonical form. 

fs:define-canonical-type canonical -type default &body specs 

This defines a new canonical type, canonical -type is the symbol for the new 
type, the body is a list of specs giving the surface type corresponding to this 
canonical type for various hosts, default is the surface type for any hosts 
not mentioned in the body. Here is how the :lisp canonical type is 
defined: 



(f s:def ine-canonical-type :lisp "LISP' 
((:tops-20 :tenex) "LISP" "LSP") 



Section 6.3 Pathnames 133 



( :unix "L" "LISP" ) 
( :vms "LSP") ) 

The :host message to pathnames returns the host component, which will always be 
an instance of some flavor built on net:basic-host. The messages :device, directory, 
.name, and :type return the corresponding component value, with any strings given 
in interchange case. The messages :raw-device, :raw-directory, :raw-name, and 
:raw-type are similar, but use raw case for all strings. The :version message returns 
the version (case is not an issue since versions are never strings). The :canonical- 
type message returns two values; together they indicate the type component of the 
pathname, and what canonical type — if any — it corresponds to. (See the docu- 
mentation for details.) 

The messages :new-device, :new-directory, :new-name, and :new-type all take one 
argument and return a new pathname which is just like the one that received the 
message except that the value of the specified component will be changed. The 
argument is interpreted as being in interchange case. You can guess what :new- 
raw-device, :new-raw-directory, :new-raw-name and :new-raw-type do. :new-version 
and :new-canonical-type also do the obvious thing, and have no "raw" form for the 
obvious reasons. 

:new -pathname allows wholesale replacement of component values; its arguments 
are alternating keywords and values, with the same keywords accepted as by 
fs:make-pathname. 

There are a set of messages for getting strings that describe the pathname. The 
returned strings come in different forms for different purposes. :string-for-printing 
returns the string that you see inside the printed representation of a pathname. 
:string-for-host shows the file name (not including the host) the way the host file 
system likes to see it. There are several others. 

:get, rputprop, :remprop and :plist all do the obvious thing with the pathname's 
property-list. Keep in mind the distinction between the pathname's property-list 
and the list returned by fs:file-properties, or the :pro per ties message to pathnames. 
The latter are the properties of a file, and require accessing the host's file system. 
The former are the properties of a pathname, a lisp object which may not even 
correspond to any files. 

6.3.6 Logical Pathnames (12.9.10, Volume 5) 

There are some pathnames which don't correspond to any particular file server, but 
rather to files on a logical* host. The logical host may then be mapped onto any 



134 STREAMS AND FILES Chapter 6 



physical host, thus defining a translation from logical pathnames to physical path- 
names. This feature improves transportability of code. Take the lisp machine sys- 
tem software as an example. Every lisp machine site keeps the source code on a 
different computer. But there are many functions that want to be able to find these 
files, no matter what site they're running at. The solution is to use logical path- 
names: all the system software is in files on the logical host "sys." Each site gives 
the "sys" host an appropriate physical host, and then it works just fine to open a 
file with a name like "sys: io; pathnm.lisp," which happens to be the file containing 
the pathname code. At my site that corresponds to the file ">sys-6>io> 
pathnm.lisp" on the lisp machine laphroaig. 

The function fs:set-logical-pathname-host defines the mapping of file names from a 
logical host to the corresponding physical host. The call to fs:set-logical-pathname- 
host is supposed to be placed in the file "sys: site; host. translations." Then if you 
call the function fs:make-logical-pathname-host with an argument of the host name, 
it will look for and load the appropriate file, thus evaluating the fs:set-logical- 
pathname-host. The format of the arguments to fs:set-logical-pathname-host is best 
explained by example. This is an abridged version of the contents of "sys: site; 
kwc. translations," which defines the "kwc" logical host: 

( f s : set-logical-pathname-host 
" kwc " 

: physical-host "Sola" 
translations 

' ( ( "distribution; " M //lispm//kwc//rel6//distribution//" ) 

( "distribution;*; " "//lispm//kwc//rel6//distribution//*//" ) 
( "distribution;*;*; " "//lispm//kwc//rel6//distribution//*//*//" ) 
("*;" "//lispm//kwc//rel6//*//") ) 
: rules 

mix 

' : new-pathname :name "PUBSYS") 
:new-pathname :name "INPUT-ED") 
' :new-pathname :name "COMTAB-EX") 
.*" :new-pathname :name "CALL-MINI") 
: new-pathname :name "MVG-ICONS" ) ) ) ) 

As you can see, the mapping is done on a directory-by-directory basis. Wild-cards 
are allowed. For instance, files in the directory "kwc: distribution; new-class" are 
mapped to the directory "/lispm/kwc/rel6/distribution/new-class/" by the second 
entry in the : translations argument. The : rules argument allows us to 



' ( ( : unix 






( "kwc : 


:** 


; public-systems . * 


( "kwc: 


:** 


; input-editor . * . * 


( "kwc : 


:•• 


; comtab-example . * 


("kwc: 


:** 


; call-mini-buffer 


( "kwc : 


:** 


; moving- icons. *. * 



See hacker's definition at end of chapter. 



Section 6.3 Pathnames 135 



specify additional transformations to be carried out in special cases. Since our ver- 
sion of UNIX doesn't allow filenames longer than 14 characters, we take advantage 
of this facility to define shortened names for the UNIX physical filenames 
corresponding to logical pathnames with long names. 

Given a pathname for some logical host, the mapping to physical pathname is car- 
ried out by sending the logical pathname the :translated-pathname message. An 
earlier version of the text for this chapter is in a file whose logical pathname is 

#<LOGICAL- PATHNAME "KWC: DISTRIBUTION; NEW-CLASS; STREAMS .TALK" >. 
When that pathname is sent the : trans lated-pathname message, it returns 
#<UNIX-PATHNAME "S : //lispm//kwc//rel6//distribution//new-class// 

streams . talk" >. 



6.4 Fun and Games 

From The Hacker's Dictionary, Guy L. Steele, Jr., et al: 

LOGICAL adjective. 

Conventional; assumed for the sake of exposition or convenience; not the 
actual thing but in some sense equivalent to it; not necessarily corresponding 
to reality. 

Example: If a person who had long held a certain post (for example, Les 
Earnest at Stanford) left and was replaced, the replacement would for a 
while be known as the "logical Les Earnest." Pepsi might be referred to as 
"logical Coke" (or vice versa) . 

At Stanford, "logical" compass directions denote a coordinate system in 
which "logical north" is toward San Francisco, "logical south" is toward San 
Jose, "logical west" is toward the ocean, and "logical east" is away from the 
ocean — even though logical north varies between physical (true) north near 
San Francisco and physical west near San Jose. The best rule of thumb 
here is that El Camino Real by definition always runs logical north-and- 
south. In giving directions, one might way, "To get to Rincon Tarasco Res- 
taurant, get onto EL CAMINO BIGNUM going logical north." Using the 
word "logical" helps to prevent the recipient from worrying about the fact 
that the sun is setting almost directly in front of him as he travels "north." 

A similar situation exists at MIT. Route 128 (famous for the electronics 
industries that have grown up along it) is a three-quarters circle surrounding 
Boston at a radius of ten miles, terminating at the coast line at each end. It 



136 STREAMS AND FILES Chapter 6 



would be most precise to describe the two directions along this highway as 
being "clockwise" and "counterclockwise," but the road signs all say "north" 
and "south," respectively. A hacker would describe these directions as "log- 
ical north" and "logical south," to indicate that they are conventional direc- 
tions not corresponding to the usual convention for those words. (If you 
went logical south along the entire length of Route 128, you would start out 
going northwest, curve around to the south, and finish headed due east!) 



Section 6.4 Fun and Games 137 



6.5 Problem Set #6 

Questions 

1. A. There is a function named print-disk-label that, when called with no 

arguments, prints on the screen a listing of the contents of the fep file 
system. Find a way to print this listing to a file instead. (Hint: check 
out the optional arguments to print-disk-label, and use with-open-file.) 

B. There's another function named si:print-login-history that prints a list 
of everyone who has logged in to the local machine since it was cold- 
booted (and the contents of the login history when the world load was 
made). This one has no optional argument for what stream to do the 
printing on — it always prints to standard-output. How can you get it 
to print the listing to a file? (Hint: make standard-output point to a 
file.) 

2. Suppose there is a file whose contents are numbers in the range 
-2,147,483,648 < n < 2,147,483,647 (32-bit integers). How can we read 
the file into an array of fixnums? It'd be convenient to open a 32-bit stream 
to the file and just do : tyi's or a : string-in, but most file servers won't 
allow a 32-bit stream. We'll have to use a 16-bit stream. One strategy is to 
read two 16-bit bytes at a time and build a 32-bit number by shifting one 
number 16 bits and adding them together. This will work, but it's awfully 
slow. Can you think of anything better? (Hint: think about displaced 
arrays of different types.) 



138 STREAMS AND FILES Chapter 6 



Solutions 

1. A. (with-open-f ile (str "s://usr//hjb//disk-label" 

: direction : output) 
(print-disk-label si : *boot-unit* str)) 

B. (with-open-f ile (standard-output "s ://usr//hjb//logins" 

: direction : output) 
(si:print-login-history) ) 

2. The slow way: 

(defun foo (file ^optional array) 

(with-open-f ile (str file :characters nil :byte-size 16.) 
(or array ( setq array 

(make-array ( // (send str : length) 2)))) 
( loop for i from 

for c1 = (send str :tyi) 
for c2 = (send str :tyi) 
while c1 

do (setf (aref array i) (+ d (lsh c2 16)))) 
array) ) 

The fast way: 

(defun bar (file ^.optional array32 array16) 

(with-open-f ile (str file :characters nil :byte-size 16.) 
(or array32 

(setq array32 (make-array (// (send str : length) 2) 

: initial-value 0))) 
(send str : string-in nil 

(or array16 (make-array (* 2 (array-length array32)) 
:type 'art- 16b 
:displaced-to array32))) 
array32) ) 



Chapter 7 

THE TREE EXAMPLE 



This chapter is very much like the graph example two chapters back — a later sec- 
tion contains a code listing, and this one describes some of the new features* of the 
code. Much of the code was copied directly from the graph example (with "graph" 
changed to "tree"). The most interesting of the new parts have to do with menus. 

Once again, if your site has the tape for this book, you can load the code by using 
the CP command Load System tree [or evaluating (make-system 
'tree)]. Once the code has been read, start the program by evaluating (send 
(tv: make -window 'tree-frame) : select). 



7.1 The Nodes and Arcs 

•root* and *the-real-root* 

These two variables are declared at the very beginning of the file. Rather than 
keep a list of all the nodes, as "graph" does, we simply keep track of the root of the 



See hacker's definition at end of chapter. 



140 THE TREE EXAMPLE Chapter 7 



tree and follow the connections from there. The value of *the-real-root* is constant 
throughout the lifetime of a given tree. It changes only when we throw away the 
tree to start another. *root* refers to the node which is displayed at the top center 
of the window. Initially, this is the same as *the-reaI-root*, but you can change it 
to be any arbitrary node in the tree. That way you can move your window around 
over a tree too large to be viewed at once. 

The node defflavor 

The connections between nodes {arcs, in "graph") are no longer real data objects. 
Each node now knows directly which other nodes it's connected to, instead of know- 
ing which arcs it's connected to. children is a list (possibly empty) of the direct 
inferiors, and parent is the superior (nil for the node which is the value of *the- 
real-root*). The x-pos and y-pos instance variables have been thrown out, since 
nodes no longer have fixed positions. Each parent determines where its children 
will be drawn. The space -requirements instance variable somehow packages up 
everything a node's parent needs to know about the node and its children in order 
to determine where to draw it. The first time this information is requested it is 
recursively calculated, and saved for future requests. The saved info is flushed 
whenever something happens that would invalidate it (such as a change in the 
number of children), so that it is recalculated the next time someone asks for it. 
Consequently, anyone needing the information should use the : get-space- 
requirements method, which calculates if necessary, rather than looking at the 
instance variable directly. 

The :f lush-space-requirement method 

This method is called whenever the space-requirement info has been invalidated. It 
sets the instance variable to nil, and recurses upward, because anytime a node's 
space requirements change its parent's also do. It gets called whenever the node's 
label is changed, and whenever a child is added or removed. (And whenever any of 
these things happens to one of its descendants.) 

Fancier format directives 

The format statement inside the : print- self method uses two features you may 
not have seen before. "- {...-}" is an iteration construct, which takes a list as an 
argument, and repeats the interior of the { }'s until the list elements are exhausted. 
"-©[...-]" checks the next argument, and if it is nil, does nothing. If it is non- 
nil, the argument is not used up but remains the next one to be processed, and the 
interior of the [ ]'s is executed. 

The effect here is to print a list of all the children (using -A so that only their 



Section 7.1 The Nodes and Arcs 141 



names are printed), with all but the last in the list being followed by "; ". Both 
- { and - [ exist in several forms, with and without : and/or @, allowing various 
kinds of iteration and selection. 



Drawing 

The methods : draw-self -and-children and : get-space- 

requirements have all the smarts. It's complicated, but I don't think it's partic- 
ularly interesting. I won't go into it here since there's little of general value. Do 
feel free, however, to look through the code on your own. 



7.2 The Windows and the Mouse 

As with "graph," the first half of the file is adequate if you're willing to type awk- 
ward forms to a lisp listener. The second half provides a better user interface, 
mainly using the mouse. 

The tree-frame defBavor 

This time we have three panes instead of two. The new one is a command menu. 
Many system utilities based on frames have a command menu pane, including Peek 
(Select P), Zmail (Select M), and File System Maintenance (Select F). Command 
menus differ from other menus in that they stay exposed indefinitely, becoming 
active only when you move the mouse over them, and in that they don't themselves 
produce any action when you choose an item, but simply stuff a blip into 
somebody's io-buffer. It's up to whoever reads from the io-buffer to do something 
with the blip (often sending it back to the command menu with an : execute 
message) . There are more details on how menus work later in the chapter. 

Shared io-buffers 

For the process running in the tree pane to see the blips from the command menu, 
the two windows must share one io-buffer. The : after : init method on tree- 
frame arranges this. I could have built tree-frame on tv:bordered-constraint-frame- 
with-shared-io-buffer instead of plain tv:bordered-constraint-frame, but then the lisp 
pane would also share the one io-buffer, and that wouldn't work. (Some input 
intended for the tree-pane's process would be read by the lisp-pane's process, and 
vice versa) 

Tree-window's : main-loop 



142 THE TREE EXAMPLE Chapter 7 



There are now two kinds of blip to watch for: the familiar : typeout-execute 
blips from the mouse-sensitive items, and new :menu blips, from the command 
menu. For now, all you need to understand about the action taken for :menu 
blips is that the command-menu itself is sent an : execute message with an argu- 
ment of the menu item that was chosen. 

Tree-window's : refresh 

Drawing the tree is accomplished by sending : draw-self -and-children to 
the current *root*, which will recursively send the same message to its descendants. 
The initial arguments put the *root* at the top-center of the window. 

The menu-item-list 

Now we get into menus. First off, I should mention that the documentation on 
menus — Part III of volume 7 — is not too bad. (In fact, much of this stuff I had 
actually never messed with until the day before writing the first version of this 
chapter. I just read the documentation and did it.) The basic idea is that menus 
are special kinds of windows that maintain a list of items to choose from, and do 
something appropriate if you click on one of the items. The list of items is kept in 
the instance variable item-list; once a menu has the right item-list, the : choose 
method does the rest: it exposes the window, waits for you to click on some item 
(the : mouse-buttons method tells it when that has happened by setting the 
chosen-item instance variable), and sends itself the : execute message with an 
argument of the chosen item. The : execute message does something appropri- 
ate, depending on the type of the item. 

And now for the format of the items on the item-list, and what it means to "do 
something appropriate" (the task of the : execute message). The simplest kind 
of item is just a string or a symbol. The string or symbol is displayed in the menu 
as itself, and executing such an item just means to return it. The item may also be 
a list (or dotted-pair) of two elements; the first is the symbol or string to be 
displayed, the second is what is returned by execution of the item. The most gen- 
eral kind of item is a list of three or more elements. The first is what to display in 
the menu, the second is a keyword for the type of this item, the third is an arbi- 
trary argument whose interpretation depends on the type of the item, and the rest 
of the list is alternating pairs of modifier keywords and values. The keyword in 
position two may be any of: : VALUE, :EVAL, rFUNCALL, .-FUNCALL- 
WITH-SELF, : NO-SELECT, : WINDOW-OP, :KBD, :MENU, or : BUTTONS. 
The first three are the most commonly used. : VALUE means to return the argu- 
ment (the third element of the list), :FUNCALL means to funcall the argument 
(presumably the name of a function) and return its return value, and :EVAL 
means to evaluate the argument (presumably a lisp form) and return its return 



Section 7.2 The Windows and the Mouse 143 



value. The only defined modifier keywords are :FONT and : DOCUMENTATION. 
:FONT specifies which font should be used to display this item in the menu, 
: DOCUMENTATION is what appears in the who-line when the mouse is over this 
item. 

If you look at the *tree-command-menu-item-list*, you'll see that all three items use 
the general form. Two of them are of the rFUNCALL type and one is of the 
: EVAL type. 

tv:menu-choose 

The easiest way to use menus is to call the function tv:menu-choose with an argu- 
ment of a suitable item-list. This function will allocate and expose a menu, set its 
item-list instance variable to be the argument you supplied, and send it the 
.•choose message. Its : choose method then waits for you to click on an item, 
and sends the menu : execute of the chosen item. If you look at the : mouse- 
click method for tree-window, you'll see that clicking right anywhere except over 
a mouse-sensitive item does just that. It calls tv:menu-choose with an argument of 
*tree-command-menu-item-list*. (The use of process-run-function is necessary 
because the : mouse-click method runs inside the mouse process — without it 
the mouse process would be hung until tv:menu-choose returned, but tv:menu- 
choose would never return because the mouse process is hung.) 

The command menu revisited 

The command menu pane uses exactly the same item-list, as you can see from look- 
ing at the tree-frame defflavor, in the : panes section. But as I said earlier, com- 
mand menus work differently; you don't send them the : choose message. They 
stay exposed indefinitely, and when you click on one of their items they just stuff a 
blip into their own io-buffer. In our case, that means the tree pane's io-buffer. 
When the :main-loop finds it there, it sends the : execute message back to 
the command menu (with most menus the : choose method does this for you), 
and the chosen item is executed normally. 



7.3 Fun and Games 

From The Hacker's Dictionary, Guy L. Steele, Jr., et ah 

FEATURE noun. 

1. An intended property or behavior (as of a program). Whether it is good is 
immaterial. 



144 THE TREE EXAMPLE Chapter 7 



2. A good property or behavior (as of a program). Whether it was intended is 
immaterial. 

3. A surprising property or behavior; in particular, one that is purposely incon- 
sistent because it works better that way. For example, in the EMACS text 
editor, the "transpose characters" command will exchange the two characters 
on either side of the cursor on the screen, except when the cursor is at the 
end of a line; in that case, the two characters before the cursor are 
exchanged. While this behavior is perhaps surprising, and certainly incon- 
sistent, it has been found through extensive experimentation to be what most 
users want. The inconsistency is therefore a feature and not a BUG. 

4. A property or behavior that is gratuitous or unnecessary, though perhaps 
impressive or cute. For example, one feature of the MACLISP language is 
the ability to print numbers as Roman numerals. See BELLS AND WHIS- 
TLES. 

5. A property or behavior that was put in to help someone else but that happens 
to be in your way. A standard joke is that a bug can be turned into a feature 
simply by documenting it (then theoretically no one can complain about it 
because it's in the manual), or even by simply declaring it to be good. 
"That's not a bug; it's a feature!" 

The following list covers the spectrum of terms used to rate programs or por- 
tions thereof (except for the first two, which tend to be applied more to 
hardware or to the SYSTEM, but are included for completeness): 



CRASH 


BUG 


CROCK 


WIN 


STOPPAGE 


LOSS 


KLUGE 


FEATURE 


BRAIN DAMAGE 


MISFEATURE 


HACK 


PERFECTION 



The last is never actually attained. 
7.4 The Program 



Section 7.4 



The Program 



145 




146 



THE TREE EXAMPLE 



Chapter 7 







0) 






,_l 






^x 






0) 43 


CD 


•H 








o> 






0) <D 


s 




0) -» 




C 


■O o 


T3 


•H 








U 


C 


73 


43 73 


Oi O 




C +J 




0) 


id 


01 


73 








•p 








•d 


0) rl 




0^ 




rl 


(3 0) 0> 


01 


<d ai 










■H 


>, 


rH C 


rl 




O rH 




13 


43 


C 


rl 43 








0) 


P 


id 




■P id 




CO rl 0) 




r-\ 


CO >,+J 





-p <-. 








43 


•H 


rH 


O >w 






■H £1 


0) 


•rl 


•H 43 


o) c 


0) ^ 








P 


CO 


ft 


c o 


c 




43 oi id 


T3 


43 


43 4h 


13 


43 W Oi 













CO 




Xi -rl 




H-> 43 rH 








-P -0 


0) 


■P C 








4-1 


ft 


•rl 


£ tH 


•P Xi 




■P 


C 




0) 


C rl 


•rl 













73 


4-> 0) 


•P 




4H 4-1 




CO 


43 0) 3 


id 


«« X O 










P 




•H -p 


C -H 




O 0> 


0) 


p 


CO 


id id 








p 





CO 


S 0) 


■H > 




rl 


43 


•H 


CO 


•H 0) 


e ft 














•H 


s 






CO v fi 


P 




T> t3 


43 rl 


u co 











M 




CO -H 


CO CO 




rl 0) -P 




T3 


0> (V 


■P 0> 


to 0) 








M 




(V 


rl 


> o> 




O > C7> 


C 


(3 


T3 0) 43 


43 


•H 43 rH 










c 





73 


73 




•h a 


•H 


id 


0) O -P 


4-1 -P 


rH +J Id 








0) 


•H 


u 


ft 


rl 




rl 4-1 0) 






0) (d ^ 


•H 


O 








fl 




•p 


C 


c 




OI -H rH 


Tl 


<D 


(3 ft 


4H 


Id 73 -H 








p 


B 




73 


c 




4H 


0) 


T3 


co u 


0) -H 


C 4-» 










a) 


4H (3 


a) -p 




CH C 


fh 





0> 0) 


O 


'- «3 rl 








p 





43 


<d 


o> c 




•H -H O 


<d 


C 


O H 45 


id co 


-« ai 








(d 


43 


■P 




5 0) 




— C 






id (d -P 


ft C T3 






0> 




CO 




— rH 


■P o 




-' -P 


ft 


CO 


ft -P 0> 


CO 0) 


rH ~ 






rH 


0) 




43 


CO 01 


0) id 




co C 


to 


•H 


co a oi 


ft 


•H CO 0> 






a 


u 


>, 


o 


rH A 


43 n 




Ol +J 0) 


•H 


43 





rH ft 43 0) C 






a 


C 


rH 


■H 


0) Id 


•O 




•O C -O 


■d 


P 


rH N +J 


(d <d 


O C -H 






id 


id 


P 


43 


X rH 


co id 




O 0i C 






id -h 


•P 43 


•H C 




1 


X 


P 


c 


5 


•H 


rH 




C rl 0> 


<v 


>> -P 





rH rH -H 






IV 


to 


0> 




ft C 


01 C 




id ft 43 


43 


coo) 


■P 43 


rH g 




1 




S3 


H 


c 


0) 


X 0) 




rl ft 01 






43 rl 


O 


(d 0> rl 








•H 


M 


•H 


C 0) 


■H d) 




0) T3 


T) 


n -a 


0) -H 


e c oi 




o 


43 




3 




•H > 


ft S 




43 co -^ 


■p 


a) 


•H rH rH 


43 43 


CO -H 4J 






ft 







5 


>- 4J 


4-> 




■P » 




■0 


rl Id "H 


■P » 


4-> 01 






id 













4-1 0) 




0> CO 


•> 


0) 


-P 43 




01 O 73 






u 


-o 





73 


0> £1 


O X) 




13 rH 


Cn 


0) 


43 O 


6 - 


C 0) 







&> 


-d 


c 


N 






4-1 0) 


C 


(3 


■p 


M 


C rl 




en 




_c 





■H 


•H CO 


rl CO 




OCX 


•H 




rH 01 


u 0> 


C 




id 






C 


2 


CO rH 


<U rH 




■H 


rl 


0) 


id oi 43 


4H 43 


(0 4-1 




OQ 


rl 








01 


43 0) 




■P CO ft -P 





■P 43 -P 


4-» 


id o >- 









o; 


<D 


a) 


0) X 


§ X 




CO -H 


to 


id 


-P 


CO 0) 


43 




.a. 


•H 


A 


43 


43 


43 -H 


3 -H 




•rl 43 C 




ft -p 


rl t^ 


0) 4H 




Cm 


i-l 


p 


p 


■P 


4-> ft 


C ft 




rH 4-> -H 


id 


CO 


<4H rH 


0) 


4-1 43 rH 




w 

CO 


u 
id 
o 




















oi o <d 

43 

■p -p >, 


4H +J 
4H 
•H 4-» 


•H 4-> 0) 
CO 
73 Ol 






















^. 
























CO 43 


73 


c c o> 


CO 




a) 




















•H 


ft 


id -h c 


3 


a) 


43 




















•• rH XI 


CO 


> -rl 


*-» -H 


0> 


■p 




















CO 0> 


•rl C 


0> id 73 


4J 73 


<0 






















-P id -o 


43 0) 


■H U rj 


C id 


M 


CO 




















0" of 0) 


■P rl 


43 73 rH 


01 u 


o 


id 




















T3 


o 


rl 


ID 






















e -p c 


1 t-* 


C0 rl C 


<d C 


& 


a) 

rH 














* 






oi c 

rH 0) 0) 


•H 
0> 43 


•H -H 

4H 


ft 0) 

rl 


•*> 


>, 














CO 






0) T3 O 


C O 


Q) «_- - 


rH 73 


(U 


4-> 














3 






C id 


•H 


73 CO 


0) rH 


CO 


CO 














•H 






0) 0) ft 73 CO 


Cr 


43 -H 


H 
















-0 






> O CO 


73 -P 


C a> c 


•d 43 


J 


a) 














id 






•H CO 


Id -H 


rl id 


rH O 




e 








O 


o 




U 




r-i 


4H 0> 0> 


ft 


CO 73 73 






id 










o 




i 




•H 


T3 43 


rH 


•H rH C 


CO CO 


OI 


CO 










*-» T- 









C 


M-l H-> 


(0 rH 


43 -H 0) 


01 0) 


"8 










* — 


o 




TJ 






O CO 


rj Id 


4-» 43 O 


r-t rH 


a) 








CO CO 


co * 




O 




CO 


+1 ... 


rH 


U CO 


43 43 


s 


43 


rH 






3 


Ot 




n 




p 


■P -H C 


ft C 


4-1 to 


id id 




-P 


•H 






•H * 


* (3 




i 




(3 


CO 0> 


id 


•H d) 73 


•H -H 


•« 




C 




rH 


73 0) 


0> -H 




1 




0) 


•H 43 rl 


■P 43 


43 


IH rl 


a 


c 






■rl 


Id N 


c o 






B 


rH -P T) 


CO 4-1 


rl 4J rH 


•d <d 


CO 


■H 






c 


rl -rl 


•h id 




— B 




0) 


•H rH 


•H 


rH 


> > 


•H 




P 






1 CO 


O ft 




r-t -H 




iH 


Id » -H 


rH 0) 


4H Id 


i i 


rH 









* 


0) 1 


id co 




•H — (3 




■H 


43 


O 


- o 


01 0) 


id 


CO 







2 


•o c 


ft i 




(3 rH -rl 


-~* 





CO rl O 


co id 


C 4H 


o o 


•p 


(V 


i-l 


-^ 





O -H 


CO rH 




•H e 


rH 


cr 


•H 


ft 


0> 43 


c c 


(V 







rH 


■o 


C 0> 


i <d 




c c * 


■H 


0) 


X! 0) 


co 


rl O 


id <d 


N 


u 


H 


■H 


c 


1 rl 


rH +J 




(V 


13 


rl 


CO -P 43 


•H 


73 (d -H 


4-1 4-1 




4-1 


id 


C 


■H 


l§ 


Id a 




rl -P CO 






■H 01 -P 


> 0) 


rH 01 -H 


CO CO 






0) 




» 


O O 


0> 


TJ (3 D 


i-H 


01 


43 d 


01 rl 


•H 73 


c c 


X 


4-1 


H 


* 




e i 


•H N 


X) 


H lid 


0) 





Eh *H 


U 43 4H (d 


•H -H 


id 







p 


0) 


•H 0) 


-P -H 





■h nd 


42 


<d 


■-■ +J 


ft e 


O O rl 


1 1 


-p 


>^ 


43 






a) 

rl 


C 73 
■H O 


U U 
0) O 


c 


43 id id 

t) ft rl 


id 


ft 
to 








0) 01 


id 


P 


rl 


■P 


e c 


> rH 


rl 




-^ 


•-' 






••> •• ••• — » 


— 43 43 


CO 


rH 


* 


* 


* 


* * 


* * 


o 

> 


^ 












— itj as 

•P 4-1 


1 


CO 


ri 


M 


rl 


u u 


u u 


id 














4J 4-1 




•H 


id 


m 


id 


id <d 


id id 


rH 














01 ai 


1 


■o 


> 

4-1 


> 

4H 


> 

4H 


> > 

4H 4H 


> > 

4-1 4-1 


4H 
4-1 














CO 0^ 






<D 


0> 





0> 0) 


U 01 


01 
















!I 


!I 


73 


X3 


•o 


73 -d 


•O T3 


■o 

















Section 7.4 The Program 147 

















♦J 








... 




































g 








s 




































UH 








i 




































p 








•H 




































a 








* 




































CD 






































»-» 






U 








a) 




































a 








a) 






























<N 












u 




































o 








■p 










































































rH 






CD 







































CD 






£1 








c 




















--» 










£ 






P 






































13 














(0 




















c 










rH 






■H 








•H 




















CD 

rl 










£1 














Q) 




















■d 










P 














P 




















rH 










en 






rH 








V 




















■H 










c 






CD 








5 














.-» 


ft 




— 43 










a; 






•Q 




















<-» 


I 




CU U 










rH 

1 






<t5 

rH 








V 














to 


>1 

UH 




u 

a, cd 










Cn 














rH 














p 


•H 




tH e 










C 






CD 








•H 














c 


fl 




Eh Iti 










■rl 
P 






5 








1 














CD 

e 


to 

03 




•• C 










P 
























<-\ 




CD 


rH 




i B ^ 










to 






*H 








•d 










■H 




rl 


CO 












•• 















0) 

■p 




„, 






C 




•H 


CD 




« « 










* 






A 








(0 




CD 






»-» 




cr 


rl 




Eh r-> 










s 






P 








0) 




rl 






to 




CD 







to l 

















en 








P 











p 




Sh 


a 














t3 






c 








O 




a 




— » 


C 




i 


Cn 




Pn •" 










C 






CD 












en 






CD 




CD 


•H 




J ■-> 








* * 


•H 




.—* 


H 








co 




■H 




to 


e 











W @J 








to a) 


S 




CD 










1 




« 




p 







it) 


s 




CO I 








3 N 




-^ 


P 


CD 














-— 


C 


rl 




ft 


03 


<-• 


— < 








•H -H 


CD 







42 








CD 








CD 


■H 




to 


CD 






—* 






•a to 


<D 


^-~ 


c 


P 








T> 




r-i 


to 


e 


3 




1 


rl 


—^ 


Eh — 








It 1 


iH 


* 


en 















CD 


3 


CD 


& 




45 


P 


z 


O i 








u c 


-P 


to 


■H 











(3 




X) 


•H 


rl 


CD 




to 


to 


T3 


w ^ 


0) 






1 -H 


* 


;3 




p 












id 


TJ 


■H 


rl 









CD 


T) 


■d 






at en 




•H 


*J 














rH 


03 


3 




rH 


rH 




e 


« t - 









•d p 


n 


T3 


to 


en 












1 


rl 


cr 


CD 


■H 


UH 


^^ 


its 


° ^ ~ 


a 






i« 


c 


ffl 


CD 


c 




--~ 




en 


«— « 


P 


I 


CD 


U 


C 




UH 


c 


1 < — 








a e 


CD 


P 


u 


•H 




* 




Pi 




CD 


P 


rl 


it) 






rH 


§ 


2 i -- 


10 








to 


1 


<A 


T3 




* 




■H ~ 


^- 


to 


CD 


| 


ft 


to 


P 


CD 


9 


B = g 









i d 




CD 




u 









c <^ 






to 


CD 


to 


P 


C 


CO 




•H 








T3 









T3 




P <P 


to 




CD 


U 


1 


G 


CD 


1 




z e a> 


T3 






e o 


\ 


O 


-~- 


o 




S3 


rH 


<0 rH 


3 


rl 


rl 


it) 


.£ 


CD 


rl 


-p 


rH 


5 03 P 


4 






•H (3 


V, 


c 


*i 


u 




•H 


•rH 


3 CD 


•H 


CD 




a 


to 


e 


its 


c 


CD 


« a) -p 


M 






c * 






■H 


Its 


^- 


s 


C 


= m 


«d 


P 




to 


3 


CD 


ft 


•H 


X) 


1 rl to 


I 






■H 




i 


c 






1 






* 


IH 


* 




rH 


rl 




M 


it) 


O -P 


4-> 






a + 




•H 


to 


rH 


CD 


> 




p 


03 


? 


X! 


UH 


•H 


■d 


ftrH 


Z CO CD 


0) 










e 




3 


CD 


CD 


UH 




i 







to 




3 


c 






0.H g 


to 




r-i 






•H 




•H 


43 


P 


•H 




p 




T3 







er <u 




P 


1 Eh 4-» US 


CD 




<v 


X 




Pi 


CD 


T3 


Its 


P 


P 




CD 


CD 


(3 


rH 


CD 


0) 


to 


CD 





*» « c 


M 




A 


(0 




•H 


T3 


* 


rH 









to 


-a 


•H 


UH 


X} 


rl 


^^ 


T3 


-^ 


uh h e 




CO 


03 


e 




s 





U 






c 




0) 





IS 







i 









•H « P O 


"§ 


d 


rH 






* 


c 




P 


P 






rl 


a 


1 




a 


CD 


P 


C 


CD 


43 Cu C 


•H 












CD 








> 








CD 


UH 




U 


c 




s 


(0 •• UH -H 


43 d 


UH 










fl 


G 


C 


p 








CD 


rH 




it! 


CD 




03 


fl) H w ^ 


4J 





•H 








T3 


P 










P 


■d 


rl 


CD 


T3 


ft 


M 


X) 


C 


rH CO ft 





P 




























P 


to 





to 


it) 







to — ~- 


S 


cr 












P 
CD 


■d 










A 
P 




T3 


A 
P 


cr 


ft 


p 


■*■* 


UH 


c 


p 










CD 


to 


c 










CD 


T3 


C 


CD 


p 


■d 


CD 


P 


•rl 


3 


a; 










E 















e 


(3 


CD 


e 


CD 


a 


B 





%-» 


IH 


to 










UH 


.» 


CJ 










UH 


* 


to 


UH 


a 


03 


UH 


rH 




0) 












CD 














CD 






CD 






CD 






T3 












T3 














T3 






HD 






T3 







148 THE TREE EXAMPLE Chapter 7 



to -h g» 





4-) 


,_» 






•H 

















*-» 




X! 


to 






tj 












s 




o 




&> 


3 






id 












•H 




13 




•H 


•rl 


^-^ 




rl 












rl 




•H 




CD 


TJ 


o 
















o 




1 




£ 


(0 
iH 


•rl 




rH 
«J 












* 




^ 




(V 








P 
















>>^- 




c 


X 


>1 




O 












P 




1 '-» 




•rl 








P 












^ 




P — » 




rH 


i 


rH 
Id 

a 




to 

rl 




« 








CJ> 

•rl 

u 




X — 

CD >, 

C 1 




£ 


^» 


o 









<^ 












p 




O 


to 


•H 




•rl 




CO 








+ 




X X 




■a 


s 


P 




rl 


n 


El 








«-* 




I CD 




C 


•H 


a 




CD 


P 


■H 












> C 




•H 


TJ 


o 




«H 


C TJ 








c 




CU 




> 


A3 


uS 




•rl 


CD 

e 


T3 








CD 




C X 

1 




TJ 




>■, 






0) 










p 




> J 




c 


>, 






to 


iH 


X 












CD 




a> 




x 




P 


H 


« 












TJ C 




rH CO 


I 






13 


3 


B 








«"^ 




c 




d) ^ 


^ 


» 




CD 


cr 










CN 




•H fc 




A 









E 


CD 


CM 












> . 




id \ 




tj 




CD 


iH 










f-i 




rS 




rH \ 


to 


13 




rl 


1 


* 






to 


id 




£ ^ 









•rl 




•H 


CD 








P 


P 




— CD X 




&> 


•rl 


> 




3 


U 








c 







CN rl 




C >i 


tj 






cr 


id 


* 






CD 


P 




TJ CO 




•rl 


It) 






<D 


ft en 






E 


1 




^H S 




iH 1 


H 






rl 


to 


c 






CD 


CO 




P -H -rl 


>^ 


P — ' 




a 




1 


i 


■H 






iH 


iH 




.C 43 TJ 


(0 


X 


CD 




rH 


•p 


O 






■H 


O 




&> t> a) 


M 3 






rl 




It) 


CD 


03 






d 


•H 




•H 1 U 


TJ CO 


1 


tj 




n 


& 


a 


•— 




cr 


rl 




U TJ 


O TJ 


(D 




rH 




TJ 




to 


u 




CD 


CD 




(3 S 


rl -H 




•rl 


««» 


•H 




1 


C 




iH 


>H 


cr p (d o 


TJ <d 


CD TJ 


M4 


,13 


>( 


> 


4H 


H 


•H 






c 


0) 


4H 1 T3 


c P. 


P id 


rH 


O 




•rl 


rH 


it) 


1 




rH 


■rl 


in 


CD HH (3 


■rl 


(3 in 


ai 




X 


■0 


CD 


o 


>, 




id 






rH rH -rl 


i * 





to to 


■0 




c 


CO 


•H 






g 


N> 


-p 


CD » 


O X 


d) 


c 


S 


•H 




-P 


>> 




TJ 


\ 


4H 


+ CO 


*" X 


1 


rH 0) 


It) 







TJ 


iH 




c 


■H 




CD 


^^ 1 CO 




>> + 


•O TJ 


1 


T) 


rH 


a 


CD 


+ 


cu 


> 




r-\ 


S CD 


<w 0) 


id ~ 


(3 


<M 


c 


■rl 


CD 


> 


~-^ 


iH 


■rt 


X 




\ id TJ 


iH rH 


rH 


<D C 


H 


•H 


c 


CO 


* 




TJ 


TJ 


•H 


+ 


\ U 


CD U 


ft~ 


r3 •• 


CD 


* 




— 




II 


rH 


c 


•H 1 


-^ 


— TJ C 


V) U 


to to 




CO 








+ 




■rl 


■H 


>o ~^ 




• • 1 


1 -H 


•H 3 


4H a 




IH 


TJ 




-^ 


^43 




id 


II 


II P 


S u 


TJ -H 


•H 0) 


* 


H 


C 






I 


CJ 


C 


U II 




o o 


id i 


.. <o 


1 -P 


(0 


CD 


•H 




V 


■P 




■H 




■P 


X CD 


TJ id 


(d 


Tj -H 


rl 


CO 


A 




a 


X 


fi 




C P 


A 


i tj a 


£ iH 


S3 I 


•0 




1 




•H 


CD 


■H 


cr 


•H IW 


&> ? 


•• M 


O 


d) <D 




St 


&> 




1 


C 




CD 


CD 


•H 


CD CD O 


TJ 


TJ X 


10 > 




A3 


c 




>> 







iH 


H rH 


rl 


C to O 


0) •• 


a 


•• -rl 


CD 


rl 


(3 -rl 






A 












TJ 


■H 1 


P 


tj TJ 


CD U 




4H 


V 


M 


iH 


rl U 


rl 


rl 


O > 


> — ' 


S -H 







U S 




CD 


•H 














o 


(3 




E 


fi 




•o p 




N 


» 


4H 


4H 


•4H MH 


MH 


>*H TJ 


■Z t3 


rH TJ 


TJ -H 




UH 


rH O 




•H 














c 


CD Pi 


fl n 




rH 


•H 







ft 












TJ -rl 


A CD 


•rl ft 


tj 


CD A U 




e 


8 












> 


a] to 


* •• 





CO 


O P 




CD 












^ 


rH ^ 




.£3 




CO 




e 


H 












P TJ 




tj 


p 


T3 


c .2 




^ 


^^ 












CD (3 TJ 


a 


(V 


a 


CD TJ 


















e a) 


C 


01 


E 


CD 


■S w 


















uh to 


ItJ 


to 


MH 


CO 


S 



















Section 7.4 The Program 149 















•• 














P 




































o 














X 




































■d * 














S 




































G cr. 


















































0> G 












i) 


X 






















<»^> 














0) -H 












u 


03 






















(N 














~ O 












a 

10 


e 






















(0 '-- 
<N 
ft CO 














CO 














to 






















>, 














'0 rH 






rH 






g 


X) 
03 






















C ^ 














10 <d 






03 






o 


P 






















CO 














P 4-> 






P 






























O (N 

ft to 














1 (3 











XS 




rH 


































X o 






P 




03 


03 


03 




















-^ 


X o 














(0 N 










rl 


P 


p 






















ft 










-~~ 




e -h 











1 





O 




















--^ 


<N X 


H 








CO 




1 u 






p 




X 


P 


P 




















4H 


u 


■H 








G 




4-1 O 






G 




03 
























r-t 


(N 


a 








X3 




G .G 

■H * 


„ 




•H 




e 


03 


to 




















0) 
CO 


t- u 
to — 










03 






CO 











a 


cu 






















ft to ~ 


n 








P 




• g 


G 




tn 




p 




u 








*-» 








--» 




X3 


-p 















•H 


to 


G 




c 
























rH 


>^ O (N 


g 








rH 




rH A 


X> 


cr 


•H 




•H 


* 










to 


T3 


»-» 




CO 




•H 


ft >, 











■H 




•rl P 


03 


CD 


X> 


to 




p 










p 


rH 


c 




p 




X 


«- >^ 


£ 








G 




A 


P 


P 


X) 


xs 


X) 


to 










C 


•P 


<D 




c 




U 


CO -» (N 


0) 












O 






03 


03 


03 


■H 




T3 






<D 


X! 


P 




01 






<N r- X 


P 




^-* 




rH 




rH 







a 


rl 


P 


rH 




rH 






e 


O "O 




s 




01 


ft ^ to 


■H 








•H 


G 


•rl II 


u 


-p 












■H 






D 




rH 




0) 




> 


X< 2&^ 


3 




en 




G 


0) 


G 




c 


p 





X 






^ 






P 




•H 




p 







cr 




G 






P 


&>T3 


•H 


o 


p 


03 


G 




O 






•H 




A 




•H 




e 


»- X X 


<u 


co 


•H 




rH 


X) 


rH G 


g 




.G 


c 


e 


P 




■-* 




4H 


3 


-o 


O 


-~~ 


3 




CD 


p «- 


p 


+J 


XS 




■H 


rH 


■H -H 


CD 


0) 




■H 


i 


G 








rH 


cr 


<H 




r-{ 


cr 


rH 


P 


-<- r- X 


i 


G 


03 




G 


■H 


G -0 


co 


o 


<v 




4H 


P 




^-. 




0) 


0) 


•H 


-o 


•H 


CD 


•H 




S >. P 


<u 


<D 


P 






^ 


XI 


— ^ 


flj 


o 


>d 


c 


CD 




T3 




to 


p 


x: 


rH 


C 


P 


C 




O 0) 


u 


e 






CD 


U 


0) 0) 




ft 01 


« 


•P 


P 




rH 






i 


U 


•H 








P 


x> ^- to G 


03 


0) 


03 


^ 


U 




O ft 


II 


CO 


a 


P 








■H 




P 


cu 


i 


X\ 


P 


(1) 


— 


c 


G X CD -H 


a 


p 




c 


03 


g 


(0 1 






CO 




(1) 






.£ 




C 


o 


0) 


u 


G 





CU 


CD 


•rl «^ X> rH 


co 


•H 




CD 


a 


•H 


ft u 


X? 


p 




P 


N 


r^ 




<J 




0) 


03 


> 




aj 


03 


p 


P 


S 1 


1 


G 


~^- 


P 


CO 




to o 


03 


o 


+ 


u 


■rH 


rH 




1 


c 


p 


a 





cr 


p 


a 


<D 


03 


— XJ G * 


p 


cr 




X) 


| 


O 


~ ,C 


P 


0) 


._ • 


cu 


e 


T-i 




T3 


0) 


03 


to 


e 


rH 


03 


CO 


rH 


a 


G 1 03 


0) 


0) 


0) 


rH 


g 








rH 




rH 


•H 


id 




13 


P 


a 


1 


0) 


ID 


a 




CU 




CO -H 4H P 


Cn 


P 


o 


■H 


P 


u u 


P 


rH 


I 


rH 


X 


c 




03 


T3 


i 


XI 


p 


T3 


i 


-d 


T) 


T3 


CD A TJ 






(0 


-G 




















It) 


•H 






rH 


p 


CO 




^-^ 


p 


CO 




c 


■d 1 1 •• 




0) 


a 


O 




'tH 


4H 4H 


4H 


O 


to 


O 


e 


4H 






■H 


0) 


3 






0) 


rJ 




CD 


CD 10 


CD 


u 


CO 




* 




















0) 


^1 


to 


rH 


<D 


C 


CO 


rH 


0) 


CO 


G G <D > 


T3 


03 




r-( 


4-> 


a 


















13 


O 




4H 


n 


0) 




4H 


T3 


«-» 


1 rH tn O 





a 


g 


rH 


CO 

































P 






O 




V (0 X) XJ 


G 


V) 


3 


•H 





















C 


T3 


T3 




G 


•o -o 




C 


P 


O > CD G 









c 


rH 


rH 




















rH 


rH 


4h 




rH 


<-{ 


4H 




G 


CD 1 1 -rl 




4H 




























■H 


•H 


r-{ 




•H 


•H 


r-i 




'V 


G CD x) S 


X) 


(1) 


_ 
























•o .c 


^1 


1' 


n 


X! X\ 


0) 


T3 


P 


G rH G 





N 




4-4 

























U 


O 


W 





O 


o 


CO 


O 


03 


ft -H X) 


.G 


■H 


p 


•H 






















J3 








-C 








£1 


a 


O -H 4H G 


P 





0) 
























p 


^1 


-o -o 


p 


cr -o 


T3 


P 




4J *-- CD 


a; 


B 


rH 
























OJ 


CO 


c 


c 


0) 


4J 


C 


c 


0) 


T3 


G rH 10 


g 


CD 


























e 


3 


0) 


CD 


e 


CD 


d) 


0) 


e 


G 


G G — 


4H 


e 


























4H 


a 


CO 


CO 


4H 


to 


CO 


CO 


4H 


■d 


4H 6 


0) 




























D 








0) 








0) 




<D ~ 


X) 




























T3 








T3 








X) 




X) 



150 



THE TREE EXAMPLE 



Chapter 7 






^-» 


ft 


»-» 


X 








CM 


^ — 


u 


■CJ — 










CO 


TJ XI £i .G .G 


a 


+J 4-> 4-» -P 


* tx> cj> & 1 &> 


>, 


~ G G G G 




a> cu cu cu 




^ rH iH iH rH 


CO 




^ 


ft 


t- t- CN <N 


X 


X >H u u u 


,_ 


H ~ 


*■"• * fl "O t) "o 






T— 


T~ * * # * 


0) (0 


(Q + «_- ^ ^ — 


OJ 
•O ft 


ft" S \ N N 


O X 


>>P \ \ \ \ 


g 




i cn 


cm tr 


>4-l 0) 


0) 01 r- r- (N CN 





O -H (0 (0 10 0) 


1 ft 


ft— 

>, ft ft ft ft 


CO X 


V 


X! X >. X * 


0> I 


1 +J 


X) ~ 


w- (J* + + 1 1 


CU 




T> TJ 


•O rH tO 


G — 


w ^ 0) 


•rl — 


n 


M-t 


iH 




to 


G P 


> 


CU 


« — 


4-1 rH 




0) ~ 




TJ 





id 
u 
p 

(0 

a 
o 
o 

v u 

%% 
u u 

UH O 

I £1 

<y .. 

cp > 

H -P 

4J ^ 

M 

O 

> 



c 

M cu 
to > 
i« <v 



G ft 
G co 



rH rH CU G G 

I o m H H 

g O U X\ £ 

d) •• V P P 

p «-».... 

■H — G 

.. — -H G 

a> is -h 

a> G 6 * 

G «J — e 

* ft -' 

ft i +» 

i u G co 

G cu o cu 

c c >^ n 

cu cu to -h 

g +J rH CO 

I «»•••• 

_ T3 . H — ~ 

CD G rH 

G « I g 

•0 g ft-H 

ft g CO IT) 

ft I O -rl g 

10 CD O rH ~ 

•H 0) •• •• — 

rH H > > «• 

» +J +J .p 

CO 

a> a; ft c 

C <d G co o 

HJ H 0) -H -H 

ft+J g rH P 

4j i — - — - — m 

in tj — y 

■HO)' G 

rH P &> 

ft O CO -H 

i at a> uh 

P rH G G 

■H 0) Ifl O 

G co ft O 









M -H 










C 










•H &» 










A C 










P -H 










•o 










S -H 










n 










c u 










0) 










^ > 










CU 










M 










(0 










P n 










O ITJ 










a) 










rH CU 










CU ? 










(0 










■o 










CU 










A A 










V V ~ 










a) • 










CU g UH 










CO rH 










CU tt> 










n) X! to ~ 










O En P — 










CU >— -H 




„ 






J3 ~ 




0) 






CU CO 




iH 




*_ 


- • a » 









*-* 


J CU i0 




& 




u 


I g n -o 

+J id w C 




•H 




<D 


O U 1 -H 






n 


UH 


11 IH ID J 




*J 


CU 


4H 


rH 1 0) 1 




tO 


4-1 


s 


CU CU fc T3 




CU 


IH 


£1 


CO CU P CU 




M 


3 




H -P 




cS 


X) 



■H 


10 P CU o 

•h x; <i> 











> 10 P rH 






•H 




V 




P 


1 


(V 


cu UH c to 




•H 


4-> 


0) 


rH U 1 




C 


<l) 


M 


XJ 3 »H 




•H 


V) 


-P 


•H T) P 










(0 10 0) UH 
CO CU M 1 




iH 


2 


CU 


CU P CO 




CU 


a 


C 


O 01 T3 10 




JJ 


CU 


* 


O d rH -rl 




4H 


e 


ft 


fl-ri 3H 




It) 




T3 


i0 
CU H > •• 






CU 


C 


S <" _ 




a> 


c 


CU 


.0 c -o 5> 




g 


(0 


to 


u a) c e 




3 


ft 




UH P 10 10 




iH 


i 




CO VH 




<4H 


X) 


UH 


H -rl CU UH 


0) 


1 


c 


rH 


3 rH g 1 


G 


CU 


CU 


V 


O 1 10 CU 


<0 


CU 


CO 


to 


ft n cu 


a 


u 






CO CO UH u 


i 


V 




T3 


CU -H 1 -P 


T) 




<+H 


c 


>!H li- 


CU 




iH 


CU 


lt -H 


P 


? 


<U 

to 


to 


g i0 to T3 
iO 


O 

(1) 


fl 






co co A ^ 


rH 


+J 


TJ 




•H * -P 


CU 


<u 


C 




Xi P C cu 


to 


g 


CU 




e-i -H o e 




HH 


CO 




UH 


> 


a> 






... ... .► CU 


P 


■d 






T) 





Section 7.4 The Program 151 



I 



ft 

B 

n 

p <« a» a> i 

(0 o -p > 

to c 

cd p -h *o — a» 

a w in o BE 

(0 -H ,C 0) 

ftrH CD P P AJ 

CO) -H CO 

a a) i« a i rtt 

to 43 o. to e 

■h +j a> a i 

^ ft ,g c 

V (0 Eh CO 

V M •<* -* OP 

45 (0 rH -HP 

p g p ~ 3 

CD <U ,C P M <w 

CD ,* P -rl ~ d)H B 

CO -H — ft CD CD 

t— I <U CO O to P 

>, > a> a) -h ~ 

cucoroxc a» — ~ i — » 

«t?^'H * ~- PftC — 

G <W ft C 3 -H CD — 

P-HT3 I O OrHCO — 

O 43 rH 10 Tj -rl* llfl 0« 

cd P 3 -h cd V U X ,C ft 

rH O .C P OCO CU-dO-H 

CD tO > E-l O C-H I M rH 

coat a) 0i-i +j-hi3X3 

O P rH «H « 9 A G 

a) t3 h • at ii OPcu'd 

4* ~ CO ~ rH CD CD — g G 

p 43 cd •• ~ cd ft p, •• o 

cu-h0(Opo cd p ^ p ft cd 

>! 43 £3 M - Tj rHI CD •• -H CO 0) 

<d U CD »4H fi I g U ^rH-H-^ 

ggl^.H ft CD ~ O XI 

g CD £3 £ O P ~ £3 CO D CD 

OCDgCD O I P -rl ~ CJl -H TJ £3 P 

p p CD M ~ -H CD II -H-H ~ £3 CD 3 

CO P P — P CD £ CD <N 3 COOgO 

•OJ^tO O U OCD^-P O gOCD 

•H 10 >, CD ~ ~ CD P T> M rH CO TJ CD CD TJ X 

fl m^ • »h co fi p 43 cd C -PcofiCD 

> P > > CD a g -H * •• M -H -H — flj •• 

POCDOOCQ H CD S CO «4 2 g 

CO TJ 43 M T3 Tl I X P IP -P ~ — rH ~ 0) rH * ~ 

2CP0GCH -H -H CD 10 (3 -H-HgrHOft 

•n -H IH -H -H O g I 41 'H H O - C G >> (tf -H 

£ *W 3 3 <+H I CD M rH -H u-t p O P gOgrH 

CD OCDIII P > P rf (3 ~ -rl -H — I O fi Ofl 

> CD O rH CD CD O -H^l^ £3 p ft J*, M 3 M 

43 £3 £3 flJ rH g CD P » CD ft -rl O O (3 <4H <4H 4H 43 

&> p o o -h 43 m in -h ftio.- c o m- - +j 

fi-rlplflC CD CO 0) >, M « 3 H •• P, IH (Oh 

•H <+-l P t! C P •• CO £ (OPCDg M 4-1 I -H ft CD ft 3 

A O A C 0) O I CD CD I >« I CD I ClHrH-HP-HO 

P O <0 CO CD CD CD CM OgCP P -- rH ^H H XI H 3 H IH 



P COrHfl 03 -HI OCD-rlfi <4-l ~ CD-- (fltt) A U X) 

1* M P *4H CD CD ffl 3 X CD M P rH O K) U > "« glOP CD 

M <fi O r-t tOft O — -H 01 a-H X) <M "rH CDft •• 10 <« X <« Tj 



flJ ft CD CD £3 •• I g ~ g 3 CD HO TJHOCDOG 

D H ffl O T) ~ I 10 >C0 IO>C-H I CD 

GCDCDP CDCD — O > CO g — P O ft»H OCDMhPPPW 

co jC to -h co g p C o oi i M TJ* Oi t) m ^ fl S fl) - 

P -HiDO CDI THI O O 'H C» PC G~ gog 

CD CDM MCD CCD CO-HTSrH -HO l-H -H 0*hCD^d 

^ to^ O t7><nH (OC -HOtofift U-O ><0 SllPOftOC 

E-«CDP<WCICD ftfl > h <tJ -H I IC Og I 0<4-l>,>4-ICD 

0) -HCDtO Ift I ft XJ S P CD -H T3 •• CDftCD P g 

fc CD TJ CD •• CD •• CD H CD > C CD -H t-l •- •• •- •• 

•CWOO-HH> CD> CD>>>C Ml -H> HHO"--- 

M C <W C M P P MP hppp-H PCD SO P-Qtfl 

010 OM-^ p_p^ I ^CD I t) - - 

rCOlO— CD-O P MCDC U 

*> , OCM M iH T3PCD-HTJOO 

PfHOCDOOCD O O O * M£ Oiw-O 

^CDt3O^03> > (0 X3 P 43 

C>C-HCDP^(0 (0 iw PO* -OPft 

OCD-H?MCD-rH rH CD CDPfiGCDO 

QrH>p(0g^4-l »w -O gCD 0CD gO 

IH^-CH <4H •• H 01 IH 01 UH 

..* .,...,.. d) , qj q) >_, ci) •— ' CD — ^ CD • 

• « aw ■» •• ■« rQ ir^ frj rr^ »Q frj 



152 THE TREE EXAMPLE Chapter 7 



<rt ~ — fi ft 10 -H 

v ~ * o i ** « 

4J - C -H 2 S -H O 

m (o * -p fi , i ft 

03 - H 2*2 

p, -h «h a g c p 

£ 5 ~ ft -cog o 

P G h 

jj .. o jj nJ fi "O = 

o 00- i 2 S £5 

+J O o | « -P 

•H P P O g 0> O C 

C+j 0) G O +J<1) 

r< fl C U C fl -C -HI G P 

+5 C o p -h o p .c ?> S 

w p 3 *o »w o p <o 

> J «j o — os-P a co 

1 ^~. CCUPO^»'-~ >iO did) 

U g p to t-t • ~ -h to .22 

3— 3-HOO) 0) H •» O EG 

+J G O »> .C ft *d 2 o s m 

-w+J o « p >> >, o a f „, 2 

o * moag p 2 o 



& 



0)0 0)0) 0) o — — C C d _ 

cu in p g p o c >^r- •• c ^ 



•H«J13 P <« O -n C ^ ^ * S * , , *J 

C -H P O tO «TJ <W X _ * -P -H 

P tO 10 I - P B = p .* fc £ S ? 

0) (fl -3 -rl (O-drHrHrH Pi "fl S E 1 ^ V m 

<3o-HP |CpCfl> I PEh HJ P P 

ocu p o tn >> = m r4 a \ a 00 

~ .- 7 .C 3 rH P -H <2 \ +JJQWC ftv; « 

me- toc+jop<w — johs ■V ft-P 

O)5>*-H0OP X ~ t* = II 

ni+3pMtotoaje!<o * " -K tt - § 8 £ 

lH4-l~COiH0,l3"P P OWC — (UXflJ 

p \ r-l O PtO O CrHPq-H -H -H g ft 

W\ I fi^H (J>- C P -» ^ •HOW P C lltQ 

I w gSPrHC O * ~ — ^ Pll O « « - d 

to Siw p-sopifltu crto pto ototo^-3 p n^5 

P HH 

14_| t) V 

(0 •• tO 3 CU CD M-l 



'U U* ^J Wi -f Wl W W< V< ^- -»— f-l ^- w 

H Cffl>Q PQJ O0> -H3!Dl<w to POPS 

1=0)3=0)= (OP OP rHOOPI -H *g = 



CQ)P"C C — a) 10) 3 •• •• 0> 3 «3 0) 

P 0)PP 0=0 — P rjP '°^^2V «, a 

S O ge<= -HO) •H-'*" <0-- ^ 31 4) >% 

O—O I >pprHP P 0) ' O &, O 10 P'*' 

TJ—P TjaOIOlUPtJ 0* P* PTJJgtO >i I 

a * cScoppp a>o? —is ccw/o) p g 

•HPTJ JoZtfC-HC PPO -0)0 rO-HtO^O I « 

SOC g nJ 0)J0) -P i "O fi "O 'd ? o— g P 

100 gPPg g IrHC PPC CI-OCOP— 0) -H 

0PIO OP0>0)3l03 Z <H -ri 0*-H S0CCft— P I 

«*«-' u m>j n u v u 00> o > t) « « o^+j -h p 

n i-P(do>ooo CPi p*i 0ptop i g 

JJ4J4J 0) 1)1 S d! fl Q 1) 110 I+J0 MP — PC O 

i O O = = =••= : • • P P O — 3&i 0) 

00 p — — — p.cp 0OP M _t!- fl P fl 8 1 

■a^fc +j>— flpptopp-H-dOP p>» 

o— *» +)**o>** ociia *p 

45 — t3 co p (o^i^^^- 1 

±i a u W 0"0 -r\ ±) Pt3 

0)P(0 <<J C+JCCPC430-O 5*2 

gO)--- > S00300PgC ><0 

IUH 4-1 M-ICOlOd-ltOtO <H<fl VW" 

4)^, 0) O)^^^^0^^^' , *0^-' 0> 

<0 tj '0'0«- , «o +j 



The Program 153 







rH 


rH 


















,_^ 


















u 
1 


•rl 


•H 




P 














rH 


















9) 








TJ 














H 


















-d 


a) 


CO 




rH 














c 


















i 


Pi 






•rl 
X! 

o 












0) 


1 




















co c 


1 


1 
















T3 




















M 


ai 


01 




» 















0) 


















(0 -H 


p 


s 




CO 












C 


Pi 


















e p 


(V 


id 




Pi 














■H 


















1 -rl 


i-t 


c 
















01 


rH 


















0) CO 


01 


Of 




CO 












£ 


T5 


















W 


TJ 


M 




CO 












P 


(0 


















3 ft 


1 






d 














0) 





















ai 


cy 

















>H 


rl 


















e p 


(0 


CO 




s 




































S 


3 
















4-1 


=*t 


















= 










E 
































p p 


e 


e 




TJ 












rH 


P 



























rH 












01 


0) 


















c 








■H 












£) 


0) 


















OS -H 


01 ~ 

■p = 


01 

e 


= 














rH 


43 

CO 


















a) a> 


01 • 


« 


0) 
















1 


















M <d 


rH 0) 


c 


TJ 


5 












tj 


0) 


















(0 


01 0> 


0) 





CO 














CO 


















s c 


Q U 


a 


a 


55 












rl 


3 


















E 


E p 






B 












0) 





















(0 






CO 














p 


e 


















Q) -H 


a) a> 


0) 


•H 


CO 












c 




















-O X! 


n a 


TJ 


.C 


T3 


E 










w 


> 


















P 


P 





P 















: 


p 


















a 


a 


a 




Pi 


CO 






























•• ^3 


.. m 




rl 




TJ 










T3 




















P 























rH 




















* tH 


* 




UH 




c 










« 




















P ? 


■P P 


p 




P 












o 




















CO 


co 3 


CO 


rH 


to 


CO 




— - 






£i 




















•H 0> 


•H 


■H 


0) 


■H 


•H 










!>, 




















rH Q) 


rH 


rH 


A 


rH 


£ 




0) 






0) 




















iC H 


IT] (1) 


« 


tT5 


IT] 


P 




■d 






* 


















--» 


1 P 


1 -o 




rH 


1 































> 


(9 


CO 


CO 




CO 







c 






B 












■—• 









ft (U 


ft G 


ft 5 


ft p 























> 






•d 


J*.c 


K 


>» 


0) 


J* 












rl 



















c 


■p -p 


P CO 
1 -H 


P 
1 


Pi 


p 

1 


■d 

H 




0) 

u 




£ 


4H 






3 












•rH 


e >. 


e a 


e 


a] 


a 


■H 


*— . 


c 







01 













■H 








0) IT] 


0) 4-> 


0) 




CO 


£ 


•t 


fC 




T3 


c 






"3 






s 






Oi — 


P rH 


p 


p 


0) 


p 


u 





p 




C 


•H 






C 












-d p 


•H ft 


•H CO 


•H 


«d 


•rl 




■d 


CO 




■H 


rH 






•H 






CO 






o c — 


1 CO 


1 o 


1 


■H 


1 


id 


c 


c 




S 


| 






2e 






■d 






c o> ^ 


<D -H 


CO -H 


0) 


> 


CO 






•H 






P 



















— M '- 


a> tj 


CO rH 


0) 


C 


CO TJ 


s 






0) 


0) 






0) 






c 






10 ~> 


m a' 


U ft 


U 


u 


rl 


TJ 




O 1 




■d 


5i 






T3 












P ft X! 


P 06 


P W 


p 


a, 


P 


< 


0) 


M 


























•• ^co 


* = 


* = 


* 


c 


* 




TJ 



e 




c 


> 

P 






PJ 






p 
o 






— P CO 

U W ft pj SH 





CO 


0) 




CO 




C 



























1 TJ 11 CI <rl 


ft 


ft 


ft 




ft 








*-. 


0> 






^-~ 


0) 




*-* 


u 




-^ 


p o v u a) 


>> 


£ 


K 




>* 






tj 


& 


■d 


rH 




A 


T3 




£ 


i 




* 


C C £1 10 rH 


P 


p 


p 




p 




TJ 


rH 


co 





0) 




CO 







00 


0) 




CO 


0) ~ ft .. 






1 




1 




rH 


■ H 


0) 


Pi 


-Q 




0) 


Pi 


-— 


cu 


-d 




Oi 


n -d 


B 


e 


e 




e 




•H 


£ 


in 




id 




rl 




0) 


Sh 


o 


-~~ 


rl 


<d C — * S 


V 


co 


0) 




CO 




£ 


u 


4H 


0) 


rH 




UH 


Oi 


P 


UH 


Pi 


0) 


IH 


ft 4) P P 


p 


P 


p 




p 







1 


0) 


e 


| 




01 


P 


Oi 


OJ 




T3 


0) 


i to c o *d 


•rl 


•rl 


•H 




■H 






TJ 


M 


(0 


P 




Sh 


01 


rH 


rl 


CO 





Sh 


0)<- 01 O C 


1 


| 


1 




1 




> TJ 




c 


01 






rH 


CO 




X 


Pi 




>i Sh rH -H 


P 


P 


P 




P 




CO 


(0 




0) 


CO 






Oi 


■d 




(0 






iO P 10 * > 


3 


3 


3 




3 




G 




» 


rl 






s 


TJ 




5 


a 


* 


S 


e c ft 









































i 


P 





i oi cr tj 


V 


CO 


0) 




CO 




0) 


0) 


XI 


0) 


0) 




T3 


0) 


0) 


TJ 


0) 





TJ 


<u u p p c 


ft 


ft 


a 




ft 




CO 


■d 


Pi 


CO 


T3 




Pi 


CO 


TJ 


c 


CO 





c 


M 10 CO CO 


rs 


K 


K 




I* 




3 





•H 


3 







•H 


3 





•H 


2 


r^ 


•H 


3 ft C co co 


p 

1 


p 


p 




P 




i 


a 


s 


i 


Pi 




s 



5 


C 


* 




e 


* 


£ 


o r 


-0 


■0 


■d 




■d 






TJ 


T3 




TJ 




TJ 




TJ 


T3 




D"d 


I4H 


-d 


TJ 


■d 




TJ 




PS 


G 


C 


c 


C 




Pi 


a 


C 


C 


c 


p 


Pi 


C P -H 


•0 


ITJ 


aj 




id 




3 


0) 


0) 


3 


0) 




0) 


2 


CO 


Oi 


rJ 


0) 


0) 


rJ co -- 














UH 


no 


CO 


4-< 


CO 




CO 


UH 


CO 


DO 


<4H 


CO 


DO 


<4H r-i 


> 


> 


> 




> 




0) 






0) 








01 






CO 






CO — 


p 


P 


p 




p 




TJ 






T3 








TJ 






■d 






TJ 



154 THE TREE EXAMPLE Chapter 7 



o> 

9) H - IW 

■d 0) >, >W 

rd XI -O 3 

O • O -P 

h Ji O XI co 

•O -P 

91 O <U TJ 

XI O <D .3 c 

!-t -P 10 

e T3 -H 

CO 0) <4-l tT> >^ 

5 rH C T3 

S -H P -HO 

ft <0 -P XI 

P B 3 3 

■H O -P ft 0) 

o 6 3 

H OP 

O P o o 

U U 4-1 (1) 

O 0) i+j 4_) 

nj fc -d os 

e n a) ft 

o en v g 

<o o c ho 

i0 2 O 

CO P M CO 

+J 0> id ■ M 0) 

•h g 3 = 

0*0 0) CO +J • 

<u p c p p 

O rO CO O •> rH 

C TJ >> 'riH 3 

•H tt) - CO • > -H CO 

wh iii >, a» n v 

•H rH = T> H H ~ 

ft -H (I) O ft CO — 

• 6 <H J) XJ -HO) — 

•won a> xi >> 

0)O<UP — »W 3 O 4-> TJ 

N P = >*, O P O O 

■H CO (0 <0 H fi X> 

O-H H J) O-PCO u 

g <03 J3htJ iw D 

<1> <1> ft -P 3 rH H -P 

Eh ti M» O a> C — • 

•HCOdJ ■Od)X! fc Cna) 

«w *w >« o U • OS 

O Art X) PT3C fc rH 

CO g cdttJ-HlOQ)— ftlO 

g-HC .C 0)3— — > 

0XS-H3 o+JC+Jp--- 

•h-p^o o a> co g a> 

•H 4H O *- N P -rH G CO H O^ 

CO-HC -H (OC «H-> 

•h +> a> «h o « "O a> > . --» 

'mp-h.c in Eh id u tr « a) 

OJCOCS N « H «1 O - ^IH 3 

X><l)-H . H gC0rH ~+JrH 

n uh p o i (u ai io 

a> a; co goc<uc!SOPco> 

£ mi) h oipoxj-h i-ioa)— - 

■PXJ-H g C lUHH 

P CO «W O C P > - — 

CO -H O O CO <0 rH — 

•HW^Tl HrH-HOS—H 

« P 01 CJ CO O 

a>o T3 loaiopai-P — 

Mfe-Ptf g CO O -H fc <D ' 

ttJW^O 4H D rH rH 

K CQ ft rH a> = frjOi — 

■O 4H C 45 
— H (0 P 



Section 7.4 The Program 155 



7.5 Problem Set #7 

Questions 

1. Write a function which puts up a menu with five choices: "Truth," "False- 
hood," "Confusion," "Panic," and "Mega-panic!." Clicking on "Truth" 
returns the string "Truth;" clicking on "Falsehood" also returns the string 
"Truth;" clicking on "Confusion" randomly returns one of the strings 
"Truth" or "Falsehood;" clicking on "Panic" enters the Fep; clicking on 
"Mega-panic!" enters the Fep and does a cold boot. 

2. Use the tree code to display flavor component trees. Ignore "included- 
flavors" if you like. 

3. You may have noticed that in the editor (and in some other contexts), put- 
ting the mouse in the top-right or bottom-right corners causes the mouse 
blinker to change to a squat vertical arrow, and bumping it against the top or 
bottom edge of the window causes scrolling. This behavior is called "flashy- 
scrolling," and is controlled by the flavor tv:flashy-scrolling-mixin. Add this 
mixin to the tree window and write the necessary methods so that bumping 
the mouse against the top-right corner will "scroll," i.e., make the parent of 
the current root be the root. 

4. There's an awful lot of duplication in the graph and tree examples. The right 
thing to do would have been to take out the common portions, and build 
graph and tree on top of them. Re-implement graph and tree in that fashion. 
(It sounds like a lot of work, but I'll bet it won't take more than an hour.) 



156 THE TREE EXAMPLE Chapter 7 



Hints 



Your function need simply call tvrmenu-choose with an argument of an 
appropriate item list. See section 14.3 of volume 7 for a description of the 
possible forms for menu items. The last three menu items will have to be of 
the "general list" form. 

Constructing a tree which corresponds exactly to the ordered list of flavors 
used for building combined methods is tricky because of "included-flavors." 
But it's not hard to make a tree showing the regular components. Given a 
flavor's name in the form of a symbol, ( si : f lavor-depends-on (get 
flavor-name 'si: flavor)) returns a list of the components. Give the 
node corresponding to a flavor one child for each of the flavor's components, 
and recurse on them. To make the tree fit on the screen you'll probably want 
to switch to a smaller font, and decrease the values of *vertical-spacing* and 
* horizontal -spacing* . 

The best way to find out about tv:flashy-scrolling-mixin is to read the source 
code. There isn't very much of it. You'll have to write methods to handle 
the messages : scroll-more-above and : scroll-more-below (which 
should return t when it is meaningful to scroll in the given direction and 
nil when it is not), the message :y-scroll-to, which should do the 
actual scrolling, the message :scroll-bar-p, which allows or inhibits 
scrolling, and the message : handle-mouse-scroll. I suggest that 
: scroll-more-above return nil when *root* is eq to *the-real-root*, 
and t otherwise; that : scroll-more-below always return nil; that 
:y-scroll-to call the function mouse-make-parent-root on *root* and 
self; that :scroll-bar-p always return t; and that : handle -mouse - 
scroll always return nil. (The : handle-mouse-scroll method isn't 
directly related to flashy-scrolling, but because our :scroll-bar-p 
method returns t, the system is going to think that in addition to flashy- 
scrolling, we have a standard scroll bar in the left margin. So every time the 
mouse bumps against the left margin, our window will be sent that message. 
The method needn't do anything, but it had better be defined or we'll get an 
error. This may sound like a modularity problem, and in fact it is. It 
appears that someone assumed only windows with scroll bars would use flashy 
scrolling.) Don't forget to make another tree-frame, since mixing in 
tv:flashy-scrolling-mixin will be an incompatible change to tree-window. 

The basic part might define flavors node, node-window, node-pane and node- 
frame, and methods for them. Graph would then build graph-node on top of 
node, and graph-pane and graph-frame on top of node-pane and node-frame. 
Tree would similarly build tree-node on top of node and tree-pane and tree- 






Section 7.5 Problem Set #7 157 



frame on top of node-pane and node-frame. 



158 THE TREE EXAMPLE Chapter 7 



Solutions 

1. (defun silly-menu ( ) 

( tv : menu-choose 
' ( "Truth" 

( " Fa 1 s ehood " " Truth " ) 
("Confusion" :eval (nth (random 2) 

'("Falsehood" "Truth"))) 
("Panic" :funcall sirhalt) 
( "Mega-panic I " :eval (sirhalt (format nil "b~%" ) ) ) ) ) ) 

2. Here is a crude first pass at making flavor component trees. It ignores 
included flavors as well as duplication of components. 

(setq *vertical-spacing# 5) 
(setq *horizontal-spacing* 10) 

(send *tree-window* : set-font-map '( fonts : tiny ) ) 

(defun show-flavor-tree (flavor-name) 
( start-new-tree ) 
(send *the-real-root* : set-label 

(format nil' "~S" flavor-name)) 
(show-flavor-subtree flavor-name *the-real-root* ) 
(send *tree-window* : refresh ) ) 

(defun show-flavor-subtree (flavor-name parent) 
(loop for component- flavor 

in (reverse ( si : f lavor-depends-on 

(get flavor-name 'si : flavor )) ) 
for node = (make-instance 'node : label 

(format nil "~S" component-flavor)) 
do (send parent :add-child node) 

(show-flavor-subtree component- flavor node))) 

We can avoid duplication by keeping a list of all the flavors seen so far, and 
using a new flavor only if it isn't already on the list. (Modifications in upper 
case.) If you want try accounting for all the vagaries of "included-flavors," 
look at the function si:compose-flavor-inclusion 

(DEFVAR *SEEN-LIST*) 



Section 7.5 Problem Set #7 159 



(defun show-flavor-tree (flavor-name) 
( start-new-tree ) 
(send *the-real-root* : set-label 

(format nil "-S" flavor-name)) 
(LET ( (*SEEN-LIST* (LIST FLAVOR-NAME))) 

(show-flavor-subtree flavor-name *the-real-root* ) ) 
(REVERSE-ALL-DESCENDANTS *THE-REAL-ROOT* ) 
(send *tree-window* : refresh)) 

(defun show-flavor-subtree (flavor-name parent) 
(loop for component-flavor 

in ( si :f lavor-depends-on 

(get flavor-name 'si: flavor)) 
UNLESS (MEMQ COMPONENT- FLAVOR *SEEN-LIST*) 
DO (LET ((node (make-instance 'node rlabel 
(format nil "~S" 

component-flavor) ) ) ) 
(PUSH COMPONENT- FLAVOR *SEEN-LIST* ) 
(send parent :add-child node) 
(show-flavor-subtree component-flavor node)))) 

This function will make nonsense of any existing space requirement info. 
Fortunately, we can be sure there won't be any, since these nodes were just 
created and have never been displayed. (We couldn't just reverse the chil- 
dren as we get to them the way we did above because then we'd keep the 
wrong node when a flavor appears more than once.) 

(DEFUN REVERSE-ALL-DESCENDANTS (NODE) 
(SEND NODE : EVAL-INSIDE-YOURSELF 

'(SETQ CHILDREN (NREVERSE CHILDREN))) 
(LOOP FOR CHILD IN (SEND NODE : CHILDREN) 

DO (REVERSE-ALL-DESCENDANTS CHILD))) 

3. (def flavor tree-window () 

( tv:f lashy-scrolling-mixin ; this was added 
tv : process-mixin 
tv: basic-mouse- sensitive-items 
tv: window) 
( :default-init-plist 

: process ' (tree-window- top-level-function) 
: item-type-alist *tree-item-type-alist* 
:blinker-p nil 
: font-map ' (fonts :hl12i )) ) 



160 THE TREE EXAMPLE Chapter 7 



(def method (tree-window : scroll-more-above) nil 
(neq *root* *the-real-root* ) ) 

(def method (tree-window : scroll-more-below) nil 
nil) 

(def method (tree-window :y-scroll-to) (ignore ignore 
(mouse-make-parent-root *root* self)) 

(def method (tree-window : scroll-bar-p) nil 
t) 

(def method (tree-window : handle-mouse-scroll ) nil 
nil) 



4. See the file "book: tape; graph &tree.lisp' 



Chapter 8 

RANDOM USEFUL TOPICS: RESOURCES & SYSTEMS 



8.1 Resources 

The documentation on resources (chapter 1 8 of volume 8) is not bad. What follows 
is primarily a condensation of it. 

In cases where a program uses and then discards large objects at a high rate, it can 
be worthwhile to do the storage management manually, rather than relying on the 
garbage collector to eventually clean up. The resource facility provides a simple 
way to do so, and is widely used throughout the system software. The Chaosnet 
code allocates and frees packets, which are moderately large, at a very high rate. 
The window system allocates and frees certain kinds of windows, which are very 
large, moderately often. Both use resources. 

For each resource defined, there is a free list kept of suitable objects. Allocating a 
resource involves checking the list of available objects and returning one if there are 
any. If not, a new one is created and returned. Deallocating a. resource involves 
returning a previously allocated object to the free list. So the storage space occu- 
pied by a deallocated object is not really freed in the sense that the garbage collec- 
tor reclaims free space; it does not become available to be used as part of any 



162 RANDOM USEFUL TOPICS: RESOURCES & SYSTEMS Chapter 8 



newly created lisp object. The original object continues to occupy the storage 
space, but may itself be reused through being allocated again. 

The four functions and macros which together compose the resource facility are 
defresource, for defining a new resource, allocate-resource, for allocating an object 
from a resource, deallocate-resource, for freeing an allocated object, and using- 
resource, which temporarily allocates an object and then deallocates it. 

A call to defresource looks like this: 

(defresource name parameters 
keyword value 
keyword value 
... ) 

name should be a symbol, which will be the name of the resource, and which will 
get a defresource property of the data object representing the resource. 
parameters is a (possibly empty) lambda-list of pseudo-arguments which will re- 
strict the objects considered suitable to some subset of those on the free list. For 
instance, a resource of 2D arrays might have two parameters, the number of rows 
and the number of columns. When allocating an object from this resource, you 
could specify how many rows and columns it should have. The free list would be 
filtered for arrays with the requested dimensions — if all the arrays on the free list 
had the wrong dimensions, a new one would be created. 

There are seven possible keyword options. Only one is required, the constructor 
option. 

constructor 

The value is either a form or the name of a function. It is responsible for 
making an object, and is used when someone tries to allocate an object and 
there are no suitable free ones. If value is a function, it is given the internal 
data structure for the resource and any supplied parameters as its argu- 
ments. If it is a form, it may access the parameters as variables. 

initializer 

Value is again either a form or the name of a function. If an initializer is 
provided, it will be called on each object as it is about to be allocated, 
whether the object was just created or is being reused. If value is a func- 
tion, its arguments will be the resource data structure, the allocated object, 
and the supplied parameters. If value is a form, it may reference the 
parameters as variables, and also the allocated object, via the variable 
object. 



Section 8.1 Resources 163 



rchecker 

A form or the name of a function. The job of the checker is to determine 
whether a given existing object is safe to allocate. If no checker is specified, 
the default action is to consider an object safe if it is not currently in use 
(i.e., has not been allocated without being deallocated). If you specify a 
checker it will be used instead. A function here will be passed arguments of 
the resource data structure, the existing object being considered for alloca- 
tion, the value of in-use-p for that object, and the supplied parameters. A 
form may reference the parameters as variables; the object under considera- 
tion, as object; and in-use-p. As you can see, the free list for a resource is a 
somewhat hypothetical object. When you ask to allocate an object, all of 
the existing objects are initially eligible. The default checker creates the 
functional equivalent of a free list by approving only those objects which are 
in fact free, but you needn't have this behavior. Supplying your own 
checker will change it. If, for instance, your checker always returned t, a 
given object could be simultaneously in use in any number of places, because 
it would always be considered safe for allocation, regardless of whether the 
previous allocater had deallocated it. And if your checker always returned 
nil, no object would be reused; every allocation request would result in the 
construction of a new object. 

matcher 

A form or the name of a function. If no matcher is specified, an object is 
considered to satisfy the supplied parameters if they are equal to the param- 
eters supplied at the time the object was constructed. If you specify a 
matcher, it will be used instead. A function here will be passed arguments 
of the resource data structure, the existing object being considered for allo- 
cation, and the supplied parameters. A form may reference the parameters 
as variables, and the object under consideration, as object. 

rfinder 

A form or the name of a function. If this option is provided, the usual 
method for finding an object to allocate will not be used. The finder will 
instead be expected to somehow come up with an object. The checker, 
matcher, and constructor will not be called, unless the finder does so expli- 
citly. A form or function specified here will see the same arguments as the 
constructor would. 

:initial-copies 

Value is a number, defaulting to 0. The specified number of objects will be 
constructed when the defresource is evaluated, thus creating an initial free 
pool of unallocated objects. If a resource has parameters and one or more 
initial copies are specified, the parameters must all be optional; the initial 
copies will have the default values of the parameters. 



164 RANDOM USEFUL TOPICS: RESOURCES & SYSTEMS Chapter 



:free-list-size 

Value is a number, defaulting to 20. It specifies the size of the array used 
to contain all the objects. (If the number of objects ever exceeds this size, 
the array is automatically replaced with a larger one.) :free-list-size is a 
misnomer, since the array contains both the free objects and the ones that 
are in use. As the earlier discussion of the : checker option pointed out, 
there isn't really any free list at all. 

For all of the options which accept a form or the name of a function, if a form is 
supplied it is compiled during the evaluation of defresource, and put on the property 
list of the name of the resource. 

allocate-resource resource -name &rest parameters 

An object is allocated from the specified resource, matching the given 
parameters. The exact procedure followed depends on which options were 
supplied to defresource for this resource. If there is a finder, it is called and 
whatever it returns is used. Otherwise the set of existing objects is searched 
for one which satisfies both the checker (by default, is not in use), and the 
matcher (by default, was constructed with parameters equal to the current 
ones) . If none are found, the constructor is called to create one. Finally, no 
matter which of the three routes yields an object, the initializer (if any) is 
called on it, and the object is marked as being in use. 

deal locate -resource resource -name object 

The object is conceptually returned to the specified resource's free-list, i.e., 
its in-use marker is turned off. 

using-resource {variable resource parameters ...) body ... 

This macro, which calls allocate-resource and deallocate-resource, is pre- 
ferred over calling those two functions directly. The body forms are 
evaluated inside a context where variable is bound to an object allocated 
from resource with the specified parameters. The object is deallocated at 
the end. An unwind-protect is used to guarantee that the object is deallo- 
cated before using-resource is exited. 

Now an example. We define a resource of 2D arrays, with parameters for the 
number of rows and columns, which default to 100 each. A matcher is provided 
which accepts any array whose dimensions are at least as great as the given param- 
eters. (The default matcher would require that the dimensions be exactly the same, 
meaning that we would very rarely reuse an object.) And an initializer fills the 
array with 0's. 



Section 8.1 Resources 165 



(defresource sloppy-2D-array (^optional (rows 100) (columns 100)) 
: constructor (make-array (list rows columns)) 
: matcher (and (^ (array-dimension-n 1 object) rows) 

(^ (array-dimension-n 2 object) columns)) 
: initializer (fillarray object '(0))) 



And to use our resource: 

(defun do-complex-computation (x y) 

(using-resource (temp-array sloppy-2D-array x y) 

(setf (aref temp-array i j) ( calculate-value i j)) 
.. .)) 

There are several other built-in functions for dealing with resources. 

deallocate-whole-resource resource-name 

Deallocates all allocated objects of the specified resource. Use with caution, 
as it can lead to allocation of objects which somebody else is still using. 

clear-resource resource-name 

Makes the resource forget about all its existing objects. Future calls to 
allocate-resource will result in creation of new objects. Useful if the 
resource has been changed so that the old objects are no longer usable, or if 
some of the old objects have been damaged. 

map-resource resource-name function &rest args 

Applies function to each object known about by the resource. The argu- 
ments to function will be: the object, the value of in-use-p for the object, 
resource-name, and any additional arguments as specified by args. 



8.2 Systems 

The system facility provides a mechanism for keeping track of multiple files which 
together make up a single program. The group of files taken together is defined to 
be a system with the defsystem macro. Loading and/or compiling some or all of 
the files in a system is accomplished via the make-system function. 

The system facility is far more complicated than the resource facility, and not 



166 RANDOM USEFUL TOPICS: RESOURCES & SYSTEMS Chapter 8 



necessarily very well-designed ("hairier than a breadbox," in the local parlance). It 
is supposed to be completely redone in a forthcoming Symbolics software release, so 
it's probably not worth your trouble to learn the more difficult features just now. 
We'll talk about some of the basic features; just enough for you to be able to use 
systems for your own programs. 

The documentation on systems is Part II of volume 4, and is also quite extensive 
but not necessarily very well-designed, so this portion of the notes will follow the 
manual less closely than the resource section did. 

Here is a typical call to defsystem: 

(def system bar 

( : pathname-default "q : >george> " ) 

(: module reader-macros "rdmac") 

(: module other-macros "macro") 

(: module main-program "main" "commands") 

( :compile-load reader-macros) 

( :compile-load other-macros (:fasload reader-macros)) 

( :compile-load main-program 

(rfasload reader-macros other-macros))) 

All four files involved are in the "george" directory on host "q." They are divided 
into three modules: reader-macros and other-macros, which consist of one file 
each, and main-program, which contains two files. The reason for this particular 
division is that it reflects the dependencies among the files, as specified in the 
: compile -load clauses. Each :compile-load clause states that the files in 
the specified module should be compiled if necessary (if the newest source file is 
more recent than the newest object file), and then loaded if necessary (if the newest 
object file is more recent than the last one to have been loaded), possibly subject to 
certain dependencies. 

The reader-macros module (file "rdmac") does not depend on any other modules. 
The other-macros module (file "macro"), on the other hand, does depend on 
reader-macros. The (rfasload reader-macros) dependency for other- 
macros means that the file(s) in reader-macros have to be loaded before those in 
other-macros may be compiled or loaded. The reason is presumably that the file(s) 
in other-macros contain calls to macros defined in reader-macros, which must be 
loaded for the calling functions in other-macros to compile correctly. The files in 
main-program are dependent on both the other two modules. Presumably they con- 
tain calls to macros defined in both reader-macros and other-macros, and so require 
that both modules be loaded before main-program may be compiled. 



Section 8.2 Systems 167 



Once the system "bar" has been defined in this manner, it can be loaded and/or 
compiled with make-system, (make-system 'bar) will load any files that need 
to be loaded, without doing any compilation. (make-system 'bar : com- 
pile) will first do any compilations that are needed, and then do any loading that 
is necessary. By default, make-system asks for confirmation before actually doing 
any compiling or loading. 

One bit of terminology: the operation of compiling or loading an individual file is 
called a transformation. So a defsystem could be seen as defining what transforma- 
tions a system is composed of, and a make-system as a command to see which of 
the transformations are necessary, and to carry them out. 

Now we'll go into some more of the various options for defsystem and make-system. 
Many will be skipped entirely. 

For defsystem: 

We've already seen rpathname-default, : module, and :compile-load. 

:component-systems 

The mechanism for including other defined systems as parts of this one. 
What follows the keyword is a list of systems. When a make-system is done 
on this system, it will also be done on each of the component systems. By 
default, the transformations for this system will be performed before the 
transformations for each of the component systems. (Yes, that seems wrong 
to me, too.) But the default ordering can be overridden. If some of the 
local transformations depend on having the component systems done first, 
you can use (: do -components nil). Put it at any position in the body 
of the defsystem, and the transformations of the component systems will be 
performed at a time corresponding to the chosen position in relation to the 
local system's : compile- load transformations. 

:package 

Specifies a package in which the transformations are to be performed, over- 
riding any package specifications in the attribute lists of the individual files. 

:patchable 

Allows the system to be patched* (incrementally updated). Appropriate for 



PATCH 

1. noun. A temporary addition to a piece of code, usually as a quick-and-dirty remedy to an 
existing BUG or MISFEATURE. A patch may or may not work, and may or may not eventu- 
ally be incorporated permanently into the program. 



168 RANDOM USEFUL TOPICS: RESOURCES & SYSTEMS Chapter 8 



large systems which are to be distributed to many users. The latest patches 
for a patchable system may be loaded with the load-patches function. 

And for make-system: 

(Recall that the :compile keyword must be specified for any compilations to occur. 
By default, only loading is done.) 

:noconfirm 

Assumes a yes answer for the questions make-system would otherwise ask 
before performing transformations. 

:print-only 

Performs no transformations at all; just prints information about which 
transformations would need to be done. 

:version 

Loads a particular version of a patchable system. There are many different 
ways to specify which version — see the documentation. 

One last issue remains with respect to systems. Since make-system only works 
after the corresponding defsystem has been evaluated, it's important to have a con- 
venient way to get the defsystem done. Knowing what file it's in and loading that 
file manually before doing a make-system for the rest is not convenient. For- 
tunately, there is something better. Whenever make-system is called on an 
unknown system, i.e., one for which a defsystem has not yet been done, make- 
system looks in a predetermined place for a file to help it out. If there is a file 
named "sys: site; system -name. system" (a logical pathname whose physical transla- 
tion depends on your site), make-system will first load that file, and then try to 
make the system. 

The file should contain either the defsystem itself, or a call to si:set-system-source- 
file, which will tell make-system what file does contain the defsystem. The two 
arguments to si:set-system-source-file are the name of the system and the file where 
the system definition may be found. If you're the only person likely to be using the 
system, another idea would be to put the call to si:set-system-source-file in your 
login init file, thus eliminating the need to put a special file in the "sys: site;" 

2. verb. To fix something temporarily; to insert a patch into a piece of code. See KLUGE 
AROUND. 

(The Hacker's Dictionary, Guy L. Steele, Jr., et at) 



Section 8.2 Systems 169 



directory. 



170 RANDOM USEFUL TOPICS: RESOURCES & SYSTEMS Chapter 8 



8.3 Problem Set #8 

Questions 

1. Find out about def window -resource. It's used many times in the file "sys: 
window; sysmen", which contains the code for the system menu. It's also 
used in the "Smiling Face" example, "sys: examples; smile". (If you have 
Release 5 documentation, you can find a description of this example, includ- 
ing a few comments on def window -resource, in WINDEX). Now think of 
some sort of window for which it would be useful to have a resource, define it 
with defwindow-resource, and use it. 

2. Look through the "sys: site;" directory. Pay close attention to the system 
definition files and the logical host definition files. (Recall that system 
definitions are by default found in "sys: site; sys -name. system''' and logical 
host definitions in "sys: site; host -name. translations" . Note also that if the 
"sys:" logical host happens to translate at your site to a UNIX system with 14 
character limit on filenames, then "sys-name.system" will be translated to 
"sys- name. sy" and "host -name. translations" to "host -name. Id".) 

Most of the system def files will probably not directly include the defsystem, 
but will have a call to si:set-system-source-file, specifying some other file as 
the system source file. Track down a few of these pointers, and examine the 
defsystems. (Keep in mind that if si:set-system-source-fiIe uses a logical 
pathname, the logical host must be defined with fs:make-logical-pathname- 
host before you can find the file.) Assure yourself that you understand how 
it is that make-system can find the defsystem for a new system. (You might 
want to look at the source code and see how make-system calls find-system- 
named, which calls maybe-reload-system-declaration, which calls make- 
system-site-file-pathname.) 



Section 8.3 Problem Set #8 171 



Solutions (roughly speaking) 

There isn't much to say about this. 

Let's consider what happens if you do (make -system 'ip-tcp) on a 
machine that so far knows nothing about "ip-tcp." Since a system named 
"ip-tcp" has not been defined, make-system will look in the "sys: site;" direc- 
tory for a file named "ip-tcp.system". At my site, the logical pathname "sys: 
site; ip-tcp.system" translates to the physical pathname "l:>sys-6> site > ip- 
tcp.system". Having found that file, make-system will load it. Here's what's 
in the file: 

;;; -*- Mode: LISP; Package: USER; Base: 10 -*- 

( f s :make-logical-pathname-host "IP-TCP" ) 

(si: set-system-source-file "IP-TCP" "IP-TCP: IP-TCP; SYSTEM") 

The second form tells make-system where to find the defsystem for ip-tcp. 
But the file is specified as a logical pathname, using host "ip-tcp," which is 
not yet defined. Thus the necessity of the first form, the fs:make-logical- 
pathname-host. Recall that this function, when given an unknown host, also 
has a specific place to look for a file to define the logical host: "sys: site; ip- 
tcp.translations". At my site again, that translates to "l:>sys-6>site>ip- 
tcp.translations". So as part of the evaluation of (fs:make-logical-pathname- 
host "ip-tcp"), that file will be (recursively) loaded. And here's what's in it: 

;;; -*- Package: USER; Base: 10; Mode: LISP -*- 

( f s : set-logical-pathname-host 
"IP-TCP" 

: physical-host "L" 
translations '(("IP-TCP;" ">sys-6>ip-tcp>" ) 

("IP-TCP; PATCH;" ">sys-6>ip-tcp>patches>" ) ) ) 

Now things begin to bottom out. This form defines the logical host "ip-tcp," 
and specifies which directories on physical host "1" (Laphroaig, one of our 
lisp machines) the logical pathnames should translate to. As the loading of 
this file is completed, the call to fs:make-logical-pathname-host will also 
return, and we continue on to the si:set-system-source-file. But now the logi- 
cal pathname "ip-tcp: ip-tcp; system" is meaningful, and translates to 
"l:>sys-6>ip-tcp> system". So make-system is now informed as to which 
file contains the defsystem for ip-tcp, and proceeds to load it. Here's what's 



172 



RANDOM USEFUL TOPICS: RESOURCES & SYSTEMS Chapter 8 



in that file: 



-*- Mode: Lisp; Package: TCP; Base 
DOD Internet Protocol support. 



10 



Symbolics' copyright notice 



(def system ip-tcp 
:name "IP-TCP") 
:maintaining-sites :scrc) 
: pathname-default " IP-TCP : IP-TCP ; " ) 
:patchable "IP-TCP: IP-TCP; PATCH;") 
: component- systems 

tcp tcp-service-paths ip-tcp-applications! 
:module chaos "chaos-unc-interf ace" ) 
: module global "ip-global") 
:module main ("ip" "ip-routing" ) ) 
:module ip-protocols ("icmp" "udp" "egp")) 
:compile-load chaos) 
:compile-load global) 

:compile-load main (:fasload global)) 
:compile-load ip-protocols (:fasload global)) 
: do -components (:fasload global))) 



. . . defsy stems for tcp, tcp-service-paths, and ip-tcp -applications . . . 

There's all kinds of stuff at the tail end of this file, which is a perfectly legiti- 
mate short-cut. We can assume that it will all be read the first time someone 
does a (make-system 'ip-tcp). But the crucial part is that this file 
must contain the defsystem for ip-tcp, which you can see above. Once the 
loading of the file is complete, make-system will continue. It now knows how 
the ip-tcp system is defined, and can proceed to load the files which compose 
the system. The filenames are all specified with ip-tcp logical pathnames, but 
that's okay since we've already defined the ip-tcp logical host. 

This sort of bootstrapping may seem awfully baroque, but notice that the 
whole mess can be transferred to some other site with a minimum of effort. 
The only line of code that would need to be changed is : physical-host 
"L" in the "sys: site; ip-tcp.translations" file. 



Chapter 9 

SIGNALING AND HANDLING CONDITIONS 



9.1 Overview 

The material for this chapter comes entirely from Part XI of volume 2 of the Sym- 
bolics documentation. 

An event is some set of circumstances a running program can detect. Some events 
are classified as errors, but not all are. Division by zero is an event which is an 
error. When an event occurs, the program reports that fact, and finds some user- 
supplied code to execute as a result. 

The reporting process is called signaling, and the user-supplied code which subse- 
quently assumes control is a handler. The system software includes default 
handlers for a standard set of events. 

The mechanism for reporting an event relies on flavors. Each class of events 
corresponds to a flavor, called a condition. Signaling is more fully described as sig- 
naling a condition, which involves creating a condition object (an instance of the 
appropriate flavor). When division by zero occurs and is signalled, the condition 
object created is an instance of the flavor sys:divide-by-zero. The instance variables 



174 SIGNALING AND HANDLING CONDITIONS Chapter 9 



of the condition object will contain information about the event, including what 
string to use if an error message becomes necessary. 

Each handler is defined to be applicable only for a particular flavor of condition 
object. It can be used only when the condition signalled is an instance of that 
flavor, or one built on it. The set of conditions a handler can handle is thus deter- 
mined by the flavor inheritance mechanism. Handlers have dynamic scope, so 
finding a handler to invoke for a given condition involves stepping through the stack 
and grabbing the first handler which is applicable to that condition. 

There are several kinds of actions a handler can take. It may instruct the program 
to continue past the point where the condition was signalled, possibly after correct- 
ing the circumstances that led to the condition being signalled. This is called 
proceeding. Or it may unwind the stack all the way to the point where the handler 
was bound, flushing the pending operations. (This behavior is essentially equivalent 
to what you'd get with a catch in place of the handler, and a throw — with the 
correct tag — in place of the signaling of the condition.) Or it may partially 
unwind the stack to some intermediate point and reexecute from there. This kind 
of handler is called a restart handler. 

There are three ways to customize the condition mechanism: 

• Defining handlers for existing flavors of conditions which may be signalled by 
the system code. 

• Signaling existing flavors of conditions within your code, which may invoke the 
system's default handlers or ones that you've written. 

• Defining new flavors of conditions. 



9.2 A Few Examples 

(condition-case () 
(// a b) 
( sys : divide-by-zero *inf inity* ) ) 

This form binds a handler for the sys:divide-by-zero condition, and evaluates ( // 
a b) in that context. If the division finishes normally, its value is returned from 
the condition-case. But if b turns out to be zero, the sys:divide-by-zero condition is 
signalled, and our handler is invoked, which simply causes the condition-case to 
return the value of the symbol * infinity*. 

(def flavor block-wrong-color () (error)) 



Section 9.2 A Few Examples 175 



(def method (block-wrong-color : report) (stream) 

(format stream "The block was of the wrong color.")) 

This defines a new error condition. (To define a condition which is not to be 
treated as an error, build it on the flavor condition rather than error.) The 
: report method is required. If your program now executes (error 'block- 
wrong-color), your new condition will be signalled. If there are no handlers 
currently bound for this condition, a default handler will cause an entry into the 
debugger and use the : report method to generate the error message. This par- 
ticular error message, however, is not terribly informative. It would be nice to 
know which block had the wrong color, and what color it had. Here: 

(def flavor block-wrong-color (block color) (error) 
: initable-instance-variables 
: gettable-instance-variables ) 

(def method (block-wrong-color : report) (stream) 
( format stream 

"The block ~S was ~S, which is the wrong color." 
block color) ) 

Now that we've added the block and color instance variables, we can do some- 
thing like 

(error 'block-wrong-color : block the-bad-block 

: color the-bad-color ) 

which will initialize the instance variable as specified, and thus allow the : report 
method to get at that information. 

Another function which may be used to signal conditions is signal. It has the same 
syntax as error, but may be used with any flavor of condition, whereas error is re- 
stricted to use with error conditions, i.e., conditions built on the flavor error (which 
is indirectly built on the base flavor condition, via the intermediate flavor 
dbg:debugger-condition) . There are two additional differences, signal allows 
handlers to proceed the condition, and error does not. (Thus error is guaranteed 
never to return to its caller.) And when called on a simple condition {i.e., one not 
built on dbg:debugger-condition, as the flavor error is) , signal returns nil if there are 
no handlers currently bound for the condition. (This is actually more a difference 
in the behavior of different flavors of condition than a difference in the behavior of 
the functions signal and error, but since error can't be used with simple conditions, 
it works as well to think of it as related to the function used.) If you signal any 



176 SIGNALING AND HANDLING CONDITIONS Chapter 9 



condition built on dbg:debugger-condition, with either signal or error, and there are 
no handlers bound for that condition, you always end up in the debugger. 

The function most frequently chosen for signaling is actually neither of these, but 
rather ferror. It's used to signal an unproceedable error when you don't particu- 
larly care which condition is utilized, (ferror eventually calls error, with a condi- 
tion flavor of ferror.) It allows you to specify a format control string and argu- 
ments to be used to construct the error message. 

The macros check-arg and check-arg-type are also very handy for signaling an 
error in case a function has been sent inappropriate arguments. 



9.3 More on Handlers 

The following is (I believe) a complete list of the macros provided for convenient 
binding of handlers: ignore-errors, condition-case, condition-case-if, condition-bind, 
condition-bind-if, condition-bind-default, condition-bind-default-if, condition-call, 
and condition-call-if. We will discuss four of the nine. 

ignore-errors body... 

This one's easy. It binds a handler which handles absolutely every kind of 
error condition (not simple conditions) and does absolutely nothing. Upon 
seeing the error, the ignore-errors form returns. There will be no indication 
that the error ever occurred (except, of course, that any code within the 
ignore-errors following the error will not have been executed), ignore-errors 
is intended to replace the older forms errset and catch-error. 

condition-case (vars...) form clauses... 

form is evaluated in a context with handlers bound as specified in clauses. 
If form returns without signaling any conditions, the condition-case also 
returns (subject to one exception — see below). If a condition is signalled, 
the clauses are checked for a handler bound for that condition. If one is 
found, the rest of that clause tells how to handle the condition. If a condi- 
tion is signalled for which the condition-case has not bound any handlers, 
the signal continues up the stack. 

Each clause is a list whose car is the name of a condition flavor (or list of 
condition flavors) and whose cdr is a list of forms to evaluate. If a condition 
is signalled matching the flavor (s) (i.e., equal to it or built on it) specified in 
a clause, the "handler" consists of executing the forms in the dynamic 
environment of the condition-case, not the environment where the signal 
occurred. That is, the stack is automatically unwound before the handler is 



Section 9.3 More on Handlers 177 



executed. As a result, the handler may not proceed the condition. While 
the handler is running, the first symbol in vars will be bound to the condition 
object. 

As a special case, the car of the last clause may be : no-error. Then if 
no condition is signalled during execution of the body, instead of returning 
form's return values, the vars will be bound to those values, the mo- 
error forms will be evaluated in that context, and condition-case will 
return whatever they return. 

This example is essentially equivalent to ( ignore-errors (do-this) ): 

(condition-case () 
(do-this) 
(error nil) ) 

And this one uses the condition object: 

(condition-case (e) 

(time rparse string) 
(time: parse-error (format error-output 

"-A, using default time instead." 
e) 
♦default-time*) ) 

condition-bind bindings body... 

Condition-bind provides similar functionality to condition-case, with the 
additional capability of proceeding from conditions. Each binding in the list 
of bindings is a list of two elements, the name of a condition flavor (or list of 
flavors), and a form which produces a handler function. The form is typi- 
cally a quoted symbol, with the symbol being given a function definition 
elsewhere. But the form may also be a lambda expression. The body con- 
sists of any number of forms. If a condition is signalled during the evalua- 
tion of the body, the bindings are searched just as with condition-case. If a 
match is found, the handler function is called with one argument, the condi- 
tion object. The handler runs in the dynamic environment in which the 
error occurred; unlike with a condition-case, the stack is not unwound. 

The handler function has three options. It may return nil to indicate that 
it doesn't wish to handle the condition after all. (The search will then con- 
tinue for a willing handler.) It may use throw to unwind the stack to some 
outer catch. Or it may proceed the condition by returning a non-nil value. 
There are several things to keep in mind if you wish to proceed a condition. 
First, the condition must be of a type which is proceedable; second, the 



178 SIGNALING AND HANDLING CONDITIONS Chapter 9 



condition must have been signalled with signal, rather than with error; and 
third, the handler should send the condition the : proceed message (with 
an appropriate argument) and return whatever values the : proceed 
method returns, because the : proceed method may decline to actually 
proceed and return nil, in which case the handler should also return nil. 

Apart from being able to proceed conditions, the other advantage of running 
in the environment where the condition was signalled is that you may exam- 
ine the stack. A handler might choose from among its three options accord- 
ing to what it finds on the stack, or it might print some message whose con- 
tents is determined by the state* of the stack. Section 63.4 ("Application: 
Handlers Examining the Stack") discusses the functions which are available 
for this purpose. 

condition -bind -default bindings body... 

Beyond the regular bound handlers, you can also define default handlers, 
with condition-bind-default. The list of current default handlers is checked 
only after all the bound handlers have declined to handle a condition. Thus 
by setting up a default handler you can allow outer bound handlers to take 
precedence over your handler, but still have your handler invoked if there 
are no appropriate bound handlers. (See chapter 65, "Default Handlers and 
Complex Modularity.") 



9.4 Restart Handlers 

There are several macros for establishing restart handlers. Here's an example 
taken from the chaosnet code: 

(defun connect (address contact-name 

^optional (window-size default-window-size) 
(timeout (* 10. 60 . ) ) 



STATE noun. 

Condition, situation. Examples: "What's the state of your latest hack?" "It's WINNING 
away." "The SYSTEM tried to read and write the disk simultaneously and got into a totally 
WEDGED state." 

A standard question is "What's your state?" which means "What are you doing?" or "What 
are you about to do?" Typical answers might be "I'm about to GRONK OUT" or "I'm 
hungry." 

Another standard question is "What's the state of the world?" meaning "What's new?" or 
"What's going on?" 

(The Hacker's Dictionary, Guy L. Steele, Jr., et at) 



Section 9.4 Restart Handlers 179 



&aux conn real-address (try 0)) 
( error-restart 

( connection-error 

"Retry connection to -A at -S with longer timeout" 
address contact-name) 
forms... ) ) 

This function evaluates forms and returns the last value if successful. But if the 
debugger assumes control as a result of a chaosreonnection-error condition during 
the evaluation, the user will be given the opportunity to restart by typing one of the 
super keys. The debugger printout will include a line that looks something like 

s-A: Retry connection to SCRC at FILE 1 with longer timeout 

If the user then types s-A the body of the error-restart will be executed again from 
the beginning. Now the full descriptions of two of the macros that may be used to 
establish restart handlers: 

error-restart {condition -flavor format -string format-args. . . ) body . . . 

This form establishes a restart handler for condition-flavor and then evalu- 
ates the body. If the handler is not invoked, error-restart returns the values 
produced by the last form in the body and the restart handler disappears. 
When the restart handler is invoked, control is thrown back to the dynamic 
environment inside the error-restart form and execution of the body starts 
all over again, condition-flavor is either a condition or a list of conditions 
that can be handled, format-string and format-args are a control string 
and a list of arguments to be passed to format to construct a meaningful 
description of what would happen if the user were to invoke the handler. 
format args are evaluated when the handler is bound. The debugger uses 
these values to create a message explaining the intent of the restart handler. 

error-restart-loop (condition -flavor format -string format - args. ..) body. . . 

Similar to error-restart, but with an infinite loop. If the handler is not 
invoked, instead of returning the body is reexecuted. (The loop may be 
exited with return.) This form is commonly used in the top-level function 
for a process, with condition-flavor being (error sys:abort). 



9.5 More on Proceeding 

Chapter 68 ("Proceeding") is a cogent five-page discussion of what is involved in 
programming proceedable errors. I recommend reading it. I will include just a few 
highlights here. 



180 SIGNALING AND HANDLING CONDITIONS Chapter 9 



For proceeding to work, two conceptual agents must agree: 

• The programmer who wrote the program that signals the condition 

• The programmer who wrote the condition-bind handler that decided to proceed 
from the condition, or else the user who told the debugger to proceed. 

The signaller signals the condition and provides a set of alternative proceed types. 
The handler chooses from among the proceed types to make execution proceed. A 
proceed type is defined by giving the condition flavor a .'proceed method. 
(: proceed methods are combined using the : case combination type, so that one 
flavor may have any number of : proceed methods, each defining a different type. 
The first argument to the method dictates which : case is to be called.) 

The body of the : proceed method can do anything it wants, generally trying to 
repair the state of things so that execution can proceed past the point at which the 
condition was signalled. It may have side-effects on the environment, and it may 
return values (which will then be returned by signal) so that the function that 
called signal can try to fix things up. Its operation is invisible to the handler; the 
signaller is free to divide the work between the function that calls signal and the 
: proceed method as it sees fit. 

Review: suppose a condition is signalled for which a handler has been bound with 
condition-bind. The handler function is called with one argument, the condition 
object, and it may throw to some tag, or return nil to decline to handle the condi- 
tion, or try to proceed the condition. To proceed, it must first determine which 
proceed types are valid for the condition object. This must be done at run-time 
because condition objects can be created that do not handle all of the proceed types 
for their condition flavor, via the :proceed-types init option, and because con- 
dition objects created with error instead of signal will have no proceed types. The 
handler may use the :proceed-types message to get a list of the available 
proceed types, or it may use the :proceed-type-p message to check a particu- 
lar candidate. Having chosen a proceed type, the handler sends the condition 
object a : proceed message with one or more arguments. The first argument is 
the proceed type, and the rest are the arguments for that proceed type. Sending 
the : proceed message should be the last thing the handler does. It should then 
return immediately, propagating the values from the : proceed method back to 
its caller. Determining the meaning of the returned values is the business of the 
signaller only; the handler should not look at or do anything with these values. 

The signal-proceed-case macro provides a convenient way to signal a proceedable 
condition, choose which of the defined proceed types for that flavor of condition 
should be considered available to the handlers, and specify separate actions to take 



Section 9.5 More on Proceeding 181 



for each of the proceed types (after the : proceed method returns). 



Chapter 10 

THE MOVING ICONS EXAMPLE 



The original version of the moving icons example was put together by Ken Church 
for a class he taught in 1984. I've made some cosmetic modifications, and updated 
it to take advantage of some more recently written support software. The basic 
idea is that you have a frame split into two panes: a command menu of icons the 
user may "pick up" with the mouse, and an initially empty pane where the user 
may drop icons that have been picked up. 

As before, if your site has loaded the tape that comes with the book, do Load 
System moving-icons [or (make-system ' moving- i cons )] to load the 
code. But this time, to make a frame and start the action, get the system menu 
and click on Moving Icons at the lower right. Click left over one of the icons to 
pick it up, move the mouse over the main pane, and drop the icon by clicking left 
again. 



10.1 General 

It's my impression that there are four concepts in this short piece of code which are 
new: using Zmacs-style command tables ("comtabs"), pop-up mini-buffers, 



184 THE MOVING ICONS EXAMPLE Chapter 10 



typeout windows, and changing the appearance of the mouse blinker. Most of the 
dirty work involved in getting the first three to work is taken care of by the "corn- 
tab" system (locally written software which both Ken and I have worked on). The 
zwei:window-with-comtab flavor captures most of the fruits of this work, and is 
itself quite easy to use. Another portion of the support code redefines many inter- 
nal editor functions for reading typein from the mini-buffer to also work outside the 
editor, with pop-up mini-buffers. 

A comtab associates characters with functions, so that whenever a certain key is 
pressed the corresponding function is called. In the editor, for instance. #\c-F is 
bound to the function corn-forward, which moves the cursor forward. ("Charac- 
ters" includes mouse characters, so functions may also be bound to particular 
mouse clicks.) In addition to single key commands, a comtab may include 
extended commands. These are accessible via Meta-X. You then type in the full 
name of a command to a mini-buffer. (Completion is active, so you frequently 
need only to type a few characters.) If you're in the editor proper, the permanent 
mini-buffer at the bottom of the screen is used. If you're using the window-with- 
comtab, a temporary mini-buffer pops up. 

The window-with-comtab flavor has a comtab instance variable, and also includes 
the flavor tv:process-mixin. The top-level function for the process is a loop which 
reads characters and looks them up in the window's own comtab, calling the func- 
tions that are found. (It also does something appropriate if it sees a blip instead of 
a character.) All you need do is define the functions and put them in the comtab. 
By copying so closely the mechanism used by the editor, we are able to use many of 
the editor functions without change (or with small changes), most notably the on- 
line documentation features. The Help key is active in any window built on 
window-with-comtab, providing various functions for finding out about the currently 
defined commands. And a number of extended commands have also been brought 
over from the editor, including Edit Key, Edit Extended Command, Lookup Key 
Bindings, Describe Key Bindings, Set Variable, and List Variables. 

Any window built on window-with-comtab will also have a typeout window associ- 
ated with it. Just as in the editor, if you hit the Suspend key, the typeout window 
will become exposed, and you will enter a break loop, so that you may type arbi- 
trary lisp forms to be evaluated. 

Let's take a look at the code now. 



Section 10. 1 General 185 



10.2 moving-icons-frame 

We have two panes, the command menu and the main pane. The frame is a bor- 
dered constraint frame with shared io-buffer, so that the process running in the 
main pane will see the blips from the command menu. The only new stuff is in the 
default-init-plist specified for the menu. The most interesting is the specified value 
for : item-list. As in the tree example of three weeks ago, we've used the 
"general" item type. Each element of the list, corresponding to one item in the 
menu, is a list of five elements. The first is the string which will be printed to 
display the item in the menu. As you can see from the form of the loop, the string 
will be one character long for every item, with the character code ranging from to 
127. Since each item is of type :eval, the effect of executing an item will be to 
evaluate the form following the :eval keyword. And the form sends the main 
pane the : pick-up- icon message, with an argument of the item's character 
code. (It helps to know that the window-with-comtab code takes care of binding 
the variable zwei:*window-with-comtab* to the object which has the window-with- 
comtab mixin, in this case the main pane.) So if I choose the item in the upper left 
corner of the menu, the main pane will receive a : pick-up-icon message with 
an argument of 0. 

The :rows init spec instructs the menu to display its 128 items in 4 rows of 32 
each, implying that it must do some horizontal spreading. And the : default- 
font spec is crucial. Since the items are really just one-character strings, the way 
they appear depends on what font the menu uses for printing them. By default, 
command menus use a standard variable-width alphabetic font called jess 14. But 
we've specified the font named mouse, which happens to contain many of the char- 
acters which are used for the mouse blinker in various situations. You could use 
any other font — either an existing one or one of your own creation — by changing 
the : default-font spec (or by sending the : set-icon-font message, which 
is done by Meta-X Set Icon Font). You can read about using fonts in section 12.7 
of volume 7. See also the Zmacs commands Meta-X List Fonts and Meta-X 
Display Font. For modifying a font or creating a new one, use the Font Editor, 
which is described in Part II of volume 3. 



10.3 moving-icons-main-pane 

This flavor is built on zwekwindow-with-comtab, with tv:pane-no-mouse-select-mixin 
added, to make it a pane, and one which will not confuse the select menu. An 
instance variable keeps track of the current icon. The default-init-plist specifies 
what comtab to use (*icon-comtab* is defined at the end of the file) and what font 
the window should print with. This font obviously needs to match the font of the 



186 THE MOVING ICONS EXAMPLE Chapter 10 



command menu. 

The first two methods are quite simple. The : set-icon-font method sets the 
default font of the command menu (which causes it to redisplay all the items in the 
new font) and sets the window's own font-map to match (which affects only subse- 
quent typeout — the current display is left alone). The : pick-up- icon mes- 
sage, recall, is sent when a menu item is executed. The method sets the icon- 
character instance variable, and sends the window the : mouse-standard- 
blinker message, which we'll see has the effect of making the mouse blinker look 
like the item which was just chosen. 



10.4 Messing with the mouse blinker 

The easiest way to alter the appearance of the mouse blinker (though not the way 
we do it in this example) is with the function tv:mouse-set-blinker. It has one 
required argument — a keyword symbol — and two optional ones. The keyword 
tells what sort of blinker to switch to, and the system must already have been told 
how to get a blinker of that type. Teaching the system about new types of blinkers 
is not difficult, but it's also not necessary in this case, so we don't need to go into it. 
The reason it's not necessary is that there's already a kind of blinker which is 
sufficiently flexible for our needs, and that is the : character blinker. 

This sort of blinker has two instance variables, one specifying a font to use and one 
a character code. The blinker draws itself as the given character in the given font. 
So by adjusting the values of the instance variables, a single blinker can be made to 
look like any character in any defined font. This is exactly the reason for the 
existence of the "mouse" font; most of the various mouse blinkers you're used to 
seeing are actually the same : character blinker, set to varying characters in the 
mouse font. 

And finally we come to the function tv:mouse-set-blinker-definition, which is what 
the example uses in place of tv:mouse-set-blinker. The former takes several addi- 
tional arguments, which allow you to send an arbitrary message to the "new" 
blinker (which may really be the same object as the old blinker). The message we 
send is : set-character, which takes two arguments, the new character code, 
and (optionally) the font to use. In our case the character is the value of the 
instance variable icon-character, which will have been set by the : pick-up- icon 
method, and the font is the main pane's current font (accessed via the instance 
variable tv: current-font), which we have been careful to make sure is always 
the same as the menu's font. For a slightly different effect, type this at a lisp 
listener: 



Section 10.4 Messing with the mouse blinker 187 



(tv: mouse-set-blinker-definition : character t : set-character 
#\M ' fonts :43vxms) 

The second and third arguments to tv:mouse-set -blinker-definition specify the jc- 
offset and y -offset for the blinker. By default, the offsets are 0, meaning that the 
blinker draws itself with its upper left corner at the actual mouse position. Often 
you would rather the blinker position itself differently, perhaps with its center over 
the real mouse position. That's when you need to set non-zero offsets. In the 
example, we use whatever offsets the previous blinker had, to minimize any 
apparent motion of the mouse as we switch blinkers. And if you glance down at 
the : drop-icon method you'll see we need to adjust for the offsets again when 
drawing the icon on the main pane, so that the icon is placed exactly under where 
the mouse appears to be. 

But let's return to the : mouse- standard-blinker method. Why did I make 
the : pick-up- icon method call this one to change the mouse blinker, instead of 
just including the multiple-value-bind form directly in : pick-up-icon? And 
why does : mouse-standard-blinker test whether icon-character has a 
non-nil value when : pick-up-icon will have just given it one? The answer to 
both questions is that the mouse process will occasionally be sending our window 
the : mouse-standard-blinker message, and I want to do something 
appropriate then as well as when : pick-up-icon sends the message. Exactly 
when the mouse process sends : mouse-standard-blinker is difficult to 
explain, but a reasonable approximation is that it will happen whenever the mouse 
crosses into the window. There is a default handler for : mouse- standard- 
blinker, which our window would have inherited, and its action is simply to pass 
the same message up to the window's superior. (If all of the window's superiors 
also follow the default route of passing the message up, it will eventually reach 
tv: main- screen, which will restore the blinker to the familiar NNW arrow seen 
in a lisp listener.) But our method supersedes the default one. If there is no 
current icon-character, ours behaves just like the default; if there is an icon- 
character, ours makes the mouse blinker look like the icon. Had I put the 
tv:mouse-set-blinker-definition in : pick-up-icon and kept the default method 
for : mouse-standard-blinker, we would have lost the special appearance of 
the mouse blinker every time it crossed into the main pane, including the manda- 
tory first trip down from the command menu. 



10.5 The :drop-icon method 

Dropping the icon involves setting the cursor position to the correct spot, outputting 
the character, resetting the icon-character instance variable, and restoring the 



188 THE MOVING ICONS EXAMPLE Chapter 10 



mouse blinker to its usual form. The only tricky step is setting the cursor position 
— the mouse position will be provided in terms of outside coordinates. These must 
be converted to inside coordinates by subtracting the margin widths, and then 
corrected for the blinker offsets. 



10.6 Setting up the comtab 

The way to define a command is with the defcom macro (in the zwei package). 
The first argument is the name of the command, which should begin with "com-". 
Then there's a documentation string, which the help key will know how to get at. 
The third argument is a list of options which are not relevant outside the editor. 
The rest is the body of the command. Note that there is no "argument list"; func- 
tions defined with defcom are intended to look for their arguments as the value of 
zwei:*numeric-arg*. Recall that "arguments" to editor functions are numbers, 
struck with the control or meta keys down before the main command character is 
pressed. The effect of the numeric control keys is to bind *numeric-arg* appropri- 
ately. 

Executing a defcom just defines a function and adds the name of the command and 
its documentation to a list of all commands, but does not make the command 
usable — it is not included in any comtab. What puts the command into a comtab 
is the zwei:set -comtab function, set-comtab adds a list of character-command pairs 
(its second argument) to an existing comtab (the first arg) . The third argument, if 
present, is a list of extended commands, i.e., commands that will be accessible via 
Meta-X. The list should be created with zwei:make-command-alist and may be 
appended with the extended command list of some other comtab. A single com- 
mand may appear in a comtab any number of times, paired with different charac- 
ters and/or as an extended command. And it may simultaneously appear in any 
number of different comtabs. 

The function zweirset-comtab-indirection may be used to cause inheritance from 
another comtab. Any characters not found in the current comtab will be looked up 
in the second one. In particular, we need to inherit from *basic-comtab* (the one 
defined with window-with-comtab) the numeric argument commands and the help 
functions. 



10.7 Getting in the System Menu 

The last form in the file is what puts "Moving Icons" in the rightmost column of 
the system menu. The function tv:add-to-system-menu-programs-column takes 



Section 10.7 Getting in the System Menu 189 



three arguments. The first, a string, is what you want to appear in the menu. The 
second is a form to be evaluated should your item be chosen from the menu. This 
is usually a call to the function tv:select-or-create-window-of-flavor, with the one 
argument being the flavor of window you want created. Finally there's a documen- 
tation string, which appears in the mouse documentation line whenever the mouse is 
over your item in the system menu. 



10.8 The Program 



190 



THE MOVING ICONS EXAMPLE 



Chapter 10 







Section 10.8 The Program 191 



d 5?« fl-9 * -a 

o) -h = e C > H «, 

2 N " 8 B » " S3 

C --* >— fl 1 •• — Q) 0> 

m u en* <u 3 "O 

•§ iS -H rH 3 O C <1> O U 



O P gHH S ° ° ° i 6 CO 

1 I 2 L£3 ti3s 3 is: 852*3 e 

& i § * - 5 a S >~ g 2 2 8 * > * 

2 •? Hss as » 13?l§? 



£ 



O 0) o ^- -^ .0 3 

+J 5 «S -P «« 

0) C i-l +J 0) 

B . . iw <D T> 

<W > 4-1 01 •• 

0) +J (U •• ~ 



192 



THE MOVING ICONS EXAMPLE 



Chapter 10 






































Pi 




























4-1 
1 
















s 




























P 
















Pi 




























C 
















o 




























CU 
















•H 




























p 
















P 




























p 
















■iH 













































CO — > 




























u 
















R7 
























^ 




> 








--» 








>^ 
























CO 




p 








CO ^ 








<D 1 
























p 












p "- — 








CO CU 










^^ 














0) 




p 








0) 0) — 








S CO 


H 






•— » 


JJ 














CO 




cu 








CO N 0) 








Pi 


■H 








c 














4-1 




p 








4-1 -H N 








E O 


C 






En 


o 














4-1 




u 








4-1 CO -H 








E 








z 


4H 

1 

















P 


03 
U 








O 1 CO 








cu * 

Xi •• 


3 






r O — 
CO Cu — 


> 


















03 




--» 




•H Pi 








P -H 


c 






Eh » — 


v 










iH 




P 


4-1 


X! 




>> 




P Ol-rl 








cu 


<D 






2 -* 


c 










■rl 




0) 


4-1 



U 




cu 




l> P Cn 
M 03 P 








P s 

id n 


E 






O — -» 
fa X ~ 


p p 














c 




C 




(0 




Pi E <g 










C 






s --» 


c c 














•H 


>> o 









■H 1 E 








- * 









J X 


o 










p 




rH 




O 









rH P 1 








* X 


o 






Z ^ 


4H <w 
1 1 










a) 




XI 


4-1 
4-1 


■H 




6 




xi 4h a 

1 0) 








Pi 1 

id cu 


•H 






H > i-i 

w <d 


5 P 




c 






a 




cu 





P 




X 




(1) rH P 








(0 


CU 






w 2 > 


0) r-l 




o 






■H 




CO 




0) 




I 




10 •• •• 








4H Pi 


X! 






J >H cu 


C 3 




u 






rH 







X 


P 




0) 




PI > > 








•h g 


P 






OWE 
S ~ ^ 


— o3 




•H 






X) 









U 




(0 




P P 








E 








4H 










1 




E 


u 


03 









E 








•> * 


4H 




p< 


S co 


— > Q) 










■d 






cu 


P 









•• 4H 4H 








Pi •• 







w 


tM P4 — 


p tj 




,-» 






P 




> 


p 


03 


»-» 


E 




> 4H 4H 








-H 






fu 


CO w 


c I 




c 






03 




P 


u 


XJ 








POO 








u cu 


P 


P 


fn 


1 (U — 


O P 




o 






■0 






03 


O 


p 






1 1 








•H S 


Pi 


PI 


& 


a >i x 


4-1 0) 




o 






C 




T3 


u 


1 


ID 


»-» 




-O X >> 








N 








PQ 


W Eh 


1 10 




■H 






id 




C 


03 


P 


M 


Pi 




Pi 








P 


4H 


4-1 




w — < 


C •• 


_ 








■P 




(1) 


Xi 


CU 


3 







cu x >, 








Pi Pi 




1 


H 


o 




a 






CO 




CO 


u 


to 


•H 


o 




CO 1 1 








0) 


CU 


PI 


Z 


o *-+ 




3 






i 










<-i 


•H 




_- CU 0) 








P O 


XI 





H 


Eh X 2 


•H 


+J 


i 






(V 










XI 


1 




CO CO 






--» 


P -H 


P 


o 


S 


2 Cu 


1 C 


c 


x 






CO 




«-~ 


a 






a 




— pj pt 






p 


* JL 




•rl 


1 


H CU 1 


4j a) 





u 











4-1 


o 




T3 







4H 






0) 


o a 


CO 


1 


S 


1 Q Eh 


<D e 


4-1 


■H 











4-1 


•rl 




P 


p 




4H E E 






M 





cu 


P 


o 


J 2 W 


(0 » 


1 


a 






E 







P 




03 


•o 




o 






Pi 


CU P 


tr 0) 


« 


< t> o 




? 






p 








•H 




TJ 








P 




•H 


X! TJ 


Pi 


CO 


h 


yo- 


V 


0) 






0) 






>t c 




C 






>,— ~ 


CU 




rH 


p •• 


03 




i 


o m 


V c 


c 


CU 




M 


0) 






•H 




03 


CU 






p 




XI 




XI 




9 


►J '-' CO 


C id 




c 




C 


a 




4-1 


4-1 




P 


c 




4-1 CO 







1 


CO * 


u 


* 


2 


(0 O, 4-1 


(0 




■H 


id 




4-1 


CU 




CO 


03 


a 4-i o 


03 




x> 


a xi 




XI 


w 


O X o 


Q, 1 


CO 


a 




rH 


a 




X) 




1 


a 


CU 


o a 


P 


»-« 


p 


o id 




03 


Pi 


2 U 


1 p 


-rl 






XI 


i 




1 


1 




CU 




cu 


1 u 


03 


rH 


id 


p p 


p 


P 




HP — 


C CD 


tH 


c 




1 


f: 




X 


p 




CO 


c 


XI 


X 


Xi 


■H 


X) 


Q E 


g 


E O 


S^EH 


•H D> 




•H 




T) 


■H 






cu 




53 


•H 




— CO 


U 


Pi 


Pi 


= 


o 





z 


<d •• 




03 


a 


P 


03 






* 







flj 




u 






<d 


o 


4-1 


u 


H 


— U 


S 


a 


6 


o 


03 


6 




XI 


c 




E 


6 


^~ 


X) pi 


Pi 


p 


P 


S I 


1 


1 


En 


= X w 


1 u 


03 




O Tl 


i 




c 


■H 






i 


p 


Pi o 





cu 


CO 


Xi 


Pi X! 


W 


2 J 


co o 


a 


CO 


•H 


c 


CO 




•H 


r-i 






CO 


cu 


•H 1 


u 


p 


i 


O P 





p 


J 


P P< W J 


C -H 


i 


c 




03 


Pi 




X) X) 




P 


a 


p 


Xt P 


•H 


u 


V 


•H -rH 


CJ 


•H 


a. 


c o a o 


O P 


p 





u 


P 







1 


1 




O 





u 


1 0) 




03 


to 


r. S 


•H 


? 


2 


o fa s u 


o a> 


c 


u 


CU 


CO 


O 




cu 


P 




■H 


o 


03 


0) CO 





p 


p» 


a i 


1 


1 


O 


fa 


•h a 





•H 


P 




•H 


p 


3 


CU 




P 


■H 


P 


pi •• 


>, 03 





o ? 


P 


£ U 


fa 


i 3 


4-1 




o 


a) 




CD 


rH 


CO 




CU 


1 


03 


rH 


P 


45 


E 


P 


CU 







? 2 


&> to 




C7> 


ifl 


CO 


&> P 


03 


1 




a 


Cn X! 


0) 4H 




o 




XI XI 


CO 


X) 


•H 


cu O 


Pi •• 


P 


C 


u 





Pi 


U 


> 


cu 




n 


Pi 


O 


> rH 




1 




L c 


1 


c 


CU 


2 J 


•H > 


<D 


•H 


03 





•H 


03 


1 


CO 




CO 


•H 


1 


1 0) 


4H 


PI 


4H 


i "d 


E 


•H 


5 




> P 


CO 


> X! 


E 


> 


P 


0) 









> 


C 


0) CO 


r-{ 





r-t 


o » 





s 


N 












o 







03 


rH 







> 





o 


rH 


0) 


o 


<U 


o * 


u 


* 






E TJ 




e 


1 




exi 


a e 




p 


E 


o 


ax» 


CO 


•H 


CO 












— c 


4-1 




c 


4-1 




U 


•H 










•H 


•rl Pi 








I " H 


E 


•H 


P 




0) 


r-l 







rH 






P 


> 




T3 






P CU 


X) 


tr xi 


0) 





0) 


XI 




xi co 


CD 


xs 


u 


(1) 


n 


C 


H 


p 




fl 


•O 


P 


rH CO 


C 


p 


Pi 


O S 


u 


> 


U 




-— 


CO 





•H 


CO 








3 






CU 








Pi — 


cu 


cu 


0) 


4H N 


4H 


N 






X! 




Xi 






X) 


u 


E 






CO 


X! 


c 


e 


CO 


CO 


CO 


CU 


CU 








P XI Xl 


p 


crx» 


+j 


•H 








— 


P 


^-- 




— » 


— - 


"— 


XI XI 


XI 


XI 






<D C 


c 


CU 


-p 


a 


CD 












CU 












•• Pi 




PI 






E 0) 


cu 


e 


CU 


0) 


a 


4-1 










E 


4-1 










•rl CU 


■H 


CU 






<4-l CO 


CO 


4-1 


CO 


CO 


4-1 


■H 










4-1 


■H 










CU CO 


CU 


CO 






CD — 




0) 






0) 












tt) 












> — 


£ 








T3 




T3 






xi 












•o 












N 


N 









Section 10.8 The Program 193 



XX 














Ifl 














e 














■o 














a 



























s 


o ^ 






*-+ 




















3 


to * 












a 


C Xi 






p 






^ 0) 


O fl 






c 






j) a 


O P 













a 


h a 






<4-l 






fl <0 









1 






p _ 


Oi o 






c 






«w a 


C I 













I 


•H O 






o 






01 P 


> -H 






■H 






C m 


01 






1 









£ IT) 






p 






U co 


= A 






tt) 






■H C 


* 






01 






I 


XI •• 






1 






Oi o 


fl -H 






a 






C -H 


P tt) 













•H 


B ? 




*-« 


o 






> Xi 


N 




c 








O P 


O 







v 






6 -d 


1 * 













» £ 


4) £1 




•H 


p 








co nS 




1 


01 






p tt) 


P P 




ft 


■H 






P 


to e 







rH 


g 




> 


ft 




1-1 


id 


g 




HJ p 


CO o 

1 1 




1 


13 


iH 




rH O 
<4-l -H 


tt) G 




e 


A 







1 ft 


P O 







HJ 


o 




«H 


<c o 







I 


1 




O (0 


tt) -H 






CO 




1 


p * 


* 


T— 


O 


a 




> D> 


o 


Xi 


| 


o 


<tj 




O C 


•• c 


a 


r-\ 


1 


p 




T3 -H 


•H 


p 


1 


0) 


o> 




C S 


tt) -H 


B 


tt) ^ 







•H fl 


> -P 


O 


CO 


s 


u 




> P 


N O 


u 


53 


ft 




1 X) 


~ tt) 




O 








tt) 


P 


a 


e 


•H 


3 




P P 


* -H 





/ 


tt) 


c 




(0 


A X) 


o 


% 


s 


0) 




tt) <+-! 


fl C 


•H 




N 


a 




p 


P -H 


* 






i 




o s 


a i 








a 




I 


O Xi 


£1 






tt> 


z 


P -0 


O fl 


fl 






p 


0) 


c 


i -p 


P 






0) 


c 


1 -H 


C g 


B 






^ 





P s 





O 






01 





o 


o o 


u 








H 


0) fl 


•H 1 


1 






O 




iH 


* p 


p 






P 


Cr 


tt) p 


0) 


tt) 








n 


CO o 


P W 


0) 






•o 


■H 


.. 0) 


(d •• 








•o 


> 


> -H 


> -H 


■H 






10 





P tt) 


<4-l tt) 


<D 








s 


^ CO 


tt) > 


s 






> 


r 


X E 


■O N 


N 






p 







194 THE MOVING ICONS EXAMPLE Chapter 10 



10.9 Problem Set #9 

Questions 

1. Make it possible to individually erase icons that have been drawn on the 
main pane. (I think the best way to do so would be to use the mouse sensi- 
tive items facility. You might also try doing it on your own, without mouse 
sensitive items. That would probably entail duplicating some of the ms-item 
stuff, but the limited functionality required here shouldn't involve too much 
duplication.) 

2. If you've chosen the mouse sensitive item route for (1), add some more func- 
tions to the menu. For example, one option might ask for a keystroke then 
change the icon to the one corresponding to that character code (in the same 
font) . Another might prompt for the name of a font then redraw the icon in 
that font (with the same character code) . 

3. In an earlier version of the window-with-comtab support code, the typeout 
window didn't restore the image of the window underneath it upon being 
deexposed. The main pane therefore needed to be able to regenerate the pic- 
ture. Though it's no longer strictly necessary to have such a : redisplay 
method, it's still a good exercise.* Your solution to (1) should give you some 
way of knowing what icons are currently displayed and where. Use this 
knowledge to write the : redisplay method — it should do a : clear- 
window and then redraw the current icons. While you're at it, make the 
: redisplay method accessible through the comtab, via #\c-L and 
#\ref resh. 



Sorry for resorting to such a pedantic rationale. I didn't plan it this way, but at the last minute I 
ruined what had been a perfectly good problem through my own industrious improvements to the 
comtab code. 



Section 10.9 Problem Set #9 195 



Hints 

Don't forget to put your code in the "icons" package! 

1. Adding mouse-sensitivity involves the following steps: mix tv:basic-mouse- 
sensitive-items into moving-icons-main-pane; make an item type alist with 
tv:add-typeout-item-type, and put it on main-pane's default plist; write the 
function(s) to be called when an item is chosen; and alter the : drop-icon 
method to use the : item or : primitive-item messages. (Processing 
the blip and calling the indicated function will be taken care of by the 
window-with-comtab mixin; your function will be called with one argument, 
the item.) 

To erase the icon, draw over it in xor mode. It's probably easiest to use the 
.-draw- char message. Since the icons themselves are just character codes, 
and don't contain information about their screen position, you'll probably 
want your mouse-sensitive items to actually be some sort of data structure 
containing the x and y coordinates as well as the character itself. 

2. Erase the icon as in (1), then redraw it with the new character or font. 
: draw- char is probably the easiest way again. 

3. Assuming again that you've chosen the mouse-sensitive-items route, you'll 
need to get at the list of current items in order to redraw each of them. The 
list is the value of the instance variable tv.item-list. (Remember to grab the 
list before doing the : clear-window, because the : clear-window will 
set the list to nil.) 



196 THE MOVING ICONS EXAMPLE Chapter 10 



Solutions 

1 . The structure representing the item is a list of the character code, the current 
font, and the x and y coordinates. The advantage of including the font is 
that if Meta-X Set Icon Font is done, we can still properly erase old icons in 
the original font. 

( def flavor moving-icons-main-pane 
( ( icon-character nil ) ) 
(tv:pane-no-mouse-select-mixin 

tv: basic-mouse-sensitive- items new 

zwei : window-with-comtab ) 
: settable-instance-variables 
( :default-init-plist :comtab *icon-comtab* 

: item-type-alist *icon-item-type-alist* 
: font-map '( fonts : mouse) \new 

:blinker-p nil 
:save-bits t ) ) 

(defvar *icon-item-type-alist* nil) 

(tvradd-typeout- item- type *icon-item-type-alist* : icon "Erase" 

erase-icon t "Erase this icon.") 

(def method { moving-icons-main-pane : drop-icon) 
( mouse -x mouse-y) 
(if (not icon-character) (beep) 

(multiple-value-bind (x-off y-off) 
(send tv: mouse-blinker : offsets) 
(send self : draw-icon 

(list icon-character tv: current-font 

(- mouse-x x-off tv: left-margin-size) 
(- mouse-y y-off tv: top-margin-size) ) 
:add)) 
(setq icon-character nil) 
(send self : mouse-standard-blinker )) ) 

(defmethod (moving-icons-main-pane :draw-icon) 
(char-info item-action) 
(destructuring-bind (char font x y) char-info 
(send self : draw-char font char x y tv:alu-xor) 
(selectq item-action 






Section 10.9 Problem Set #9 197 



(:add (send self .'primitive-item 
:icon char-info x y 

(+ x (send self : character-width char font)) 
(+ y (font-char-height font) 
(send self :vsp) ) ) ) 
(: delete (setq tv:item-list 

(del #' (lambda (item list) 

(eq item (second list))) 
char-info tv: item-list ) ) ) ) ) ) 

(defun erase-icon (char-info) 
(send zwei : *window-with-comtab* 

: draw-icon char-info : delete)) 

( tv : add- typeout- item- type 

♦icon-item-type-alist* : icon "Change Character" 

change-icon-char nil 

"Replace this icon with a different character.") 

(defun change-icon-char (char-info) 
(let ((new-char (read-single-char))) 
(process-sleep 30) 

When the typeout window is deexposed, it restores the window 
underneath to how it was when the typeout window was first 
exposed, so if we leave the typeout window exposed while we change 
the display, our changes will be lost when it does get deexposed. 
(send zwei : *typeout-window* rdeexpose) 
( send zwei : *window-with-comtab* 

: draw-icon char-info : delete) 
(setf (first char-info) new-char) 
(send zwei : *window-with-comtab* 

:draw-icon char-info :add))) 

(defun read-single-char nil this is borrowed from the code 

zwei : ( LET ( CHAR ) for Help-C (com -self- document) 

(TYPEIN-LINE "New char: ") 
(SETQ CHAR (TYPEIN-LINE-ACTIVATE 

(EDITOR-INPUT :MOUSE :RETURN) ) ) 
(TYPEIN-LINE-MORE "~:(5>C" CHAR) 
char ) ) 

( tv : add- typeout- item- type 

♦icon-item-type-alist* :icon "Change Font" change-icon-font 



198 THE MOVING ICONS EXAMPLE Chapter 10 



nil "Redraw this character in a different font.") 

(defun change-icon-font (char-info) 

(let ( (new- font (read-font-f rom-mini-buf f er ) ) ) 
(send zwei : *window-with-comtab* 

: draw-icon char-info : delete) 
(setf (second char-info) new-font) 
(send zwei: *window-with-comtab* 

: draw-icon char-info :add) ) ) 

where ( read-f ont-f rom-mini-buf fer) is the body of com -set -icon - 
font starting at ( cdr . . . ) , and com-set-icon-font should be changed to 
call read-font... 

3. In addition to the redisplay, I've also thrown in a com-clear-window to 
remove all the current icons. 

(defmethod (moving-icons-main-pane :redisplay) nil 
(let ((old-item-list tv: item-list ) ) 
(send self : clear-window) 
(loop for (nil item) in old-item-list 

do (send zwei : *window-with-comtab* 
:draw-icon item :add)))) 

( zwei : def com com-redisplay 

"Regenerates display from current dropped icons" 
nil 
( send zwei : *window-with-comtab* : redisplay) ) 

(zwei: def com com-clear-window 

"Removes all dropped icons from the window" nil 
(send zwei : *window-with-comtab* : clear-window) ) 

(zwei:set-comtab *icon-comtab* 

'(#\c-L com-redisplay 
#\refresh com-redisplay 
#\clear-input com-clear-window) ) 



Chapter 11 

MORE ADVANCED USE OF THE EDITOR 



The standard Zmacs commands are generally quite well documented by the on-line 
help facilities. So there should be no difficulty in becoming fluent in the use of the 
built-in commands simply by consulting the automatic documentation. Or, if you 
prefer, many of the more common built-in commands are described on paper, in 
Part I of volume 4. 

The methods for adding new commands, on the other hand, are not documented so 
completely. It is upon that topic that this class will concentrate. 



11.1 Keyboard Macros 

keyboard macros allow you to bundle up any number of keystrokes and execute 
them all with one keystroke. (These actually are documented, but since they fit in 
with the rest of today's chapter, I thought we should look at them as well.) The 
Zmacs command "c-X (" starts a keyboard macro. Whatever keys you press 
from then up until you type a "c-X )" are remembered while they are executed. 
When you type the c-X ) the macro will be defined. It can be re-executed by 
typing c-X E. The effect will be as though you had typed all the keystrokes in 



200 MORE ADVANCED USE OF THE EDITOR Chapter 11 



the macro definition (but faster). Giving a numeric argument to c-X E will cause 
the macro to be repeated that many times. 

c-X E always executes the most recently defined macro, so if you define another 
macro with c-X (, the definition of the first one will be lost, unless you have pre- 
viously saved it somehow. One way of saving a macro is to give it a name, with 
M-x Name Last Kbd Macro. Once a macro has been named, you can install it on 
a key with M-x Install Macro. The name of the macro and the keystroke on which 
to install it will be prompted for in the mini-buffer. From then on (until you dein- 
stall the macro, or install some other command on the same key), typing that key- 
stroke will execute the macro. When M-x Install Macro asks for the name of the 
macro to install, if you just type a carriage return instead of the name of a macro, 
the one most recently defined will be installed on the specified key. It's therefore 
unnecessary to ever name your macros, as long as you install them before defining 
another. 

Here's a simple example, something which I often did while working on the early 
versions of these lectures, in the troff text formatter. I'll define a keyboard macro 
for inserting the troff directives for switching to an italic font and back, and install 
it on super-I. 

c-x ( start keyboard macro definition 

\f i\f p insert the text 

c-B c-B c-B move the cursor back to the correct position for inserting 

italic text 
c-x ) end macro definition 

M-x install Macro [prompted with "Name of macro to install (CR for last 

macro defined):"] 
<return> [prompted with "Key to get it:"] 

s-i [menu pops up for choosing which comtab to use] 

<click on Zmacs> 

The next step, one which I've been too lazy to ever take, but really should, would 
be to put something in my login init file to automatically define this keyboard 
macro every time I login. As things stand, I have to run through the above 
sequence of commands whenever I start writing a text file (unless the machine 
hasn't been booted since the last time I defined the macro). The way to define a 
keyboard macro in lisp code is with the function zwekdefine-keyboard-macro. The 
first argument is the name the macro will have, the second (usually nil) indicates a 
repeat count, and the rest are the character codes for the keystrokes. Once the 
macro has been defined, you can insert it into a comtab. So if I weren't so lazy, I 
would add this to my init file: 



Section 11.1 Keyboard Macros 201 



(zwei: DEFINE -KEYBOARD -MACRO italic-font (nil) 
#\\ #\f #\I #\\ #\f #\P #\c-B #\c-B #\c-B) 

(zwei : command- store ( zwei : make-macro-command : italic-font ) 
#\s-I 
zwei : *zmacs-comtab* ) 

If I were adding several macros at one time, and to the same comtab, I would use 
set-comtab rather than command-store. And as for the choice of comtab, specify- 
ing *zmacs-comtab* is equivalent to clicking on "Zmacs" in the menu that M-x 
Install Macro pops up, and *standard-comtab* is equivalent to clicking on "Zwei." 
Each editor has its own comtab, but they are all indirected to *zmacs-comtab*, so 
putting a command there means that it will be accessible in all instances of the 
Zmacs editor, unless of course the command is shadowed by a binding to the same 
key in an individual editor's comtab. And *zmacs-comtab* is indirected to 
*standard-comtab*, as are all the other zwei-based editors* (e.g., Zmail and Con- 
verse). So a command inserted in *standard-comtab* will be available in all the 
zwei editors, unless shadowed. 



11.2 Writing New Commands 

Most extensions to the editor are not expressible as a sequence of keystrokes. For 
these you need to write a function, with defcom, and then add it to the comtab of 
your choice with command-store or set-comtab. Among the things you may want to 
do from your function are: insert text into a buffer, read text out of a buffer, get 
user input from the mini-buffer, and send text to the typeout window. All of these 
are reasonably straightforward, once you know about a few key variables and func- 
tions. 



11.3 Buffers and Streams 

The functions zwekopen-editor-stream and zwei:with-editor-stream open a bidirec- 
tional stream to an editor buffer. They are analogous to open and with-open-file in 
that open-editor-stream simply creates the stream and returns it, while with-editor- 
stream puts a call to open-editor-stream inside a useful wrapper, and so is prefer- 
able if your control structure allows it. (The wrapper in this case guarantees not a 



As I understand it, eine and zwei, apart from being "one" and "two" in German, were the names of 
the first two text editors written for lisp machines. They are acronyms, respectively, for Eine Is Not 
Emacs, and Zwei Was Eine Initially. 



202 MORE ADVANCED USE OF THE EDITOR Chapter 11 



close, which isn't meaningful for editor streams, but a : force-redisplay, so 
any changes to the buffer will be apparent.) Either of these functions ultimately 
ends up calling interval-stream, which does a make-instance of flavor interval- 
stream. For more control over how the stream is made, you may wish to call 
interval-stream directly. But in general, open-editor-stream provides a good 
higher-level interface. 

There is some documentation on these two functions in chapter 44 of volume 7, 
mainly on the various options for specifying which buffer the stream should point 
to, and where in the buffer it should initially point. You must specify at least one 
of the following options: : interval, : buffer-name, : pathname, : win- 
dow, or : start. : buffer-name and : pathname are easy enough. If a 
buffer exists which matches the given information, it is used; if not, one is created 
(unless the :create-p option has been used to specify otherwise). Understand- 
ing the others requires knowing a bit more about the editor data structures. 

The base flavor for all buffers is zwekinterval. The value of the variable 
zwei:*interval* will be the current buffer, an object whose flavor is likely to be 
something like zwehfile-buffer, which is indirectly built on interval (via node, top- 
level-node and buffer). Thus references to the current "interval" mean the current 
buffer. An interval may also be created to contain any portion of a buffer; some 
intervals are actually buffers, while many others are temporary objects used to 
point to arbitrary regions of text. An object of flavor interval-stream (see above) is 
simply a stream whose "peripheral device" is an interval. 

The interval flavor has (among others) two instance variables, for the beginning and 
end of the text it refers to. These two are represented as buffer pointers, a type of 
object defined by the zweirbp defstruct. A bp is a list consisting of three elements: 
an object of type line (defined by the zwekline defstruct), an index into the line, 
and a keyword we needn't be concerned with here. A line, in turn, is a string (the 
text of the line) with all kinds of information in the string's array-leader, most 
importantly pointers to the next and previous lines in the buffer. So given an inter- 
val you can get bp's for the first and last character positions in the buffer, given a 
bp you can tell what line it refers to (as well as which character in the line), and 
given a line you can find the preceding and following lines. 

The value of the variable zwei:*window* is an object of the type defined by the 
defstruct zwei:window (not to be confused with objects of type tvrwindow). It con- 
tains information about the portion of the buffer currently visible. Among its slots 
are a pointer to the interval (buffer) that window is displaying part of, a bp for the 
position of point (the cursor), a bp for the first character in the line currently 
displayed at the top of the screen, and a count of how many lines are visible. The 



Section 11.3 Buffers and Streams 203 



window defstruct uses the : array- leader type, meaning that the object is an 
array, with all the slots going into the array-leader. The array itself contains a row 
of information for each line in the area the window maps to, including the "line" 
object. 

The macro zwei:point, called with no arguments, returns the bp for the current 
point. As you might expect, the macro expands into ( ZWEI : WINDOW-POINT 
ZWEI : *WINDOW*), the accessor for the "point" slot of the current window. A 
similar macro, zwei:mark, returns a bp for the most recently dropped mark, which 
is another slot in the window defstruct. 

Now back to the options for open-editor-stream. The ones we delayed discussing 
were : interval, : window and : start. We're now in a position to make 
sense out of these. If you use the : interval option, the value supplied should be 
an interval; you may use zwei:* interval* or any of a number of functions which 
exist to create an interval pointing to an arbitrary text area. The stream created 
will read from and write to the given interval. The : window option is similar; you 
provide a (zwei) window, and open-editor-stream returns a stream into that win- 
dow. The : start option is a little more complicated. It may be used either 
alone or in combination with other options. If the value you provide is a bp, the 
stream will begin at the specified bp. In this case no other options need be sup- 
plied, and the stream's "end of file" will be at the end of the buffer containing the 
bp. (You can force some other termination point with the : end option.) The 
other possible values for : start are all keywords, and all require that some other 
option (like : interval or : window) indicate which buffer to use. The effect of 
the : start keyword will be to determine where within the buffer the stream will 
start. Among your choices are : beginning, :end, :mark, : point, and 
: region. 

There are quite a few other options to open-editor-stream to control various details 
of its behavior, but the ones we've already seen are sufficient to write all sorts of 
useful applications. You'll find many examples in the editor code to use as models. 
These are likely to use interval-stream directly, rather than through open-editor- 
stream, because open-editor-stream is a relatively new feature. Your own functions 
will probably be clearer and easier to write if you use open-editor-stream (or with- 
edi tor-stream ) . 

Here are a few trivial examples, to illustrate the basic concepts. (All assume the 
current package is zwei.) 

(with-editor- stream (str : interval *interval*) 
(send str : string-out 



204 MORE ADVANCED USE OF THE EDITOR Chapter 11 



"surprise text inserted at end of current buffer")) 

(with-edi tor- stream ( str : interval *interval* : start : beginning) 
( send str : string-out 

"surprise text inserted at beginning of current buffer")) 

(with-editor-stream (str : start (point)) 

(send str : string-out "surprise text inserted at point")) 

(with-editor-stream (str :buffer-name "mbox //usr//hjb// S:" 
: start : beginning) 
(send str : line-in)) returns first line of buffer containing my mbox file 

One slightly subtle point to keep in mind is that the variables *interval* and •win- 
dow* are not global; they're bound partway down the stack in the Zmacs process. 
This makes no difference if you're writing editor commands, because they'll be exe- 
cuted in the same process. But it does mean you'll have to be careful if you write 
code intended to interact with the editor's buffers from another process, because 
those variables will then be unbound. In particular, of the four examples just given, 
the first three would bomb if evaluated in a lisp listener (the third because point 
has to access *window*), while the fourth would work. All four work fine from the 
editor's typeout window (as long as the package is correct), since the typeout 
window's break loop is in the Zmacs process. 



11.4 Reading from the Mini-buffer 

Another set of tools often used in writing editor commands are the functions for 
reading from the mini-buffer. There are many — their names generally begin with 
"typein-line-," and the varieties differ in how they know when the typein is com- 
pleted, and in what form they return the typein. Here are a few of them (all in the 
zwei package): 

typein-line-readline ctl-string &rest args 

A prompt (created by format using ctl-string and args) is printed in the 
typein line (just above the mini-buffer — you've seen it used frequently), 
and keyboard input is directed to the mini-buffer. When the Return or End 
keys are pressed, a string is constructed out of all the preceding characters 
and returned. The behavior is analogous to that of the readline function. 

typein-line-read ctl-string &rest args 



Section 11.4 Reading from the Mini-buffer 205 



Same as above except the lisp reader scans the string before it is returned, 
and the lisp object returned by the reader is returned from typein-line-read. 
The behavior is roughly analogous to that of the read function. 

typein-line-form-to-eval prompt &optional initial -contents initial -char -pos 

Similar to typein-line-readline except that the Return key does not terminate 
input — it simply moves to a new line. Only the End key terminates input. 
A string is returned (possibly containing Return characters). 

typein-line-multi-line-read ctl-string &rest args 

Combination of typein-line-read and typein-line-form-to-eval. Multiple lines 
are read, terminated by End, and the input is scanned by the lisp reader 
before being returned. 

read -buffer-name prompt default &optional impossible-is-ok-p 

Prints prompt in the typein line, and does a completing read in the mini- 
buffer, using the names of all the buffers as the set of possible completions. 
default is chosen if the user just types Return. The actual buffer object 
corresponding to the selected string is returned. 

typein-line-completing-read history default blank-line-defaults prompt alist 
&optional ... 

The function called by read-buffer-name (and many others) to do the com- 
pleting read. It has more options than you even want to think about (until 
one of them turns out to be exactly the thing you need), all of which are 
described in great detail at the function definition. It allows for the use of a 
history as well as a default, so you can pop your way through the history to 
reuse earlier inputs. 

com pie ting-read -from -mini -buffer prompt * completing- alist* &optional ... 

The function called by typein-line-completing-read (and many others) to 
really do the completing read. You may want to call it directly because it 
has a somewhat simpler interface, if fewer facilities. 

read-defaulted-pathname prompt * reading-pathname -defaults* &optional ... 

Used by c-X c-F (and many others) to read a pathname and merge it 



206 MORE ADVANCED USE OF THE EDITOR Chapter 11 



with some set of defaults. 



11.5 A Real Example 

Here's something taken out of the editor code, the definition for M-x Evaluate Into 
Buffer. 

(DEFCOM COM-EVALUATE-INTO-BUFFER 

"Evaluates forms from the minibuffer and inserts the 
results into the buffer. You enter Lisp forms in the minibuffer, 
which are evaluated when you press END. The result of each 
evaluation appears in the buffer before point. With a numeric 
argument, it also inserts any typeout that occurs during the 
evaluation into the buffer." (KM) 

(LET ((FORM-STRING (TYPEIN-LINE-FORM-TO-EVAL 

"Lisp forms to evaluate:")) 
(OUTPUT- STREAM ( INTERVAL-STREAM- INTO-BP (POINT))) 
FORM) 
(WITH-INPUT-FROM-STRING (INPUT-STREAM FORM-STRING) 
(LOOP DO (CONDITION-CASE (ERROR) 

(SETQ FORM (READ INPUT-STREAM) ) 

(SYS:END-OF-FILE (RETURN DIS-TEXT)) 

(SYS: READ-ERROR (BARF ""A" ERROR))) 

(FORMAT OUTPUT-STREAM "-{-&-S-}" 

(LET-IF *NUMERIC-ARG-P* 

((STANDARD-OUTPUT OUTPUT- STREAM) ) 
(MULTIPLE-VALUE-LIST ( EVAL FORM)))) 
(MOVE-BP (POINT) 

(FUNCALL OUTPUT-STREAM ' :READ-BP) ) ) ) ) ) 

typein-line-form-to-eval returns a string, presumably containing lisp forms. 
( interval-stream-into-bp (point)) is like (open-editor-stream 
: start (point) :end (point)). We make input- stream point to the 
string of forms, and then loop, reading one form at a time from the string. For 
each one, assuming there are no errors, we use format to print the results of 
evaluating the form into the buffer, via the open editor stream, and move point. 



Section 11.5 A Real Example 207 



.6 Problem Set #10 

Questions 

1. Write com-comment-out-lines-in-region, and com-uncomment-lines-in-region, 
to insert (and remove) semi-colons at the beginning of each line in the region. 
(Both of these already exist as parts of com-comment-out-region, but that 
version includes lots of hair for handling messy cases. Write something sim- 
ple.) 

2. Write com-insert-text-into-other-buffer, which should read any amount of 
text from the mini-buffer (terminated by #\End), prompt for the name of a 
buffer, and append the text to the end of the given buffer. 

3. Write a macro to be used either inside or outside the editor, which redirects 
all typeout during execution of its body to a newly created editor buffer. 



208 MORE ADVANCED USE OF THE EDITOR Chapter 11 



Solutions 



(This all goes in the zwei package.) 



1. (defcom com-comment-out-lines-in-region 

"Comments out each line in the region." nil 
(region-lines (start end) 

(loop for line = start then (line-next line) 
until (eq line end) 

do (insert (create-bp line 0) #\;))) 
dis-text) 

( defcom com-uncomment-lines-in-region 

"Removes semi-colons from beginning of each line in 
region." nil 

(region-lines (start end) 

(loop for line = start then (line-next line) 
until (eq line end) 
when (char-equal (aref line 0) #\;) 

do (let ((end-idx ( string-search-not-char 
#\; line 1)) 
(start-bp (create-bp line 0))) 
(delete-interval 
start-bp 

(if (null end-idx) (end-line start-bp) 
(forward-char start-bp end-idx)))))) 
dis-text) 

Don't forget to add the commands to a comtab so you can use them. Do 
something like: 

(set-comtab *zmacs-comtab* 

' (#\s-; com-comment-out-lines-in-region 

#\h-; com-uncomment-lines-in-region) 
( make-command-alist 

' ( com-comment-out-lines-in-region 
com-uncomment-lines-in-region) ) ) 

2. (defcom com-insert-text-into-other-buf fer 

"Appends text from the mini-buffer to the end of 
any buffer." nil 

(let ((text (typein-line-form-to-eval 

"Text to append to other buffer:")) 



Section 11.6 Problem Set #10 209 



(buffer (read-buffer-name "Buffer to append text to:" 

: other ) ) ) 
(with-editor-stream ( str : interval buffer) 
(send str : string-out text))) 
dis-none) 

3. Anything sent to standard-output during execution of body will be inserted 
into a buffer named buffer-name. There will also be messages inserted 
before and after body is executed. 

(def macro with-output-to-editor-buf fer ((buffer-name) 

Sibody body) 
* (with-editor-stream (standard-output 

: buffer-name , buffer-name) 
(format t "-2X;;; Diverting to buffer ( ~\datime\) ~2%" ) 
, @>body 
(format t "-2%;;; End of diversion ( -\datime\) " ) ) ) 

Sample usage: 

(with-output-to-editor-buf fer ( "test" ) 

(princ "The contents of the FEP file system follows:") 
(print-disk-label) ) 



Chapter 12 

A QUICK LOOK AT "THE NETWORK" 



Although it is common to refer to a lisp machine's connections to the rest of the 
world as "the network," as if the machine were connected via a single mechanism 
to a unified system of linkages, such is not the case. There are several means of 
communication, operating via several different hardware and software protocols. 
And there is considerable overlap, with different software protocols operating simul- 
taneously over the same hardware. It's not really very complicated, but it's easy to 
become highly confused if the basic issues are not kept clear. 



12.1 The "Gee-Whiz" Overview 

The first distinction to keep in mind is between hardware and software. The 
hardware basis for any given network service will be something like coaxial cable 
and transceiver boxes, or a serial line. The software utilizing this hardware, say 
"Internet" or "Chaosnet," must itself be viewed as composed of several theoreti- 
cally independent levels. The various pieces of this modularity are coordinated by 
the namespace database. The terms used by the namespace for the different levels 
are service, protocol, and medium. (Don't be concerned if the exact meaning of the 
various concepts is not clear at this point; all that matters for now is that you have 



212 A QUICK LOOK A T "THE NETWORK" Chapter 1 2 



a general understanding of what sorts of entities the terms refer to.) The distinc- 
tions may at times appear somewhat strained or artificial, but in general a service is 
the highest level entity, describing what the user wants out of the network connec- 
tion. A service may be discussed without reference to which network is providing 
it. Typical services are file transfer and remote login. Each network has its own 
protocol (s) for providing any particular service. Chaosnet provides file transfer ser- 
vice via the "qfile" protocol, while Internet provides the same service via the "tftp" 
protocol. A medium is a mode of connection, like "byte-stream" or "chaos"; each 
protocol requires some medium as the minimal type of connection which must be 
present for the protocol to operate. A connection can be made to a remote host in 
order to request a certain service when both the local and remote hosts are on a 
network of a type adequate to support the medium required by the protocol under 
which the remote host offers the desired service. 

Let's look at excerpts from the namespace descriptions of two machines to see some 
of this terminology in action. 

HOST JONES 

SYSTEM-TYPE UNIX 

MACHINE-TYPE VAX 

ADDRESS CHAOS 1015 

ADDRESS INTERNET 192.11.39.9 

ADDRESS TAMDHU- SERIAL 3 

SERVICE FILE CHAOS QFILE 

SERVICE LOGIN SERIAL- PSEUDONET TTY-LOGIN 

SERVICE LOGIN TCP TELNET 

This (partly fictional) fragment states that the UNIX host "jones" has addresses on 
the chaos, internet and tamdhu-serial networks, and that it offers the file service 
(file transfers) via the qfile protocol on the chaos medium, and the login service 
(remote login) via either the tty-login protocol on the serial-pseudonet medium, or 
the telnet protocol on the tcp medium. 

HOST TAMDHU 
SYSTEM-TYPE LISPM 
MACHINE-TYPE LISPM 
ADDRESS CHAOS 1003 
ADDRESS TAMDHU-SERIAL 
ADDRESS INTERNET 192.11.39.5 

And this fragment tells us that the lisp machine "tamdhu" is on the chaos, 
tamdhu-serial and internet networks. Combining this with the description of jones, 



Section 12.1 The "Gee -Whiz" Overview 213 



we can tell that from tamdhu a user could invoke file transfer service on jones, 
since both machines are on the chaos network (and chaosnet supports the chaos 
medium) . As for remote login service, the user gets a choice: s/he could invoke it 
on the network called "tamdhu-serial" (which both hosts are on, and which sup- 
ports the serial-pseudonet medium) or on Internet (which supports the tcp 
medium) . 



12.2 The Beginning of the Real Explanation 

Until recently, what most people had in mind when they said "the network" with 
reference to lisp machines was Chaosnet, a local area network developed in 1975 by 
the MIT AI Lab, specifically for use as the medium for communications among lisp 
machines. But as it was designed to minimize the difficulty of bringing other kinds 
of machines into the network, by now quite a variety of computers — as well as 
peripherals — may be connected via Chaosnet. The "chaos" in the name refers to 
the lack of centralized control. 

The hardware and software portions of Chaosnet, although designed for each other, 
are logically independent. The Chaosnet software may operate on media other than 
the Chaosnet hardware, and the software for other network protocols may use the 
Chaosnet hardware. The transmission medium is sometimes called ethernet, which 
can be misleading because the same term is applied to a type of network (including 
hardware and software) developed by Xerox. But since the Ethernet hardware and 
the Chaosnet hardware are largely compatible, the term "Ethernet" is frequently 
applied to the hardware for any network using this sort of transmission medium, 
regardless of which software protocol is in operation. 

We'll return to Chaosnet shortly, but first let's complete the overview of the lisp 
machine's network connections. Coexisting with Chaosnet on the ethernet cable is 
the Internet, an entirely different software protocol. The hardware requirements of 
the two types of network are compatible; although some kinds of computers use 
different boards for the two interfaces, everything external to the individual 
machines is identical. In the case of the lisp machine, even the internal hardware is 
shared, so the distinction between the two networks is solely what happens to the 
transmitted information in software. The software for Internet is not, however, part 
of the basic lisp machine system. It's another product which must be purchased 
separately, as "ip-tcp." The Bell Labs/Murray Hill lisp machine community has a 
site license, and ip-tcp is installed on all our machines. As with Chaosnet, Internet 
is understood by a wide variety of computers. In fact, Internet has become a 
Department of Defense standard, so one may reasonably expect virtually all 
manufacturers to support Internet in their new products, while Chaosnet may be 



214 A QUICK LOOK AT "THE NETWORK" Chapter 12 



expected to gradually fade from view. 

The third means of communication available to the lisp machine is the serial i/o 
facility. Each lisp machine has three serial ports, which may be used to communi- 
cate with any device that understands the RS-232 protocol. At my site we connect 
these ports to a VAX* terminal line, to allow use of the lisp machine as a terminal 
logged in to a UNIX system, or to speech synthesizer boxes, or a modem. Because 
the related software uses a construct called a serial-pseudonet, it appears from the 
user's point of view that each lisp machine is the center of its own star-shaped net- 
work (on an equal footing with Chaosnet and Internet) connecting it to the devices 
at the other end of the serial lines. 

So all together there are two kinds of physical connection to the outside world (eth- 
ernet and serial line), and three kinds of conceptual connection (Chaosnet and 
Internet via the single ethernet, and serial-pseudonet via any number of serial 
lines). The term "network" — now that Chaosnet no longer stands alone — usu- 
ally refers to these three conceptual connections, either one of them taken individu- 
ally or the set of them considered collectively. It is possible, though unusual, to 
define additional types of conceptual networks, sharing the existing physical connec- 
tions. 

Most of the physical and conceptual connections are documented in volume 9 of the 
Symbolics manuals, from which I have borrowed for this chapter. Chaosnet, both 
hardware ("ethernet") and low-level software, is covered in chapter 15. Part I of 
volume 9 describes the namespace database and how the namespace manages 
requests for network services. Serial i/o is in Part III of volume 5. 



12.3 The Ethernet 

The transmission medium (the ether) which supports both Chaosnet and Internet is 
1/2 inch coaxial cable, with a transceiver box at each point where a machine joins 
the cable. A single ether must be a linear cable, with no branches or loops. The 
maximum length of an ether is about a kilometer. Multiple ethers may be joined 
by bridges, i.e., machines on both of two ethers, which relay packets from one to 
the other, so that the two subnets may act as one large ethernet without exceeding 
the length limitation. For example, the portion of the Murray Hill ethernet that 
local lisp machine users need to be concerned with has three single ethers joined by 
bridges. One connects all the building 2 lisp machines (except Churchill), about 
five VAXen and some Sun workstations; one (the "tempo net") connects a variety 



VAX is a trademark of Digital Equipment Corporation. 



Section 12.3 The Ethernet 215 



of machines in building 3; the third (the "backbone") runs for about a mile (with 
repeaters inserted at strategic points, since a mile is more than a kilometer) con- 
necting the other two subnets and who knows what else, hitting about fifty 
machines along the way. Sola (a VAX in building 2) serves as the bridge between 
the building 2 subnet and the backbone; Vivace links the backbone and the tempo 
net. The current list of subnets can be found in /etc/networks on any UNIX 
machine running Internet. 

Returning to the operation of a single ether, one machine at a time may seize the 
ether and transmit a packet with the address of some other machine. The packet 
will be seen by every machine connected to the ether; it is up to each to check the 
address in the packet and decide (in hardware) whether it is the intended recipient. 
If the address is correct, the packet is received and relayed up to the appropriate 
software (Chaosnet or Internet, depending on the type of the packet). Otherwise it 
is ignored. 

The ether can tolerate temporary breaks in the cable for about a minute — long 
enough to splice a transceiver in or out of the ether. The effects of longer breaks 
vary with the type of the machine, but can be disastrous for some — VAXen crash 
when reconnected after a long break. If such a machine is to be spliced out of the 
network while running, a pair of terminators should be attached to its transceiver. 
The terminators present an impedance similar to that of an intact ether, so the 
machine sees what appears to be a legitimate ether which just happens to be com- 
pletely inactive. It can later be reattached with no difficulty. 

Lisp machines are insensitive to ether disruptions. To physically remove a lispm 
from the network it is safe and easy to disconnect the transceiver cable where it 
plugs into the back of the machine. You may reconnect at any time. Actually, it's 
rarely necessary to physically disconnect the machine. The equivalent may be done 
in software by evaluating (neti : reset ), which disables the ethernet interface, 
(neti: enable) starts it up again. The CP command Reset Network does a 
reset immediately followed by an enable. 



12.4 Chaosnet 

The previous section discussed the portion of Chaosnet which is shared with Inter- 
net, i.e., the Ethernet hardware. Now a bit about the portions which are unique to 
Chaosnet. 

Chaosnet addresses are simple numbers, consisting of three or more octal digits. 
The least significant eight bits indicate the machine's address on its own subnet, or 



216 A QUICK LOOK AT "THE NETWORK" Chapter 12 



single length of ethernet cable. The higher order bits indicate which subnet the 
machine is on. The subnet codes used in Murray Hill are 1 for the backbone, 2 for 
building 2, and 3 for the tempo net. So an octal address of 406 (Pancake's 
address) means machine 06 on the backbone. Note that the numbering of 
machines on a subnet has no relation to their physical order. A lisp machine's 
opinion of what its own address is comes from the "Set Chaos-address" fep com- 
mand. Every boot file should have one of these. The machine's opinion as to its 
name is derived from its address: it believes whatever the namespace database says 
is the mapping between names and addresses. So all that's required to make 
Abelour (address 1002) believe that it's really Glengarioch (address 1006) is to 
boot Abelour from a boot file that contains the line "Set Chaos-address 1006." No 
physical alterations to the network connections are involved. Then Abelour will 
receive and answer any packets intended for Glengarioch. There is no sense in 
which Abelour will not, in fact, be Glengarioch. (To avoid having two Glen- 
gariochs, this stunt should only be pulled when Glengarioch is down, or itself 
booted as somebody else.) The file "fep0:> namespace. boot" on Abelour does 
exactly this. We boot Abelour as Glengarioch if the real Glengarioch (our 
namespace server) is down, so that Abelour will act as the namespace server until 
Glengarioch is fixed. 

The same method for address-swapping allows us to transform Laphroaig (1001) 
into Ghost-of-Laphroaig (401), but since the new address implies being on a 
different subnet, the switch additionally involves plugging the machine into a nor- 
mally unused transceiver on the backbone. This trick allows us to transfer large 
files (like world loads) to machines on the backbone without having to go through 
the bridge. Executing a band transfer through a bridge takes at least twice as long 
as going direct, as well as completely tying up the chaos server on the bridge for 
the duration. 

A UNIX machine's idea of who is at what address is based on the contents of its 
host table. The Chaosnet host table is in the file 
/usr/chaos/lib/libhosts/hosts. local. (The Internet host table is in /etc/hosts.) 

From volume 9, 15.3: "The principal service provided by Chaosnet is a connection 
between two user processes. This is a full-duplex reliable packet-transmission chan- 
nel. The network undertakes never to garble, lose, duplicate, or resequence the 
packets... When first establishing a connection, it is necessary for the two commun- 
icating processes to contact each other... One process is designated the user, and the 
other is designated the server. The server has some contact name [indicating the 
type of service] to which it listens. The user process requests its local operating 
system to connect it to the server, specifying the network address and contact name 
of the server. The local operating system sends a message (a Request for 



Section 12.4 Chaosnet 217 



Connection, or RFC) to the remote operating system, which examines the contact 
name and creates a connection to an existing listening process, or creates a new 
server process and connects to it, or rejects the request." 

The first option (an existing process) is used for simple requests that can be 
answered quickly and easily, such as a request for the current time. The main 
server process handles these itself. More elaborate requests, which require 
extended attention and multiple interchange of packets, are handled by spawning a 
new process for that purpose. On a UNIX chaos server, this means simply execut- 
ing a file in the /usr/chaos/server directory. The name of the file will be exactly 
the contact name that was used to request the connection. So, for example, if a lisp 
machine wants to read a file from a UNIX machine, it would send an RFC packet 
to the UNIX machine, with contact name "FILE." The chaos server on the UNIX 
end, upon receiving the packet, would start up a process running the contents of the 
file /usr/chaos/server/FILE. The chaos server would then route any further pack- 
ets related to the file transfer to this new process. The effect is as though the FILE 
process on the UNIX system and the process requesting the file transfer on the lisp 
machine were communicating directly with each other. 

From a lisp machine, the easiest way to establish a connection with a server process 
on a remote host is with the function chaos:open-stream. The two required argu- 
ments specify the host and the contact name. (Several optional keyword arguments 
offer more detailed control of the type of connection.) If a connection is success- 
fully established, chaos:open-stream returns an open stream object. You may then 
use all the usual messages to read characters from and write characters to the 
stream. Conversion to and from the packet level is completely transparent — all 
the user sees is a character stream. 



12.5 A Bit More on Serial Streams 

The programmer interface to the serial i/o facility also works via lisp stream 
objects. The function si:make-serial-stream returns an open stream to one of the 
serial ports (which one may be specified with the :unit keyword argument). The 
usual messages for reading and writing may again be used. Details are in chapters 
21 and 22 of volume 5. 



12.6 The Role of the Namespace 

The namespace database coordinates interaction with the various network facilities. 
It is always possible to directly manipulate the stream connections as outlined 



218 A QUICK LOOK AT "THE NETWORK" Chapter 12 



above, but this is necessary only if you are adding a new type of network service. 
To invoke any existing service which has already been integrated into the 
namespace, you may use the higher-level interface provided by the namespace. 
This interface insulates the user from having to know any details about how the 
connection is established, or even which network is used. The namespace takes care 
of finding an appropriate path. 

The simplest way to invoke a network service through the namespace is with the 
function net:invoke-service-on-host. The first argument is the name of a defined ser- 
vice, and the second is a host object. The local host will find the best path to the 
target host, over all available network connections, and use it to invoke the named 
service. So to obtain Sola's idea of what time it is, I could do (net: invoke- 
service-on-host :time ( si : parse-host 's)). (Seeing as how Sola's 
namespace entry says that it provides the time service via the time-simple 
protocol on the chaos-simple medium, we can tell this will end up being a 
Chaosnet transaction, but we needn't be concerned with that level of detail.) 

In cases where you need some service but don't care on which host it is invoked, the 
function net:hnd-paths-to-service (called with an argument of the service name) 
returns a list of service access paths, one for each host which provides the service. 
The list is sorted by decreasing desirability. Having decided which path to use, you 
may invoke the service by calling net:invoke-service-access-path on the chosen ser- 
vice access path. 

Another option is to invoke a service simultaneously on more than one host, with 
service futures. You can then pick the first or best of several responses without a 
long waiting period. The handiest way to manipulate service futures is with the 
macro net:invoke-multipIe-services. This example prints every host's idea of the 
current time, ignoring those which fail to respond: 

(defun all-hosts-time () 

( net : invoke-multiple-services 

( (net :f ind-paths-to- service :time) (* 60 10) "Time") 
(host time) 

(sys : network-error nil) ; catch the error and do nothing 
( : no-error 
(format t "~&~A: ~ : [unknown- ; ~\TIME\- ] " host time time)))) 



Section 12.6 The Role of the Namespace 219 



12.7 Troubleshooting 

Typing Function-H [or evaluating (hostat)] will show which machines your 
lispm is able to contact via Chaosnet. If you can't reach any remote hosts, some- 
thing is probably wrong locally. If you can reach some and not others, something is 
probably wrong out in the network somewhere. Here are a couple of hints: 

Don't forget about netirreset and neti:enable. If a reset has been done, hostat will 
fail everywhere. 

The transceiver cable locks into place, at both the machine and transceiver ends, 
with a tab which is slid sideways after the connector is pushed into the socket. A 
fairly common cause of "network failure" is for the cable to fall off the back of the 
machine because the tab wasn't used (or was defective). 

Check the state of the process called "3600 Ethernet Receiver" in Peek. If it's not 
"Ethernet Packet," something's wrong — maybe you ignored a Function-0-S 
notification. 

For more elaborate troubleshooting, try the "network" option in Peek. 



APPENDIX: BASIC ZMACS COMMANDS 



While it is true that there are a great many Zmacs commands, and trying to learn 
them all would be a close to hopeless task, it is also true that the situation is really 
much less difficult than it might at first appear. For one thing, you can edit files 
quite effectively with a relatively small subset of the Zmacs commands. (This 
should not be taken to imply that the remaining commands are superfluous; the 
"quite effective" editing you can do without them is transformed into astonishingly 
effective editing with them.) Another saving grace is that there is some pattern to 
the pairing of keystrokes with editing functions. For instance, control characters 
often act on single letters or lines; meta characters on words, sentences, or para- 
graphs; and control-meta characters on lisp expressions. Thus c-F moves forward 
one character, m-F moves forward one word, and c-m-F moves forward one lisp 
expression. c-K means "kill" (delete) to the end of the line, m-K means kill to the 
end of the sentence, and c-m-K means kill to the end of the current lisp expression. 
So the amount of memorizing you have to do to start editing is really not very 
great. 

I can't overemphasize the utility of the Help facility in Zmacs. It can be a real 
lifesaver, both when you don't know what commands there are to do something, 
and when you've forgotten how to invoke a command you know about. So don't 
limit yourself to the commands listed below. Consider the list a crutch, to help get 



222 



APPENDIX: BASIC ZMACS COMMANDS 



you started, but try to leave it behind as soon as possible. 



Movement Commands 



C-F 
c-B 
C-N 
c-P 
C-A 
C-E 
mous 



e left 



Move forward one character 
Move backward one character 
Move down one line ("next") 
Move up one line ("previous") 
Move to the beginning of the line 
Move to the end of the line 
Move to mouse position 



m-F 
m-B 
m-A 
m-E 
m-[ 
m-] 
m-< 
m-> 



Move forward one word 

Move backward one word 

Move to the beginning of the sentence 

Move to the end of the sentence 

Move to the beginning of the paragraph 

Move to the end of the paragraph 

Move to the beginning of the buffer 

Move to the end of the buffer 



c-m-F 
c-m-B 
c-m-A, c- 
c-m-E, c- 



m-[ 
m-] 



Move forward one lisp expression 

Move backward one lisp expression 

Move to the beginning of the current definition 

Move to the end of the current definition 



Deletion Commands 

c-D Delete forward one character 

Rubout Delete backward one character 

Clear Input Delete to the beginning of the line 

c-K Delete to the end of the line 

m-D Delete forward one word 

m-Rubout Delete backward one word 

m-K Delete forward one sentence 



c-m-K 
c-m-Rubout 



Delete forward one lisp expression 
Delete backward one lisp expression 



APPENDIX: BASIC ZMACS COMMANDS 



223 



C-Y 
m-Y 



Restore ("yank") text deleted with any of the above, except c-D 
and Rubout 

Immediately following a c-Y or another m-Y, replace the yanked 
text with the previous element of the kill history 



c-Space 



c-W 
m-W 
mouse middle 

mouse drag left 



Region Commands 

Set the mark at the current position, and turn on the 

"region." Subsequent movement commands will define the 

region to be the area between the mark and the new 

position. 

Delete the region, putting it on the kill history 

Put the region on the kill history without deleting it 

Mark (make into the region) the object the mouse is 

pointing at 

Mark the area dragged over (between button press and 

button release) 



File Commands 



C-X C-F 



c- 


-X 


c-S 




c 


-X 


c-W 




M 


-x 


Compi 


le 



File 



Read ("find") a file into its own buffer, creating an 
empty buffer if the file doesn't exist 
Write ("save") a buffer back to its file 
Write a buffer to any file, specified by name 
Compile a file, i.e., write a binary version of the file. 
This has no effect on the current Lisp environment. 
(Compare to M-x Compile Buffer.) 



Buffer Commands 

c-m-L Switch to the previous ("last") buffer 

c-X B Switch to a buffer specified by name 

c-X c-B Display a list of the buffers 



c-sh-E 



Lisp Commands 

Evaluate (call the Lisp interpreter on) the region, if 



224 



APPENDIX: BASIC ZMACS COMMANDS 



c-sh-C 

M-x Evaluate Buffer 
M-x Compile Buffer 



End, s-E 



it's active, or the current definition if it's not 

Compile the region or current definition into the Lisp 

environment 

Evaluate the entire buffer 

Compile the entire buffer into the environment. This 

has no effect on the file system. (Compare to M-x 

Compile File.) 

Murray Hill Standard Utilities only. Evaluate the 

region or current definition and insert the result into 

the buffer. 



Miscellaneous 



Suspend Enter the typeout window. (Resume returns.) 

m- . Find the definition of a given function 

c-X D Directory edit — shows a directory listing and enables manipulation 

of the files in it 

Help A Apropos — list all commands containing a given substring 

Help C Describe the command associated with a given keystroke 

Help D Describe a command specified by name 



INDEX 



* variable 52-53 

*catch special form 64 

*throw function 64 

: activate method 48 

: alias-f or-selected-windows 

method 87 
:blinker-p init keyword 88 
: bury method 49 
: byte-size open option 126 
: canonical-type method 133 
:case method combination 180 
: character blinker 186 
: characters stream operation 121 
: checker defresource option 163 
: choose method 142-143 
: clear- input stream operation 122 



: clear-output stream operation 

122 
: clear-screen stream operation 

123 
: clear-window 

method 76, 195 

stream operation 123 
: close stream operation 122 
: compile make-system option 167 
:compile-load defsystem clause 

166 
: component- systems defsystem 

clause 167 
: compute-all-handlers-once 

method 40 
rconfigurat ions init keyword 87 



226 



INDEX 



: constructor defresource option 

162 
: creation-date stream operation 

128 
: deactivate method 48 
rdeexpose method 48-49 
: default-font init keyword 185 
:default-init-plist defflavor 

option 87-88 
: describe method 31 
: deselect method 48 
rdevice method 133 
: direction 

open option 125 

stream operation 121 
: directory method 133 
: do- components defsystem clause 

167 
: draw- char method 195 
: draw-circle method 76 
: draw- line method 36 
: draw-lines method 36 
: draw-point method 76 
: draw-rectangle method 76 
: draw- triangle method 76 
: execute method 141-143 
: expose method 48 
: fas load defsystem clause 166 
: finder defresource option 163 
: finish stream operation 122 
: force -output stream operation 

122 
: force-redisplay method 202 
: free-list-size defresource 

option 164 
: get method 133 
:get-handler-f or method 31 
: gettable-instance-variables 

defflavor option 19 



; host method 133 

; if -exists open option 126 

; included-f lavors defflavor 

option 23 
: init method 84 
; initable-instance-variables 

defflavor option 20 
; initial-copies defresource 

option 163 
; initializer defresource option 

162 
; inside-size method 76 
litem method 90, 195 
: item-list init keyword 185 
ikill method 48 
: length stream operation 128 
: listen stream operation 121 
: matcher defresource option 163 
:menu blip 141-143 
: method-combination defflavor 

option 28 
: module defsystem clause 166 
: mouse -buttons method 142 
: mouse-click, 

essential-mouse's method for 30 

method 29, 86, 89-90, 143 
: mouse-moves method 90 
: mouse-standard-blinker 

method 186-187 
:name method 133 
: new-canonical -type method 

133 
: new-device method 133 
: new-directory method 133 
: new-name method 133 
: new-pathname method 133 
: new-raw-device method 133 
: new-raw-directory method 133 
: new-raw-name method 133 



INDEX 



227 



: new-raw-type method 133 

: new- type method 133 

: new- vers ion method 133 

: no- error condition-case clause 177 

rnoconf irm make-system option 

168 
: or method combination 29, 89 
: override method combination 89 
: package defsystem clause 167 
: panes init keyword 87 
: patchable defsystem clause 167 
: pathname stream operation 128 
: pathname-default defsystem 

clause 166 
:plist method 133 
: primitive-item method 90,195 
: print -only make-system option 

168 
: print- self method 31,140 
: proceed method 178,180 
:proceed-type-p method 180 
:proceed-types method 180 
: process init keyword 88 
: properties method 133 
: putprop method 133 
: raw-device method 133 
: raw-directory method 133 
: raw-name method 133 
: raw- type method 133 
:read-cursorpos stream operation 

122 
: read-pointer stream operation 

123 
: remprop method 133 
: report method 175 
: required-init-keywords 

deffiavor option 84 
:reverse-video-p method 76 
:rows init keyword 185 



select method 48, 87 
selectable-windows method 87 
selected-pane init keyword 87 
send-if-handles method 84 
set-character method 186 
set-cursorpos stream operation 

123 
set-pointer stream operation 123 
set-reverse-video-p method 

76 
settable- instance-variables 

deffiavor option 19 
: string-for-host method 133 
: string-f or-printing method 

133 
: string- in stream operation 121 
: string-out stream operation 

120-121 
: trans lated-pathname method 

135 
: truename stream operation 128 
:tyi 

method 76 

stream operation 120, 126 
: ty i -no-hang stream operation 1 22 
: tyipeek stream operation 121 
:tyo stream operation 120, 124, 126 
: type method 133 
:typeout-execute blip 88-89 
: untyi stream operation 120,125 
: version 

make-system option 168 

method 133 
: which-operations 

method 3 1 

stream operation 120 
: who- line -documentation- 
string method 89 
-[ format directive 140 



228 



INDEX 



~ { format directive 140 

Abort key 7, 51 

activation in the input editor 54 

active processes 45 

advising functions 51 

after daemon 26, 84, 88-89 

allocate-resource function 162, 

164 
allocation, resource 161 
always loop keyword 70 
and 

loop keyword 70 

special form 62 
append loop keyword 69 
apropos function 52 
arrest-reasons instance variable 

45 
arresting processes 45 
background window 124 
base-flavor-first 29 
base-flavor-last 29 
beep function 73 
before daemon 26, 84, 89 
bit-save array 47 
blinker 

: character 186 

mouse 184-186 
blip 

:menu 141-143 

: typeout-execute 88-89 
block special form 63 
boot 

cold 11 

warm 1 1 
Boot Fep command 1 1 
bp 202 

bridge 214, 216 
brightness, display 12 
buffer 



i/o 85, 89 

pointer 202 

shared i/o 141 
bugs, reporting 52 
c-A Zmacs command 222 
c-Abort 7 
c-B 

debugger command 51 

Zmacs command 222 
c-D Zmacs command 222 
c-E 

debugger command 52 

Zmacs command 222 
c-Escape input editor command 53 
c-F Zmacs command 222 
c-Help input editor command 53 
c-K 

input editor command 53 

Zmacs command 222 
c-M debugger command 52 
c-m-[ Zmacs command 222 
c-m-] Zmacs command 222 
c-m-A 

debugger command 5 1 

Zmacs command 222 
c-m-Abort 7 

c-m-B Zmacs command 222 
c-m-E Zmacs command 222 
c-m-F Zmacs command 222 
c-m-K Zmacs command 222 
c-m-L 

debugger command 51 

Zmacs command 223 
c-m-R debugger command 52 
c-m-Rubout Zmacs command 222 
c-m-Suspend 7 
c-m-Y 

input editor command 53 

Zmacs command 54 



INDEX 



229 



C-N 

debugger command 5 1 

Zmacs command 222 
c-P 

debugger command 5 1 

Zmacs command 222 
c-R debugger command 52 
c-sh-A 

input editor command 54 

Zmacs command 54 
c-sh-C Zmacs command 223 
c-sh-E Zmacs command 223 
c-sh-M Zmacs command 71, 77 
c-Space Zmacs command 223 
c-Suspend 7 
c-W 

input editor command 53 

Zmacs command 223 
c-X 

( Zmacs command 199 

) Zmacs command 199 

B Zmacs command 223 

c-B Zmacs command 223 

c-F Zmacs command 13, 223 

c-S Zmacs command 13, 223 

c-W Zmacs command 223 

D Zmacs command 13, 224 

E Zmacs command 199 
c-Y 

input editor command 53 

Zmacs command 53, 222 
canonical type 130 
case in pathnames 131 
catch special form 64, 76 
catch-error macro 176 
chaos : open- stream function 217 
Chaosnet 211, 213-215 

addresses 215 
check-arg macro 176 



check-arg-type macro 176 
chosen-item instance variable 142 
circular-list function 76 
Clear Input 

input editor command 53 

Zmacs command 222 
clear-resource function 165 
clock function list 44 
cold boot 1 1 
cold-load stream 45, 50 
collect loop keyword 69, 76 
combined methods 23 
command 

Edit Namespace Object 9 

extended 184, 188 

Halt Machine 11 

history 54 

Login 9 

menu 141, 143, 183 

Reset Network 215 

Show Documentation 8 
Command Processor 8 
Common Lisp 6 
Compile 

Buffer, M-x 223 

File, M-x 223 
component flavors 22, 155 
comtab 183-184, 188 
cond special form 61 
cond-every macro 63 
condition 173 

simple 175 
condition flavor 175 
condition-bind macro 177,180 
condition-bind-def ault macro 

178 
condition-case macro 174, 176 
condition-case clause, : no-error 

177 



230 



INDEX 



conditional 61 
conditions 

proceeding 174-175, 177, 179 

signaling and handling 173 
Continue Fep command 10 
continue -whopper function 27 
control, flow of 61 
Converse 6, 201 
Copy File, M-x 127 
copyf function 127 
count loop keyword 69 
current process 43 

resetting the 46 
daemon 

after 26, 84, 88-89 

before 26, 84, 89 
dbg function 51, 59 
dbg : arg function 51 
dbg: loc function 51 
deactivated windows 46-47 
deallocate-resource function 

162, 164 
deal locate -whole -re source 

function 165 
deallocation, resource 161 
debugger 5 1 

command, c-B 51 

command, c-E 52 

command, c-M 52 

command, c-m-A 51 

command, c-m-L 51 

command, c-m-R 52 

command, c-N 51 

command, c-P 51 

command, c-R 52 
debugging 50 
deexposed windows 46 
deexposed-typeout-action 

instance variable 47 



default 

handler 178 

handler for streams 120, 122, 124 

pathnames 132 
def const special form 36 
defflavor option 

:default-init-plist 87-88 

: gettable-instance- 
variables 19 

: included-f lavors 23 

: initable-instance- 
variables 20 

: method-combination 28 

:required-init-keywords 84 

: settable-instance- 
variables 19 
defflavor special form 18 
def method special form 18 
defresource option 

: checker 163 

: constructor 162 

: finder 163 

:free-list-size 164 

: initial-copies 163 

: initializer 162 

: matcher 163 
defresource macro 162 
def select macro 76 
defstruct 

zweirbp 202 

zwei:line 202 

zwei: window 202 
defsystem 

clause, :compile-load 166 

clause, ."component- systems 
167 

clause, : do- components 167 

clause, :fasload 166 

clause, : module 166 



INDEX 



231 



clause, : package 167 

clause, rpatchable 167 

clause, : pathname-default 
166 

dependency 1 66 

transformation 167 
def system macro 165 
def un-method macro 84 
defvar 

macro 84 

special form 36 
def whopper macro 27 
def window-resource macro 170 
deletef function 127 
dependency, defsystem 166 
describe function 21 
Describe Key Bindings, M-x 184 
device pathname component 131 
Dictionary, Hacker's 11, 31, 34, 54, 

58, 71,91, 135, 143, 167, 178 
directory 128 
directory pathname component 

131 
Dired 13 

disassemble function 52 
dispatch macro 63 
display brightness 12 
Display Font, M-x 185 
do 

loop keyword 68, 70 

special form 63-64, 66 
Document Examiner 6 
dolist macro 67, 76 
dotimes macro 67 
edit screen menu 36, 49, 90 
Edit Namespace Object com- 
mand 9 
Edit 

Callers, M-x 52 



Combined Methods, M-x 52 

Extended Command, M-x 184 

Key, M-x 184 

Methods, M-x 52 
editor, Zmacs 6, 12, 53-54, 199, 221 
else loop keyword 70 
End 

input editor command 54 

Zmacs command 224 
End key 71 
error 

flavor 175, 179 

function 175 
error-output variable 124 
error-restart macro 179 
error-restart-loop macro 179 
errset macro 176 
Escape input editor command 53 
essential-mouse's method for 

:mouse-click 30 
ethernet 213-214 
Evaluate 

Buffer, M-x 223 

Into Buffer, M-x 206 
example 

graph 83 

moving icons 183 

tree 139 
exposed windows 47 
extended command 184, 188 
FEP 10 
Fep command 

Boot 11 

Continue 10 

Set Chaos-address 216 

Start 11 
f error function 176 
fibonacci numbers 74 
file 125 



232 



INDEX 



File System Maintenance 6 
finally loop keyword 70, 77 
finger 7 

flashy scrolling 155 
flavex: flavor flavor 40 
flavor 1 7 

condition 175 

error 175, 179 

f 1 a vex : f 1 a vor 40 

fs:pathname 129 

f s :unix-pathname 129 

net: basic-host 130, 133 

si : vanilla-flavor 30,84 

sys: abort 179 

tv: basic-mouse- sensitive- 
items 88-90, 195 

tv : bordered-constraint- 
frame 141 

tv : bordered-constraint- 
f rame -with- shared- io- 
buffer 141 

tv:dont-select-with- 
mouse-mixin 87 

tv:f lashy-scrolling-mixin 
155 

tv: lisp-listener 17,85 

tv: lisp-listener-pane 87 

tv:pane-mixin 87 

tv:pane-no-mouse-select- 
mixin 87, 185 

tv:process-mixin 88, 184 

tv: sheet 47, 88 

tv: stream-mixin 44 

zwei: buffer 202 

zwei : file-buff er 202 

zwei : interval 202 

zwei: interval-stream 202 

zwei: node 202 

zwei: top-level-node 202 



zwei :window-with-comtab 
184-185 
Flavor Examiner 6, 33, 59 
flavors 

component 22, 155 

mixing 22 
flow of control 61 
font-map instance variable 88 
Font Editor 185 
for loop keyword 68, 70 
format directive 

-[ 140 

-{ 140 
format function 140 
frame 85 

Front-End Processor 10 
f s : change-file-properties 

function 1 27 
f s : complete -pathname function 

128 
f s:def ine-canonical-type func- 
tion 132 
fs:directory-list function 128 
fs : file-properties function 127 
f s : make- logical-pathname- 
host function 134,171 
f s : make-pathname function 1 32 
fs:merge- pathnames function 132 
fs:parse -pathname function 129 
f s : pathname flavor 1 29 
f s : set-logical-pathname-host 

function 1 34 
f s : unix-pathname flavor 1 29 
function 

♦throw 64 

allocate-resource 162, 164 

apropos 52 

beep 73 

chaos : open- stream 217 



INDEX 



233 



circular-list 76 

clear-resource 165 

continue -whopper 27 

copyf 127 

dbg 51, 59 

dbg:arg 51 

dbg:loc 51 

deallocate-resource 162, 
164 

deal locate -whole -re source 
165 

deletef 127 

describe 21 

disassemble 52 

error 175 

ferror 176 

format 140 

f s : change-file-properties 
127 

f s: complete-pathname 128 

f s : def ine-canonical-type 
132 

f s:directory-list 128 

f s :f ile-properties 127 

f s : make-logical-pa thname- 
host 134, 171 

f s :make -pathname 132 

f s :merge-pathnames 132 

f s : parse-pathname 129 

f s : set-logical-pathname- 
host 134 

gensym 85 

grind-top-level 71 

hostat 219 

intern 76 

load 127 

load-patches 168 

login 9 

macroexpand 71 



make-instance 19, 84 

make-system 165, 167-168 

map-resource 165 

mapcan 66, 76 

mapcar 66, 69 

mapcon 66, 76 

maplist 66 

mexp 71, 74 

nconc 66 

net : f ind-paths-to-service 
218 

net : invoke-service- 
access-path 218 

net : invoke-service-on- 
host 218 

netirenable 215, 219 

neti:reset 215, 219 

open 125, 201 

probef 127 

process-run-function 46, 
143 

process-wait 44, 47 

read 205 

readline 204 

renamef 127 

rplacd 76 

send 19 

si : examiner-compute- 
magic-list 40 

si:halt 11 

si:login-to-sys-host 9 

si rmake-serial-stream 217 

si:parse-host 218 

si : set-system-source-file 
168 

signal 175, 180 

spec 51 

stream-default-handler 124 

string-append 76 



234 



INDEX 



tv : add- to- system-menu - 
programs -column 188 

tv:get-line-from-keyboard 
90 

tv: make -window 19, 48 

tv: menu- choose 143 

tv: mouse-set-blinker 186 

tv : mouse-set-blinker- 
definition 186 

tv: select-or-create- 
window-of -flavor 189 

viewf 127 

who-calls 52 

zwei: command-store 201 

zwei : completing-read- 
from-mini-buf f er 205 

zwei : find-combined- 
methods 40 

zwei: interval-stream 202 

zwei : interval-stream- 
into-bp 206 

zwei :make-command-alist 
188 

zwei : open-editor-stream 
201 

zwei: read-buffer-name 205 

zwei : read-def aulted- 
pathname 205 

zwei : set-comtab 188,201 

zwei : set-comtab- 
indirection 188 

zwei : type in- line - 

completing-read 205 

zwei : typein-line-f orm-to- 
eval 205 

zwei :typein-line-multi- 
line-read 205 

zwei:typein-line-read 204 

zwei :typein-line-readline 
204 



Function 

Apropos, M-x 52 

key 6, 45, 47-50; 59, 219 
gensym function 85 
go special form 68 
graph example 83 
grind-top-level function 71 
grindef special form 52 
Hacker's Dictionary 11, 31, 34, 54, 

58, 71, 91, 135, 143, 167, 178 
Halt Machine command 11 
handler 173-174 

default 178 

restart 174, 178 
Help Zmacs command 13, 221, 224 
Help key 6, 184 
history 

command 54 

input 53 

kill 53 
host 

logical 133 

physical 134 

table 216 
host pathname component 130 
hostat 7, 219 
hostat function 219 
hyper-control- Function 1 1 
i/o buffer 85, 89 

shared 1 4 1 
if macro 62 
ignore variable 84 
ignore-errors macro 176 
inactive processes 45 
inferiors instance variable 46 
init keyword 

:blinker-p 88 

: configurations 87 

: default-font 185 



INDEX 



235 



: item-list 185 
: panes 87 
rprocess 88 
:rows 185 
: selected-pane 87 
initial values for instance variables 20 
initially loop keyword 70 
input 

editor 53 

editor, activation in the 54 
editor command, c-Escape 53 
editor command, c-Help 53 
editor command, c-K 53 
editor command, c-m-Y 53 
editor command, c-sh-A 54 
editor command, c-W 53 
editor command, c-Y 53 
editor command, Clear Input 

53 
editor command, End 54 
editor command, Escape 53 
editor command, m-D 53 
editor command, m-Rubout 53 
editor command, m-Y 53 
history 53 
Inspector 6 

Install Macro, M-x 200 
instance 17 

variable, arrest-reasons 45 
variable, chosen- item 142 
variable, deexposed-typeout- 

action 47 
variable, font-map 88 
variable, inferiors 46 
variable, item-list 142 
variable, item-type-alist 

88-89 
variable, run-reasons 45 
variable, superior 46 



variable, tv: current-font 186 

variable, tv: item-list 195 

variable, x-offset 187 

variable, y-offset 187 

variables 1 7 

variables, initial values for 20 
intern function 76 
Internet 211, 213-214, 216 
interval 202 
ip-tcp 213 
item, menu 142, 185 
item-list instance variable 142 
item-type-alist instance variable 

88-89 
iteration 64 
key 

Abort 7, 51 

End 71 

Function 6, 45, 47-50, 59, 219 

Help 6, 184 

Local 12 

Resume 7, 51 

Select 6, 48-49, 87 

Suspend 7, 184 
keyboard 5 

macro 1 99 
keys, modifier 5 
kill history 53 
kwc-letf macro 39 
let special form 69 
let-globally special form 32 
letf special form 39 
line 202 

lisp listener 8, 53 
List 

Callers, M-x 52 

Combined Methods, M-x 37, 40, 
52 

Fonts, M-x 185 



236 



INDEX 



Methods, M-x 52 

Variables, M-x 184 
load function 127 
load-patches function 168 
Local key 1 2 
locks, window 50 
logical 

host 133 

pathname 133 
login function 9 
Login command 9 
Lookup Key Bindings, M-x 184 
loop keyword 

always 70 

and 70 

append 69 

collect 69, 76 

count 69 

do 68, 70 

else 70 

finally 70, 77 

for 68, 70 

initially 70 

maximize 69 

minimize 69 

nconc 69 

never 70 

repeat 68, 76 

return 70 

sum 69 

thereis 70, 77 

unless 70 

until 70 

when 70, 76 

while 70 

with 69 
loop macro 64, 68 
m- . Zmacs command 13, 71, 224 
m-< Zmacs command 222 



m-> Zmacs command 222 

m- [ Zmacs command 222 

m- ] Zmacs command 222 

m-A Zmacs command 222 

m-Abort 7 

m-B Zmacs command 222 

m-D 

input editor command 53 

Zmacs command 222 
m-E Zmacs command 222 
m-F Zmacs command 222 
m-K Zmacs command 222 
m-Rubout 

input editor command 53 

Zmacs command 222 
m-sh-M Zmacs command 71, 77 
m-Suspend 7, 51 
m-W Zmacs command 223 
M-x 

Compile Buffer 223 

Compile File 223 

Copy File 127 

Describe Key Bindings 184 

Display Font 185 

Edit Callers 52 

Edit Combined Methods 52 

Edit Extended Command 184 

Edit Key 184 

Edit Methods 52 

Evaluate Buffer 223 

Evaluate Into Buffer 206 

Function Apropos 52 

Install Macro 200 

List Callers 52 

List Combined Methods 37, 40, 52 

List Fonts 185 

List Methods 52 

List Variables 184 

Lookup Key Bindings 184 






INDEX 



237 



Name Last Kbd Macro 200 

Set Variable 184 

Trace 50 
m-Y 

input editor command 53 

Zmacs command 53-54, 222 
macro 62, 71 

catch-error 176 

check-arg 176 

check-arg-type 176 

cond-every 63 

condition-bind 177, 180 

condition-bind-default 178 

condition-case 174, 176 

defresource 162 

defselect 76 

defsystem 165 

defun-method 84 

defvar 84 

defwhopper 27 

def window-resource 170 

dispatch 63 

dolist 67, 76 

dotimes 67 

error-restart 179 

error-restart-loop 179 

errset 176 

if 62 

ignore-errors 176 

keyboard 199 

kwc-letf 39 

loop 64, 68 

net : invoke-multiple- 
services 218 

select 62 

selector 62 

selectq 62, 76 

selectq-every 63 

setf 51 



signal-proceed-case 180 

tv: add- typeout- item-type 
89, 195 

typecase 63 

unless 62 

using-resource 162, 164 

when 62 

with-open-f ile 126, 201 

zwei: def com 188, 201 

zwei : def ine-keyboard- 
macro 200 

zwei: mark 203 

zwei: point 203 

zwei :with-editor-stream 
201 
macroexpand function 71 
make-instance function 19, 84 
make -system function 165,167-168 
make-system option 

: compile 167 

:noconfirm 168 

: print-only 168 

:version 168 
map-resource function 165 
mapcan function 66, 76 
mapcar function 66, 69 
mapcon function 66, 76 
maplist function 66 
mapping operators 64-65 
margins, window 76 
maximize loop keyword 69 
medium 211-212 
menu 142 

command 141, 143, 183 

edit screen 36, 49, 90 

item 142, 185 

system 12, 36, 45-46, 48, 50, 188 

trace 50 
merging pathnames 132 



238 



INDEX 



method 1 7 

: activate 48 

: alias -for- selected- 
windows 87 

:bury 49 

.•canonical -type 133 

: choose 142-143 

: clear-window 76, 195 

: compute-all-handlers- 
once 40 

: deactivate 48 

rdeexpose 48-49 

rdescribe 31 

rdeselect 48 

.•device 133 

: directory 133 

: draw-char 195 

: draw-circle 76 

: draw-line 36 

: draw-lines 36 

: draw-point 76 

: draw-rectangle 76 

: draw-triangle 76 

: execute 141-143 

: expose 48 

: force-redisplay 202 

:get 133 

:get-handler-for 31 

:host 133 

:init 84 

: inside-size 76 

:item 90, 195 

:kill 48 

: mouse -buttons 142 

: mouse-click 29,86,89-90, 
143 

: mouse -moves 90 

: mouse-standard-blinker 
186-187 



name 133 

new-canonical-type 133 
new-device 133 
new-directory 133 
new-name 133 
new-pathname 133 
new-raw-device 133 
new-raw-directory 133 
new-raw-name 133 
new-raw-type 133 
new- type 133 
new-version 133 
plist 133 

primitive-item 90, 195 
print-self 31, 140 
proceed 178, 180 
proceed-type-p 180 
proceed-types 180 
properties 133 
putprop 133 
raw-device 133 
raw-directory 133 
raw-name 133 
raw-type 133 
remprop 133 
report 175 
reverse-video-p 76 
select 48, 87 
selectable-windows 87 
send-if -handles 84 
set-character 186 
set-reverse-video-p 76 
string-for-host 133 
string-for-printing 133 
trans lated-pathname 135 
tyi 76 
type 133 
version 133 
which-operations 31 



INDEX 



239 



:who-line-documentation- 

string 89 
combination, :case 180 
combination, :or 29, 89 
combination, : override 89 
for : mouse -click, essential- 
mouse's 30 

methods 

combined 23 
primary 25 

mexp function 71, 74 

mini-buffer, 

pop-up 183-184 
reading from the 204 

minimize loop keyword 69 

mixing flavors 22 

modifier keys 5 

more processing 50 

mouse 

blinker 184-186 
documentation line 89 
process 29, 46, 58, 86, 88, 143, 
187 

mouse 

drag left Zmacs command 223 
left Zmacs command 222 
middle Zmacs command 223 

mouse-sensitive items 85, 88-89 

moving icons example 183 

multiple windows and processes 85 

Murray Hill standard utilities 52, 59 

name pathname component 1 3 1 

Name Last Kbd Macro, M-x 200 

namespace 9,211,214,216-217 

nconc 

function 66 
loop keyword 69 

net: basic-host flavor 130,133 

net : f ind-paths-to-service 
function 218 



net : invoke-multiple-services 

macro 218 
net : invoke-service-access- 

path function 218 
net : invoke-service-on-host 

function 218 
neti tenable function 215,219 
neti: reset function 215, 219 
network 211 
never loop keyword 70 
nonlocal exits 64 
Notifications window 6 
open option 

:byte-size 126 

: direction 125 

:if-exists 126 
open function 125, 201 
or special form 62 
output hold 47 
package 1 2 

user 12 
pane 85 
pathname 129 

component, device 131 

component, directory 131 

component, host 130 

component, name 131 

component, type 130 

component, version 130 

components 1 30 

logical 133 

physical 134 
pathnames 

case in 131 

default 132 

merging 132 
Peek 6, 45-47, 49, 219 
physical 

host 134 



240 



INDEX 



pathname 134 
point 202 

pop-up mini-buffer 183-184 
primary methods 25 
prime numbers 74 
probef function 127 
proceed types 180 
proceeding conditions 174-175, 177, 

179 
process 43, 85 

current 43 

mouse 29, 46, 58, 86, 88, 143, 187 
process-run-function function 

46, 143 
process-wait function 44, 47 
processes 

active 45 

arresting 45 

inactive 45 

multiple windows and 85 

resetting 45 

un-arresting 45 
processing, more 50 
prog special form 63, 68 
protocol 211-212 
race condition 86 
read function 205 
reading from the mini-buffer 204 
readline function 204 
renamef function 127 
repeat loop keyword 68, 76 
reporting bugs 52 
Reset Network command 215 
resetting 

processes 45 

the current process 46 
resource 1 6 1 

allocation 161 

deallocation 161 



restart handler 174, 178 
Resume key 7, 51 
return 

loop keyword 70 

special form 64, 77 
return- from special form 63 
rplacd function 76 
Rubout Zmacs command 222 
run bars 12 

run-reasons instance variable 45 
s-E Zmacs command 224 
scheduler 43 
screen 46 

scrolling, flashy 155 
select macro 62 
Select key 6, 48-49, 87 
selected windows 47 
selector macro 62 
selectq macro 62, 76 
selectq-every macro 63 
self variable 19 
send function 19 
serial 

lines 214,217 

streams 217 
serial-pseudonet 214 
service 211-212, 218 

access path 218 

futures 218 
Set Chaos-address Fep command 

216 
Set Variable, M-x 184 
setf macro 51 
shared i/o buffer 141 
Show Documentation command 8 
si : examiner-compute-magic- 
list function 40 
si :halt function 11 
si : login-to-sys-host function 9 






INDEX 



241 



si :make-serial-stream function 

217 
si: parse-host function 218 
si : set-system-source-file 

function 168 
si : vanilla-flavor flavor 30, 84 
signal function 175, 180 
signal-proceed-case macro 180 
signaling and handling conditions 173 
simple condition 175 
site directory 134, 168, 170 
spec, function 51 
special form 

♦catch 64 

and 62 

block 63 

catch 64, 76 

cond 61 

defconst 36 

def flavor 18 

def method 18 

defvar 36 

do 63-64, 66 

go 68 

grindef 52 

let 69 

let-globally 32 

letf 39 

or 62 

prog 63, 68 

return 64, 77 

return-from 63 

throw 64, 76 

trace 50 

untrace 50 
standard utilities, Murray Hill 52, 59 
standard- input variable 123 
standard-output variable 123 
Start Fep command 1 1 



stream 119 
cold-load 50 

operation, : characters 121 
operation, : clear-input 122 
operation, : clear-output 122 
operation, : clear-screen 123 
operation, : clear- window 123 
operation, : close 122 
operation, : creation-date 128 
operation, : direction 121 
operation, : finish 122 
operation, : force-output 122 
operation, : length 128 
operation, : listen 121 
operation, : pathname 128 
operation, :read-cursorpos 

122 
operation, : read-pointer 123 
operation, : set-cursorpos 123 
operation, : set-pointer 123 
operation, : string-in 121 
operation, : string-out 120-121 
operation, : truename 128 
operation, :tyi 120, 126 
operation, :tyi -no-hang 122 
operation, :tyipeek 121 
operation, :tyo 120, 124, 126 
operation, :untyi 120, 125 
operation, :which-operations 

120 
synonym 1 24 

stream-default-handler func- 
tion 124 

streams, default handler for 120, 122, 
124 

string-append function 76 

subnet 214-216 

sum loop keyword 69 

superior instance variable 46 



242 



INDEX 



Suspend Zmacs command 13, 224 

Suspend key 7, 184 

synonym stream 124 

sys : abort flavor 179 

system 165 

menu 12, 36, 45-46, 48, 50, 188 

terminal-io variable 123 

Terminal window 6 

terminator 215 

thereis loop keyword 70, 77 

throw special form 64, 76 

trace menu 50 

trace special form 50 

Trace, M-x 50 

tracing functions 50 

transceiver 214 

transferring text between windows 53 

transformation, defsystem 167 

tree example 139 

tv : add- to- system-menu- 
programs-column function 188 

tv:add-typeout- item- type 
macro 89, 195 

tv: basic-mouse- sensitive- 
items flavor 88-90, 195 

tv : bordered-constraint-f rame 
flavor 1 4 1 

tv : bordered-constraint- 
frame-with- shared- io- 
buf f er flavor 141 

tv: current-font instance variable 
186 

tv:dont-select-with-mouse- 
mixin flavor 87 

tv:f lashy-scrolling-mixin 
flavor 155 

tv:get-line-from-keyboard 
function 90 

tv: item- list instance variable 195 



tv: lisp-listener flavor 17, 85 
tv: lisp-listener-pane flavor 87 
tv: main- screen variable 187 
tv: make -window function 19, 48 
tv: menu-choose function 143 
tv: mouse-process variable 46 
tv: mouse-set-blinker function 

186 
tv: mouse -set-blinker- 
definition function 186 
tv : pane -mixin flavor 87 
tv:pane-no-mouse-select- 

mixin flavor 87, 185 
tv : previously-selected- 
windows variable 47, 49 
tv: process -mixin flavor 88,184 
tv: select-or-create-window- 

of- flavor function 189 
tv: selected-window variable 48 
tv: sheet flavor 47, 88 
tv : stream-mixin flavor 44 
type pathname component 1 30 
typecase macro 63 
typein line 204 
typeout window 13,184 
un-arresting processes 45 
unless 

loop keyword 70 
macro 62 
until loop keyword 70 
untrace special form 50 
user package 12 

using-resource macro 162, 164 
variable 
* 52-53 

error-output 124 
ignore 84 
self 19 
standard- input 123 



INDEX 



243 



standard-output 123 




command, 


c-A 222 


terminal-io 123 




command, 


c-B 222 


tvrmain-screen 187 




command, 


c-D 222 


tv: mouse-process 46 




command, 


c-E 222 


tv: previously- selected- 


command, 


c-F 222 


windows 47, 49 




command, 


c-K 222 


tv : selected-window 


48 


command, 


c-m-[ 222 


zwei:*interval* 202 


204 


command, 


c-m-] 222 


zwei : *numeric-arg* 


188 


command, 


c-m-A 222 


zwei: * standard- comtab* 201 


command, 


c-m-B 222 


zwei : *window* 202,204 


command, 


c-m-E 222 


zwei : *zmacs-comtab* 


201 


command, 


c-m-F 222 


version pathname component 130 


command, 


c-m-K 222 


viewf function 127 




command, 


c-m-L 223 


wait-function 44 




command, 


c-m-Rubout 222 


warm boot 1 1 




command, 


c-m-Y 54 


when 




command, 


c-N 222 


loop keyword 70, 76 




command, 


c-P 222 


macro 62 




command, 


c-sh-A 54 


while loop keyword 70 




command, 


c-sh-C 223 


who- calls function 52 




command, 


c-sh-E 223 


whopper 26 




command, 


c-sh-M 71, 77 


window 46, 85 




command, 


c-Space 223 


background 124 




command, 


c-W 223 


locks 50 




command, 


c-X ( 199 


margins 76 




command, 


c-X ) 199 


windows 




command, 


c-X B 223 


and processes, multiple 8f 




command, 


c-X c-B 223 


deactivated 46-47 




command, 


c-X c-F 13, 223 


deexposed 46 




command, 


c-X c-S 13, 223 


exposed 47 




command, 


c-X c-W 223 


selected 47 




command, 


c-X D 13, 224 


transferring text between 


53 


command, 


c-X E 199 


with loop keyword 69 




command, 


c-Y 53, 222 


with-open-f ile macro 126, 201 


command, 


Clear Input 222 


wrapper 28 




command, 


End 224 


x-of f set instance variable 


187 


command, 


Help 13, 221, 224 


y-of f set instance variable 


187 


command, 


m-. 13,71,224 


Zmacs 




command, 


m-< 222 



244 



INDEX 



command, m-> 222 

command, ra-[ 222 

command, m-] 222 

command, m-A 222 

command, m-B 222 

command, m-D 222 

command, m-E 222 

command, m-F 222 

command, m-K 222 

command, m-Rubout 222 

command, m-sh-M 71, 77 

command, m-W 223 

command, m-Y 53-54, 222 

command, mouse drag left 
223 

command, mouse left 222 

command, mouse middle 223 

command, Rubout 222 

command, s-E 224 

command, Suspend 13, 224 

editor 6, 12, 53-54, 199, 221 
Zmail 6, 201 
zwei : *interval* variable 202, 

204 
zwei : *numeric-arg* variable 188 
zwei : *standard-comtab* variable 

201 
zwei : *window* variable 202, 204 
zwei : *zmacs-comtab* variable 

201 
zwei : bp defstruct 202 
zwei : buff er flavor 202 
zwei : command- store function 201 
zwei : completing-read-f rom- 

mini-buf f er function 205 
zwei :def com macro 188,201 
zwei : def ine-keyboard-macro 

macro 200 
zwei : file-buffer flavor 202 



zwei : find-combined-methods 

function 40 
zwei: interval flavor 202 
zwei : interval-stream 

flavor 202 

function 202 
zwei : interval-stream-into-bp 

function 206 
zwei : line defstruct 202 
zwei :make-command-alist func- 
tion 188 
zwei :mark macro 203 
zwei mode flavor 202 
zwei : open-editor-stream func- 
tion 201 
zwei : point macro 203 
zwei : read-buff er-name function 

205 
zwei : read-def aulted-pathname 

function 205 
zwei : set-comtab function 188, 

201 
zwei : set-comtab-indirection 

function 188 
zwei: top-level-node flavor 202 
zwei : type in- line - 

completing-read function 205 
zwei : typein-line-f orm-to- 

eval function 205 
zwei : typein-line-multi- 

line-read function 205 
zwei : typein-line-read function 

204 
zwei : typein-line-readline 

function 204 
zwei : window defstruct 202 
zwei :window-with-comtab flavor 

184-185 
zwei :with-editor-stream macro 

201 



Please send me a copy of the examples tape that accompanies Using the 
Lisp Machine. Enclosed is my check for $40.00, plus applicable sales tax,* 
made payable to Symbolics, Inc. This fee includes domestic postage and 
handling. (Outside North America, add $10.00 for postage.) 

Ship the tape to the following street address (no PO boxes, please): 



(name) 



(company) 



(street) 



(city) (state) (zip) 



( ) 
(phone) 



♦Residents of the following states add appropriate sales tax: AZ, CA, CO. CT, FL, GA, IL. K.S. MA, 
MN, NJ, NM, NY, OH, PA, TX, VA, WA. 



LISP LORE: A GUIDE TO PROGRAMMING THE 
LISP MACHINE is a course in programming a Lisp 
machine. The book presents a readily understandable 
introduction to several representative areas of interest, 
including enough information to show how easy it is to 
build useful programs on the Lisp machine. A graduated 
series of exercises, with hints and solutions, is also 
included in the text. 

The book assumes some background in LISP and experi- 
ence with some dialect of the language; however, no 
experience with the Lisp machine itself is required. 



Klu wer A cademic Publishers 0-89838-220-3