ted@nmsu.edu (Ted Dunning) (06/06/91)
even though this is the response to an email message, i think it should be given wider circulation. Date: Tue, 4 Jun 91 08:13:31 +0200 From: Michael Dahmen <dahmen%ecrc.de> > why in the world do they use the names block/3 and exit_block/1? > why not the much more customary catch and throw? Maybe because they don't known or don't like LISP ... :-) isn't this a wonderful motivation for making a proposal for an iso standard? gives me shivers of awe thinking about the deliberations of that august standards body working on my behalf and on the behalf of all the other little people in the world of prolog users. i suppose that they would object to naming something unwind_protect on the same grounds. i understand doing something differently in a new language because it was done poorly before. but i have a hard time understanding a change in the name _only_ in order to be different, especially when the previous implementation worked pretty well. this all sounds pretty childish. block and exit_block sound like they refer to blocks. blocks are very commonly (from algol onward) to refer to static reference scopes, not installing handlers with dynamic extent. how about handle_exception and raise_exception, or handle_event, raise_event or any number of _descriptive_ names. -- When in doubt, take the trick. Hoyle & Hoyle (quoting Hoyle)
dave@quintus.UUCP (David Bowen) (06/08/91)
In article <TED.91Jun6083527@kythera.nmsu.edu> ted@nmsu.edu (Ted Dunning) writes: > Date: Tue, 4 Jun 91 08:13:31 +0200 > From: Michael Dahmen <dahmen%ecrc.de> > > > why in the world do they use the names block/3 and exit_block/1? > > why not the much more customary catch and throw? > > Maybe because they don't known or don't like LISP ... :-) > >isn't this a wonderful motivation for making a proposal for an iso >standard? gives me shivers of awe thinking about the deliberations of >that august standards body working on my behalf and on the behalf of >all the other little people in the world of prolog users. I don't know where the names came from. However, the U.S. committee (X3J17) recommended changing them to catch and throw and this was agreed upon at the last meeting of the ISO committee (WG17) last November. The committees working on Prolog standardization are not particularly august. They are mostly made up of people who have full-time jobs doing other things, and thus it takes a while for even obviously bad ideas, like the names block and exit_block, to be cleared up. (How those names got in the draft in the first place I do not know.)
dc@dcs.qmw.ac.uk (Daniel Cohen;E303) (06/10/91)
In <1536@quintus.UUCP> dave@quintus.UUCP (David Bowen) writes: >In article <TED.91Jun6083527@kythera.nmsu.edu> ted@nmsu.edu (Ted Dunning) writes: >> Date: Tue, 4 Jun 91 08:13:31 +0200 >> From: Michael Dahmen <dahmen%ecrc.de> >> >> > why in the world do they use the names block/3 and exit_block/1? >> > why not the much more customary catch and throw? >> >> Maybe because they don't known or don't like LISP ... :-) >> >>isn't this a wonderful motivation for making a proposal for an iso >>standard? gives me shivers of awe thinking about the deliberations of >>that august standards body working on my behalf and on the behalf of >>all the other little people in the world of prolog users. >I don't know where the names came from. However, the U.S. committee (X3J17) >recommended changing them to catch and throw and this was agreed upon at the >last meeting of the ISO committee (WG17) last November. And the latest draft of the standard ( N72 ) refers to catch and throw, so it looks like this one has been cleared up, at least until Paris when someone will no doubt try to change the names back again! -- Daniel Cohen Department of Computer Science Email: dc@dcs.qmw.ac.uk Queen Mary and Westfield College Tel: +44 71 975 5249/4/5 Mile End Road, London E1 4NS, UK Fax: +44 81 980 6533 *** Glory, Glory, Hallelujah ***
bimbart@hera.cs.kuleuven.ac.be (Bart Demoen) (06/11/91)
perhaps some people are interested in my KUL-CW report 97: "A 20' Implementation of Catch and Throw in WAM" it describes the implementation of block/exit_block (or catch/throw if you prefer) as defined by ISO Bart Demoen
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (06/13/91)
In <1536@quintus.UUCP> dave@quintus.UUCP (David Bowen) writes: > I don't know where the names came from. However, the U.S. committee (X3J17) > recommended changing them to catch and throw and this was agreed upon at the > last meeting of the ISO committee (WG17) last November. I believe the names were proposed by AFNOR. The earlier proposal (for if_error/3 and signal_error/1) failed, having had an Auckland postmark. In article <dc.676561471@guinness>, dc@dcs.qmw.ac.uk (Daniel Cohen;E303) writes: > And the latest draft of the standard ( N72 ) refers to catch and throw, so > it looks like this one has been cleared up, at least until Paris when > someone will no doubt try to change the names back again! I believe that ALS are represented on the ANSI committee, and the last time I saw a manual for ALS Prolog on the Mac it called the operations 'catch' and 'throw'. Surprise! (The "Personal" version on the PC lacks these operations.) The names are marginally better than `block' and `exit_block', but they really are not at all good. Let me start by pointing out that in Common Lisp and MIT Scheme and other modern Lisp-based systems a very sharp distinction is drawn between catch/throw and exception handling. catch/throw or escape functions (Pop2 "jumpouts") are for non-local transfers of successful control. Exception handling is for handling exceptions. An exception handler may indicate *recovery* by executing a throw (calling an escape function), but error *signalling* is most definitely *not* based on catch/throw. Indeed, my use of structured terms to represent error situtations in the Quintus design was directly inspired by the proposal which eventually became the basis of the present Common Lisp "condition" system. The parallel goes something like this: QP CLtL2 signal_exception error [p886] if_exception handler-bind [p898] <error term> <condition> [p901] There's nothing quite like CL's "restarts". Perhaps there should be. The way an interactive user can select a restart in, say, Oaklisp, is rather neat. I've tried to keep my Lisp skills reasonably current. I believe that a good AI programmer will not lock himself into one programming language, even if it is as good as Prolog, so that if he comes across an excellent program written in the "other" language he'll still be able to learn from it. I claim that my experience with Scheme and Lisp has conditioned me to expect that 'throw' is like selecting an alternative SUCCESS continuation, whereas my knowledge of exception handling systems (such as "recovery blocks" and "restarts") is that arriving in an exception handler should be like selecting an alternative FAILURE continuation. To put one consequence of this plainly, I expect that var(X), catch(*, (X=1, throw(*))) => X == 1 but that var(X), if_exception(*, (X=1, signal_exception(*)), true) => var(X) If something called catch/throw *does* undo my variable bindings, I am going to be _very_ annoyed, and I will write nasty letters to the vendor in question for providing me with a useless implementation of non-local exit. If something advertised as an exception handling mechanism *doesn't* restore my variable bindings to the state they were in before the protective was donned, I am going to be _very_ _very_ annoyed indeed, and I will demand my money back. In 1984 I proposed as a guiding principle for any Prolog standard that it should contain nothing that would _forbid_ a coroutining implementation. Frank McCabe did announce in 1985 that the BSI committee had a guiding principle: to produce a minimal standard. But the "don't kill MU Prolog" principle was not adopted. None-the- less, I still think it's a good principle. NU Prolog and other coroutining Prolog systems pose an extremely interesting question. Suppose I do signal_exception(foo(X)) at a time when X is _constrained_ (by one or more delayed goals) but not _instantiated_? *EXCEPTION* handling means that it makes no sense to continue the current conjunct, so we mustn't wake up the delayed goals. What to do? For catch/throw, because we're selecting a new continuation point in the *same* conjunct, it does make sense to continue, and we can wake up the delayed goals when we need to, but then we can't use the mechanism for recovery, and we cannot use the mechanism to abandon a computation that is known to be useless, because any amount of it could be persisting as suspensions. What to do? I'm really not sure what the "right" answer is. If someone wants to provide catch and throw in a Prolog system, the only problem is that it can't be used as an exception handling/recovery mechanism. For exception handling, The only suggestion I have is that in QP, if storage permits, signal_exception(X) and ( assert('Snark'(X), Ref), instance(Ref, 'Snark'(Y)), erase(Ref), signal_exception(Y) ) behave the same, so that signal_exception/1 in a coroutining system should treat constrained but uninstantiated variables the same way that assert/1 does (or, by a similar argument, the way write/1 does). I hope someone else has a better idea. -- Q: What should I know about quicksort? A: That it is *slow*. Q: When should I use it? A: When you have only 256 words of main storage.
bimbart@hera.cs.kuleuven.ac.be (Bart Demoen) (06/14/91)
In <6245@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes > If something called catch/throw *does* undo my variable bindings, I am > going to be _very_ annoyed, and I will write nasty letters to the > vendor in question for providing me with a useless implementation of > non-local exit. catch/throw as currently defined by WG17, undo the variable bindings; still, that doesn't make them useless for an alternative SUCCESS continuation, because through the ball you 'throw' and its unification with the catcher, you can pass any information from deep down, higher up; e.g. var(X), catch((X=1, throw(X)),X,true) => X == 1 it doesn't look very nice, but at least you have the option Bart Demoen
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (06/15/91)
In article <3855@n-kulcs.cs.kuleuven.ac.be>, bimbart@hera.cs.kuleuven.ac.be (Bart Demoen) writes: > perhaps some people are interested in my KUL-CW report 97: > "A 20' Implementation of Catch and Throw in WAM" > it describes the implementation of block/exit_block (or catch/throw if you > prefer) as defined by ISO Perhaps it might be a good idea to send a list of logic-programming-related KUL-CW reports to comp.lang.prolog, together with instructions for getting them. I know that _I_ would be interested in seeing such a list. -- Q: What should I know about quicksort? A: That it is *slow*. Q: When should I use it? A: When you have only 256 words of main storage.
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (06/18/91)
In <6245@goanna.cs.rmit.oz.au> I wrote > If something called catch/throw *does* undo my variable bindings, I am > going to be _very_ annoyed, and I will write nasty letters to the > vendor in question for providing me with a useless implementation of > non-local exit. In article <3946@n-kulcs.cs.kuleuven.ac.be>, bimbart@hera.cs.kuleuven.ac.be (Bart Demoen) writes: > catch/throw as currently defined by WG17, undo the variable bindings; still, > that doesn't make them useless for an alternative SUCCESS continuation, > because through the ball you 'throw' and its unification with the catcher, > you can pass any information from deep down, higher up; e.g. > > var(X), catch((X=1, throw(X)),X,true) > => X == 1 > > it doesn't look very nice, but at least you have the option. No, I'm afraid that doesn't do the job. It can only restore the bindings of variables that (occur in the bindings of variables that) are visible at the point of the throw. If I do var(X), catch(Ball, (X = 1, p(Ball)), true) there is no definition I can give to p/1 which will result in the value of X being preserved. My main points remain: (1) The Lisp community, from which the names `catch' and `throw' were ``borrowed'', distinguishes between non-local control transfer (in Scheme, this is analogous to backtracking) and exception handling, and catch/throw are NOT the exception handling tools. The kind of unnecessary confusion this introduces (I'm reading a Mach manual set at the moment, and `catch' does _not_ refer to exception handling there either) could be compared, say, to forcing people to say ``interrupt'' instead of ``system call''. If we use operation names borrowed from another WIDELY KNOWN language or family of languages, we should not be so discourteous as to assign meanings to them so greatly at variance with what they meant in their ``home'' language. (A linguistic parallel: I believe `divan' originally meant a bound book of poems.) (2) The interaction of exception handling with coroutining needs to be explicitly addressed. It is _not_ a trivial generalisation of the strictly ordered case. I would again suggest that the dynamic-wind construct found in many Schemes would repay study. -- Q: What should I know about quicksort? A: That it is *slow*. Q: When should I use it? A: When you have only 256 words of main storage.
ward@vlsi.waterloo.edu (Paul Ward) (06/18/91)
Could someone please explain, briefly and with examples, exactly what catch and throw are and when and where they might be used, and what relationship they have to logic. Paul Ward University of Waterloo -- They will say, "As surely as the LORD lives, who brought the Israelites up out of the land of the north and out of all the countries where he had banished them." For I will restore them to the land I gave to their forefathers. Jeremiah 16:15
bimbart@hera.cs.kuleuven.ac.be (Bart Demoen) (06/19/91)
In <6378@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) wrote: > No, I'm afraid that doesn't do the job. It can only restore the > bindings of variables that (occur in the bindings of variables > that) are visible at the point of the throw. If I do > > var(X), catch(Ball, (X = 1, p(Ball)), true) > > there is no definition I can give to p/1 which will result in the > value of X being preserved. that's correct and I didn't imply that you wouldn't have to rewrite - in particular: add arguments to - some of the predicates in your program; in the example above, X should be visible at the point of the throw, so you have to make it a parameter of p - that's why I said that ot doesn't look nice I appreciate Richard's comments about the distiction between non-local control transfer and exception handling, but it seems to me that Prolog can do both with just one mechanism - or one pair of builtin predicates; and for me, there remains the question: should WG17 try to standardize non-local control transfer and exception handling ? Bart Demoen
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (06/19/91)
In article <1991Jun18.125519.7422@vlsi.waterloo.edu>, ward@vlsi.waterloo.edu (Paul Ward) writes: > Could someone please explain, briefly and with examples, exactly what > catch and throw are and when and where they might be used, and what > relationship they have to logic. Which catch and throw do you mean? Do you mean the ``non-local return to a label with dynamic scope'' things in Lisp-like languages, or the ``Ada-like exception handling things with misleading names'' proposed for ISO Prolog? The basic point is that in real-world programming you come up with situations where it is not possible to succeed with any binding, but it would be wrong to fail. Consider, for example, get0(C) issued after the last character of the file has been consumed. You can't suceed, because there isn't any character to bind C to. But you can't fail, either, because failure would mean "I _did_ read a character, but it didn't unify with C". This is an instance of what I call an ``existence error''; the program has asked for (some attribute of) a well-identified object which doesn't exist. (Trying to open a non-existent file for input is another.) The scheme that I proposed to the BSI at the end of 1984 was if_error(Goal, ErrorTerm, Handler) signal_error(ErrorTerm) It is now clear that the argument order for if_error was at the very least an error of taste. The ErrorTerm should be in the _same_ argument position in both commands (and in other commands related to exception handling). Quintus decided that 'exception' was a better name than 'error'. So we have if_exception(ErrorTerm, Goal, Handler) acts exactly like Goal, unless a call to signal_exception occurs while Goal is running, in which case Goal is abandoned, variables are reset to the state they had before if_exception was started (this includes variables in ErrorTerm). If the error term that was signalled unifies with ErrorTerm, the Handler is executed in place of the Goal. (The Handler is _not_ regarded as ``inside'' the if_exception form; any errors in it will _not_ result in the Handler being restarted.) If the error term that was signalled does not unify with ErrorTerm, the error is in effect resignalled. signal_exception(ErrorTerm) makes of copy of ErrorTerm, then keeps on failing until it finds an _ancestor_ if_exception(E, Goal, Handler) where E unifies with the copy of ErrorTerm. I describe this as "failing into the success continuation". Many built in operations may signal an exception. For example, floating- point overflow should signal a representation fault. There is a mathematically defined answer, but the system can't represent it, so can't succeed, but it would be wrong to fail because the answer does exist. Concerning the relation to logic: every solution of if_exception(E,G,H) is either a solution of G or a solution of (E=T,H) for some term T. every solution of var(X), if_exception(X,G,H), var(X) is a solution of G. every solution of var(X), if_exception(X,G,H), nonvar(X) is a solution of (X=T,G) for some term T, where T does not share variables with any other term. if_exception(E, G, H) is identical in effect to if_exception(X, G, (X = E -> H ; signal_exception(X)) As a tiny example of exception handling: open_input_file(Name0, Name, Stream) :- if_exception(existence_error(_,_,_,_), ( open(Name0, read, Stream), Name = Name0 ), ( format('~&~w does not exist. Try another name.~%', [Name0]), read(Name1), open_input_file(Name1, Name, Stream) )). There are many other things that can go wrong with a call to open/3, but an existence error means that you had a file name that made sense but failed to name an existing file. Oh yes, one point. A pons asinorum of exception handling is to mistake them for a way of handling interrupts. Now an interrupt handler might well decide to signal an exception, but you wouldn't, for example, want to handle SIGCONT that way... -- Q: What should I know about quicksort? A: That it is *slow*. Q: When should I use it? A: When you have only 256 words of main storage.