Built-ins are my primary concern but perhaps I’m misunderstanding. In pl-prims.c
there are 45 calls to PL_error
, not including another 5 calls to PL_type_error
, 3 to PL_domain error
, and 5 more to PL_representation
error. Do these not generate exceptions rather than failures? I don’t know how many of these would reasonably mean logical failure, but I suspect there’s quite a few.
Libraries and user code are an issue, but one I think, as a programmer, have some control over. On the other hand I’m stuck with the built-ins, they can’t be redefined. Furthermore, I don’t have the same performance concerns calling a library predicate vs. calling a builtin.
Agreed, but it would be nice to have something to confine. If the default is the status quo I don’t see the risk. If step one was (optionally) no confinement, what exactly would break? Since most programs don’t normally(?) depend on these kinds of low level exceptions from builtins for proper execution, that leaves those with catches of the types of errors I’m interested in. Of those, the ones that just fail are fine. The remaining are those whose proper operation depends on handler code. Obviously those programs wouldn’t change the default without careful consideration.
Bottom line: it’s not obvious to me that a no confinement would be that bad. I barely understand enough about the module system to use it, let alone whether it can be used to contain this kind of semantics.
And this is a possible route I’m willing to explore. But I think it still has a few issues. Just considering the built-ins, there are almost 60 potential exceptions for consideration. It would be extremely helpful if these were documented in the predicate semantics. And this should be extended to library predicates as well, especially if the exceptions are thrown transitively from built-ins. (So document at least; Java, and others, think this important enough to be part of the method/function syntax.)
The second issue is that in majority of existing cases, the guards are already in place due to the usual necessity of avoiding exceptions in running code. So, for working code at least, the checks would actually be done 3 times: in the original code, in the expanded code, and in the builtin to detect the conditions to throw the exception.
Thirdly, and perhaps my failing, I don’t understand the containment semantics of goal_expansion.
How so? There seem to be a limited number of PL_error
-like functions. Check a flag, if true continue with existing code, else fail. (Probably a gross over-simplification, I know.)
I don’t relate to this description at all. If I inserted a guard to avoid calling a builtin that might generate an exception, that’s just (premature) failure. I just want to avoid the necessity of the guard. That’s a pretty typical use case isn’t it?
Only with a fair amount of work and the result still has a containment issue (does it not?) and incurs some level of overhead (probably acceptable in most cases, but irksome).
Any examples of those that cause problems? I can think of flags that do this, but I’m not aware of any specific problems. And this particular use seems fairly limited to me.
I freely admit I don’t understand all the ramifications of what I’m proposing so here’s another idea that could be used to implement my objective, albeit at some cost. Permit user:exception
to be a handler of last resort for any exception. That would permit the addition of a global handler to optionally turn any exception into a failure under my control.
Aside: If that passes muster, I would also like the option of succeeding (Action=succeed
) like a normal catch handler so at some point I could turn an instantiation error into a constraint. And yes, that’s not Prolog, but it is logic programming.