Closed dram closed 7 years ago
The goal you provide with the -t
does not satisfy the requirements for a top-level goal. See the SWI-Prolog documentation at http://www.swi-prolog.org/pldoc/man?section=runoptions Notably:
If the top level raises an exception, this is printed as an uncaught error and the top level is restarted.
You can prevent the infinite loop when the top level goal is restarted using e.g.
$ swilgt.sh -t "catch(time::now(_, _, _), _, halt(1))"
SWI-Prolog will prompt for action for this case, instead of an infinite loop, i.e.:
% swipl -q -t foo
ERROR: '$runtoplevel'/0: Undefined procedure: foo/0
Exception: (3) foo ?
Anyway, according to the document, I think I can use -g goal -t halt
instead, which is what I needed.
Thanks!
SWI-Prolog, by default, sets its debug_on_error
flag to error
and is apparently honoring this flag value for undefined procedures. But ::/2
is defined and thus not trapped.
Thanks for your detailed explanation.
SWI-Prolog's behaviour seems a bit strange. I can reproduce this problem without Logtalk, e.g. swipl -t 'halt(foo)'
. I will file an issue on SWI-Prolog's repo.
BTW, a small correction, value of debug_on_error
is of type bool
, according to the document.
There is no such thing as a different behaviour on different error exceptions. The system does have dedicated interactive behaviour for exceptions of the form error(Formal, Context)
and exceptions that are not caught. AFAIK, the latter is what cause Logtalk programs to behave different from native programs with an error because Logtalk wraps toplevel goals in catch/3
and thus all errors are always caught as far as Prolog is concerned. Really uncaught exceptions bubble up to the C code that (re)starts the toplevel goal.
@JanWielemaker Logtalk does wrap top-level ::/2
calls with a catch/3
but the error handler eventually throws the exception after possibly rewriting it. I.e. the errors are passed back to Prolog. Being uncaught exceptions, as you explain in your last sentence, the top-level goal is restarted thus resulting in the observed loop. Also note that:
?- catch(foo::bar, Error, true).
Error = error(existence_error(object, foo), logtalk(foo::bar, user)).
This suggests that we don't get the interactive behavior in this case for some other reason. Could it be due to the second argument of the error/2
exception term not being what SWI-Prolog expects?
The interactive behaviour of trapping the debugger at the location of the error happens because
error(_,_)
exceptiondebug_on_error
flag is true
Your intermediate catch-rewrite-and-rethrow breaks the notion of being uncaught. Instead of rewriting the way you do, you might get away rewriting the exception as it happens using user:prolog_exception_hook/4
. See library(prolog_stack) for an example.
Thanks for explaining. The code that rewrites the exceptions is portable and thus unlikely to change (specially in this case where the advised use of the command-line options solves it: https://github.com/SWI-Prolog/swipl-devel/issues/203). I do have (commented out) code (in the adapters/swihooks.pl
file) that uses user:prolog_exception_hook/4
for writing stack traces. But uncommenting this code doesn't seem to avoid the infinite loop in this case.
The infinite loop is by design. It is not a bug, but simply how -t
is defined and I can't see anything wrong with that. Use -g
if you don't want to restart on errors or wrap the goal in a catch/3. The exception hook serves a different purpose: get the debugger active in the error context and/or printing a nice stack trace. Both speedup development as they often avoid the need to restart the program under the debugger and carefully navigate to the error.
When using SWI
-t
option to execute a goal, non-existent object error will drop SWI into an infinite loop, e.g.:I'm using Logtalk 3.9.3-rc3 and SWI 7.2.3.