#lang scribble/doc
@(require "mz.rkt"
          (for-label racket/unsafe/undefined))

@title[#:tag "unsafe-undefined"]{Unsafe Undefined}

@note-lib-only[racket/unsafe/undefined]

The constant @racket[unsafe-undefined] is used internally as a
placeholder value. For example, it is used by @racket[letrec] as a
value for a variable that has not yet been assigned a value.  Unlike
the @racket[undefined] value exported by @racketmodname[racket/undefined],
however, the @racket[unsafe-undefined] value should not leak as the
result of a safe expression, and it should not be passed as an optional
argument to a procedure (because it may count as ``no value provided'').
Expression results that potentially
produce @racket[unsafe-undefined] can be guarded by
@racket[check-not-unsafe-undefined], so that an exception can be
raised instead of producing an @racket[undefined] value.

The @racket[unsafe-undefined] value is always @racket[eq?] to itself.

@history[#:added "6.0.1.2"
         #:changed "6.90.0.29" @elem{Procedures with optional arguments
                                     sometimes use the @racket[unsafe-undefined]
                                     value internally to mean ``no argument supplied.''}]

@defthing[unsafe-undefined any/c]{

The unsafe ``undefined'' constant.

See above for important constraints on the use of @racket[unsafe-undefined].}


@defproc[(check-not-unsafe-undefined [v any/c] [sym symbol?])
         (and/c any/c (not/c (one-of/c unsafe-undefined)))]{

Checks whether @racket[v] is @racket[unsafe-undefined], and raises
@racket[exn:fail:contract:variable] in that case with an error message
along the lines of ``@racket[sym]: undefined; use before
initialization.''  If @racket[v] is not @racket[unsafe-undefined],
then @racket[v] is returned.}

@defproc[(check-not-unsafe-undefined/assign [v any/c] [sym symbol?])
         (and/c any/c (not/c (one-of/c unsafe-undefined)))]{

The same as @racket[check-not-unsafe-undefined], except that the error
message (if any) is along the lines of ``@racket[sym]: undefined;
assignment before initialization.''}


@defproc[(chaperone-struct-unsafe-undefined [v any/c]) any/c]{

Chaperones @racket[v] if it is a structure (as viewed through some
@tech{inspector}). Every access of a field in the structure is checked
to prevent returning @racket[unsafe-undefined]. Similarly, every
assignment to a field in the structure is checked (unless the check
disabled as described below) to prevent assignment of a field whose
current value is @racket[unsafe-undefined].

When a field access would otherwise produce @racket[unsafe-undefined]
or when a field assignment would replace @racket[unsafe-undefined], the
@racket[exn:fail:contract] exception is raised.

The chaperone's field-assignment check is disabled whenever
@racket[(continuation-mark-set-first #f
prop:chaperone-unsafe-undefined)] returns @racket[unsafe-undefined].
Thus, a field-initializing assignment---one that is intended to replace the
@racket[unsafe-undefined] value of a field---should be wrapped with
@racket[(with-continuation-mark prop:chaperone-unsafe-undefined
unsafe-undefined ....)].}


@defthing[prop:chaperone-unsafe-undefined struct-type-property?]{

A @tech{structure type property} that causes a structure type's
constructor to produce a @tech{chaperone} of an instance
in the same way as @racket[chaperone-struct-unsafe-undefined].

The property value should be a list of symbols used as field names,
but the list should be in reverse order of the structure's fields.
When a field access or assignment would produce or replace
@racket[unsafe-undefined], the @racket[exn:fail:contract:variable]
exception is raised if a field name is provided by the structure
property's value, otherwise the @racket[exn:fail:contract] exception
is raised.}
