Skip to content

DeprecatedR6RSSyntaxAndProcedures

Felix S. Klock II edited this page Jul 28, 2013 · 5 revisions

== Deprecated R6RS Syntax and Procedures ==

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

Although a few of the R6RS features that Larceny currently supports are deprecated in Larceny, we have no plans to remove those features so long as the R6RS remains the relevant standard for R6RS-style programs. On the other hand, we share the hope expressed by several R6RS editors that the R6RS will soon be superseded by revisions that address its problems. In the case of several R6RS features that have been deprecated in Larceny, the simplest and best solution would be to remove the misfeature.

Deprecation of an R6RS feature in Larceny is not meant to signal our determination to remove the feature from Larceny at the cost of compatibility with the relevant standard. It is meant to warn our users that

  • we advocate removal or revision of the deprecated feature in the next revision of the relevant standard, and
  • we think there is or will be a growing consensus within the R6RS community that the feature should be removed or its specification changed in the next major revision of the R6RS.

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, 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 ERR5RS record system, which will be described by a SRFI, instead of the R6RS record system. (In Larceny, ERR5RS records are the same as R6RS records, and ERR5RS record-type descriptors are the same as R6RS record-type descriptors, but the ERR5RS API is superior.)

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. See [for further discussion of this. We recommend that all programmers use the ERR5RS record system, which will be described by a SRFI, instead of the R6RS record system. (In Larceny, ERR5RS records are the same as R6RS records, and ERR5RS record-type descriptors are the same as R6RS record-type descriptors, but the ERR5RS API is superior.)

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

These procedures 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 following procedures instead:


open-output-string
get-output-string
reset-output-string
open-output-bytevector
get-output-bytevector
reset-output-bytevector
open-input/output-bytevector

The first three procedures above are specified by SRFI 6, and the next three are analogous. The get-output-bytevector and reset-output-bytevector procedures also work on the input/output ports created by open-input/output-bytevector.

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 ERR5RS 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