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