Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!munnari.oz.au!goanna!ok From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) Newsgroups: comp.lang.prolog Subject: Re: block and exit_block Message-ID: <6388@goanna.cs.rmit.oz.au> Date: 19 Jun 91 10:21:39 GMT References: <3946@n-kulcs.cs.kuleuven.ac.be> <6378@goanna.cs.rmit.oz.au> <1991Jun18.125519.7422@vlsi.waterloo.edu> Organization: Comp Sci, RMIT, Melbourne, Australia Lines: 100 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.