Page 1 of 1

Exception Raiser not called

Posted: 15 Sep 2014 14:44
by Martin Meyer
Hi Thomas and all,

my user defined run-time exception raiser does not get called by exception::raise_error and similar predicates (in VIP 7.5). The below code shows the problem. Is the behavior intended, resp. is there a way to set an exception raiser, which will be called on all kinds of exceptions?

Regards
Martin

Code: Select all

class facts     originalOnException : programControl::exceptionRaiser := erroneous.   class predicates     onException : programControl::exceptionRaiser. clauses     onException(TraceId) :-         stdIo::write("my user defined run-time exception raiser was called\n"),         originalOnException(TraceId).   clauses     run() :-         originalOnException := programControl::setRuntimeExceptionRaiser(onException),         exception::raise_error().

Posted: 16 Sep 2014 8:50
by Thomas Linder Puls
You are misunderstanding the purpose of the runtime exception raiser. This predicate is invoked by the runtime system when a runtime exception (such as division by zero) occurs.

The functionality you look for does not exist. What will you use it for?

Posted: 16 Sep 2014 17:41
by Martin Meyer
The use is in the thing I told before in http://discuss.visual-prolog.com/viewtopic.php?t=11882. It is, I am trying to set up an object type, which shall deliver the functionality of the former reference variables. I am following the construction described in your tutorial http://wiki.visual-prolog.com/index.php ... _a_Project.

A drawback of the tutorial's construction is however, that predicates like unify/2 have to be declared as nondeterm rather than determ. Since backtracking is used to undo the binding of variables, cuts cannot be used anymore in all situations, where it also would cut off a backtrack point to unify/2.

Thus, when unify/2 is nondeterm, essential code constructions are unusable. For example if unify(A, B) then ... else ... end if is unusable, because it cuts off a backtrack point to unify/2. To code a reference variable version of the function list::getMember_nd/1-> is not suitable, because enumeration of the list members by backtracking cannot be stopped anymore by a cut.

In short, nondeterminism is a deal-breaker for unify/2. Some way is needed to make it determ. I proposed a way in http://discuss.visual-prolog.com/viewtopic.php?t=11882. My trick worked out in a simple example, but unfortunately it relies on some unchecked conversion and turned out to lead to crashes in situations, which are a little more complicated than my example.

I came across another way, to construct a determ unify/2 predicate: I let unify/2 push undo-actions on a stack. These undo-actions can be executed later to undo variable bindings. The stack is implemented as a facts database:

Code: Select all

class facts     undoRec : (         programControl::stackMark ApplicableAt,         predicate UndoAction)         nondeterm.
Each call to unify/2 (and to predicates, in which unify/2 is used) must be done by a wrapper declared in the fashion:

Code: Select all

predicates     do_dt : (predicate_dt ActionDt)         determ. clauses     do_dt(ActionDt) :-         StackMark = programControl::getBackTrack(),         (                 ActionDt(),                 relegateUndoActions(StackMark)             orelse                 undoTo(StackMark),                 fail         ).
It is, instead of calling unify/2 the usual way as in

Code: Select all

unify(A, B)
I wrap the call in do_dt/1, so it becomes

Code: Select all

do_dt({:- unify(A, B)})
Nevertheless the orelse generates a backtrack point in do_dt/1 before ActionDt is called, the predicate do_dt/0 is determ as well as ActionDt resp. unify/2 are.

In case ActionDt() succeeds, relegateUndoActions/1 will update the stack marks of the undo records, which ActionDt has asserted, to further delay execution of the undo actions, and
in case ActionDt() fails, undoTo/1 will execute the undo actions.

To wrap calls to predicates, which use reference variable objects and have modes procedure, multi, nondeterm or failure, I code similar wrapper predicates do_pr, do_mt, do_nd and do_fl.

In case of an exception, I want to give the reference variable objects the same behavior as ordinary variables have. In detail, if any kind of exception occurs in Body in

Code: Select all

try     Body catch Var do     Handler end try
all bindings made in Body should be undone through undoTo/1 before Handler is executed. For that use I wanted to utilize the user defined runtime exception raiser.

Regards
Martin

Posted: 22 Sep 2014 12:56
by Martin Meyer
After a lot of experimenting I came to conclusion, that my above proposed way to construct a determ unify/2 predicate, does not work out too. Now I am using a nondeterm unify/2 predicate.

To be able to stop enumeration of solutions of reference variable counterparts of nondeterm predicates like list::getMember_nd/1->, I give them an additional output parameter CutM of type varM_boolean. For example my declaration of a class predicate member/3 reads:

Code: Select all

    member : (         refTerm{Atom} Elem,         refTerm{Atom} Lst,         varM_boolean CutM [out])         nondeterm.
If a call to member/3 succeeds, the variable CutM is returned, which is initialized to false. Setting CutM:value := true will cause further backtracking into member/3 to fail and thus stop the enumeration of solutions (without cutting off the backtrack points to unify/2, which are needed to undo bindings).

The user of my member/3 predicate must not stop the enumeration of solutions by an ordinary cut - neither an explicite cut nor an implicite as the one in the condition of if-then-else. Furthermore reference variable bindings made in the body of try-catch are not undone, if the body terminates with an exception. I suppose, these drawbacks are inevitable. Or do you know a way, how to circumvent them?

Regards
Martin