Path: utzoo!attcan!uunet!munnari.oz.au!goanna!ok From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) Newsgroups: comp.lang.prolog Subject: Re: error handling (was about arg/3) Message-ID: <4090@goanna.cs.rmit.oz.au> Date: 26 Oct 90 03:20:01 GMT References: <1328@n_kulcscs.kuleuven.ac.be> <1804@ecrc.de> Organization: Comp Sci, RMIT, Melbourne, Australia Lines: 94 Just to get something minor out of the way first: Please could people write letters of protest or something about the appallingly unprofessional names 'block' and exit_block/1 for the "catch" and "throw" operations? There is *no* excuse for using bad or confusing or misleading names for operations in the standard, especially when the names "if_error" and "signal_error" proposed in 1984 were far less confusing. Even "catch" and "throw" would be MUCH better than "block" (I know what a block is in Algol, C, &c, and I know what blocking an exception means -- it means making sure that the exception ISN'T SIGNALLED until after the block is cleared -- and I know about variants of "block" in lots of languages, and in none of them does it mean HANDLE an exception). "handle_exception" and "raise_exception" would be good names. "catch" and "throw" are what ALS and NU Prolog call them. That's "Prior Art". I rather dislike "catch" and "throw", but *anything* reasonable (even IBM Prolog's err_catch/ and error/) would be better than the incredibly incompetently chosen block and block_exit. Concerning Meir's worries about whether local error-handling is sufficiently powerful: Remember that there is nothing in the standard that says there can't be additional error handling machinery. Suppose someone wants a "global" error handler (I have always been opposed to this). For errors signalled by his own code, nothing could be easier: my_signal_error(ErrorTerm) :- current_predicate(global_handler(_)), !, global_handler(ErrorTerm). my_signal_error(ErrorTerm) :- signal_exception(ErrorTerm). For errors signalled by other predicates, it's again fairly easy: my_functor(Term, Symbol, Arity) :- if_exception(ErrorTerm, functor(Term, Symbol, Arity), my_signal_error(ErrorTerm)). IBM Prolog's "priority prefix" feature can be used to advantage here, or almost any kind of package. So a wrapper has to be added for each EP? So what? The code is repetitive, a query ?- tell('wrappers.pl'), system_predicate(Skel), write('my_'), write((Skel :- if_exception(E, Skel, my_signal_error(E)))), write(.), nl, fail ; told. is all the work you need to do to create the wrappers. Note that a standard can only define the effect of a program that is written entirely in Prolog, using only the EPs defined in the standard. If you call an operation which is not in the standard, anything can happen. So a vendor who had some clever idea about handling could perfectly well provide it, enabling it when you do set_prolog_flag(global_error_handler, my_handler) and disabling it when you do set_prolog_flag(global_error_handler, standard). What's the really important point about global error handlers? Simply that they are only useful for programs where *all* of the source code is under the direct control of a small group. You can't use global handlers in the construction of library packages. The portray/1 mechanism was mentioned. Precisely! portray/1 does _not_ work very well with library packages; the Quintus library defines add_portray/1 and del_portray/1 to work around it. Global error handlers are far worse. And for EPs like arg/3, there simply isn't any global handler that makes sense, precisely because arg/3 is at such a low level that it *means* different things (implements different abstract notions) at different places in a program and so needs to be handled differently. The local error handling scheme I proposed to the BSI in 1984 (essentially the present scheme except for having meaningful names) was a straight steal from Ada (also ML, also a language you won't have heard of called SMALL which had something called "fault procedures"). The point of such a scheme is to enable you to write reliable *components*. The goal is to let people write code which can be _sure_ of handling its own errors (not errors in code that it doesn't know about) without interference. Global handlers make it very hard to write reliable components that handle errors, as a global handler may not only "steal" an exception report, but it may not be able to do anything with it. -- Fear most of all to be in error. -- Kierkegaard, quoting Socrates.