Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Wow. What does your Lisp do with this?

100 views
Skip to first unread message

kenny

unread,
Dec 12, 2010, 4:48:54 PM12/12/10
to
(defun wow ()
(lambda (x)
(print x)
(when (= x 42)
(return-from wow))))

(let ((w (wow)))
(funcall w 42))

AllegroCl backtraces on "Attempt to the non-existent tag #\backspace"

kt

kenny

unread,
Dec 12, 2010, 4:50:08 PM12/12/10
to

er, "Attempt to /throw to/ the non-existent tag #\Backspace"

kt

Mario S. Mommer

unread,
Dec 12, 2010, 4:54:28 PM12/12/10
to

Meh.

Latest sbcl (1.0.45) gives

attempt to RETURN-FROM a block or GO to a tag that no longer exists
[Condition of type SB-INT:SIMPLE-CONTROL-ERROR]

vanekl

unread,
Dec 12, 2010, 5:07:40 PM12/12/10
to


ccl:

; SLIME 2010-10-09
CL-USER> (defun wow ()


(lambda (x)
(print x)
(when (= x 42)
(return-from wow))))

WOW
CL-USER> (let ((w (wow)))
(funcall w 42))

42 ; Evaluation aborted on #<CCL::CANT-THROW-ERROR #x185D615E>.
CL-USER> (lisp-implementation-version)

"Version 1.6-dev-r14370M-trunk (LinuxX8632)"

Can't throw to tag (0 . -520093696)
[Condition of type CCL::CANT-THROW-ERROR]

Pascal J. Bourguignon

unread,
Dec 12, 2010, 5:17:12 PM12/12/10
to
kenny <kent...@gmail.com> writes:

Mine? It throws daemons out of your nose!

The others:

[pjb@kuiper :0.0 ~]$ clall -r '(defun wow () (lambda (x) (print x) (when (= x 42) (return-from wow))))' '(let ((w (wow))) (funcall w 42))'

Armed Bear Common Lisp --> WOW
Armed Bear Common Lisp Unmatched block WOW for RETURN-FROM outside of lexical extent.
International Allegro CL Free Express Edition --> WOW
International Allegro CL Free Express Edition No longer in block WOW, cannot return from it.
Clozure Common Lisp --> WOW
Clozure Common Lisp Can't throw to tag ((#<CCL::STANDARD-KERNEL-METHOD PRINT-OBJECT (CONDITION T)> #<CCL::STANDARD-KERNEL-METHOD PRINT-OBJECT (STANDARD-OBJECT T)>) . 17532716786926)
CLISP --> WOW
CLISP RETURN-FROM: the block named WOW has already been left
CMU Common Lisp --> WOW
CMU Common Lisp Attempt to THROW to a tag that does not exist: (NIL)
ECL --> WOW
ECL RETURN-FROM: The block WOW with id 11 is missing.
SBCL --> WOW
SBCL attempt to RETURN-FROM a block or GO to a tag that no longer exists

========================================================================

--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

x

unread,
Dec 13, 2010, 12:59:04 AM12/13/10
to
kenny <kent...@gmail.com> wrote in news:ea6f762f-bc3f-497f-a7e3-
287ba9...@j18g2000prn.googlegroups.com:

LWW 4.3:

42
Uncaught throw of NIL to (#:WOW).

In any case, it's correct for it to be an error, because it's an attempt
to return more than once from the same function call. The first time it
returns, the function call becomes garbage. The 2nd time, it's trying to
return from garbage. The cryptic/incorrect error message is probably
caused by the information being lost that would help give a better error
message.

Frode V. Fjeld

unread,
Dec 13, 2010, 4:27:38 AM12/13/10
to
x <a@b.c> writes:

> In any case, it's correct for it to be an error, because it's an
> attempt to return more than once from the same function call. The
> first time it returns, the function call becomes garbage. The 2nd
> time, it's trying to return from garbage.

There's no first and second time. It's just a trivial example of trying
to transfer control to an exit point that has been "disestablished"
(CLHS 3.1.6 Extent).

> The cryptic/incorrect error message is probably caused by the
> information being lost that would help give a better error message.

It looks to me as if the implementations' internal identifiers for exit
points are leaking into the error messages, showing up as meaningless
values.

--
Frode V. Fjeld

Mark Wooding

unread,
Dec 13, 2010, 7:17:26 AM12/13/10
to
"Frode V. Fjeld" <fr...@netfonds.no> writes:

> It looks to me as if the implementations' internal identifiers for exit
> points are leaking into the error messages, showing up as meaningless
> values.

Indeed. It seems as if many implementations are implementing
BLOCK/RETURN-FROM in terms of CATCH/THROW, which surprises me somewhat.
I'd have thought that they'd be better off using BLOCK as the primitive,
since BLOCK names are lexically scoped and therefore more amenable to
compile-time analysis, e.g., building tables to explain how to do the
jump to escape a BLOCK, or even noticing that the BLOCK is never
RETURNed-FROM.

I suppose that the compiler might notice that a CATCH tag is freshly
consed and doesn't escape the lexical scope and do similar analysis from
there, but that seems like more work to me.

I'm obviously wrong, though, since completely respectable compilers are
doing it the other way around; so what am I missing?

-- [mdw]

Frode V. Fjeld

unread,
Dec 13, 2010, 7:50:47 AM12/13/10
to
m...@distorted.org.uk (Mark Wooding) writes:

> Indeed. It seems as if many implementations are implementing
> BLOCK/RETURN-FROM in terms of CATCH/THROW, which surprises me
> somewhat. I'd have thought that they'd be better off using BLOCK as
> the primitive, since BLOCK names are lexically scoped and therefore
> more amenable to compile-time analysis, e.g., building tables to
> explain how to do the jump to escape a BLOCK, or even noticing that
> the BLOCK is never RETURNed-FROM.

I don't think you can consider CATCH/THROW or BLOCK/RETURN-FROM as
primitives in this sense. The crucial point is whether the control
transfer itself is "lexical" (i.e. everything between the jump and the
target is known at compile-time) or not. This is almost orthogonal to
the difference between C/T and B/R, which is about the scope of the
identifiers.

For example:

(defun f1 (x)
(catch 'tag
(when x (throw 'tag 1))
2))

(defun f2 (x)
(block tag
(when x (return-from tag 1))
2))

Both F1 and F2 do "lexical" control transfers, and it would be very
reasonable for an implementation to compile them identically.

Here's an example of a "non-lexical" BLOCK/RETURN-FROM:

(defun f3 (x)
(block tag
(zap (lambda ()
(when x
(return-from tag 42))))))

Here the BLOCK/RETURN-FROM must be implemented basically the same way as
a general CATCH/THROW, and this is also what we saw in the OP example.


Point is: There are two (pairs of) conceptual primitives, and they are
somewhat related to CATCH/THROW vs. BLOCK/RETURN-FROM, but they are not
identical to those.

--
Frode V. Fjeld

Captain Obvious

unread,
Dec 13, 2010, 8:08:53 AM12/13/10
to
PJB> Armed Bear Common Lisp --> WOW
PJB> Armed Bear Common Lisp Unmatched block WOW for RETURN-FROM
PJB> outside of lexical extent.

Lexical extent, huh?

"The block named name has lexical scope and dynamic extent."

Tim Bradshaw

unread,
Dec 13, 2010, 8:26:45 AM12/13/10
to
On 2010-12-13 12:50:47 +0000, Frode V. Fjeld said:

> Here's an example of a "non-lexical" BLOCK/RETURN-FROM:
>
> (defun f3 (x)
> (block tag
> (zap (lambda ()
> (when x
> (return-from tag 42))))))
>
> Here the BLOCK/RETURN-FROM must be implemented basically the same way as
> a general CATCH/THROW, and this is also what we saw in the OP example.

I think that's lexical: the RETURN-FROM is within the lexical scope of
the BLOCK. It might not be within the dynamic *extent* of the BLOCK
(depending on what ZAP does), but it is definitely within the lexical
*scope* of it. Just the same way that X in the is used within the
lexical scope of its binding, and X was special it might or might not
be within the dynamic extent of the binding.

I don't disagree with what you're saying, but I think the terminology
is wrong. In particular I think there are at least three things here:

* lexical scoping (which will allow compile-time detection of
mismatched tags for BLOCK/RETURN-FROM)
* dynamic extent, which is not generally completely checkable at compile-tme
* "simpleness" (bad word) which is whether the RETURN-FROM has to
unwind bits of stack that are not known at compile-time.

So I think what you're talking about is simpleness vs non-simpleness
(again, this is a bad term, it's just not as bad as lexical, which is
wrong).

As best I can tell CATCH/THROW is very easy to implement in terms of
BLOCK/RETURN-FROM: something like the below mostly does it, I think:

(defvar *grabbers* '())

(defmacro grab (tag &body body)
(let ((b (make-symbol "B")))
`(block ,b
(let ((*grabbers* (acons ,tag #'(lambda (v)
(return-from ,b v)) *grabbers*)))
,@body))))

(defun fling (tag value)
(let ((r (assoc tag *grabbers*)))
(unless r
(error "no grabber for ~S" tag))
(funcall (cdr r) value)))

Frode V. Fjeld

unread,
Dec 13, 2010, 8:40:20 AM12/13/10
to
Tim Bradshaw <t...@tfeb.org> writes:

> I don't disagree with what you're saying, but I think the terminology
> is wrong.

Well, I invented the terminology on the spot, which is what I meant to
indicate by putting it in quotes. Also, I tried to make the distinction
between the "lexcial" /control transfer/ which I was talking about, and
the lexical scope of the identifiers which is what one normally
considers wrt. CATCH/THROW and BLOCK/RETURN-FROM.

> * "simpleness" (bad word) which is whether the RETURN-FROM has to
> unwind bits of stack that are not known at compile-time.

This I suspect is precisely what I termed "lexcial" vs. "non-lexical"
control transfer. I don't see how that terminology is particularly
wrong. The details of the control tranfer are resolved by lexical
analysis of the code, thus "lexical control transfer".

Sometimes a BLOCK/RETURN-FROM degenerates into what's essentially a
CATCH/THROW. And vice versa.

--
Frode V. Fjeld

Michael Livshin

unread,
Dec 13, 2010, 8:32:57 AM12/13/10
to
"Frode V. Fjeld" <fr...@netfonds.no> writes:

> The crucial point is whether the control
> transfer itself is "lexical" (i.e. everything between the jump and the
> target is known at compile-time) or not. This is almost orthogonal to
> the difference between C/T and B/R, which is about the scope of the
> identifiers.

and every time I find myself wondering why the "non-lexical" B/R is even
allowed by the spec at all, I think for another 5 seconds and remember:
"macros!".

regards,
--m

Tim Bradshaw

unread,
Dec 13, 2010, 9:14:02 AM12/13/10
to
On 2010-12-13 13:40:20 +0000, Frode V. Fjeld said:

> This I suspect is precisely what I termed "lexcial" vs. "non-lexical"
> control transfer. I don't see how that terminology is particularly
> wrong. The details of the control tranfer are resolved by lexical
> analysis of the code, thus "lexical control transfer".

I think it's unfortunate (rather than wrong) because "lexical" has so
much other baggage associated with it, and because it's really not
something that people writing code should ever need to worry about (for
instance a compiler might never bother doing the analysis at all).

Raffael Cavallaro

unread,
Dec 13, 2010, 10:43:10 AM12/13/10
to
On 2010-12-12 16:48:54 -0500, kenny said:

> (defun wow ()
> (lambda (x)
> (print x)
> (when (= x 42)
> (return-from wow))))
>
> (let ((w (wow)))
> (funcall w 42))

LispWorks seems to get this right in the interpreter:

42
Error: No longer in block WOW, cannot return from it.
1 (abort) Return to level 0.
2 Return to top loop level 0.

Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.


but when wow is compiled, not so much
- even if we (declare (optimize (debug 3) (speed 0) (safety 3))):

CL-USER 5 > (let ((w (wow))) ;; wow is compiled here
(funcall w 42))

42
Error: Uncaught throw of NIL to (WOW . 1).
1 (abort) Return to level 0.
2 Return to top loop level 0.

Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.


warmest regards,

Ralph

--
Raffael Cavallaro

Tim Bradshaw

unread,
Dec 13, 2010, 11:04:45 AM12/13/10
to
On 2010-12-13 15:43:10 +0000, Raffael Cavallaro said:

> but when wow is compiled, not so much
> - even if we (declare (optimize (debug 3) (speed 0) (safety 3))):

In what sense is this wrong? It is causing an exception (which is good,
since it is not actually required to), but the exception is somewhat
less informative in compiled code.

Duane Rettig

unread,
Dec 13, 2010, 12:28:40 PM12/13/10
to

The internal term we use in Allegro CL is "catchified" (how's that for
direct?)

I believe a bit more strongly that "lexical" is in fact an incorrect
term, because although the word lexical isn't defined in the glossary,
there are other terms beginning with "lexical" which infer that
lexical can be replaced loosely with "textual", and the example given
is clearly textually visible.

A non-local transfer of control (e.g. a return-from or go) is
"catchified" when there are things that need to be done (e.g. specials
need unbinding or unwind-protects are present between) the transfer-of-
control and the target, or if the transfer crosses a lambda boundary
(as is the case in the original example). Otherwise, the transfer-of-
control remains a simple jump. We also sometimes go the other way
around and turn a catch/throw into a simple jump, but that is much
harder to come by, because the compiler has to prove that there is no
way to get to the tag by other means (e.g. within an interrupt in the
body form of the catch).

Duane

Peter Keller

unread,
Dec 13, 2010, 1:12:12 PM12/13/10
to
Tim Bradshaw <t...@tfeb.org> wrote:
> As best I can tell CATCH/THROW is very easy to implement in terms of
> BLOCK/RETURN-FROM: something like the below mostly does it, I think:
>
> (defvar *grabbers* '())
>
> (defmacro grab (tag &body body)
> (let ((b (make-symbol "B")))
> `(block ,b
> (let ((*grabbers* (acons ,tag #'(lambda (v)
> (return-from ,b v)) *grabbers*)))
> ,@body))))
>
> (defun fling (tag value)
> (let ((r (assoc tag *grabbers*)))
> (unless r
> (error "no grabber for ~S" tag))
> (funcall (cdr r) value)))
>

Lisp in Small Pieces has a very similar piece of code to this in it in
chapter 3 for this very purpose. I remember the author stating there
was some subtle problem with it, but I don't have my copy handy...

-pete

RG

unread,
Dec 13, 2010, 1:44:03 PM12/13/10
to
In article <ie5nls$e2b$1...@news.eternal-september.org>,
Peter Keller <psi...@cs.wisc.edu> wrote:


I have not been following this whole thread so someone else may have
already pointed this out, but this seems relevant:

http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Issues/iss15
2-writeup.html

rg

Raffael Cavallaro

unread,
Dec 13, 2010, 2:08:44 PM12/13/10
to

Not wrong, just much "less informative," as you put it.

I guess my use of "not so much" was too literal - meaning "not as
right" rather than the more usual sarcastic usage of "not so much" to
mean "not at all." Sorry for any confusion as a result.

Rob Warnock

unread,
Dec 14, 2010, 3:18:43 AM12/14/10
to
RG <rNOS...@flownet.com> wrote:
+---------------

| I have not been following this whole thread so someone else may have
| already pointed this out, but this seems relevant:
| http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Issues/
| iss152-writeup.html
+---------------

And this classic usually helps in these cases, too:

http://home.pipeline.com/~hbaker1/MetaCircular.html
Metacircular Semantics for Common Lisp Special Forms
Henry G. Baker (1992)
...
We will show that only one of the three non-local exit mechanisms
block/return-from, tagbody/go, catch/throw is required to be primitive,
by showing how to emulate any two in terms of the third.
...


-Rob

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Tim Bradshaw

unread,
Dec 14, 2010, 4:13:28 AM12/14/10
to
On 2010-12-13 17:28:40 +0000, Duane Rettig said:

> I believe a bit more strongly that "lexical" is in fact an incorrect
> term, because although the word lexical isn't defined in the glossary,
> there are other terms beginning with "lexical" which infer that
> lexical can be replaced loosely with "textual", and the example given
> is clearly textually visible.

That's what I was trying to say, except put better (better put?), thank you

Anti Vigilante

unread,
Jan 10, 2011, 7:33:24 PM1/10/11
to
kenny wrote:

Do not trust this man. He dares to attempt to solve the Halting
Problem. Admittedly there are a few lines left to get there. But the
evidence is unambiguous.

0 new messages