A new bug in my old code?

I’m using: SWI-Prolog version 10.0.2.

I want the code to: retract all dynamic predicates that are not built-in.

But what I’m getting after cleanup each time I consult a file is: ERROR: Domain error: `file_type’ expected, found `prolog’.

My code looks like this:

cleanup :- forall(dynamic_not_built_in(X),retractall(X)).

dynamic_not_built_in(X) :- predicate_property(X,dynamic),
                           \+predicate_property(X,built_in).

Call the above program mwe.pl, consult it and run cleanup. Then consult it again and get the ERROR above. Code like this has never given any problem in versions < 9. From 9 on I get this behaviour. I suspect cleanup now retracts too much, perhaps an essential dynamic predicate which is not a built-in. Any help is highly appreciated! Marc

I suspect cleanup now retracts too much,

You can easily check this hypotesis. In cleanup change retractall to writeln, and check whether the result looks reasonable.

There is no overlap, so that will not filter as intended:

Welcome to SWI-Prolog (threaded, 64 bits, version 10.0.2)

101 ?- predicate_property(X, dynamic), predicate_property(X, built_in).
false.

Good suggestion, see the list below. I would have expected all of these are built-in.

I guess the last one is the culprit.

61 ?- cleanup.
prolog_load_file(_7456,_7458)
portray(_7456)
expand_answer(_7456,_7458)
resource(_7456,_7458)
exception(_7456,_7458,_7460)
term_expansion(_7456,_7458)
goal_expansion(_7456,_7458,_7460,_7462)
term_expansion(_7456,_7458,_7460,_7462)
resource(_7456,_7458,_7460)
file_search_path(_7456,_7458)
goal_expansion(_7456,_7458)
expand_query(_7456,_7458,_7460,_7462)
message_hook(_7456,_7458,_7460)
thread_message_hook(_7456,_7458,_7460)
library_directory(_7456)
prolog_file_type(_7456,_7458)
true.

But something must have changed. I seem to remember (but the program is 20y old) that it was necessary to exclude built-in predicates in those days:


 ```Welcome to SWI-Prolog (threaded, 64 bits, version 8.0.3)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.For online help and background, visit http://www.swi-prolog.org

For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- cleanup.
prolog_exception_hook(_7210,_7212,_7214,_7216)
thread_message_hook(_7210,_7212,_7214)
true.

?- [mwe].
true.

All these were built-in in version 8:


```
?- predicate_property(X,dynamic),predicate_property(X,built_in).

X = prolog_event_hook(_7564) ;
X = file_search_path(_7564, _7566) ;
X = term_expansion(_7564, _7566) ;
X = resource(_7564, _7566, _7568) ;
X = prolog_file_type(_7564, _7566) ;
X = goal_expansion(_7564, _7566) ;
X = goal_expansion(_7564, _7566, _7568, _7570) ;
X = portray(_7564) ;
X = term_expansion(_7564, _7566, _7568, _7570) ;
X = expand_query(_7564, _7566, _7568, _7570) ;
X = expand_answer(_7564, _7566) ;
X = message_hook(_7564, _7566, _7568) ;
X = library_directory(_7564) ;
X = prolog_load_file(_7564, _7566) ;
X = resource(_7564, _7566) ;X = exception(_7564, _7566, _7568) ;
false.

In conclusion: from version 8 to version 10 the number of system-like predicates that are dynamic (but not built-in) increased substantially.

My problem is now: how to discriminate in a robust way between user-defined dynamic predicates and all other dynamic predicates?

maybe you can discriminate based on file of origin:

predicate_property(P,dynamic),
predicate_property(P,file(F)),
\+ sub_atom(F,_,_,_,'/swipl/library/'),
\+ sub_atom(F,_,_,_,'/swipl/boot/').

if it has these in the name probably is not a user defined one. Not 100% safe, but may be a stopgap.

Appreciated the help, and tried it. However, on my platform (LM22.3) the substring /swipl/ should be /swi-prolog/, so I’m afraid it’s very fragile. For the moment I’m just going to exclude `prolog_file_type` from the retract of dynamic predicates. Hopefully a little more robust, but again a stop-gap. The better solution would be to change the input format.

For historic reasons, many hooks live in the user module and are dynamic. Just wiping these seems a bad idea (as you noted). As you will also wipe term/goal expansion, you are likely to kill far too much. You might get closer to what you want by not wiping predicates marked as multifile or not wiping predicates that have a source location, i.e., (part of) their clauses result from loading a file rather than assert/1.

The real question is of course what you want to achieve. Quite likely there is a more elegant solution :slight_smile:

A good, robust solution would be to include the signature of the logical theory in the input data. If only I had understood that 20 years ago … Another solution (which I have chosen for the moment) is a small reduction of the functionality of the code.

I want to thank everybody for their responses. One last question: what was the reason that more than a dozen system-like predicates have lost the property “built-in” in between version 8 and version 10? (I hopped over v9 after a long break). I feel that “historical reasons” cannot explain this.

I don’t know … Built-in predicate detection typically serve a role in meta-interpreters (do not meta-interpret this). I have no clue when this was changed and whether or not this was on purpose. Ideally, the user module should be empty and all hooks should live in prolog or the module using the hook. History blocks doing so. Net result is that the user module contains stuff to keep the system going :frowning: