Skip to content

DeprecatedR6RSSyntaxAndProcedures

Will Clinger edited this page May 11, 2016 · 5 revisions

Deprecated R6RS Syntax and Procedures

The implementors of Larceny wish to support all relevant standards for Scheme.

The R7RS (small) standard supersedes several of the more unfortunate parts of the R6RS, but the R6RS remains relevant for R6RS libraries and programs written before the R7RS took effect. Larceny continues to support the R6RS standard in its R6RS mode, but may abandon some of the R6RS-specific features in R7RS modes.

Deprecation of an R6RS feature in Larceny warns our users that (with a few exceptions noted below):

  • the deprecated feature was removed in a later standard (R7RS), and
  • the deprecated feature may not be supported by future versions of Larceny.

identifier-syntax

Historically, Scheme expressions that look like identifiers have no side effects. Some macros rely on this invariant. Using identifier-syntax to break that invariant is universally condemned. If you use identifier-syntax, please maintain the invariant.

char-titlecase, char-foldcase

Although Unicode defines locale-independent case conversions for characters, and these procedures were retained by the R7RS, it usually makes more sense to perform case conversions on strings.

endianness, eol-style, error-handling-mode

In Larceny, all three of these syntaxes are equivalent to the quote syntax but are less efficient (because uses of deprecated features generate a warning). Use quote instead.

utf16->string, utf32->string

The R6RS specifications of these procedures require two or three arguments, which was an error introduced into the R5.95RS draft by some editor who misinterpreted John Cowan's response of 27 May 2007 to an ambiguous question posed by Mike Sperber. Larceny corrects this error by allowing these procedures to accept a single argument, as in the R5.93RS and R5.94RS drafts, in which case these procedures behave as though their second argument were the symbol big. (As specified by the R6RS, the only way for a programmer to obtain the official Unicode semantics for the UTF-16 and UTF-32 encoding forms is to specify big as an explicit second argument, which requires more knowledge of both Unicode and the R6RS than the average Scheme programmer possesses.)

buffer-mode, buffer-mode?

The R6RS forbids buffer-mode and buffer-mode? to recognize Larceny's datum mode, which is the buffer mode recommended for interactive output ports. This is likely to be an error in the R6RS, but repairing this error would make buffer-mode equivalent to quote (but less efficient) and buffer-mode? equivalent to symbol? (but less efficient), so these features would still be deprecated. Use quote instead of buffer-mode. (There is no conceivable use for buffer-mode? anyway, so warning against its use would be redundant.)

make-record-constructor-descriptor

This procedure complicates the usual cases without simplifying the unusual cases enough to justify its existence. Unfortunately, the R6RS provides no way to create a record without using this procedure. We recommend that all programmers use the R7RS, SRFI 9, SRFI 99, or SRFI 131 record systems instead of the R6RS record system. (In Larceny, R7RS, SRFI 9, SRFI 99, and SRFI 131 records are the same as R6RS records, and SRFI 99 and SRFI 131 record-type descriptors are the same as R6RS record-type descriptors, but the SRFI 99 and SRFI 131 APIs are superior to the R6RS APIs. The SRFI 99 and SRFI 131 APIs are fully compatible extensions of R7RS records.)

syntactic record layer

Poor design of the record layers was mentioned by 10 of the 35 electors (out of 102) who voted against ratification of the R6RS. We recommend that all programmers use the R7RS, SRFI 9, SRFI 99, or SRFI 131 record systems instead of the R6RS record system. (In Larceny, R7RS, SRFI 9, SRFI 99, and SRFI 131 records are the same as R6RS records, and SRFI 99 and SRFI 131 record-type descriptors are the same as R6RS record-type descriptors, but the SRFI 99 and SRFI 131 APIs are superior to the R6RS APIs. The SRFI 99 and SRFI 131 APIs are fully compatible extensions of R7RS records.)

If you feel compelled to use an R6RS API, use the procedural layer, which has fewer problems than the R6RS syntactic layer. Do not be fooled by the R6RS's misleading assertions that the syntactic layer is more efficient than the procedural layer; those assertions are not true in well-engineered implementations such as Larceny.

opaque conditions

The R6RS allows condition types to be opaque, but Larceny will not recognize instances of opaque condition types as conditions. They are, after all, supposed to be opaque.

standard-input-port, standard-output-port, standard-error-port

These procedures aren't really deprecated, but their names are misleading and their specifications vague. From their names, many programmers are likely to assume these procedures have something to do with the redirectable standard streams known to C programmers as stdin, stdout, and stderr. Not so. The R6RS says nothing about redirection, and requires these procedures to create _fresh binary_ ports. In Larceny, as in most implementations of Scheme, the redirectable standard streams correspond to the _textual_ ports that are returned (but not created) by the current-input-port, current-output-port, and current-error-port procedures.

with-input-from-file, with-output-to-file

Although these procedures were retained by the R7RS, they implement a paradigm that breaks down in multithreaded programs.

open-string-output-port, open-bytevector-output-port

These poorly designed procedures do not interoperate conveniently with call-with-port. Use the R7RS procedures instead.

set-port-position! on textual output ports

The R6RS semantics for set-port-position! models the Posix semantics, which is well-defined only for binary i/o and for textual i/o in which each character is represented by a single byte. In a failed attempt to extend the Posix semantics to Unicode i/o, the R6RS requires the second argument to set-port-position! to be a value returned by some previous call to port-position on the same port. Larceny's R6RS mode enforces that restriction (and its R5RS and R7RS modes issue a warning if the restriction is violated), but that restriction is not enough to provide a sane semantics for textual output ports that use variable-length encodings, and the R6RS does not specify any semantics for that situation.

Because there is no sane semantics in general, the R6RS does not require textual ports (other than custom ports, which have their own problems) to support set-port-position!. In reluctant response to user requests, however, Larceny now allows set-port-position! even on textual file and string output ports that use variable-length encodings. The semantics is of course Larceny-specific and subject to change without notice in future versions of Larceny. If a textual output port that uses UTF-8 or UTF-16 is repositioned, and its previous output is overwritten, then the boundaries between new and old output may not be legal UTF-8 or UTF-16, and decoding errors may result when the trashed output is later used for input.

An analogous problem occurs with combined input/output textual ports that use variable-length encodings.

custom ports

Custom ports are not deprecated per se, but certain aspects of the R6RS API for custom ports are deprecated for the specific reasons described below.

In addition, programmers should be aware that custom ports are unlikely to be as fast as Larceny's file, bytevector, or string ports and should not be used when a file, bytevector, or string port could be used instead. In Larceny, custom binary ports are faster than custom textual ports, and custom input-only and output-only ports are much faster than custom input/output ports.

get-port-position on custom ports

Custom implementations of get-port-position cannot work reliably, because there is no way for a buffered port to tell the custom implementation about the current position within a buffer, and all ports use lookahead buffering at the very least. Larceny ignores custom implementations of get-port-position and computes accurate port positions (in bytes for binary ports, in characters for textual ports) for all ports, whether built-in or custom.

custom input/output ports

Custom input/output ports cannot work reliably in general, because all ports support lookahead buffering (for procedures such as lookahead-u8, lookahead-char, and port-eof?) but there is no portable way for the i/o system to tell a custom port to correct for a lookahead byte or character when switching from input to output. Larceny requires custom input/output ports to support set-port-position! by providing a custom procedure that accepts accurate positions (in bytes for binary ports, in characters for textual ports). Larceny then calls set-port-position! on the custom input/output ports when a switch from input to output requires adjustment for lookahead.

textual input/output ports

Textual input/output ports whose transcoders do not use fixed-width encodings or use end-of-line styles other than none have problematic and/or partially undefined semantics at the boundaries between previous content and newly written content. See the discussion of set-port-position!.

get-bytevector-some

The R6RS semantics of this procedure is unclear; apparently it is required to return a bytevector consisting of the smallest possible nonzero number of bytes that can be read from the port, unless an end of file is reached before any bytes can be read. This procedure is extremely inefficient, and we cannot imagine a problem for which it would be part of a reasonable solution.

Clone this wiki locally