More tolerant erase/1 and clause(...) for Sicstus compatibility?

Sicstus Prolog (4.7.x) won’t mind if one calls:

  • clause(<clause ref>,...), instead of clause(<callable>,...)
  • erase(<clause ref>) for an already erased clause

In both cases, SWI 9.1 correctly throws an exception, but Sicstus just fails silently… and I’m migrating an existing Sicstus app which depends on that devious behaviour :frowning:

Any suggestions…? goal_expansion/2 is off the table, because the app does rather convoluted meta calls where clause(…) goals are expected to remain untouched.

For clause/2, that is understandable as a clause reference in SICStus is a compound term, but there are no clauses for it. In SWI-Prolog it is a blob, which is not a valid clause head. erase/1 in SICStus wants a ‘$ref’(Int,Int) term, but then just succeeds. I wonder whether they can ensure this is safe.

For now (and you seem to agree), I think SWI-Prolog is (more) right.

How to work around? Goal expansion is the cleanest, but if you like some hacking, you can also redefine clause/2 in the user module: Something like this:

erase(Ref) :-
    blob(Ref, record),
    !,
    catch(system:erase(Ref), _, true).

:- redefine_system_predicate(clause(_,_)).
:- meta_predicate
    clause(:, -).

clause(_M:Head, _Body) :-
    blob(Head, clause),
    !,
    fail.
clause(M:Head, Body) :-
    system:clause(M:Head, Body).

Note that the redefine_system_predicate/1 call is not needed for erase/1 as only ISO standard predicates are protected against redefinition. You may need to change the blob/2 conditions a bit, depending on what is really passed. I.e., does it also pass record references to clause/2.

Best, I guess, is to fix the code :slight_smile:

Thanks Jan, perfect!