93 lines
2.9 KiB
Racket
93 lines
2.9 KiB
Racket
#lang scribble/manual
|
|
|
|
@(require (for-label racket/base
|
|
racket/contract
|
|
"../main.rkt"))
|
|
|
|
@title{define/return}
|
|
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
|
|
|
|
@defmodule[define-return]
|
|
|
|
The @racketmodname[define-return] library provides definition forms with an
|
|
explicit early return. This is useful in small defensive functions, and
|
|
especially around FFI bindings, where null pointers, error codes, unsupported
|
|
states, or failed preconditions should leave the function immediately.
|
|
|
|
The early return is implemented with an internal exception. A @racket[return]
|
|
raises that exception, and the definition forms catch it around the function
|
|
body. The contracted form additionally checks early-returned values against
|
|
the result contract.
|
|
|
|
See @racketmodname[define-return/contract] for the contracted version of
|
|
this module.
|
|
|
|
@section{Return}
|
|
|
|
@defform[(return val)]{
|
|
|
|
Returns @racket[val] from the nearest dynamically enclosing
|
|
@racket[define/return] or @racket[define/contract/return] body.
|
|
|
|
The form is not a general escape continuation. It raises an internal return
|
|
exception. When used outside a body installed by this library, that exception
|
|
escapes.
|
|
|
|
}
|
|
|
|
@section{Uncontracted definitions}
|
|
|
|
@defform[(define/return def body ...)]{
|
|
|
|
Like @racket[define], but @racket[body] may use @racket[return] to leave the
|
|
definition early.
|
|
|
|
@racketblock[
|
|
(define/return (status->symbol code)
|
|
(unless (number? code)
|
|
(return 'not-a-number))
|
|
(when (= code 0) (return 'ok))
|
|
(when (< code 0) (return 'failed))
|
|
(when (> code 5) (return 'out-of-range))
|
|
(cond
|
|
((= code 1) 'normal)
|
|
((>= code 2) (string->symbol (format "code-~a" (* code code))))
|
|
)
|
|
)
|
|
]
|
|
|
|
The final expression is used when no early return is taken.
|
|
|
|
@codeblock|{
|
|
(status->symbol 0) ; => 'ok
|
|
(status->symbol -1) ; => 'failed
|
|
(status->symbol 10) ; => 'out-of-range
|
|
(status->symbol "Hi") ; => 'not-a-number
|
|
(status->symbol 1) ; => 'normal
|
|
(status->symbol 3) ; => 'code-9
|
|
}|
|
|
|
|
}
|
|
|
|
@section{Contracted definitions}
|
|
|
|
See @racketmodname[define-return/contract].
|
|
|
|
@section{Notes}
|
|
|
|
The mechanism is intentionally small. It uses @racket[with-handlers] and an
|
|
internal exception type; it does not introduce prompts, continuations, or a
|
|
new calling convention.
|
|
|
|
For @racket[define/contract/return], the normal function contract remains the
|
|
job of @racket[define/contract]. The extra returner only exists for the path
|
|
where @racket[return] leaves the body through an exception handler. That path
|
|
would otherwise bypass the ordinary result position of the function body.
|
|
|
|
The contracted form does not try to parse arbitrary contract syntax. It
|
|
splits the inline contract form syntactically and reuses its last element as
|
|
the early-return result contract. This works well for ordinary result
|
|
contracts such as @racket[number?], @racket[symbol?],
|
|
@racket[(or/c symbol? number?)], and the result position of @racket[->*]
|
|
contracts.
|