Info file: rnotes, -*-Text-*- produced by texinfo-format-buffer from file: rnotes.tex This file documents new and changed features of version 14 of the Scheme Runtime Library. Parts of this document will eventually be merged into the MIT Scheme Manual. Copyright (C) 1988 Massachusetts Institute of Technology This material was developed by the Scheme project at the Massachusetts Institute of Technology, Department of Electrical Engineering and Computer Science. Permission to copy this document, to redistribute it, and to use it for any purpose is granted, subject to the following restrictions and understandings. 1. Any copy made of this document must include this copyright notice in full. 2. Users of this document agree to make their best efforts (a) to return to the MIT Scheme project any improvements or extensions that they make, so that these may be included in future releases; and (b) to inform MIT of noteworthy uses of this document. 3. All materials developed as a consequence of the use of this document shall duly acknowledge such use, in accordance with the usual standards of acknowledging credit in academic research. 4. MIT has made no warrantee or representation that the contents of this document will be error-free, and MIT is under no obligation to provide any services, by way of maintenance, update, or otherwise. 5. In conjunction with products arising from the use of this material, there shall be no use of the name of the Massachusetts Institute of Technology nor of any adaptation thereof in any advertising, promotional, or sales literature without prior written consent from MIT in each case.  File: rnotes Node: Top, Prev: (dir), Up: (dir), Next: Summary * Menu: * Summary:: Overview of the changes in this release. * Error System:: New system for signalling and handling errors. * I/O Ports:: New representation and operations. * Stack Parser:: Program to parse continuations into stack frames. * REP Loop:: Read-Eval-Print loop redesign. * Miscellaneous:: Assorted new procedures.  File: rnotes Node: Summary, Prev: Top, Up: Top, Next: Error System Summary ******* This document describes the new and changed features for version 14 of the Scheme Runtime Library. What follows is a summary of the notable changes. Extensive changes are further documented in the following chapters. The changes incorporated in this release of the runtime library were prompted by our attempts to compile the previous release using the Liar compiler. Many of the design decisions, including various strategies for packaging and choices of data structures, caused the resulting compiled code to be less efficient than we thought reasonable. For example, our implementation of I/O ports as first class environments placed severe restrictions on the compiler's ability to optimize that code. In some cases the problems went beyond efficiency: occasionally the runtime library reflected on data structures (such as procedure objects) in a way that depended on the interpreter's representations. In these cases compiling the code changed the representations, thus violating assumptions built into the reflective code. Of course, once we had started making wholesale changes to the runtime library, it became easy to make changes unrelated to the compilation issues. In fact, most of the changes documented here are in that category. We have tried to limit the number of incompatible changes, but in general when conflicts arose between compatibility and clean design, the latter won. Most such changes are in the more obscure parts of the runtime library and hopefully will not affect the average user. Major Changes ============= * The error system has been completely rewritten. Errors and other exceptional conditions are now signalled through a general mechanism similar to that implemented on the Lisp Machine. This mechanism provides the programmer with the ability to specify the action to be taken when a particular error occurs (*Note Error System::). * I/O ports have been completely reimplemented. The new implementation represents ports with vectors for efficiency, and defines a standard interface for defining and selecting custom operations on ports (*Note I/O Ports::). * The stack parser has been redesigned. The new parser provides all of the information available on the stack, and makes few assumptions about how the information will be used. The debugger is being redesigned to take advantage of this (*Note Stack Parser::). * The read-eval-print loop has been redesigned. From the user's point of view it is very similar to the old one, but the programming model has changed significantly. The state of a REP loop is now stored in an object, called a `repl'. This allows programs to reflect on REP loops more effectively. Repl objects are built on top of `cmdl' objects, which are a primitive form of command loop (*Note REP Loop::). * The global package structure of the runtime library has been changed. All top-level packages comprising the runtime library are now bound in the environment `system-packages'. An experimental packaging system has been implemented to support the runtime library and may eventually be released for other purposes. One of the tangible benefits of the packaging system is that high-quality cross-reference information is now available for the runtime system. New Features ============ * New special form `default-object?', should be used when testing the value of an optional argument to determine if that argument has been supplied: it returns `#F' in that case. At present this is identical to `unassigned?'. In the near future the handling of optional arguments will be changed. When that happens, there will be a special class of objects representing default values for optional arguments. Defaulted optional arguments will be bound to one of those values, and `default-object?' will be a procedure which tests for that case. * A new facility for walking over SCode trees has been implemented, to replace the previous "type dispatcher" facility (*Note SCode Walker::). * New 1D weak association tables. This abstraction is a conveniently packaged "weak alist" facility. The table is implemented as an alist of weak pairs (*Note 1D Tables::). * New procedures have been defined to support booleans (*Note Booleans::). * New procedures have been defined to support weak pairs (*Note Weak Pairs::). * Simple support for multiple values has been implemented. Current implementation is low-tech but adequate for many purposes. In the future the performance of this construct will improve considerably, (most likely) without change to the interface (*Note Multiple Values::). * Bit strings now read and print using syntax similar to Common Lisp. The syntax is `#*' followed by a string of binary digits. However, the order of the digits is opposite that of Common Lisp (MSB first, making it similar to `#b'), and a length prefix is not allowed. Right now this is provided for user convenience. There is a good possibility that it will change in the future, probably to be more compatible with Common Lisp. * The variable `prime-numbers-stream' is bound to a stream of prime numbers. This is useful for a variety of things. * New user procedure `re' is like `in' (previously `%in') except that it re-evaluates the input expression in the current REP loop environment and syntax table. * New procedure `(exit)' asks for confirmation before calling `%exit'. * New procedures allow convenient user prompting which is handled specially by the Emacs interface. They return (respectively) a character, boolean, and an s-expression. (prompt-for-command-char STRING) (prompt-for-confirmation STRING) (prompt-for-expression STRING) * New procedures provide information about whether a given object is a pointer or non-pointer object. Every object satisfies exactly one of these predicates. (object-pointer? OBJECT) (object-non-pointer? OBJECT) * New procedure `(show-time THUNK)' executes THUNK, then prints the time it took and returns the value it returned. * New variable `load/default-types' is bound to a list of pathname types. These types are tried sequentially when the `load' procedure is invoked on a pathname with no type. The variable `fasload/default-types' provides an identical facility for the `fasload' procedure. * New procedures `pathname-default-COMPONENT' have been defined for all pathname components. These are like `pathname-new-COMPONENT', except that they do not override an existing component. * New procedure `init-file-truename', which takes no arguments, returns the pathname of the user's init file, if it exists, or `#F'. This procedure searches the working directory and the user's home directory, in that order. Incompatibilities ================= * The hooks for defining custom unparsers for tagged objects have been changed. The new implementation passes two arguments to the unparser: an `unparser-state' object, and the object to be unparsed. Various new output routines are available for writing unparsers, which use the `unparser-state' object. Also there is a standard unparser which handles many common cases. Compatibility procedures are available for supporting existing code, but these will eventually be deleted. *Note Custom Unparsers::, for more information. * The procedures `there-exists?' and `for-all?' have had their arguments redefined. Previously they accepted a predicate and returned a procedure which accepted a list to scan over. Now they accept two arguments, a predicate and a list, and return the appropriate boolean value. *Note Booleans::, for more information. * Pathnames now have a "host" component. At present this is not used. * The procedures `pathname-extract' and `pathname-extract-string' have been deleted. * `init-file-pathname', previously a pathname-valued variable, is now a procedure of no arguments which returns the pathname. * The `unbound?' special form, and the associated SCode type, have been deleted. In the near future, once the new argument defaulting mechanism is in place, `unassigned?' will also be deleted. Note that no real functionality is lost because of this deletion, since `unbound?' was just a macro that expanded as follows: (unbound? x) ==> (lexical-unbound? (the-environment) 'x) * The operations on representatives of the unassigned and unbound variable markers have been replaced as follows: make-unassigned-object ==> make-unassigned-reference-trap unassigned-object? ==> unassigned-reference-trap? make-unbound-object ==> make-unbound-reference-trap unbound-object? ==> unbound-reference-trap? In addition, a new operation, `unmap-reference-trap', maps a reference-trap representative into a reference-trap object, while acting as an identity procedure for all other objects. * The type system has been deleted. This was an ad-hoc mechanism which was not being used extensively. At some time in the future we may install a more carefully designed one. Note that the "type dispatcher" mechanism (which *was* used) has been replaced by a simpler code walking facility, `scode-walk' (*Note SCode Walker::). * The procedures `date' and `time' have been replaced by the new procedure `get-decoded-time' which is somewhat like the procedure of the same name in Common Lisp. This procedure returns a `decoded-time' object which has the following accessors: decoded-time/day decoded-time/hour decoded-time/minute decoded-time/month decoded-time/second decoded-time/year Likewise the procedures `date->string' and `time->string' have been replaced by the following: decoded-time/date-string decoded-time/time-string * The `event-distributor' datatype has been changed. Previously it was a procedure which was invoked by application. Now it is an unspecified datatype which is invoked using the operation `event-distributor/invoke!'. * The names of the following variables have been changed: interrupt-mask-gc-ok ==> interrupt-mask/gc-ok interrupt-mask-none ==> interrupt-mask/none interrupt-mask-all ==> interrupt-mask/all * The three different tags used by the syntaxer and unsyntaxer for identifying the three fluid-let special forms have been compressed into a single tag. The unsyntaxer now figures out which special form was intended from the code. Thus, the new variable `lambda-tag:fluid-let' replaces the following three variables: lambda-tag:shallow-fluid-let lambda-tag:deep-fluid-let lambda-tag:common-lisp-fluid-let * The procedures `breakpoint' and `read-eval-print' have been changed to require that their MESSAGE argument be a `cmdl-message' object rather than a string. The `cmdl-message' datatype is new with this release (*Note CMDL Messages::, for more details). * The following procedures have been deleted: make-null make-false make-true make-interned-symbol symbol-print-name final-segment with-threaded-continuation * Various undefined values, including the value of `*the-non-printing-object*', now print out as `#[undefined-value]'. Previously their printed representation was the null string. The REP loop treats them specially, causing them to print as `;No value' when they are the result of a top level evaluation. The new predicate `undefined-value?' discriminates objects in this set. * The procedure `format' is no longer defined. The distribution contains a library program to provide this functionality, with the following changes for compatibility with Common Lisp: 1. The DESTINATION argument is now required. It may be `#F', indicating the result should be returned as a string, or `#T', meaning it should be printed on the current output port. Otherwise it must be the desired output port. 2. The `~C' format is no longer implemented. 3. The `~A' format agrees with Common Lisp. It uses `display' to write the next argument to the output port. This functionality was previously provided, in a limited way, by `~S'. 4. The `~S' format agrees with Common Lisp. It uses `write' to write the next argument to the output port. This functionality was previously provided by `~O'. 5. The meaning of the `@' modifier has been reversed to agree with Common Lisp. The form `~NS' means "pad the argument on the *left* to size N", while `~N@S' means "pad the argument on the *right* to size N". * The following (approximate) renamings have occurred: primitive-type ==> object-type primitive-gc-type ==> object-gc-type primitive-type? ==> object-type? primitive-datum ==> object-datum primitive-set-type ==> object-new-type The new operations differ in that they all touch their arguments (this matters only in a Scheme with futures) and the `object-new-type' operation is GC safe. Also, the operation `object-datum' is guaranteed to return a non-negative integer; `primitive-datum' would sometimes return negative integers. Note that the previous definition of `object-type', which returned a symbol representing the type, has been renamed to `user-object-type'. * The procedure `initial-segment' has been renamed `list-head' (corresponding to `list-tail'). * The procedure `number->string' defaults its FORMAT argument to `'(heur)'. This means the radix defaults to decimal. Previously it defaulted to the current unparser radix. * The procedure `symbol->string' now copies the string before returning it, thus preventing accidental side-effects from screwing up the obarray. * The procedure `purify' now (by default) queues its argument until the next garbage collection, and then performs a purification of the queue rather than a GC. A second optional argument allows forcing of the purification immediately. * All user procedures previously called %FOO are now just FOO. These are: `in' `out' `ge' `ve' `gst' `vst' `cd' `pwd'. The old names are still defined for compatibility. * The  interrupt no longer resets the top-level REP loop by default. Instead, it aborts whatever computation is in progress and resumes the top-level REP loop. One consequence of this is that the top-level reader and printer histories (`%in' and `%out') are not destroyed by . Another is that, once the top-level environment is visiting an environment,  will not restore the environment to its original value (also the prompt will always be `"Visiting->"'). Executing `(proceed)' in the top-level REP loop will cause it to terminate, and a new one to be created. A user option flag, `cmdl-interrupt/abort-top-level/reset?', changes the behavior of  to be more like the old behavior. When true,  will escape from the top-level REP loop and start a new one. By default, this flag is false. * The representation of syntax tables has been changed. Also the following operations have been renamed: syntax-table-copy ==> syntax-table/copy syntax-table-define ==> syntax-table/define syntax-table-extend ==> syntax-table/extend syntax-table-ref ==> syntax-table/ref  File: rnotes Node: Error System, Prev: Summary, Up: Top, Next: I/O Ports Error System ************ The Scheme error system provides a uniform mechanism for the signalling of errors and other exceptional conditions. For most purposes, the only part of the error system that is needed is the special form `error', which is used to signal simple errors, specifying a message and some irritant objects (*Note Simple Errors::). In addition, an option to `error' permits users to do simple formatting of their error messages (*Note Error Messages::). More demanding applications require more powerful facilities. To give a concrete example, suppose you want floating point division to return a very large number whenever the denominator is zero. This behavior can be implemented using the error system. The Scheme arithmetic system can signal many different kinds of errors, including floating point divide by zero. In our example, we would like to handle this particular condition specially, allowing the system to handle other arithmetic errors in its usual way. The error system supports this kind of application by providing mechanisms for distinguishing different types of error conditions and for the specification of where control should be transferred should a given condition arise. In this example, there is a specific object which represents the "floating point divide by zero" condition type, and it is possible to dynamically specify an arbitrary Scheme procedure to be executed when a condition of that type is signalled. This procedure then finds the stack frame containing the call to the division operator, and returns the appropriate value from that frame (*Note Stack Parser:: for the details of this procedure). Another kind of behavior that is useful is the ability to specify uniform handling for related classes of conditions. For example, it might be desirable, when opening a file for input, to gracefully handle a variety of different conditions associated with the file system. One such condition might be that the file does not exist, in which case the program will try some other action, perhaps opening a different file instead. Another related condition is that the file exists, but is read protected, so it cannot be opened for input. If these or any other related conditions occur, the program would like to skip this operation and move on to something else. At the same time, errors unrelated to the file system should be treated in their usual way. For example, calling `car' on the argument `3' should signal an error. Or perhaps the name given for the file is syntactically incorrect, a condition that probably wants to be handled differently from the case of the file not existing. To facilitate the handling of classes of conditions, the error system taxonomically organizes all condition types. The types are related to one another by "taxonomical links", which specify that one type is a "kind of" another type. If two types are linked this way, one is considered to be a "specialization" of the other; or vice-versa, the second is a "generalization" of the first. In our example, all of the errors associated with opening an input file would be specializations of the condition type "cannot open input file". The taxonomy of condition types imposes a partial order on the types, because each type is allowed to have multiple generalizations. This is allowed because some condition types can be generalized in several different ways. An example of this is "floating point divide by zero", which can be generalized to either a "floating point overflow" or a "divide by zero". The latter generalization, "divide by zero", cannot be a specialization of the former, because it can also be signalled by arithmetic on numbers other than floating point. To summarize, the error system provides facilities for the following tasks. The sections that follow will describe these facilities in more detail. Signalling conditions Conditions may be signalled in a number of different ways. Simple errors may be signalled, without explicitly defining a condition type, using `error'. The `signal-condition' procedure provides the most general signalling mechanism. Handling conditions The programmer can dynamically specify handlers for particular condition types or for classes of condition types, by means of the `bind-condition-handler' procedure. Individual handlers have complete control over the handling of a condition, and additionally may decide not to handle a particular condition, passing it on to previously-bound handlers. Classification of conditions Each condition has a type, which is represented by a `condition-type' object. Each condition type may be a specialization of some other condition types. A group of types which share a common generalization can be handled uniformly by specifying a handler for the generalization. Packaging condition state Each condition is represented by an explicit object. Condition objects contain information about the nature of the condition as well as information which describes the state of the computation from which the condition arose. * Menu: * Simple Errors:: Simple operations on errors. * Error Handler:: The standard error handler. * Error Messages:: Defining and formatting error messages. * Condition Types:: Defining and manipulating condition types. * Condition Instances:: Creating conditions from types. * Condition Signalling:: Signalling conditions. * Condition Handling:: Specifying condition handlers. * Predefined Errors::  File: rnotes Node: Simple Errors, Up: Error System, Next: Error Handler Simple Errors ============= The simplest error-signalling mechanism is the special form `error'. It allows the programmer to signal errors by specifying an error message and providing a list of some objects ("irritants") that are relevant to the error. * Special form: error MESSAGE . IRRITANTS Signals an error. This special form expands into the following code: (error-procedure MESSAGE (list . IRRITANTS) (the-environment)) The use of `the-environment' would normally force the environment in which it appears to be a first class environment. However, the compiler treats error expressions specially so that errors signalled from compiled code do not supply the environment argument to `error-procedure'. * Procedure: error-procedure MESSAGE IRRITANTS ENVIRONMENT Signals an error. MESSAGE is normally a short string which summarizes the error, and IRRITANTS is a list of objects which contain interesting information about the error. ENVIRONMENT should be the environment in which the error occurred. Normally, the message and irritants are used to build a condition whose type is `error-type:vanilla', ENVIRONMENT is attached to that condition, and then the condition is signalled. However, if MESSAGE is a `condition-type' object, then that object is used (instead of `error-type:vanilla') to build the condition. The argument ENVIRONMENT is used primarily by the standard error handler. Currently there is no mechanism to retrieve this information. * Variable: error-type:vanilla This is the error type used by `error-procedure' when it signals anonymous errors. Do not use this type for signalling new errors, as some of the system code expects to find the message in a special place for errors of this type. This object is made public solely so that condition handlers can be bound to it. * Procedure: warn MESSAGE . IRRITANTS This procedure takes arguments just like `error', formats and prints a message in the usual way, but does not signal an exception. The output goes to the output-port of the nearest `cmdl' object. In the future this may be made customizable in some ways, such as allowing conditional error signalling based on a flag.  File: rnotes Node: Error Handler, Prev: Simple Errors, Up: Error System, Next: Error Messages Error Handler ============= In the absence of more specific handling, errors invoke the "standard error handler". This handler normally prints an error message and enters a new REP loop. * Procedure: standard-error-handler CONDITION This procedure is used to handle error conditions that are not otherwise taken care of. It can be useful when building custom error handlers. While the standard error handler is executing, the following procedures provide useful information. * Procedure: error-condition This procedure returns the condition that was passed to the standard error handler as its argument. If the standard error handler has not been entered, this procedure returns `#F'. * Procedure: error-message * Procedure: error-irritants * Procedure: error-continuation These procedures extract standard components from `(error-condition)'. `error-continuation' returns `#F' if `error-condition' does. * Procedure: error-irritant This procedure exists for compatibility with existing code. It is defined by this code: (define (error-irritant) (let ((irritants (error-irritants/sans-noise))) (cond ((null? irritants) *the-non-printing-object*) ((null? (cdr irritants)) (car irritants)) (else irritants))))  File: rnotes Node: Error Messages, Prev: Error Handler, Up: Error System, Next: Condition Types Error Messages ============== The error system provides a simple formatting language which allows the programmer to have some control over the printing of error messages. The basic idea is as follows. Error messages typically consist of a string describing the error, followed by some irritant objects. The string is printed using `display', and the irritants are printed using `write', typically with a space between each irritant. To allow simple formatting, we introduce a "noise" object, which is printed using `display'. The irritant list may contain ordinary objects interspersed with noise objects. Each noise object is printed using `display', with no extra whitespace, while each normal object is printed using `write', prefixed by a single space character. Here is an example: (define (error-within-procedure message irritant procedure) (error message irritant (error-irritant/noise char:newline) (error-irritant/noise "within procedure") procedure)) This would format as follows: (error-within-procedure "bad widget" 'widget-32 'invert-widget) ==> bad widget WIDGET-32 within procedure INVERT-WIDGET Note the use of a separate noise object for the newline. In general, for characters such as newline or formfeed (i.e. non-graphic characters), this is desirable since it makes it easier for the formatter to notice formatting characters with special meanings and handle them specially should it be necessary. Here are the operations supporting error messages: * Procedure: format-error-message MESSAGE IRRITANTS PORT This is the basic error message formatter. MESSAGE should be a string, IRRITANTS a list of irritant objects, and PORT an output port. Note that, during the formatting process, the depth and breadth to which lists are printed are each limited to small numbers, to guarantee that the output from each irritant is not arbitrarily large. * Procedure: error-irritant/noise VALUE Creates and returns a noise object whose value is VALUE. * Procedure: error-irritant/noise? OBJECT This is true iff OBJECT was created by `error-irritant/noise'. * Procedure: error-irritant/noise-value NOISE Returns the value of the noise object NOISE. This is the object that was passed to `error-irritant/noise' as an argument when NOISE was created. * Procedure: error-irritants/sans-noise This returns the value of `error-irritants' with the noise objects removed. It could have been written: (define (error-irritants/sans-noise) (list-transform-negative (error-irritants) error-irritant/noise?))  File: rnotes Node: Condition Types, Prev: Error Messages, Up: Error System, Next: Condition Instances Condition Types =============== Each condition has a `condition-type' object associated with it. These objects are used as a means of focusing on related classes of conditions, first by concentrating all of the information about a specific class of condition in a single place, and second by specifying inheritance relationships between types. Condition types are defined by the following operations. Any argument called CONDITION-TYPE is assumed to be a condition type object. * Procedure: make-condition-type GENERALIZATIONS REPORTER This procedure creates and returns a new condition type. GENERALIZATIONS must be a list of condition types; the resulting condition type will be a specialization of each of these types. REPORTER is a procedure of two arguments, a condition instance and an output port, which will write a concise description of the condition on the output port. As a special option, REPORTER may be a string, in which case a standard error message will be printed using that string. * Procedure: condition-type? OBJECT This predicate is true iff OBJECT is a condition type. * Procedure: guarantee-condition-type OBJECT Signals an error if OBJECT is not a condition type. Returns OBJECT as its value otherwise. * Procedure: condition-type/generalizations CONDITION-TYPE Returns the generalizations of CONDITION-TYPE. This is the reflexive and transitive closure of the GENERALIZATIONS argument to `make-condition-type', i.e. all of the members of GENERALIZATIONS plus all of their generalizations as well. This list always contains CONDITION-TYPE. * Procedure: condition-type/reporter CONDITION-TYPE Returns the report procedure for CONDITION-TYPE. * Procedure: condition-type/properties CONDITION-TYPE Each condition type contains a `1D-table' object which is used for associating arbitrary properties with the condition type. This operation returns the table associated with CONDITION-TYPE. * Procedure: condition-type/error? CONDITION-TYPE This predicate is true only of condition types which are considered to be errors. Condition types satisfying this predicate are treated specially under certain cirumstances, and are sometimes referred to as "error types". The following two expressions are equivalent (as predicates): (condition-type/error? x) (memq condition-type:error (condition-type/generalizations x)) * Variable: condition-type:error This variable contains a predefined condition type with no generalizations which is used to mark condition types as being errors. * Procedure: make-error-type GENERALIZATIONS REPORTER This operation is like `make-condition-type', except that if none of GENERALIZATIONS satisfies `condition-type/error?', it adds `condition-type:error' to the set of generalizations. * Procedure: error-type? OBJECT This predicate is true iff OBJECT is a condition type which satisfies `condition-type/error?'.  File: rnotes Node: Condition Instances, Prev: Condition Types, Up: Error System, Next: Condition Signalling Condition Instances =================== A condition, in addition to the information associated with its type, usually contains other information which is not shared with other conditions of the same type. For example, the condition type associated with unbound variable errors does not specify the name of the variable that was unbound. The additional information is captured in `condition' objects, also called "condition instances". In addition to information which is specific to a given type of condition (such as the variable name for "unbound variable" conditions), every condition instance also contains a continuation which encapsulates the state of the computation in which the condition occurred. This continuation is used when condition handlers want to restart the computation in some way, or sometimes for analyzing the computation to learn more about the context in which the condition occurred. The following operations define the `condition' datatype. Any argument called CONDITION is assumed to be a condition object. * Procedure: make-condition CONDITION-TYPE IRRITANTS CONTINUATION Makes a new condition instance, whose type is CONDITION-TYPE. IRRITANTS is a list of arbitrary objects, and CONTINUATION must be a continuation, normally the continuation of the computation which caused the condition. * Procedure: condition? OBJECT Returns true iff OBJECT is a condition instance. * Procedure: error? OBJECT Returns true iff OBJECT is a condition instance whose type satisfies `condition-type/error?'. * Procedure: guarantee-condition OBJECT Signals an error if OBJECT is not a condition instance. Returns OBJECT otherwise. * Procedure: condition/type CONDITION Returns the condition type associated with CONDITION. * Procedure: condition/irritants CONDITION Returns the irritants associated with CONDITION. * Procedure: condition/continuation CONDITION Returns the continuation associated with CONDITION. * Procedure: condition/write-report CONDITION #!OPTIONAL PORT Writes a concise description of CONDITION on PORT, which defaults to the current output port. * Procedure: condition/report-string CONDITION Similar to `condition/write-report', this returns a description of CONDITION as a string. * Procedure: condition/properties CONDITION Each condition instance contains a `1D-table' object which is used for associating arbitrary properties with the condition. This operation returns the table associated with CONDITION. * Procedure: condition/internal? CONDITION This predicate is true of certain conditions which normally should not be handled by user code. Condition handlers which handle "all" conditions should ignore conditions satisfying this predicate, unless the handler's writer has a good understanding of internal conditions. * Procedure: condition/generalizations CONDITION * Procedure: condition/error? CONDITION * Procedure: condition/reporter CONDITION These operations access the corresponding components in the type of CONDITION. For example, the following expressions are equivalent: (condition/generalizations condition) (condition-type/generalizations (condition/type condition)) Note that condition instances satisfying the predicate `condition/error?' are sometimes referred to as "error conditions", or even "errors".  File: rnotes Node: Condition Signalling, Prev: Condition Instances, Up: Error System, Next: Condition Handling Condition Signalling ==================== Once a condition instance has been created using `make-condition', it can be "signalled". The act of signalling a condition is separated from the act of creating the condition to allow more flexibility in how conditions are handled. For example, a condition instance could be returned as the value of a procedure, indicating that something unusual has happened, to allow the caller to clean up some state. The caller could then signal the condition once it is ready. A more important reason for having a separate condition signalling mechanism is that it allows *resignalling*. When a signalled condition has been caught by a particular handler, and the handler decides that it doesn't want to process that particular condition, it can signal the condition again. This is one way to allow other handlers to get a chance to see the condition. There is a single procedure responsible for signalling conditions. All other signalling mechanisms go through this procedure: * Procedure: signal-condition CONDITION #!OPTIONAL DEFAULT-HANDLER Signals CONDITION, which must be a condition instance. DEFAULT-HANDLER, if given, must be a procedure of one argument. The signalling procedure attempts to find a handler for the condition, using the following rules: * The set of condition handlers is searched, until it finds one which will handle any of the condition types specified by the generalizations of CONDITION. Each handler specifies, at the time it is bound, a set of condition types it will handle; if the intersection of that set and CONDITION's generalizations is not empty, the handler is selected. If a handler is found, it is invoked on CONDITION. If it returns a false value, that means the handler has declined to handle the condition and the search continues. Otherwise the handler's value is returned as the value of `signal-condition'. * If no condition handler is found, and the argument DEFAULT-HANDLER is supplied, it is invoked on CONDITION; its value is returned as the value of `signal-condition'. * Otherwise, `#F' is returned, indicating that no handler could be found. * Procedure: signal-error CONDITION Signals CONDITION, which must be a condition instance. If this condition is not otherwise handled, the standard error handler is invoked. This procedure is implemented as a call to `signal-condition', passing `standard-error-handler' as the second argument.  File: rnotes Node: Condition Handling, Prev: Condition Signalling, Up: Error System, Next: Predefined Errors Condition Handling ================== "Condition handling" refers to the act of defining the behavior of a signalled condition. This is controlled by the binding of "condition handlers". A "condition handler" is a procedure of one argument. When a handler is invoked by `signal-condition', the CONDITION is supplied to the handler as its argument. The handler may return a value: if the value is `#F', this indicates that the handler has decided not to handle this particular condition. In that case, `signal-condition' continues its search for another handler. Otherwise the value returned by the handler is returned as the value of `signal-condition'. Often, though, the handler will not return a value. Usually a condition handler will exit by invoking some continuation. Sometimes it will signal a different condition instead, or signal the same condition again. This latter action, resignalling the same condition, is equivalent to returning `#F' from the handler. This is true because when the handler is invoked, the set of condition handler bindings is unwound to the point at which the handler was bound. In other words, when you bind a condition handler, the set of condition handlers which is bound before you bind it is the set that will be bound when the handler is invoked. A condition handler is "bound" by specifying that it will handle a condition whose generalizations intersect a given set of condition types. condition handlers are bound using a mechanism very similar to fluid binding of variables. A condition handler binding has a dynamic extent rather than a lexical scope, that is, it is effective for a specified time segment rather than for a specified code segment. The order in which the bindings are searched (by `signal-condition') is the opposite from the order in which they are bound. Thus, more recently bound handlers appear earlier in the search order. All condition handlers are bound by the following operation: * Procedure: bind-condition-handler CONDITION-TYPES HANDLER THUNK Executes THUNK, handling any condition whose generalizations intersect the set CONDITION-TYPES by passing it to HANDLER. CONDITION-TYPES is represented as a list of `condition-type' objects. If CONDITION-TYPES is the empty list, it means HANDLER should handle *all* conditions, independent of their type; such handlers should ignore conditions satisfying the predicate `condition/internal?'.  File: rnotes Node: Predefined Errors, Prev: Condition Handling, Up: Error System Predefined Errors ================= (This section will eventually describe some of the condition types that are defined by the runtime library, once the taxonomy settles down a bit.)  File: rnotes Node: I/O Ports, Prev: Error System, Up: Top, Next: REP Loop I/O Ports ********* I/O ports are the means by which Scheme provides a uniform interface to a variety of I/O devices. This chapter describes the low-level operations which can be used to build and manipulate I/O ports. In addition to what is described here, there are a variety of higher-level operations which are documented in the Scheme standard. The purpose of this interface is twofold: (1) to allow programmers to construct new kinds of I/O ports, and (2) to provide faster I/O operations than those supplied by the standard. The latter is useful because the standard I/O operations provide defaulting and error checking, and sometimes other features, which are often unnecessary. This interface provides the means to bypass such features, thus improving performance. The abstract model of an I/O port, as implemented here, is a combination of a set of named operations and a state. The state is an arbitrary object whose meaning is determined by the operations. The operations are defined by a mapping from names to procedures; typically the names are symbols, but any object that can be discriminated by `eq?' may be used. The operations are typically divided into the following classes: * Standard operations. Every port supports a minimal set of operations. There is a specific set for input ports, and a different set for output ports. Applications can assume that the appropriate set of operations exists for each port. * Custom operations. Some ports support additional operations. For example, ports which implement output to terminals (or windows) may define an operation named `y-size' which returns the height of the terminal in characters. * Menu: * Constructing I/O Ports:: mechanisms common to input and output. * Input Port Operations:: descriptions of the standard input operations. * Output Port Operations:: descriptions of the standard output operations.  File: rnotes Node: Constructing I/O Ports, Up: I/O Ports, Next: Input Port Operations Constructing I/O Ports ====================== * Procedure: make-input-port OPERATIONS STATE * Procedure: make-output-port OPERATIONS STATE These are the standard procedures for constructing I/O ports. OPERATIONS must be an alist; each element is a list of two elements, the name and the operation. STATE can be any object. A new port of the appropriate type is created and returned. OPERATIONS need not contain definitions for all of the standard operations. Instead, there is a minimum set of operations which must be given. These procedures will provide defaults for any standard operations which are not defined by OPERATIONS. The minimum set of operations for each constructor is described in the appropriate operations section below. * Procedure: input-port/copy PORT STATE * Procedure: output-port/copy PORT STATE These procedures create a new copy of PORT (which must be of the respective type), identical to the original, except that its state component is STATE. The argument PORT is not modified. These procedures are normally used to speed up creation of ports. This is done by creating a template in the usual way, and then using the copying procedure to copy the template with the correct state. This is desirable because the procedures `make-input-port' and `make-output-port' are somewhat slow, since they must parse the OPERATIONS alist into an appropriate form, provide defaulting for missing operations, etc. * Procedure: guarantee-input-port OBJECT * Procedure: guarantee-output-port OBJECT These procedures check the type of OBJECT, signalling an error if it is not an input port or output port, respectively. Otherwise they return OBJECT. * Procedure: input-port/state PORT * Procedure: output-port/state PORT * Procedure: set-input-port/state! PORT STATE * Procedure: set-output-port/state! PORT STATE These procedures manipulate the state component of PORT. PORT must be of the appropriate type. The first pair returns the state, and the second pair alters the state component to be STATE. * Procedure: input-port/operation PORT NAME * Procedure: output-port/operation PORT NAME These procedures select and return the operation NAME from PORT. If PORT does not implement such an operation, `#F' is returned. * Procedure: input-port/custom-operation PORT NAME * Procedure: output-port/custom-operation PORT NAME These procedures select and return the custom operation NAME from PORT. If PORT does not implement such an operation, `#F' is returned. As described above, a custom operation is any operation other than the standard operations. Note that these procedures return `#F' if NAME is a standard operation for PORT. These procedures are provided in addition to `input-port/operation' and `output-port/operation' because they are more efficient for cases where NAME is known not to be the name of a standard operation.  File: rnotes Node: Input Port Operations, Prev: Constructing I/O Ports, Up: I/O Ports, Next: Output Port Operations Input Port Operations ===================== This section describes the standard operations available for input ports. As described earlier, there is a minimal subset of the standard operations which must be defined for all input ports. Any other standard operations that are not given to `make-input-port' will be emulated by calls to these operations. This set consists of the following operations: read-char peek-char char-ready? Here is an alphabetical list of (the names of) all the standard operations: char-ready? discard-char discard-chars peek-char peek-char-immediate read-char read-char-immediate read-finish! read-start! read-string The following procedures invoke the standard operations on input ports. In each case, the name of the procedure is just the name of the operation, prefixed by `input-port/'. Thus the procedure `input-port/read-char' invokes the operation whose name is `read-char'. * Procedure: input-port/read-char INPUT-PORT Removes the next character available from INPUT-PORT and returns it. If INPUT-PORT has no more characters and will never have any (e.g. at the end of an input file), this operation returns `#F'. If INPUT-PORT has no more characters but will eventually have some more (e.g. a terminal where nothing has been typed recently), the operation hangs until a character is available. *Note:* on the console input port, this operation normally turns on the operating system specific input editing features, such as character echoing and rubout handling. If this operation is invoked, it may wait until a group of characters (e.g. an entire input line) is entered before returning. * Procedure: input-port/peek-char INPUT-PORT Reads the next character available from INPUT-PORT and returns it. The character is *not* removed from INPUT-PORT, and a subsequent attempt to read from the port will get that character again. In other respects this operation behaves like `input-port/read-char'. * Procedure: input-port/discard-char INPUT-PORT Reads the next character available from INPUT-PORT and discards it. The value of this operation is undefined. In other respects this operation behaves like `input-port/read-char'. * Procedure: input-port/char-ready? INPUT-PORT INTERVAL This operation is true iff any characters are available to be read from INPUT-PORT. If no characters are available, the operation waits up to INTERVAL milliseconds before returning `#F', but returns immediately if any characters become available while it is waiting. *Note:* this operation, as implemented for the console, does not work correctly under all circumstances in the current implementation. Also it will work correctly under some operating systems and not others. When it cannot return the correct value it returns a true value by default. * Procedure: input-port/read-char-immediate INPUT-PORT * Procedure: input-port/peek-char-immediate INPUT-PORT These operations are identical to `input-port/read-char' and `input-port/peek-char' except for certain kinds of interactive input ports, such as the console input port. The normal operations on such ports provide input editing features, while these operations bypass those features. These operations read characters from the input port without any echoing or editing, and do not require a line terminator to be typed. These operations are used by the procedures `read-char' and `peek-char'. * Procedure: input-port/read-string INPUT-PORT DELIMITERS * Procedure: input-port/discard-chars INPUT-PORT DELIMITERS These operations are like `input-port/read-char' and `input-port/discard-char', except that they read (discard) multiple characters at once. This can have a marked performance improvement on buffered input ports. DELIMITERS is a character set. All characters up to, but excluding, the first character in that set are read from INPUT-PORT. `input-port/read-string' returns those characters as a string, while `input-port/discard-chars' discards them and returns an undefined value. * Procedure: input-port/read-start! INPUT-PORT * Procedure: input-port/read-finish! INPUT-PORT These operations are provided to inform input editing programs of the beginning and end of a multiple character input segment. Specifically, they are invoked at the beginning and end of a call to the `read' procedure. * Procedure: input-port/operation/read-char INPUT-PORT * Procedure: input-port/operation/peek-char INPUT-PORT * Procedure: input-port/operation/discard-char INPUT-PORT * Procedure: input-port/operation/char-ready? INPUT-PORT * Procedure: input-port/operation/read-char-immediate INPUT-PORT * Procedure: input-port/operation/peek-char-immediate INPUT-PORT * Procedure: input-port/operation/read-string INPUT-PORT * Procedure: input-port/operation/discard-chars INPUT-PORT * Procedure: input-port/operation/read-start! INPUT-PORT * Procedure: input-port/operation/read-finish! INPUT-PORT These procedures, rather than invoking the standard operations, return them as procedures. The arguments of the returned procedures are the same as for the respective operations described above. In fact, the above operations are implemented in terms of these, for example: (define (input-port/read-string port delimiters) ((input-port/operation/read-string input-port) port delimiters))