add racket/undefined

The `(letrec ([x x]) x)` pattern for getting the undefined value will
cease to work in a near-future version of Racket (ater
v6.0.1). Instead, the initial refernce to `x` will produce a "variable
used before its definition" error.

For libraries that need an "undefined" value, this new library
provides `undefined`, and the library will continue to work in future
Racket versions.

The library also provides a `check-no-undefined` operation that
normally should be wrapped around an expression to keep it from
producing `undefined`. For example, the class system initializes
object fields with `undefined`, but it could (and will, eventually)
wrap each access to a field within `class` to check that the field's
value is not `undefined`.
This commit is contained in:
Matthew Flatt 2014-04-04 10:07:08 -06:00
parent 1d8cfea1fc
commit 8abf78256a
2 changed files with 52 additions and 7 deletions

View File

@ -155,20 +155,44 @@ Sets the content of @racket[box] to @racket[v].}
@include-section["procedures.scrbl"]
@; ----------------------------------------------------------------------
@section[#:tag "void"]{Void and Undefined}
@section[#:tag "void"]{Void}
The constant @|void-const| is returned by most forms and procedures
that have a side-effect and no useful result. The constant
@|undefined-const| is used as the initial value for @racket[letrec]
bindings.
that have a side-effect and no useful result.
The @|void-const| value is always @racket[eq?] to itself, and the
@|undefined-const| value is also @racket[eq?] to itself.
The @|void-const| value is always @racket[eq?] to itself.
@defproc[(void? [v any/c]) void?]{Returns @racket[#t] if @racket[v] is the
@defproc[(void? [v any/c]) boolean?]{Returns @racket[#t] if @racket[v] is the
constant @|void-const|, @racket[#f] otherwise.}
@defproc[(void [v any/c] ...) void?]{Returns the constant @|void-const|. Each
@racket[v] argument is ignored.}
@; ----------------------------------------------------------------------
@section[#:tag "undefined"]{Undefined}
The constant @|undefined-const| is used as the initial value for
@racket[letrec] bindings.
The @|undefined-const| value is always @racket[eq?] to itself.
@note-lib[racket/undefined]
@history[#:added "6.0.0.6"]
@defproc[(undefined? [v any/c]) boolean?]{Returns @racket[#t] if @racket[v] is the
constant @|undefined-const|, @racket[#f] otherwise.}
@defthing[undefined undefined?]{The @|undefined-const| constant.}
@defproc[(check-not-undefined [v any/c] [sym symbol?]) (and/c any/c (not/c undefined?))]{
Checks whether @racket[v] is @|undefined-const|, and raises
@racket[exn:fail:contract:variable] in that case with an error message
along the lines of ``@racket[sym]: variable used before its definition.''
If @racket[v] is not @|undefined-const|, then @racket[v] is returned.
}

View File

@ -0,0 +1,21 @@
#lang racket/base
(require '#%kernel)
(provide check-not-undefined
undefined
undefined?)
;; In a future version of Racket, this `letrec` pattern
;; will not work, but the `racket/undefined` library will
;; still export an `undefined`:
(define undefined (letrec ([x x]) x))
(define (undefined? v) (eq? v undefined))
(define (check-not-undefined v s)
(unless (symbol? s) (raise-argument-error 'check-not-undefined "symbol?" 1 v s))
(if (eq? v undefined)
(raise (make-exn:fail:contract:variable
(format "~a: variable used before its definition" s)
(current-continuation-marks)
s))
v))