[R6RS] Re: Safe/unsafe mode issues

William D Clinger will at ccs.neu.edu
Tue Feb 14 16:28:12 EST 2006

> The R5RS uses these formulations in contexts where
> 1. a procedure is called on an argument it is not prepared to accept,
>    i.e. a bug in the program,

It's much more subtle than that.  The R5RS explicitly allows
implementations to extend the domains of standard procedures,
so you can't assume that calling a procedure on an argument
it is not prepared to accept is a bug.  In an implementation
so extended, it may be a proper (though non-portable) thing
to do.  If the code is then executed in some other system,
it becomes a bug, but the bug lies in the mismatch between
the expectations of the non-portable program and the person
who thought it was portable.

The classic example is (car '()), which returns the empty
list in some systems.  Other classic examples are (force 0)
and (+ (delay (* 3 7)) -21).  The R5RS explicitly allows both
to return 0.

> Most (all except Stalin?) Scheme implementations offer a "safe mode"
> which makes each situation described as "is an error" actually signal
> an error.

No, that is far from true.  Scheme48 might offer such a mode,
but I doubt whether any other implementations do.  Here is a
quick-and-dirty list of the R5RS error situations that are not
required to signal an error:


It is an error to attempt to store a new value into a location
that is denoted by an immutable object.

For example, it is an error for a procedure to be passed an
argument that the procedure is not explicitly specified to
handle, even though such domain errors are seldom mentioned in
this report.  Implementations may extend a procedure's domain
of definition to include such arguments.

It is an error to reference an unbound variable.

...it is an error to alter a constant (i.e. the value of a
literal expression) using a mutation procedure like
set-car! or string-set!.

It is an error for a <variable> to appear more than once in

It is an error for a <variable> to appear more than once in the
list of variables being bound.

It is an error for a <variable> to appear more than once in the
list of variables being bound.

One restriction on letrec is very important: it must be possible
to evaluate each <init> without assigning or referring to the
value of any <variable>.  If this restriction is violated, then
it is an error.

It is an error for a <variable> to appear more than once in the
list of do variables.

It is an error for a <keyword> to appear more than once in the
list of keywords being bound.

It is an error for the same pattern variable to appear more than
once in a <pattern>.

A subpattern followed by <tt>...</tt> can match zero or more
elements of the input.  It is an error for <tt>...</tt> to
appear in <literals>.  Within a pattern the identifier
<tt>...</tt> must follow the last element of a nonempty sequence
of subpatterns.

It is an error to use a macro keyword, within the scope of its
binding, in an expression that does not match any of the patterns.

It is an error if the output cannot be built up as specified.

If <variable> is not bound, however, then the definition will
bind <variable> to a new location before performing the
assignment, whereas it would be an error to perform a
<tt>set!</tt> on an unbound variable.

Although macros may expand into definitions and syntax definitions in
any context that permits them, it is an error for a definition or syntax
definition to shadow a syntactic keyword whose meaning is needed to
determine whether some form in the group of forms that contains the
shadowing definition is in fact a definition, or, for internal definitions,

Since it is an error to modify constant objects (those returned by
literal expressions), implementations are permitted, though not
required, to share structure between constants where appropriate.
Thus the value of <tt>eqv?</tt> on constants is sometimes

The <tt>length</tt>, <tt>vector-length</tt>,
and <tt>string-length</tt> procedures must return an exact
integer, and it is an error to use anything but an exact integer as an

It is an error if no possible result makes this expression true.

The error case can occur only when z is not a complex number
or is a complex number with a non-rational real or imaginary part.

Note that it is an error to take the car of the empty list.

Note that it is an error to take the cdr of the empty list.

It is an error if list has fewer than k elements.

It is an error if list has fewer than k elements.

It is an error to apply mutation procedures like <tt>string-set!</tt>
to strings returned by this procedure.

If a file with the given name already exists, the effect is

It is an error to read from a closed port.


> I think the R6RS should mandate a "safe mode" that requires an
> implementation to run a program, which is available in source code, and
> which relies only on libraries specified as part of R6RS, in such a
> way that *all* exceptional situations must "signal an error."  It
> should also not prohibit implementations from providing unsafe or safe
> mode selectively, i.e. via special compile switches or something, or
> saying allowing a piece of code to selectively use "the unsafe version
> of fixnum arithmetic" or something like that.

We really have to nail this down.  The R5RS requires all
implementations to provide "a syntactic mode that preempts no
lexical conventions of this report", but implementors have
not paid much attention to this.  You may remember my poll
near the beginning of the R6RS process, asking the editors
how to enter that syntactic mode in their own systems.  Most
had to scratch their heads a bit, and several realized that
there was no easy way to get their systems into a thoroughly
R5RS-conforming mode.

I don't want to duplicate that experience with safe/unsafe.
If we're going to require something, let's require it in a
way that people can use without beating implementors over
the head with the Common Lisp standard.


More information about the R6RS mailing list