bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#6591: 24.0.50; incorrect doc for `catch'


From: MON KEY
Subject: bug#6591: 24.0.50; incorrect doc for `catch'
Date: Sat, 10 Jul 2010 01:44:40 -0400

,----
| The description is not consistent and clear.  In particular, this
| part:
|
|  "With the return point in effect, `catch' evaluates the forms of
|   the BODY in textual order.  If the forms execute normally (without
|   error or nonlocal exit) the value of the last body form is
|   returned from the `catch'."
|
| "The forms of the BODY" is problematic - which BODY?  And it's
| incorrect.  The forms within a BODY are not necessarily evaled in
| textual order.
`----

Given that the Emacs Lisp dialect is described as being derived from
Maclisp and being a Lisp2 in some respects resembles Common Lisp the
following excerpts may of interest/relevance:

----

Following from the Pitmanual "Sunday Morning Edition"
The Revised Maclisp Manual Page A-5
:SOURCE (URL `http://maclisp.info/pitmanual/contro.html#5.13.3')

CATCH   Special Form    (CATCH form  [tag])

CATCH is an archaic (destined to become obsolete) special form for
doing structured non-local exits. See documentation on its
replacement, *CATCH.

CATCH forms can be translated to *CATCH as follows:

    old         new
    (CATCH form tag)    (*CATCH 'tag form)
    (CATCH form)        (*CATCH NIL form).

Historically, (CATCH form) evolved to handle the fact that programmers
were using

    (ERRSET (...(ERR)...))

to accomplish non-local returns since there was once no other way to
get that functionality. CATCH and THROW were introduced so that
programmers could write

    (CATCH (...(THROW val)...))

instead where there was really no error condition. However, it was
found that confusion would often result using unlabelled CATCH/THROW
because an unlablled CATCH could catch a throw it hadn't intended
to. This is why named CATCH was invented. It is strongly recommended,
therefore, that if you are re-writing (CATCH form) to a *CATCH
according to the above rules, you also go to the extra trouble to
choose some tag. This is not as easy because it involves changing
related THROW's in the same module to all use the same tag (and
perhaps other CATCH's, or even some *THROW's and/or *CATCH's), but
it'll enhance the reliability of your code quite a lot.

See also: *CATCH, CATCH-BARRIER, CATCHALL, THROW, ERRSET
THROW   Special Form    (THROW form [tag])

THROW is an archaic (destined to become obsolete) special form. See
documentation on its replacement, *THROW.

THROW forms can be translated to *THROW as follows:

    old         new
    (THROW form tag)    (*THROW 'tag form).
    (THROW form)        (*THROW NIL form).

See also: *THROW, CATCH, ERR

;;; ==============================
Following from an unofficial version of dpans3-texi of
ANSI Common Lisp:

catch (Special Operator)

Syntax:

 -- Special Form: catch TAG {form}* → {result}*

Arguments and Values:

TAG--a catch tag; evaluated.

FORMS--an implicit progn.

RESULTS--if the FORMS exit normally, the values returned by the FORMS;
if a throw occurs to the TAG, the values that are thrown.

Description:

‘catch’ is used as the destination of a non-local control transfer by
‘throw’.  TAGS are used to find the ‘catch’ to which a ‘throw’ is
transferring control.  ‘(catch 'foo form)’ catches a ‘(throw 'foo
form)’ but not a ‘(throw 'bar form)’.

The order of execution of ‘catch’ follows:

  1. TAG is evaluated.  It serves as the name of the ‘catch’.

  2. FORMS are then evaluated as an implicit ‘progn’, and the results
     of the last FORM are returned unless a ‘throw’ occurs.

  3. If a ‘throw’ occurs during the execution of one of the FORMS,
     control is transferred  to the ‘catch’ form whose TAG is ‘eq’ to
     the tag argument of the ‘throw’ and which is the most recently
     established ‘catch’ with that TAG.  No further evaluation of FORMS
     occurs.

  4. The TAG established by ‘catch’ is disestablished just before the
     results are returned.

If during the execution of one of the FORMS, a ‘throw’ is executed
whose tag is ‘eq’ to the ‘catch’ tag, then the values specified by the
‘throw’ are returned as the result of the dynamically most recently
established ‘catch’ form with that tag.

The mechanism for ‘catch’ and ‘throw’ works even if ‘throw’ is not
within the lexical scope of ‘catch’.  ‘throw’ must occur within the
dynamic extent of the evaluation of the body of a ‘catch’ with a
corresponding TAG.

Examples:

 (catch 'dummy-tag 1 2 (throw 'dummy-tag 3) 4) → 3
 (catch 'dummy-tag 1 2 3 4) → 4
 (defun throw-back (tag) (throw tag t)) → THROW-BACK
 (catch 'dummy-tag (throw-back 'dummy-tag) 2) → T

 ;; Contrast behavior of this example with corresponding example of BLOCK.
 (catch 'c
   (flet ((c1 () (throw 'c 1)))
     (catch 'c (c1) (print 'unreachable))
     2)) → 2

Exceptional Situations:

An error of type ‘control-error’ is signaled if ‘throw’ is done when
there is no suitable ‘catch’ TAG.

See Also:

throw

Notes:

It is customary for symbols to be used as TAGS, but any object is
permitted.  However, numbers should not be used because the comparison
is done using ‘eq’.

‘catch’ differs from ‘block’ in that ‘catch’ tags have dynamic scope
while ‘block’ names have lexical scope.

--
throw (Special Operator)

Syntax:

 -- Special Form: throw tag result-form →|

Arguments and Values:

TAG--a catch tag; evaluated.

RESULT-FORM--a form; evaluated as described below.

Description:

‘throw’ causes a non-local control transfer to a ‘catch’ whose tag is
‘eq’ to TAG.

TAG is evaluated first to produce an object called the throw tag; then
RESULT-FORM is evaluated, and its results are saved. If the RESULT-FORM
produces multiple values, then all the values are saved.  The most
recent outstanding ‘catch’ whose TAG is ‘eq’ to the throw tag is
exited; the saved results are returned as the value or values of
‘catch’.

The transfer of control initiated by ‘throw’ is performed as described
in Section 5.2.

Examples:

 (catch 'result
    (setq i 0 j 0)
    (loop (incf j 3) (incf i)
          (if (= i 3) (throw 'result (values i j))))) → 3, 9

 (catch nil
   (unwind-protect (throw nil 1)
     (throw nil 2))) → 2

The consequences of the following are undefined because the ‘catch’ of
‘b’ is passed over by the first ‘throw’, hence portable programs must
assume that its dynamic extent is terminated.  The binding of the catch
tag is not yet disestablished and therefore it is the target of the
second ‘throw’.

 (catch 'a
   (catch 'b
     (unwind-protect (throw 'a 1)
       (throw 'b 2))))

The following prints "‘The inner catch returns :SECOND-THROW’" and then
returns ‘:outer-catch’.

 (catch 'foo
         (format t "The inner catch returns ~s.~%"
                 (catch 'foo
                     (unwind-protect (throw 'foo :first-throw)
                         (throw 'foo :second-throw))))
         :outer-catch)
▷ The inner catch returns :SECOND-THROW
→ :OUTER-CATCH

Exceptional Situations:

If there is no outstanding catch tag that matches the throw tag, no
unwinding of the stack is performed, and an error of type
‘control-error’ is signaled.  When the error is signaled, the dynamic
environment is that which was in force at the point of the ‘throw’.

See Also:

block, catch, return-from, unwind-protect

Notes:

‘catch’ and ‘throw’ are normally used when the exit point must have
dynamic scope (e.g., the ‘throw’ is not lexically enclosed by the
‘catch’), while ‘block’ and ‘return’ are used when lexical scope is
sufficient.

--
/s_P\





reply via email to

[Prev in Thread] Current Thread [Next in Thread]