Use of Advice Predicates

Whether a predicate has advice associated with it is independent of whether advice on that predicate is being "checked". Advice may be thought of as a generalized spypoint, where the user specifies the action to be performed at each debugger port. Distinct built-in predicates are provided for modifying advice and influencing whether advice is being checked. Advice is associated with a predicate using add_advice/3 and deleted using remove_advice/3. You can determine what advice is outstanding by using current_advice/3. Advice on a predicate is retained if that predicate is abolished, as is likely to happen during program development. It also survives that predicate being saved to a QOF file, and is reinstated when that QOF file is loaded.

Advice checking can be enabled one predicate at a time using check_advice/1 and disabled one predicate at a time with nocheck_advice/1. These are analogous to spy/1 and nospy/1, and are similarly defined as prefix operators of precedence 900. As a convenience, check_advice/0 is provided to enable checking for all predicates that currently have advice associated with them. nocheck_advice/0 can also be used to turn off all advice checking easily. It is possible to use check_advice/1 to turn advice checking on for a predicate that does not currently have any advice, although doing so will have no effect until advice is added to the predicate. As check_advice/0 only affects predicates that currently have advice, it cannot be used for this purpose. Like the advice itself, advice checking survives a checked predicate being abolished and redefined.

Note that whether a particular call to an advised predicate is checked is determined once the call is made. If advice checking is enabled after a predicate has been entered but before it reaches a subsequent advised port of the predicate, advice checking will not be done.

Advice on any given port is checked before any debugger interaction for that port. Taking advice checking as well as debugger interaction into account in the procedure box model of Prolog execution (see dbg-bas-pbx), we have

                              +-----------+
     Call -> Advice -> Spy -> |           | Advice -> Spy -> Exit ->
                              | procedure |
                              |    box    |
     Fail <- Spy <- Advice <- |           | <- Spy <- Advice <- Redo
                              +-----------+
     

This is necessary so that advice actions can control the debugger.

It is possible (and often advisable) to write an application where advice is always present on appropriate predicates, but that advice is not checked by default. When required, advice checking can be turned on and the application monitored or debugged using the advice. This makes it unnecessary to add advice each time you want it only having to remove it when you don't want it any longer. Instead, the application's advice can persist, with modifications as desired, through development. It can also be retained once development is completed, providing diagnostics that can be turned on in case of problems.

Predicate properties (see predicate_property/2) have been added to allow you to determine what predicates have outstanding advice, or have advice checking enabled. When a predicate currently has advice associated with it, it has the property has_advice. If advice is being checked for that predicate, it has the property checking_advice. These properties are independent of each other, and are independent of whether the advised predicate is currently defined or not. For example:

     | ?- check_advice(foo/0).
     * You have no clauses for user:foo/0
     % Advice checking enabled on user:foo/0
     
     yes
     | ?- predicate_property(foo, P).
     
     P = checking_advice ;
     
     no
     | ?- add_advice(foo, call, (write(hi),nl)).
     % Advice placed on user:foo/0
     
     yes
     | ?- predicate_property(foo, P).
     
     P = has_advice ;
     
     P = checking_advice ;
     
     no