[R6RS] safe and unsafe; declarations

dyb at cs.indiana.edu dyb at cs.indiana.edu
Sun Mar 5 20:24:19 EST 2006

> Okay.  As you know, but some of the other editors may
> not, my Twobit compiler already implements an unsafe
> mode.  As I explained earlier in this thread, Twobit
> also provides fairly detailed control of several other
> things that ought to be controlled, or at least
> influenced, by the proposed declaration mechanism.  It
> would be very easy to change Twobit so it pays attention
> to the proposed declarations.  The way I would do
> that is to have the macro expander ignore declarations
> altogether, but pass them on to later phases of the
> compiler.

This would not lead to an acceptable implementation of identifier-priority
as I have described it, since priorities reported by identifier-priority
would not generally reflect accurately how the implementation itself
treats identifiers in the scope of a declaration.

In fact, I don't believe it would even be an acceptable implementation of
the proposed model for scoping of declarations, i.e., it would not respect
lexical scoping.  For example, consider:

  (lambda (ls)
    (declare (safe 1))
    (define-syntax foo
      (syntax-rules ()
        [(foo x) (car x)]))
    (let ()
      (declare (safe 0))
      (+ (foo (cdr ls)) 7)))

Note particularly that the reference to car is within the scope of the
(safe 1) declaration and not the (safe 0) declaration and should therefore
be treated as safe.

If an implementation is faithful to the lexical scoping model, this should
expand to the equivalent of:

  (lambda (ls)
    ((let () (declare (safe 0)) +)
     ((let () (declare (safe 1)) car)
      ((let () (declare (safe 0)) cdr) ls))

which we might abbreviate as follows.

  (lambda (ls) (safe0:+ (safe1:car (safe0:cdr ls)) 7))

Note that I said "equivalent of".  The actual expansion is implementation
dependent.  But it should *behave* like this, i.e., with + and cdr being
associated with safe priority 0 and car being associated with safe
priority 1.  Thus the values of + and cdr might be unsafe, but the value
of car must be safe.

On the other hand, if I understand what you mean by "the macro expander
ignore[s] declarations altogether, but pass[es] them on to later phases of
the compiler", you'll get the equivalent of:

  (lambda (ls)
    (declare (safe 1))
    (let ()
      (declare (safe 0))
      (+ (car (cdr ls)) 7)))

which we might reduce and abbreviate to the following.

  (lambda (ls) (safe0:+ (safe0:car (safe0:cdr ls)) 7))

Here, car is improperly associated with safe priority 0.  Of course, if
the implementation uses a safe version anyway, nothing bad comes of the
improper association, but we're talking about an implementation in which
safe0:car actually might evaluate to an unsafe version of the procedure. 
Similar problems can occur with other sorts of declarations as well.

> I think most compiler writers would
> want to implement a similar architecture.

Perhaps so, perhaps not.  Twobit may do as you describe, and Chez Scheme
will do as I describe.  I don't know about the rest, and I'm not willing
to concede that most will do as you describe.  I hope not, if it breaks
the lexical scoping of declarations.

> Your proposal, when considered as a fictional account,
> accurately describes the *behavior* of, but not the actual
> *implementation*, described above up to the point at which
> you introduce the identifier-priority procedure for use by
> syntax-case macros.  In my view, the utility of that
> procedure does not justify the hair involved in making my
> macro expander pay attention to declarations.  Therefore,
> in my system, the information you assume will be available
> at macro expansion time will not in fact be available.  It
> will most certainly not be available on a by-identifier
> basis.  I think most compiler writers would want to
> implement an architecture similar to mine.

Okay, but if declaration information is not available via
identifier-priority, yet later passes of a compiler receive and act upon
it, then I would consider the implementation to be broken, as I explained
near the top of this note and in my response to your earlier question
about identifier-priority returning 3 in all cases.

As I said above, however, I don't believe that the implementation you
describe actually exhibits the proposed behavior even putting
identifier-priority aside.  Furthermore, I believe that support for
identifier-priority will be straightforward to add to any implementation
that does properly implement the proposed behavior (particularly, lexical
scoping), since most of the necessary mechanism will already be in place.

> With that as background, let's look at your answers.

> [Will goes on to point out apparent contradictions in my answers that
> arise when an expander ignores declarations altogether but passes them
> through to the compiler.]

I agree that contradictions arise with your implementation of my model. 
These are not contradictions in the model per se, nor are they
contradictions in my responses to your questions.  They arise solely out
of the incompatibility of the implementation with the model.

If the only problem were contradictions that involve identifier-priority,
the simple solution would be to leave identifier-priority out of R6RS. 
Unfortunately, the problem appears to run deeper.


More information about the R6RS mailing list