[R6RS] another glimpse into the abyss

William D Clinger will at ccs.neu.edu
Tue Mar 6 15:07:23 EST 2007


Another Glimpse Into the Abyss

We've been "editing" the R6RS for three-plus years.

During that entire time, we have never sat down as
a group and tried to converge on a common vision or
guiding philosophy for the language.  That kind of
navel-gazing was discouraged at first, when we were
going to whip together the module system before we
made progress on anything else.  As that process
turned into a standoff, we began to make progress
by agreeing on square brackets and the like.  When
time began to run short, we formulated requirements
that had as much to do with what we thought we could
accomplish than with what we wanted the language to
become.  Eventually we rationalized our proposals
by stating some goals, and I understand that some
sort of larger rationale may be forthcoming.

So here we are, about to work on our third public
draft, and we have spent remarkably little time in
talking about our vision or guiding philosophy for
this document.

By submitting formal comment 198, "Allow compilers
to reject obvious violations", I hoped to enlist
public opinion against the idea that compilers
should have unlimited discretion to reject programs
at compile time, and against the idea that giving
such discretion to compilers would be a good way to
discourage abuse of the exception system.  (In my
opinion, allowing implementations to abort without
going through the exception system is a much better
way to preclude deliberate violations in portable
code.)  As there is no idea so crazy but that the
public might endorse it and make me live with the
result, the comment proposed to give compilers and
interpreters very little discretion at all---much
less than Twobit, Scheme 48, Kawa, SCM, and several
other Scheme systems have traditionally exercised.

During the discussion of that formal comment on the
r6rs-discuss list, people talked about their larger
philosophies and grander hopes for R6RS.  Despite
some abstract theoretical nonsense, most people
expressed their hope that Scheme would become a
more practical language for actual programming, and
a lot of that discussion centered upon practical
goals such as:

  * portability
  * reliability
  * interoperability

One of the more surprising outcomes is that some of
the participants recognized that these goals aren't
always compatible, and began to talk about tradeoffs
between them.  Programmers do not want compilers to
reject programs for arbitrary reasons, because that
can interfere with portability; at the same time,
they welcome warnings from the compiler and, knowing
how easy it is to overlook or to ignore warnings,
recognize the value of a mode that rejects programs
containing probable errors.  Many would like for the
reject-on-warning mode to be the default, so long as
it can be disabled.

Indeed, there seems to be widespread acceptance of
the idea that R6RS-conforming implementations are
unlikely to be R6RS-conforming by default, and that
traditional interactive development (to which R6RS
semantics does not pertain) is likely to remain the
norm.

It is probably too late to change that, and I'm not
sure I would want to change it anyway, but I worry
because, as a serious user of several implementations
and as a casual user of many more (for benchmarking
and for testing portable programs), I have had a lot
of trouble figuring out how to enter the portable
syntactic mode mandated by R5RS 1.3.1.  It is hard
for me to believe that implementors will pay more
attention to the mandates of the R6RS than they did
to things like case-insensitivity and letrec semantics
(for internal definitions, as opposed to letrec*)
that were mandated by the R5RS.

I don't think a document can force implementors or
programmers in general to do anything.  Implementors
conform to standards to the extent that conformance
simplifies implementation (by reusing someone else's
libraries) and attracts users.  Programmers conform
to standards to the extent that conformance expands
their selection of implementations and libraries.

As editors, we are proposing a standard that, if
adopted and followed, will remove some of the more
gratuitous barriers to portability: differences in
lexical, library, and program syntax, approach to
Unicode, records, binary i/o, and low-level macros,
APIs for bytevectors, sorting, fixnum and flonum
arithmetic, hash tables.  We have elected to leave
some things unspecified, and we have nothing to say
about the barriers that make it hard for Scheme
programs to interoperate with other languages.  In
my opinion, the interoperability barrier is hugely
important, but has been masked by some of the more
gratuitous barriers we had to remove first.  If we
can't get Scheme code to interoperate with Scheme
code, then forget it.

Connecting these issues to the absence of a shared
vision:  Throughout this process, I have advocated
the removal of barriers to portability, but have
not been so keen on constructing new barriers to
non-portability.  This is related to one of our
explicit goals, as stated in the June 2006 status
report:

    allow programmers to rely on a level of automatic
    run-time type and bounds checking sufficient to
    ensure type safety while also providing a standard
    way to declare whether such checks are desired

The word "safety" means different things to different
people, and that ambiguity is magnified here by the
word "type".  Scheme is a dynamically typed language,
which means type checks happen late, at run time, and
may consist of the bare minimum needed to preserve
memory safety.  Some of the editors, I believe, prefer
a definition of type safety that is more similar (and
I would say "appropriate") to what we see in statically
typed languages.  I think that accounts for some of
the increasing number of type checks that are required
by the draft R6RS, some of which are being required at
frightfully (and, IMO, inappropriately) early times.
Many of these requirements, it seems to me, have little
or nothing to do with memory safety, but are motivated
by a desire to make non-portable programs harder to
write.

In my opinion, increasing the number of runtime checks
for the purpose of stamping out non-portable usages is
appropriate for code compiled at (debug 3), or maybe
even (safety 3), but I question whether so much
portability-related checking must be the default for
production code.  It seems like the sort of thing you
would want in a special debug mode, which might also
randomize the order of evaluation of arguments, check
that every argument to map is a list whose contents
do not change between calls to the first argument,
and so on.

If you were still reading this essay, you might wonder
whether I'll ever get to the point; more likely, you'd
have decided I won't.  The point is to ask some
questions that have been bothering me:

What do we think R6RS-conformance should or will
mean, for programs and for implementations?

Does the R6RS we envision describe a language that
programmers will want to use, and that implementors
will want to implement?

If we accept that most Scheme programs will continue
to run in interactive mode, to which the R6RS does
not apply, or that most production R6RS programs are
likely to run in some default mode that is unlikely
to be strictly conforming, whatever that may mean,
then the R6RS describes something of an idealized
semantics whose requirements apply primarily when
debugging portable programs.  If so, then shouldn't
the R6RS semantics be even more idealized than it is?

Will



More information about the R6RS mailing list