[R6RS] library-based safety proposal

dyb at cs.indiana.edu dyb at cs.indiana.edu
Mon Jul 31 14:41:55 EDT 2006


Since our meeting last week, Will has privately expressed doubts whether
we can come up with a viable library-based safety mechanism, i.e., one
that does away with declarations.  He may be right.  What follows is my
first attempt at an informal semantics for library-based safety.  As much
as I dislike declarations and would like to do away with them, I think
library-based safety (at least as described in this proposal) is too
awkward (for declaring large subsets of a block of code unsafe) in the
absence of local imports.

Kent

--------

Every implementation is required to provide a second, unsafe version of
every standard library, named by a second name that indicates the
library's exports are unsafe, e.g. r6rs/unsafe.  An unsafe syntactic form
or procedure may fail to raise an exception in any situation that, in the
words of the R6RS, must raise an exception.  In all other ways, the unsafe
versions of the exports are indistinguishable from the safe versions. 
Calls and bodies nested directly within an unsafe syntactic form are
considered unsafe, and calls and bodies nested directly within a safe
syntactic form are considered safe.

For example, an unsafe procedure may not raise an exception if passed the
wrong types of arguments, an unsafe call may not raise an exception if its
first subform does not evaluate to a procedure, and an unsafe letrec or
body may not raise an exception for a violation of the letrec restriction.

Note: raise raises the specified exception even if imported from an unsafe
version of the r6rs library.

Advantages:

  * There is no need for additional language baggage, i.e., declarations.

  * Library scoping rules determine which code is safe and which is unsafe.

Disadvantages:

  * Multiple safety levels, debug levels, speed levels, etc., would
    lead to a combinatorial explosion in the number of libraries.  (We
    might be able to address this with Mike's library naming system.)

  * Without local imports, declaring large proper subsets of a library
    unsafe is awkward---in the same way that using two versions of any
    library is awkward.
 
Examples:

  (library foo
    (import r6rs/unsafe) ; everything unsafe
    (export lots of cool stuff)
    (define lots ---)
    (define-syntax of ---)
    (define cool ---)
    (define stuff ---))

  (library bar
    (import r6rs (add-prefix r6rs/unsafe u:)) ; some safe, some unsafe
    (export frob key? key->val alist->table ---)
    (define-syntax define-cell
     ; using a prefix is convenient for selected procedure calls
      (syntax-rules ()
        [(_ name init)
         (begin
           (define v (vector init))
           (define-syntax name
             (syntax-rules ()
               [(_) (u:vector-ref v 0)]
               [(_ e) (u:vector-set! v 0 e)])))]))
    (define frob
      (lambda (x)
        (define-cell agent 99)
        ---))
    ---
    (define key?
      (lambda (key table)
       ; using a prefix isn't convenient when we want an entire block
       ; of code to be unsafe.  with we had local imports, we could just
       ; put (import r6rs/unsafe) here and avoid peppering the code
       ; with u: prefixes.
        (u:let loop ((ls (u:car table)))
          (u:and (u:not (u:null? ls))
                 (u:or (u:eq? (u:car ls) key)
                       (loop (u:cdr ls)))))))
    (define key->val
      (lambda (key table)
        (u:cdr (u:assq key (u:cdr table)))))
    (define alist->table ; done infrequently, no need for unsafe code
      (lambda (alist)
        (cons (map car alist) alist)))
    ---)



More information about the R6RS mailing list