blob: ec7aaefb76c6134680f96607a0a271c3d943635f [file] [log] [blame]
Guido van Rossum2bbb3c01992-02-11 15:52:24 +00001\documentstyle[11pt,times]{article}
2
3\title{
4Interactively Testing Remote Servers Using the Python Programming Language
5}
6
7\author{
8 Guido van Rossum \\
9 CWI, dept. CST; Kruislaan 413 \\
10 1098 SJ Amsterdam, The Netherlands \\
11 E-mail: {\tt guido@cwi.nl}
12\and
13 Jelke de Boer \\
14 HIO Enschede; P.O.Box 1326 \\
15 7500 BH Enschede, The Netherlands
16}
17
18\begin{document}
19
20\maketitle
21
22\begin{abstract}
23This paper describes how two tools that were developed quite
24independently gained in power by a well-designed connection between
25them. The tools are Python, an interpreted prototyping language, and
26AIL, a Remote Procedure Call stub generator. The context is Amoeba, a
27well-known distributed operating system developed jointly by the Free
28University and CWI in Amsterdam.
29
30As a consequence of their integration, both tools have profited:
31Python gained usability when used with Amoeba --- for which it was not
32specifically developed --- and AIL users now have a powerful
33interactive tool to test servers and to experiment with new
34client/server interfaces.%
35\footnote{
36An earlier version of this paper was presented at the Spring 1991
37EurOpen Conference in Troms{\o} under the title ``Linking a Stub
38Generator (AIL) to a Prototyping Language (Python).''
39}
40\end{abstract}
41
42\section{Introduction}
43
44Remote Procedure Call (RPC) interfaces, used in distributed systems
45like Amoeba
46\cite{Amoeba:IEEE,Amoeba:CACM},
47have a much more concrete character than local procedure call
48interfaces in traditional systems. Because clients and servers may
49run on different machines, with possibly different word size, byte
50order, etc., much care is needed to describe interfaces exactly and to
51implement them in such a way that they continue to work when a client
52or server is moved to a different machine. Since machines may fail
53independently, error handling must also be treated more carefully.
54
55A common approach to such problems is to use a {\em stub generator}.
56This is a program that takes an interface description and transforms
57it into functions that must be compiled and linked with client and
58server applications. These functions are called by the application
59code to take care of details of interfacing to the system's RPC layer,
60to implement transformations between data representations of different
61machines, to check for errors, etc. They are called `stubs' because
62they don't actually perform the action that they are called for but
63only relay the parameters to the server
64\cite{RPC}.
65
66Amoeba's stub generator is called AIL, which stands for Amoeba
67Interface Language
68\cite{AIL}.
69The first version of AIL generated only C functions, but an explicit
70goal of AIL's design was {\em retargetability}: it should be possible
71to add back-ends that generate stubs for different languages from the
72same interface descriptions. Moreover, the stubs generated by
73different back-ends must be {\em interoperable}: a client written in
74Modula-3, say, should be able to use a server written in C, and vice
75versa.
76
77This interoperability is the key to the success of the marriage
78between AIL and Python. Python is a versatile interpreted language
79developed by the first author. Originally intended as an alternative
80for the kind of odd jobs that are traditionally solved by a mixture of
81shell scripts, manually given shell commands, and an occasional ad hoc
82C program, Python has evolved into a general interactive prototyping
83language. It has been applied to a wide range of problems, from
84replacements for large shell scripts to fancy graphics demos and
85multimedia applications.
86
87One of Python's strengths is the ability for the user to type in some
88code and immediately run it: no compilation or linking is necessary.
89Interactive performance is further enhanced by Python's concise, clear
90syntax, its very-high-level data types, and its lack of declarations
91(which is compensated by run-time type checking). All this makes
92programming in Python feel like a leisure trip compared to the hard
93work involved in writing and debugging even a smallish C program.
94
95It should be clear by now that Python will be the ideal tool to test
96servers and their interfaces. Especially during the development of a
97complex server, one often needs to generate test requests on an ad hoc
98basis, to answer questions like ``what happens if request X arrives
99when the server is in state Y,'' to test the behavior of the server
100with requests that touch its limitations, to check server responses to
101all sorts of wrong requests, etc. Python's ability to immediately
102execute `improvised' code makes it a much better tool for this
103situation than C.
104
105The link to AIL extends Python with the necessary functionality to
106connect to arbitrary servers, making the server testbed sketched above
107a reality. Python's high-level data types, general programming
108features, and system interface ensure that it has all the power and
109flexibility needed for the job.
110
111One could go even further than this. Current distributed operating
112systems, based on client-server interaction, all lack a good command
113language or `shell' to give adequate access to available services.
114Python has considerable potential for becoming such a shell.
115
116\subsection{Overview of this Paper}
117
118The rest of this paper contains three major sections and a conclusion.
119First an overview of the Python programming language is given. Next
120comes a short description of AIL, together with some relevant details
121about Amoeba. Finally, the design and construction of the link
122between Python and AIL is described in much detail. The conclusion
123looks back at the work and points out weaknesses and strengths of
124Python and AIL that were discovered in the process.
125
126\section{An Overview of Python}
127
128Python%
129\footnote{
130Named after the funny TV show, not the nasty reptile.
131}
132owes much to ABC
133\cite{ABC},
134a language developed at CWI as a programming language for non-expert
135computer users. Python borrows freely from ABC's syntax and data
136types, but adds modules, exceptions and classes, extensibility, and
137the ability to call system functions. The concepts of modules,
138exceptions and (to some extent) classes are influenced strongly by
139their occurrence in Modula-3
140\cite{Modula-3}.
141
142Although Python resembles ABC in many ways, there is a a clear
143difference in application domain. ABC is intended to be the only
144programming language for those who use a computer as a tool, but
145occasionally need to write a program. For this reason, ABC is not
146just a programming language but also a programming environment, which
147comes with an integrated syntax-directed editor and some source
148manipulation commands. Python, on the other hand, aims to be a tool
149for professional (system) programmers, for whom having a choice of
150languages with different feature sets makes it possible to choose `the
151right tool for the job.' The features added to Python make it more
152useful than ABC in an environment where access to system functions
153(such as file and directory manipulations) are common. They also
154support the building of larger systems and libraries. The Python
155implementation offers little in the way of a programming environment,
156but is designed to integrate seamlessly with existing programming
157environments (e.g. UNIX and Emacs).
158
159Perhaps the best introduction to Python is a short example. The
160following is a complete Python program to list the contents of a UNIX
161directory.
162\begin{verbatim}
163import sys, posix
164
165def ls(dirname): # Print sorted directory contents
166 names = posix.listdir(dirname)
167 names.sort()
168 for name in names:
169 if name[0] != '.': print name
170
171ls(sys.argv[1])
172\end{verbatim}
173The largest part of this program, in the middle starting with {\tt
174def}, is a function definition. It defines a function named {\tt ls}
175with a single parameter called {\tt dirname}. (Comments in Python
176start with `\#' and extend to the end of the line.) The function body
177is indented: Python uses indentation for statement grouping instead of
178braces or begin/end keywords. This is shorter to type and avoids
179frustrating mismatches between the perception of grouping by the user
180and the parser. Python accepts one statement per line; long
181statements may be broken in pieces using the standard backslash
182convention. If the body of a compound statement is a single, simple
183statement, it may be placed on the same line as the head.
184
185The first statement of the function body calls the function {\tt
186listdir} defined in the module {\tt posix}. This function returns a
187list of strings representing the contents of the directory name passed
188as a string argument, here the argument {\tt dirname}. If {\tt
189dirname} were not a valid directory name, or perhaps not even a
190string, {\tt listdir} would raise an exception and the next statement
191would never be reached. (Exceptions can be caught in Python; see
192later.) Assuming {\tt listdir} returns normally, its result is
193assigned to the local variable {\tt names}.
194
195The second statement calls the method {\tt sort} of the variable {\tt
196names}. This method is defined for all lists in Python and does the
197obvious thing: the elements of the list are reordered according to
198their natural ordering relationship. Since in our example the list
199contains strings, they are sorted in ascending ASCII order.
200
201The last two lines of the function contain a loop that prints all
202elements of the list whose first character isn't a period. In each
203iteration, the {\tt for} statement assigns an element of the list to
204the local variable {\tt name}. The {\tt print} statement is intended
205for simple-minded output; more elaborate formatting is possible with
206Python's string handling functions.
207
208The other two parts of the program are easily explained. The first
209line is an {\tt import} statement that tells the interpreter to import
210the modules {\tt sys} and {\tt posix}. As it happens these are both
211built into the interpreter. Importing a module (built-in or
212otherwise) only makes the module name available in the current scope;
213functions and data defined in the module are accessed through the dot
214notation as in {\tt posix.listdir}. The scope rules of Python are
215such that the imported module name {\tt posix} is also available in
216the function {\tt ls} (this will be discussed in more detail later).
217
218Finally, the last line of the program calls the {\tt ls} function with
219a definite argument. It must be last since Python objects must be
220defined before they can be used; in particular, the function {\tt ls}
221must be defined before it can be called. The argument to {\tt ls} is
222{\tt sys.argv[1]}, which happens to be the Python equivalent of {\tt
223\$1} in a shell script or {\tt argv[1]} in a C program's {\tt main}
224function.
225
226\subsection{Python Data Types}
227
228(This and the following subsections describe Python in quite a lot of
229detail. If you are more interested in AIL, Amoeba and how they are
230linked with Python, you can skip to section 3 now.)
231
232Python's syntax may not have big surprises (which is exactly as it
233should be), but its data types are quite different from what is found
234in languages like C, Ada or Modula-3. All data types in Python, even
235integers, are `objects'. All objects participate in a common garbage
236collection scheme (currently implemented using reference counting).
237Assignment is cheap, independent of object size and type: only a
238pointer to the assigned object is stored in the assigned-to variable.
239No type checking is performed on assignment; only specific operations
240like addition test for particular operand types.
241
242The basic object types in Python are numbers, strings, tuples, lists
243and dictionaries. Some other object types are open files, functions,
244modules, classes, and class instances; even types themselves are
245represented as objects. Extension modules written in C can define
246additional object types; examples are objects representing windows and
247Amoeba capabilities. Finally, the implementation itself makes heavy
248use of objects, and defines some private object types that aren't
249normally visible to the user. There is no explicit pointer type in
250Python.
251
252{\em Numbers}, both integers and floating point, are pretty
253straightforward. The notation for numeric literals is the same as in
254C, including octal and hexadecimal integers; precision is the same as
255{\tt long} or {\tt double} in C\@. A third numeric type, `long
256integer', written with an `L' suffix, can be used for arbitrary
257precision calculations. All arithmetic, shifting and masking
258operations from C are supported.
259
260{\em Strings} are `primitive' objects just like numbers. String
261literals are written between single quotes, using similar escape
262sequences as in C\@. Operations are built into the language to
263concatenate and to replicate strings, to extract substrings, etc.
264There is no limit to the length of the strings created by a program.
265There is no separate character data type; strings of length one do
266nicely.
267
268{\em Tuples} are a way to `pack' small amounts of heterogeneous data
269together and carry them around as a unit. Unlike structure members in
270C, tuple items are nameless. Packing and unpacking assignments allow
271access to the items, for example:
272\begin{verbatim}
273x = 'Hi', (1, 2), 'World' # x is a 3-item tuple,
274 # its middle item is (1, 2)
275p, q, r = x # unpack x into p, q and r
276a, b = q # unpack q into a and b
277\end{verbatim}
278A combination of packing and unpacking assignment can be used as
279parallel assignment, and is idiom for permutations, e.g.:
280\begin{verbatim}
281p, q = q, p # swap without temporary
282a, b, c = b, c, a # cyclic permutation
283\end{verbatim}
284Tuples are also used for function argument lists if there is more than
285one argument. A tuple object, once created, cannot be modified; but
286it is easy enough to unpack it and create a new, modified tuple from
287the unpacked items and assign this to the variable that held the
288original tuple object (which will then be garbage-collected).
289
290{\em Lists} are array-like objects. List items may be arbitrary
291objects and can be accessed and changed using standard subscription
292notation. Lists support item insertion and deletion, and can
293therefore be used as queues, stacks etc.; there is no limit to their
294size.
295
296Strings, tuples and lists together are {\em sequence} types. These
297share a common notation for generic operations on sequences such as
298subscription, concatenation, slicing (taking subsequences) and
299membership tests. As in C, subscripts start at 0.
300
301{\em Dictionaries} are `mappings' from one domain to another. The
302basic operations on dictionaries are item insertion, extraction and
303deletion, using subscript notation with the key as subscript. (The
304current implementation allows only strings in the key domain, but a
305future version of the language may remove this restriction.)
306
307\subsection{Statements}
308
309Python has various kinds of simple statements, such as assignments
310and {\tt print} statements, and several kinds of compound statements,
311like {\tt if} and {\tt for} statements. Formally, function
312definitions and {\tt import} statements are also statements, and there
313are no restrictions on the ordering of statements or their nesting:
314{\tt import} may be used inside a function, functions may be defined
315conditionally using an {\tt if} statement, etc. The effect of a
316declaration-like statement takes place only when it is executed.
317
318All statements except assignments and expression statements begin with
319a keyword: this makes the language easy to parse. An overview of the
320most common statement forms in Python follows.
321
322An {\em assignment} has the general form
323\vspace{\itemsep}
324
325\noindent
326{\em variable $=$ variable $= ... =$ variable $=$ expression}
327\vspace{\itemsep}
328
329It assigns the value of the expression to all listed variables. (As
330shown in the section on tuples, variables and expressions can in fact
331be comma-separated lists.) The assignment operator is not an
332expression operator; there are no horrible things in Python like
333\begin{verbatim}
334while (p = p->next) { ... }
335\end{verbatim}
336Expression syntax is mostly straightforward and will not be explained
337in detail here.
338
339An {\em expression statement} is just an expression on a line by
340itself. This writes the value of the expression to standard output,
341in a suitably unambiguous way, unless it is a `procedure call' (a
342function call that returns no value). Writing the value is useful
343when Python is used in `calculator mode', and reminds the programmer
344not to ignore function results.
345
346The {\tt if} statement allows conditional execution. It has optional
347{\tt elif} and {\tt else} parts; a construct like {\tt
348if...elif...elif...elif...else} can be used to compensate for the
349absence of a {\em switch} or {\em case} statement.
350
351Looping is done with {\tt while} and {\tt for} statements. The latter
352(demonstrated in the `ls' example earlier) iterates over the elements
353of a `sequence' (see the discussion of data types below). It is
354possible to terminate a loop with a {\tt break} statement or to start
355the next iteration with {\tt continue}. Both looping statements have
356an optional {\tt else} clause which is executed after the loop is
357terminated normally, but skipped when it is terminated by {\tt break}.
358This can be handy for searches, to handle the case that the item is
359not found.
360
361Python's {\em exception} mechanism is modelled after that of Modula-3.
362Exceptions are raised by the interpreter when an illegal operation is
363tried. It is also possible to explicitly raise an exception with the
364{\tt raise} statement:
365\vspace{\itemsep}
366
367\noindent
368{\tt raise {\em expression}, {\em expression}}
369\vspace{\itemsep}
370
371The first expression identifies which exception should be raised;
372there are several built-in exceptions and the user may define
373additional ones. The second, optional expression is passed to the
374handler, e.g. as a detailed error message.
375
376Exceptions may be handled (caught) with the {\tt try} statement, which
377has the following general form:
378\vspace{\itemsep}
379
380\noindent
381{\tt
382\begin{tabular}{l}
383try: {\em block} \\
384except {\em expression}, {\em variable}: {\em block} \\
385except {\em expression}, {\em variable}: {\em block} \\
386... \\
387except: {\em block}
388\end{tabular}
389}
390\vspace{\itemsep}
391
392When an exception is raised during execution of the first block, a
393search for an exception handler starts. The first {\tt except} clause
394whose {\em expression} matches the exception is executed. The
395expression may specify a list of exceptions to match against. A
396handler without an expression serves as a `catch-all'. If there is no
397match, the search for a handler continues with outer {\tt try}
398statements; if no match is found on the entire invocation stack, an
399error message and stack trace are printed, and the program is
400terminated (interactively, the interpreter returns to its main loop).
401
402Note that the form of the {\tt except} clauses encourages a style of
403programming whereby only selected exceptions are caught, passing
404unanticipated exceptions on to the caller and ultimately to the user.
405This is preferable over a simpler `catch-all' error handling
406mechanism, where a simplistic handler intended to catch a single type
407of error like `file not found' can easily mask genuine programming
408errors --- especially in a language like Python which relies strongly
409on run-time checking and allows the catching of almost any type of
410error.
411
412Other common statement forms, which we have already encountered, are
413function definitions, {\tt import} statements and {\tt print}
414statements. There is also a {\tt del} statement to delete one or more
415variables, a {\tt return} statement to return from a function, and a
416{\tt global} statement to allow assignments to global variables.
417Finally, the {\tt pass} statement is a no-op.
418
419\subsection{Execution Model}
420
421A Python program is executed by a stack-based interpreter.
422
423When a function is called, a new `execution environment' for it is
424pushed onto the stack. An execution environment contains (among other
425data) pointers to two `symbol tables' that are used to hold variables:
426the local and the global symbol table. The local symbol table
427contains local variables of the current function invocation (including
428the function arguments); the global symbol table contains variables
429defined in the module containing the current function.
430
431The `global' symbol table is thus only global with respect to the
432current function. There are no system-wide global variables; using
433the {\tt import} statement it is easy enough to reference variables
434that are defined in other modules. A system-wide read-only symbol
435table is used for built-in functions and constants though.
436
437On assignment to a variable, by default an entry for it is made in the
438local symbol table of the current execution environment. The {\tt
439global} command can override this (it is not enough that a global
440variable by the same name already exists). When a variable's value is
441needed, it is searched first in the local symbol table, then in the
442global one, and finally in the symbol table containing built-in
443functions and constants.
444
445The term `variable' in this context refers to any name: functions and
446imported modules are searched in exactly the same way.
447
448Names defined in a module's symbol table survive until the end of the
449program. This approximates the semantics of file-static global
450variables in C or module variables in Modula-3. A module is
451initialized the first time it is imported, by executing the text of
452the module as a parameterless function whose local and global symbol
453tables are the same, so names are defined in module's symbol table.
454(Modules implemented in C have another way to define symbols.)
455
456A Python main program is read from standard input or from a script
457file passed as an argument to the interpreter. It is executed as if
458an anonymous module was imported. Since {\tt import} statements are
459executed like all other statements, the initialization order of the
460modules used in a program is defined by the flow of control through
461the program.
462
463The `attribute' notation {\em m.name}, where {\em m} is a module,
464accesses the symbol {\em name} in that module's symbol table. It can
465be assigned to as well. This is in fact a special case of the
466construct {\em x.name} where {\em x} denotes an arbitrary object; the
467type of {\em x} determines how this is to be interpreted, and what
468assignment to it means.
469
470For instance, when {\tt a} is a list object, {\tt a.append} yields a
471built-in `method' object which, when called, appends an item to {\tt a}.
472(If {\tt a} and {\tt b} are distinct list objects, {\tt a.append} and
473{\tt b.append} are distinguishable method objects.) Normally, in
474statements like {\tt a.append(x)}, the method object {\tt a.append} is
475called and then discarded, but this is a matter of convention.
476
477List attributes are read-only --- the user cannot define new list
478methods. Some objects, like numbers and strings, have no attributes
479at all. Like all type checking in Python, the meaning of an attribute
480is determined at run-time --- when the parser sees {\em x.name}, it
481has no idea of the type of {\em x}. Note that {\em x} here does not
482have to be a variable --- it can be an arbitrary (perhaps
483parenthesized) expression.
484
485Given the flexibility of the attribute notation, one is tempted to use
486methods to replace all standard operations. Yet, Python has kept a
487small repertoire of built-in functions like {\tt len()} and {\tt
488abs()}. The reason is that in some cases the function notation is
489more familiar than the method notation; just like programs would
490become less readable if all infix operators were replaced by function
491calls, they would become less readable if all function calls had to be
492replaced by method calls (and vice versa!).
493
494The choice whether to make something a built-in function or a method
495is a matter of taste. For arithmetic and string operations, function
496notation is preferred, since frequently the argument to such an
497operation is an expression using infix notation, as in {\tt abs(a+b)};
498this definitely looks better than {\tt (a+b).abs()}. The choice
499between make something a built-in function or a function defined in a
500built-in method (requiring {\tt import}) is similarly guided by
501intuition; all in all, only functions needed by `general' programming
502techniques are built-in functions.
503
504\subsection{Classes}
505
506Python has a class mechanism distinct from the object-orientation
507already explained. A class in Python is not much more than a
508collection of methods and a way to create class instances. Class
509methods are ordinary functions whose first parameter is the class
510instance; they are called using the method notation.
511
512For instance, a class can be defined as follows:
513\begin{verbatim}
514class Foo:
515 def meth1(self, arg): ...
516 def meth2(self): ...
517\end{verbatim}
518A class instance is created by
519{\tt x = Foo()}
520and its methods can be called thus:
521\begin{verbatim}
522x.meth1('Hi There!')
523x.meth2()
524\end{verbatim}
525The functions used as methods are also available as attributes of the
526class object, and the above method calls could also have been written
527as follows:
528\begin{verbatim}
529Foo.meth1(x, 'Hi There!')
530Foo.meth2(x)
531\end{verbatim}
532Class methods can store instance data by assigning to instance data
533attributes, e.g.:
534\begin{verbatim}
535self.size = 100
536self.title = 'Dear John'
537\end{verbatim}
538Data attributes do not have to be declared; as with local variables,
539they spring into existence when assigned to. It is a matter of
540discretion to avoid name conflicts with method names. This facility
541is also available to class users; instances of a method-less class can
542be used as records with named fields.
543
544There is no built-in mechanism for instance initialization. Classes
545by convention provide an {\tt init()} method which initializes the
546instance and then returns it, so the user can write
547\begin{verbatim}
548x = Foo().init('Dr. Strangelove')
549\end{verbatim}
550
551Any user-defined class can be used as a base class to derive other
552classes. However, built-in types like lists cannot be used as base
553classes. (Incidentally, the same is true in C++ and Modula-3.) A
554class may override any method of its base classes. Instance methods
555are first searched in the method list of their class, and then,
556recursively, in the method lists of their base class. Initialization
557methods of derived classes should explicitly call the initialization
558methods of their base class.
559
560A simple form of multiple inheritance is also supported: a class can
561have multiple base classes, but the language rules for resolving name
562conflicts are somewhat simplistic, and consequently the feature has so
563far found little usage.
564
565\subsection{The Python Library}
566
567Python comes with an extensive library, structured as a collection of
568modules. A few modules are built into the interpreter: these
569generally provide access to system libraries implemented in C such as
570mathematical functions or operating system calls. Two built-in
571modules provide access to internals of the interpreter and its
572environment. Even abusing these internals will at most cause an
573exception in the Python program; the interpreter will not dump core
574because of errors in Python code.
575
576Most modules however are written in Python and distributed with the
577interpreter; they provide general programming tools like string
578operations and random number generators, provide more convenient
579interfaces to some built-in modules, or provide specialized services
580like a {\em getopt}-style command line option processor for
581stand-alone scripts.
582
583There are also some modules written in Python that dig deep in the
584internals of the interpreter; there is a module to browse the stack
585backtrace when an unhandled exception has occurred, one to disassemble
586the internal representation of Python code, and even an interactive
587source code debugger which can trace Python code, set breakpoints,
588etc.
589
590\subsection{Extensibility}
591
592It is easy to add new built-in modules written in C to the Python
593interpreter. Extensions appear to the Python user as built-in
594modules. Using a built-in module is no different from using a module
595written in Python, but obviously the author of a built-in module can
596do things that cannot be implemented purely in Python.
597
598In particular, built-in modules can contain Python-callable functions
599that call functions from particular system libraries (`wrapper
600functions'), and they can define new object types. In general, if a
601built-in module defines a new object type, it should also provide at
602least one function that creates such objects. Attributes of such
603object types are also implemented in C; they can return data
604associated with the object or methods, implemented as C functions.
605
606For instance, an extension was created for Amoeba: it provides wrapper
607functions for the basic Amoeba name server functions, and defines a
608`capability' object type, whose methods are file server operations.
609Another extension is a built-in module called {\tt posix}; it provides
610wrappers around post UNIX system calls. Extension modules also
611provide access to two different windowing/graphics interfaces: STDWIN
612\cite{STDWIN}
613(which connects to X11 on UNIX and to the Mac Toolbox on the
614Macintosh), and the Graphics Library (GL) for Silicon Graphics
615machines.
616
617Any function in an extension module is supposed to type-check its
618arguments; the interpreter contains a convenience function to
619facilitate extracting C values from arguments and type-checking them
620at the same time. Returning values is also painless, using standard
621functions to create Python objects from C values.
622
623On some systems extension modules may be dynamically loaded, thus
624avoiding the need to maintain a private copy of the Python interpreter
625in order to use a private extension.
626
627\section{A Short Description of AIL and Amoeba}
628
629An RPC stub generator takes an interface description as input. The
630designer of a stub generator has at least two choices for the input
631language: use a suitably restricted version of the target language, or
632design a new language. The first solution was chosen, for instance,
633by the designers of Flume, the stub generator for the Topaz
634distributed operating system built at DEC SRC
635\cite{Flume,Evolving}.
636
637Flume's one and only target language is Modula-2+ (the predecessor of
638Modula-3). Modula-2+, like Modula-N for any N, has an interface
639syntax that is well suited as a stub generator input language: an
640interface module declares the functions that are `exported' by a
641module implementation, with their parameter and return types, plus the
642types and constants used for the parameters. Therefore, the input to
643Flume is simply a Modula-2+ interface module. But even in this ideal
644situation, an RPC stub generator needs to know things about functions
645that are not stated explicitly in the interface module: for instance,
646the transfer direction of VAR parameters (IN, OUT or both) is not
647given. Flume solves this and other problems by a mixture of
648directives hidden in comments and a convention for the names of
649objects. Thus, one could say that the designers of Flume really
650created a new language, even though it looks remarkably like their
651target language.
652
653\subsection{The AIL Input Language}
654
655Amoeba uses C as its primary programming language. C function
656declarations (at least in `Classic' C) don't specify the types of
657the parameters, let alone their transfer direction. Using this as
658input for a stub generator would require almost all information for
659the stub generator to be hidden inside comments, which would require a
660rather contorted scanner. Therefore we decided to design the input
661syntax for Amoeba's stub generator `from scratch'. This gave us the
662liberty to invent proper syntax not only for the transfer direction of
663parameters, but also for variable-length arrays.
664
665On the other hand we decided not to abuse our freedom, and borrowed as
666much from C as we could. For instance, AIL runs its input through the
667C preprocessor, so we get macros, include files and conditional
668compilation for free. AIL's type declaration syntax is a superset of
669C's, so the user can include C header files to use the types declared
670there as function parameter types --- which are declared using
671function prototypes as in C++ or Standard C\@. It should be clear by
672now that AIL's lexical conventions are also identical to C's. The
673same is true for its expression syntax.
674
675Where does AIL differ from C, then? Function declarations in AIL are
676grouped in {\em classes}. Classes in AIL are mostly intended as a
677grouping mechanism: all functions implemented by a server are grouped
678together in a class. Inheritance is used to form new groups by adding
679elements to existing groups; multiple inheritance is supported to join
680groups together. Classes can also contain constant and type
681definitions, and one form of output that AIL can generate is a header
682file for use by C programmers who wish to use functions from a
683particular AIL class.
684
685Let's have a look at some (unrealistically simple) class definitions:
686\begin{verbatim}
687#include <amoeba.h> /* Defines `capability', etc. */
688
689class standard_ops [1000 .. 1999] {
690 /* Operations supported by most interfaces */
691 std_info(*, out char buf[size:100], out int size);
692 std_destroy(*);
693};
694\end{verbatim}
695This defines a class called `standard\_ops' whose request codes are
696chosen by AIL from the range 1000-1999. Request codes are small
697integers used to identify remote operations. The author of the class
698must specify a range from which AIL chooses, and class authors must
699make sure they avoid conflicts, e.g. by using an `assigned number
700administration office'. In the example, `std\_info' will be assigned
701request code 1000 and `std\_destroy' will get code 1001. There is
702also an option to explicitly assign request codes, for compatibility
703with servers with manually written interfaces.
704
705The class `standard\_ops' defines two operations, `std\_info' and
706`std\_destroy'. The first parameter of each operation is a star
707(`*'); this is a placeholder for a capability that must be passed when
708the operation is called. The description of Amoeba below explains the
709meaning and usage of capabilities; for now, it is sufficient to know
710that a capability is a small structure that uniquely identifies an
711object and a server or service.
712
713The standard operation `std\_info' has two output parameters: a
714variable-size character buffer (which will be filled with a short
715descriptive string of the object to which the operation is applied)
716and an integer giving the length of this string. The standard
717operation `std\_destroy' has no further parameters --- it just
718destroys the object, if the caller has the right to do so.
719
720The next class is called `tty':
721\begin{verbatim}
722class tty [2000 .. 2099] {
723 inherit standard_ops;
724 const TTY_MAXBUF = 1000;
725 tty_write(*, char buf[size:TTY_MAXBUF], int size);
726 tty_read(*, out char buf[size:TTY_MAXBUF], out int size);
727};
728\end{verbatim}
729The request codes for operations defined in this class lie in the
730range 2000-2099; inherited operations use the request codes already
731assigned to them. The operations defined by this class are
732`tty\_read' and `tty\_write', which pass variable-sized data buffers
733between client and server. Class `tty' inherits class
734`standard\_ops', so tty objects also support the operations
735`std\_info' and `std\_destroy'.
736
737Only the {\em interface} for `std\_info' and `std\_destroy' is shared
738between tty objects and other objects whose interface inherits
739`standard\_ops'; the implementation may differ. Even multiple
740implementations of the `tty' interface may exist, e.g. a driver for a
741console terminal and a terminal emulator in a window. To expand on
742the latter example, consider:
743\begin{verbatim}
744class window [2100 .. 2199] {
745 inherit standard_ops;
746 win_create(*, int x, int y, int width, int height,
747 out capability win_cap);
748 win_reconfigure(*, int x, int y, int width, int height);
749};
750
751class tty_emulator [2200 .. 2299] {
752 inherit tty, window;
753};
754\end{verbatim}
755Here two new interface classes are defined.
756Class `window' could be used for creating and manipulating windows.
757Note that `win\_create' returns a capability for the new window.
758This request should probably should be sent to a generic window
759server capability, or it might create a subwindow when applied to a
760window object.
761
762Class `tty\_emulator' demonstrates the essence of multiple inheritance.
763It is presumably the interface to a window-based terminal emulator.
764Inheritance is transitive, so `tty\_emulator' also implicitly inherits
765`standard\_ops'.
766In fact, it inherits it twice: once via `tty' and once via `window'.
767Since AIL class inheritance only means interface sharing, not
768implementation sharing, inheriting the same class multiple times is
769never a problem and has the same effect as inheriting it once.
770
771Note that the power of AIL classes doesn't go as far as C++.
772AIL classes cannot have data members, and there is
773no mechanism for a server that implements a derived class
774to inherit the implementation of the base
775class --- other than copying the source code.
776The syntax for class definitions and inheritance is also different.
777
778\subsection{Amoeba}
779
780The smell of `object-orientedness' that the use of classes in AIL
781creates matches nicely with Amoeba's object-oriented approach to
782RPC\@. In Amoeba, almost all operating system entities (files,
783directories, processes, devices etc.) are implemented as {\em
784objects}. Objects are managed by {\em services} and represented by
785{\em capabilities}. A capability gives its holder access to the
786object it represents. Capabilities are protected cryptographically
787against forgery and can thus be kept in user space. A capability is a
788128-bit binary string, subdivided as follows:
789
790% XXX Need a better version of this picture!
791\begin{verbatim}
792 48 24 8 48 Bits
793+----------------+------------+--------+---------------+
794| Service | Object | Perm. | Check |
795| port | number | bits | word |
796+----------------+------------+--------+---------------+
797\end{verbatim}
798
799The service port is used by the RPC implementation in the Amoeba
800kernel to locate a server implementing the service that manages the
801object. In many cases there is a one-to-one correspondence between
802servers and services (each service is implemented by exactly one
803server process), but some services are replicated. For instance,
804Amoeba's directory service, which is crucial for gaining access to most
805other services, is implemented by two servers that listen on the same
806port and know about exactly the same objects.
807
808The object number in the capability is used by the server receiving
809the request for identifying the object to which the operation applies.
810The permission bits specify which operations the holder of the capability
811may apply. The last part of a capability is a 48-bit long `check
812word', which is used to prevent forgery. The check word is computed
813by the server based upon the permission bits and a random key per object
814that it keeps secret. If you change the permission bits you must compute
815the proper check word or else the server will refuse the capability.
816Due to the size of the check word and the nature of the cryptographic
817`one-way function' used to compute it, inverting this function is
818impractical, so forging capabilities is impossible.%
819\footnote{
820As computers become faster, inverting the one-way function becomes
821less impractical.
822Therefore, a next version of Amoeba will have 64-bit check words.
823}
824
825A working Amoeba system is a collection of diverse servers, managing
826files, directories, processes, devices etc. While most servers have
827their own interface, there are some requests that make sense for some
828or all object types. For instance, the {\em std\_info()} request,
829which returns a short descriptive string, applies to all object types.
830Likewise, {\em std\_destroy()} applies to files, directories and
831processes, but not to devices.
832
833Similarly, different file server implementations may want to offer the
834same interface for operations like {\em read()} and {\em write()} to
835their clients. AIL's grouping of requests into classes is ideally
836suited to describe this kind of interface sharing, and a class
837hierarchy results which clearly shows the similarities between server
838interfaces (not necessarily their implementations!).
839
840The base class of all classes defines the {\em std\_info()} request.
841Most server interfaces actually inherit a derived class that also
842defines {\em std\_destroy().} File servers inherit a class that
843defines the common operations on files, etc.
844
845\subsection{How AIL Works}
846
847The AIL stub generator functions in three phases:
848\begin{itemize}
849\item
850parsing,
851\item
852strategy determination,
853\item
854code generation.
855\end{itemize}
856
857{\bf Phase one} parses the input and builds a symbol table containing
858everything it knows about the classes and other definitions found in
859the input.
860
861{\bf Phase two} determines the strategy to use for each function
862declaration in turn and decides upon the request and reply message
863formats. This is not a simple matter, because of various optimization
864attempts. Amoeba's kernel interface for RPC requests takes a
865fixed-size header and one arbitrary-size buffer. A large part of the
866header holds the capability of the object to which the request is
867directed, but there is some space left for a few integer parameters
868whose interpretation is left up to the server. AIL tries to use these
869slots for simple integer parameters, for two reasons.
870
871First, unlike the buffer, header fields are byte-swapped by the RPC
872layer in the kernel if necessary, so it saves a few byte swapping
873instructions in the user code. Second, and more important, a common
874form of request transfers a few integers and one large buffer to or
875from a server. The {\em read()} and {\em write()} requests of most
876file servers have this form, for instance. If it is possible to place
877all integer parameters in the header, the address of the buffer
878parameter can be passed directly to the kernel RPC layer. While AIL
879is perfectly capable of handling requests that do not fit this format,
880the resulting code involves allocating a new buffer and copying all
881parameters into it. It is a top priority to avoid this copying
882(`marshalling') if at all possible, in order to maintain Amoeba's
883famous RPC performance.
884
885When AIL resorts to copying parameters into a buffer, it reorders them
886so that integers indicating the lengths of variable-size arrays are
887placed in the buffer before the arrays they describe, since otherwise
888decoding the request would be impossible. It also adds occasional
889padding bytes to ensure integers are aligned properly in the buffer ---
890this can speed up (un)marshalling.
891
892{\bf Phase three} is the code generator, or back-end. There are in
893fact many different back-ends that may be called in a single run to
894generate different types of output. The most important output types
895are header files (for inclusion by the clients of an interface),
896client stubs, and `server main loop' code. The latter decodes
897incoming requests in the server. The generated code depends on the
898programming language requested, and there are separate back-ends for
899each supported language.
900
901It is important that the strategy chosen by phase two is independent
902of the language requested for phase three --- otherwise the
903interoperability of servers and clients written in different languages
904would be compromised.
905
906\section{Linking AIL to Python}
907
908From the previous section it can be concluded that linking AIL to
909Python is a matter of writing a back-end for Python. This is indeed
910what we did.
911
912Considerable time went into the design of the back-end in order to
913make the resulting RPC interface for Python fit as smoothly as
914possible in Python's programming style. For instance, the issues of
915parameter transfer, variable-size arrays, error handling, and call
916syntax were all solved in a manner that favors ease of use in Python
917rather than strict correspondence with the stubs generated for C,
918without compromising network-level compatibility.
919
920\subsection{Mapping AIL Entities to Python}
921
922For each programming language that AIL is to support, a mapping must
923be designed between the data types in AIL and those in that language.
924Other aspects of the programming languages, such as differences in
925function call semantics, must also be taken care of.
926
927While the mapping for C is mostly straightforward, the mapping for
928Python requires a little thinking to get the best results for Python
929programmers.
930
931\subsubsection{Parameter Transfer Direction}
932
933Perhaps the simplest issue is that of parameter transfer direction.
934Parameters of functions declared in AIL are categorized as being of
935type {\tt in}, {\tt out} or {\tt in} {\tt out} (the same distinction
936as made in Ada). Python only has call-by-value parameter semantics;
937functions can return multiple values as a tuple. This means that,
938unlike the C back-end, the Python back-end cannot always generate
939Python functions with exactly the same parameter list as the AIL
940functions.
941
942Instead, the Python parameter list consists of all {\tt in} and {\tt
943in} {\tt out} parameters, in the order in which they occur in the AIL
944parameter list; similarly, the Python function returns a tuple
945containing all {\tt in} {\tt out} and {\tt out} parameters. In fact
946Python packs function parameters into a tuple as well, stressing the
947symmetry between parameters and return value. For example, a stub
948with this AIL parameter list:
949\begin{verbatim}
950(*, in int p1, in out int p2, in int p3, out int p4)
951\end{verbatim}
952will have the following parameter list and return values in Python:
953\begin{verbatim}
954(p1, p2, p3) -> (p2, p4)
955\end{verbatim}
956
957\subsubsection{Variable-size Entities}
958
959The support for variable-size objects in AIL is strongly guided by the
960limitations of C in this matter. Basically, AIL allows what is
961feasible in C: functions may have variable-size arrays as parameters
962(both input or output), provided their length is passed separately.
963In practice this is narrowed to the following rule: for each
964variable-size array parameter, there must be an integer parameter
965giving its length. (An exception for null-terminated strings is
966planned but not yet realized.)
967
968Variable-size arrays in AIL or C correspond to {\em sequences} in
969Python: lists, tuples or strings. These are much easier to use than
970their C counterparts. Given a sequence object in Python, it is always
971possible to determine its size: the built-in function {\tt len()}
972returns it. It would be annoying to require the caller of an RPC stub
973with a variable-size parameter to also pass a parameter that
974explicitly gives its size. Therefore we eliminate all parameters from
975the Python parameter list whose value is used as the size of a
976variable-size array. Such parameters are easily found: the array
977bound expression contains the name of the parameter giving its size.
978This requires the stub code to work harder (it has to recover the
979value for size parameters from the corresponding sequence parameter),
980but at least part of this work would otherwise be needed as well, to
981check that the given and actual sizes match.
982
983Because of the symmetry in Python between the parameter list and the
984return value of a function, the same elimination is performed on
985return values containing variable-size arrays: integers returned
986solely to tell the client the size of a returned array are not
987returned explicitly to the caller in Python.
988
989\subsubsection{Error Handling}
990
991Another point where Python is really better than C is the issue of
992error handling. It is a fact of life that everything involving RPC
993may fail, for a variety of reasons outside the user's control: the
994network may be disconnected, the server may be down, etc. Clients
995must be prepared to handle such failures and recover from them, or at
996least print an error message and die. In C this means that every
997function returns an error status that must be checked by the caller,
998causing programs to be cluttered with error checks --- or worse,
999programs that ignore errors and carry on working with garbage data.
1000
1001In Python, errors are generally indicated by exceptions, which can be
1002handled out of line from the main flow of control if necessary, and
1003cause immediate program termination (with a stack trace) if ignored.
1004To profit from this feature, all RPC errors that may be encountered by
1005AIL-generated stubs in Python are turned into exceptions. An extra
1006value passed together with the exception is used to relay the error
1007code returned by the server to the handler. Since in general RPC
1008failures are rare, Python test programs can usually ignore exceptions
1009--- making the program simpler --- without the risk of occasional
1010errors going undetected. (I still remember the embarrassment a
1011hundredfold speed improvement reported, long, long, ago, about a new
1012version of a certain program, which later had to be attributed to a
1013benchmark that silently dumped core...)
1014
1015\subsubsection{Function Call Syntax}
1016
1017Amoeba RPC operations always need a capability parameter (this is what
1018the `*' in the AIL function templates stands for); the service is
1019identified by the port field of the capability. In C, the capability
1020must always be the first parameter of the stub function, but in Python
1021we can do better.
1022
1023A Python capability is an opaque object type in its own right, which
1024is used, for instance, as parameter to and return value from Amoeba's
1025name server functions. Python objects can have methods, so it is
1026convenient to make all AIL-generated stubs methods of capabilities
1027instead of just functions. Therefore, instead of writing
1028\begin{verbatim}
1029some_stub(cap, other_parameters)
1030\end{verbatim}
1031as in C, Python programmers can write
1032\begin{verbatim}
1033cap.some_stub(other_parameters)
1034\end{verbatim}
1035This is better because it reduces name conflicts: in Python, no
1036confusion is possible between a stub and a local or global variable or
1037user-defined function with the same name.
1038
1039\subsubsection{Example}
1040
1041All the preceding principles can be seen at work in the following
1042example. Suppose a function is declared in AIL as follows:
1043\begin{verbatim}
1044some_stub(*, in char buf[size:1000], in int size,
1045 out int n_done, out int status);
1046\end{verbatim}
1047In C it might be called by the following code (including declarations,
1048for clarity, but not initializations):
1049\begin{verbatim}
1050int err, n_done, status;
1051capability cap;
1052char buf[500];
1053...
1054err = some_stub(&cap, buf, sizeof buf, &n_done, &status);
1055if (err != 0) return err;
1056printf("%d done; status = %d\n", n_done, status);
1057\end{verbatim}
1058Equivalent code in Python might be the following:
1059\begin{verbatim}
1060cap = ...
1061buf = ...
1062n_done, status = cap.some_stub(buf)
1063print n_done, 'done;', 'status =', status
1064\end{verbatim}
1065No explicit error check is required in Python: if the RPC fails, an
1066exception is raised so the {\tt print} statement is never reached.
1067
1068\subsection{The Implementation}
1069
1070More or less orthogonal to the issue of how to map AIL operations to
1071the Python language is the question of how they should be implemented.
1072
1073In principle it would be possible to use the same strategy that is
1074used for C: add an interface to Amoeba's low-level RPC primitives to
1075Python and generate Python code to marshal parameters into and out of
1076a buffer. However, Python's high-level data types are not well suited
1077for marshalling: byte-level operations are clumsy and expensive, with
1078the result that marshalling a single byte of data can take several
1079Python statements. This would mean that a large amount of code would
1080be needed to implement a stub, which would cost a lot of time to parse
1081and take up a lot of space in `compiled' form (as parse tree or pseudo
1082code). Execution of the marshalling code would be sluggish as well.
1083
1084We therefore chose an alternate approach, writing the marshalling in
1085C, which is efficient at such byte-level operations. While it is easy
1086enough to generate C code that can be linked with the Python
1087interpreter, it would obviously not stimulate the use of Python for
1088server testing if each change to an interface required relinking the
1089interpreter (dynamic loading of C code is not yet available on
1090Amoeba). This is circumvented by the following solution: the
1091marshalling is handled by a simple {\em virtual machine}, and AIL
1092generates instructions for this machine. An interpreter for the
1093machine is linked into the Python interpreter and reads its
1094instructions from a file written by AIL.
1095
1096The machine language for our virtual machine is dubbed {\em Stubcode}.
1097Stubcode is a super-specialized language. There are two sets of of
1098about a dozen instructions each: one set marshals Python objects
1099representing parameters into a buffer, the other set (similar but not
1100quite symmetric) unmarshals results from a buffer into Python objects.
1101The Stubcode interpreter uses a stack to hold Python intermediate
1102results. Other state elements are an Amoeba header and buffer, a
1103pointer indicating the current position in the buffer, and of course a
1104program counter. Besides (un)marshalling, the virtual machine must
1105also implement type checking, and raise a Python exception when a
1106parameter does not have the expected type.
1107
1108The Stubcode interpreter marshals Python data types very efficiently,
1109since each instruction can marshal a large amount of data. For
1110instance, a whole Python string is marshalled by a single Stubcode
1111instruction, which (after some checking) executes the most efficient
1112byte-copying loop possible --- it calls {\tt memcpy()}.
1113
1114
1115Construction details of the Stubcode interpreter are straightforward.
1116Most complications are caused by the peculiarities of AIL's strategy
1117module and Python's type system. By far the most complex single
1118instruction is the `loop' instruction, which is used to marshal
1119arrays.
1120
1121As an example, here is the complete Stubcode program (with spaces and
1122comments added for clarity) generated for the function {\tt
1123some\_stub()} of the example above. The stack contains pointers to
1124Python objects, and its initial contents is the parameter to the
1125function, the string {\tt buf}. The final stack contents will be the
1126function return value, the tuple {\tt (n\_done, status)}. The name
1127{\tt header} refers to the fixed size Amoeba RPC header structure.
1128\vspace{1em}
1129
1130{\tt
1131\begin{tabular}{l l l}
1132BufSize & 1000 & {\em Allocate RPC buffer of 1000 bytes} \\
1133Dup & 1 & {\em Duplicate stack top} \\
1134StringS & & {\em Replace stack top by its string size} \\
1135PutI & h\_extra int32 & {\em Store top element in }header.h\_extra \\
1136TStringSlt & 1000 & {\em Assert string size less than 1000} \\
1137PutVS & & {\em Marshal variable-size string} \\
1138 & & \\
1139Trans & 1234 & {\em Execute the RPC (request code 1234)} \\
1140 & & \\
1141GetI & h\_extra int32 & {\em Push integer from} header.h\_extra \\
1142GetI & h\_size int32 & {\em Push integer from} header.h\_size \\
1143Pack & 2 & {\em Pack top 2 elements into a tuple} \\
1144\end{tabular}
1145}
1146\vspace{1em}
1147
1148As much work as possible is done by the Python back-end in AIL, rather
1149than in the Stubcode interpreter, to make the latter both simple and
1150fast. For instance, the decision to eliminate an array size parameter
1151from the Python parameter list is taken by AIL, and Stubcode
1152instructions are generated to recover the size from the actual
1153parameter and to marshal it properly. Similarly, there is a special
1154alignment instruction (not used in the example) to meet alignment
1155requirements.
1156
1157Communication between AIL and the Stubcode generator is via the file
1158system. For each stub function, AIL creates a file in its output
1159directory, named after the stub with a specific suffix. This file
1160contains a machine-readable version of the Stubcode program for the
1161stub. The Python user can specify a search path containing
1162directories which the interpreter searches for a Stubcode file the
1163first time the definition for a particular stub is needed.
1164
1165The transformations on the parameter list and data types needed to map
1166AIL data types to Python data types make it necessary to help the
1167Python programmer a bit in figuring out the parameters to a call.
1168Although in most cases the rules are simple enough, it is sometimes
1169hard to figure out exactly what the parameter and return values of a
1170particular stub are. There are two sources of help in this case:
1171first, the exception contains enough information so that the user can
1172figure what type was expected; second, AIL's Python back-end
1173optionally generates a human-readable `interface specification' file.
1174
1175\section{Conclusion}
1176
1177We have succeeded in creating a useful extension to Python that
1178enables Amoeba server writers to test and experiment with their server
1179in a much more interactive manner. We hope that this facility will
1180add to the popularity of AIL amongst Amoeba programmers.
1181
1182Python's extensibility was proven convincingly by the exercise
1183(performed by the second author) of adding the Stubcode interpreter to
1184Python. Standard data abstraction techniques are used to insulate
1185extension modules from details of the rest of the Python interpreter.
1186In the case of the Stubcode interpreter this worked well enough that
1187it survived a major overhaul of the main Python interpreter virtually
1188unchanged.
1189
1190On the other hand, adding a new back-end to AIL turned out to be quite
1191a bit of work. One problem, specific to Python, was to be expected:
1192Python's variable-size data types differ considerably from the
1193C-derived data model that AIL favors. Two additional problems we
1194encountered were the complexity of the interface between AIL's second
1195and third phases, and a number of remaining bugs in the second phase
1196that surfaced when the implementation of the Python back-end was
1197tested. The bugs have been tracked down and fixed, but nothing
1198has been done about the complexity of the interface.
1199
1200\subsection{Future Plans}
1201
1202AIL's C back-end generates server main loop code as well as client
1203stubs. The Python back-end currently only generates client stubs, so
1204it is not yet possible to write servers in Python. While it is
1205clearly more important to be able to use Python as a client than as a
1206server, the ability to write server prototypes in Python would be a
1207valuable addition: it allows server designers to experiment with
1208interfaces in a much earlier stage of the design, with a much smaller
1209programming effort. This makes it possible to concentrate on concepts
1210first, before worrying about efficient implementation.
1211
1212The unmarshalling done in the server is almost symmetric with the
1213marshalling in the client, and vice versa, so relative small
1214extensions to the Stubcode virtual machine will allow its use in a
1215server main loop. We hope to find the time to add this feature to a
1216future version of Python.
1217
1218\section{Availability}
1219
1220The Python source distribution is available to Internet users by
1221anonymous ftp to site {\tt ftp.cwi.nl} [IP address 192.16.184.180]
1222from directory {\tt /pub}, file name {\tt python*.tar.Z} (where the
1223{\tt *} stands for a version number). This is a compressed UNIX tar
1224file containing the C source and \LaTeX documentation for the Python
1225interpreter. It includes the Python library modules and the {\em
1226Stubcode} interpreter, as well as many example Python programs. Total
1227disk space occupied by the distribution is about 3 Mb; compilation
1228requires 1-3 Mb depending on the configuration built, the compile
1229options, etc.
1230
1231\bibliographystyle{plain}
1232
1233\bibliography{quabib}
1234
1235\end{document}