# Using message\_hook/3

**URL:** <https://swi-prolog.discourse.group/t/using-message-hook-3/4429>\
**Category:** Wiki\
**Created:** [September 12, 2021, 10:13am UTC](https://swi-prolog.discourse.group/t/using-message-hook-3/4429 "2021-09-12T10:13:51Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Wiki](https://avatars.discourse-cdn.com/v4/letter/w/e8c25b/32.png) [@Wiki](https://swi-prolog.discourse.group/u/Wiki)\
**Post date:** [September 12, 2021, 10:13am UTC](https://swi-prolog.discourse.group/t/using-message-hook-3/4429/1 "2021-09-12T10:13:51Z")

</div>

> Note: This is a topic for using message\_hook/3 with SWI-Prolog.  
> If you have [Trust level](https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/): [Basic](https://swi-prolog.discourse.group/badges/1/basic) you can edit this Wiki topic by clicking on the edit icon in the lower right. ![Capture](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/1X/bfd4c3b77dc7f3f98ece3d5ae3202fcccb0fb8b3.png)

> Note: Do not reply to this topic; questions, concerns, comments, etc. are to be handled in  
> [Wiki Discussion: Using message\_hook/3](https://swi-prolog.discourse.group/t/wiki-discussion-using-message-hook-3/4430)

* * *

* * *

message\_hook/3 as the name implies is a [hook](https://en.wikipedia.org/wiki/Hooking).  
For an overview of SWI-Prolog hooks see: [An overview of hook predicates](https://www.swi-prolog.org/pldoc/man?section=hooks).  
message\_hook/3 is called using module [user](https://www.swi-prolog.org/pldoc/man?section=resmodules), i.e. `user:message_hook(A,B,C)` instead of `message_hook(A,B,C)`.

Often when using such predicates for the first time having real world example code to look at is helpful. Such examples from the SWI-Prolog source code are referenced in the following.

The hook can be a static predicate (example [1](https://github.com/SWI-Prolog/swipl-devel/blob/6ca792818b197f3ccfb2d9f88f57d3ea2eb0ad73/library/threadutil.pl#L437-L444)) or a dynamic predicate that is [asserted](https://www.swi-prolog.org/pldoc/man?section=dynpreds). (example [2](https://github.com/SWI-Prolog/swipl-devel/blob/21e0a70e91d7aa9c5dd83b00f0d49e22c1ed8b60/library/prolog_autoload.pl#L171-L172),[3](https://github.com/SWI-Prolog/swipl-devel/blob/d7eb4d249d95a425db8837868dcc189e3e5f166b/src/Tests/charset/utf8_test.pl#L142-L144)).

Some other hooks define dynamic/1 and multifile/1 in [init.pl](https://github.com/SWI-Prolog/swipl-devel/blob/master/boot/init.pl), message\_hook/3 does not.  
If message\_hook/3 is defined in more than one file then use multifile/1 to suppress the warning message.  
Use dynamic/1 if you want to allow dynamic modification later, e.g. retract/1 and assert/1.

* * *

A simple example of message\_hook/3

This will just take the values received from the messages and print them to the current output stream.

```prolog
user:message_hook(Term, Kind, Lines) :-
    format('Term: ~w, Kind: ~w, Lines: ~w~n',[Term,Kind,Lines]).

```

* * *

A demonstration of the simple example

Directory: `C:/Users/Groot` (You can change the directory as needed).  
File: `format_example.pl`

```prolog
user:message_hook(Term, Kind, Lines) :-
    format('Term: ~w, Kind: ~w, Lines: ~w~n',[Term,Kind,Lines]).

```

Example run

```prolog
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.28-20)
...

?- working_directory(_,'C:/Users/Groot').
true.

?- [format_example].
Term: load_file(done(0,file(format_example,c:/users/Groot/format_example.pl),compiled,user,0.0,1)), Kind: silent, Lines: [~|~t~*+ - [0],~w-[format_example], ~w-[compiled], ~2f sec, ~D clauses-[0.0,1]]
Term: query(yes([],true,[]-[])), Kind: query, Lines: [ansi(truth(true),true.,[]),~N-[]]

```

* * *

An example that uses print\_message/2.

This shows both the input values output using format/2 and then uses print\_message/2 to print a message. Notice that messages with `Kind` is `silent` print\_message/2 does not print a message.

Directory: `C:/Users/Groot` (You can change the directory as needed).  
File: `print_message_example.pl`

```prolog
user:message_hook(Term, Kind, Lines) :-
    format('Term: ~w~nKind: ~w~nLines: ~w~n~n',[Term,Kind,Lines]),
    print_message(Kind, Term),
    nl,nl.

:- append([1,2],[3,4],R).

```

> **Example run (Click triangle to expand)**
>
> ```prolog
> Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.28-20)
> ...
> 
> ?- working_directory(_,'C:/Users/Groot').
> true.
> 
> ?- [print_message_example].
> Term: singletons((:-append([1,2],[3,4],_20202)),[R])
> Kind: warning
> Lines: [Singleton variables: ~w-[[R]]]
> 
> Recursive warning message: singletons((:-append([1,2],[3,4],_20202)),['R'])
> 
> Term: autoload(user:append/3,c:/program files/swipl/library/lists)
> Kind: silent
> Lines: [autoloading ~p from ~w-[user:append/3,c:/program files/swipl/library/lists]]
> 
> Term: load_file(start(1,file(c:/program files/swipl/library/lists,c:/program files/swipl/library/lists.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[1],~w-[c:/program files/swipl/library/lists], ...]
> 
> Term: load_file(done(1,file(c:/program files/swipl/library/lists,c:/program files/swipl/library/lists.pl),compiled,lists,0.0,111))
> Kind: silent
> Lines: [~|~t~*+ - [1],~w-[c:/program files/swipl/library/lists], ~w-[compiled], into ~w-[lists], ~2f sec, ~D clauses-[0.0,111]]
> 
> Term: load_file(done(0,file(print_message_example,c:/users/groot/print_message_example.pl),compiled,user,0.0,2))
> Kind: silent
> Lines: [~|~t~*+ - [0],~w-[print_message_example], ~w-[compiled], ~2f sec, ~D clauses-[0.0,2]]
> 
> Term: query(yes([],true,[]-[]))
> Kind: query
> Lines: [ansi(truth(true),true.,[]),~N-[]]
> 
> Recursive query message: query(yes([],true,[]-[]))
> 
> ```

* * *

An example that uses message\_to\_string/2.

Directory: `C:/Users/Groot` (You can change the directory as needed).  
File: `message_to_string_example.pl`

```prolog
user:message_hook(Term, Kind, Lines) :-
    format('Term: ~w~nKind: ~w~nLines: ~w~n~n',[Term,Kind,Lines]),
    message_to_string(Term,String),
    format('~s~n',[String]),
    nl,nl.

:- append([1,2],[3,4],R).

```

> **Example run (Click triangle to expand)**
>
> ```prolog
> Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.28-20)
> ...
> 
> ?- working_directory(_,'C:/Users/Groot').
> true.
> 
> ?- [message_to_string_example].
> Term: singletons((:-append([1,2],[3,4],_20202)),[R])
> Kind: warning
> Lines: [Singleton variables: ~w-[[R]]]
> 
> Singleton variables: [R]
> 
> Term: autoload(user:append/3,c:/program files/swipl/library/lists)
> Kind: silent
> Lines: [autoloading ~p from ~w-[user:append/3,c:/program files/swipl/library/lists]]
> 
> autoloading user:append/3 from c:/program files/swipl/library/lists
> 
> Term: load_file(start(1,file(c:/program files/swipl/library/lists,c:/program files/swipl/library/lists.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[1],~w-[c:/program files/swipl/library/lists], ...]
> 
> Loading c:/program files/swipl/library/lists ...
> 
> Term: load_file(done(1,file(c:/program files/swipl/library/lists,c:/program files/swipl/library/lists.pl),compiled,lists,0.015625,111))
> Kind: silent
> Lines: [~|~t~*+ - [1],~w-[c:/program files/swipl/library/lists], ~w-[compiled], into ~w-[lists], ~2f sec, ~D clauses-[0.015625,111]]
> 
> c:/program files/swipl/library/lists compiled into lists 0.02 sec, 111 clauses
> 
> Term: load_file(done(0,file(message_to_string_example,c:/users/groot/message_to_string_example.pl),compiled,user,0.015625,2))
> Kind: silent
> Lines: [~|~t~*+ - [0],~w-[message_to_string_example], ~w-[compiled], ~2f sec, ~D clauses-[0.015625,2]]
> 
> message_to_string_example compiled 0.02 sec, 2 clauses
> 
> Term: query(yes([],true,[]-[]))
> Kind: query
> Lines: [ansi(truth(true),true.,[]),~N-[]]
> 
> true.
> 
> ```

* * *

An example that uses print\_message\_lines/3.

Directory: `C:/Users/Groot` (You can change the directory as needed).  
File: `print_message_lines_example.pl`

```prolog
user:message_hook(Term, Kind, Lines) :-
    format('Term: ~w~nKind: ~w~nLines: ~w~n~n',[Term,Kind,Lines]),
    print_message_lines(current_output,kind(Kind),Lines),
    nl.

:- append([1,2],[3,4],R).

```

> **Example run (Click triangle to expand)**
>
> ```prolog
> Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.28-20)
> ...
> 
> ?- working_directory(_,'C:/Users/Groot').
> true.
> 
> ?- [print_message_lines_example].
> Term: singletons((:-append([1,2],[3,4],_20202)),[R])
> Kind: warning
> Lines: [Singleton variables: ~w-[[R]]]
> 
> Warning: Singleton variables: [R]
> 
> Term: autoload(user:append/3,c:/program files/swipl/library/lists)
> Kind: silent
> Lines: [autoloading ~p from ~w-[user:append/3,c:/program files/swipl/library/lists]]
> 
> autoloading user:append/3 from c:/program files/swipl/library/lists
> 
> Term: load_file(start(1,file(c:/program files/swipl/library/lists,c:/program files/swipl/library/lists.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[1],~w-[c:/program files/swipl/library/lists], ...]
> 
> Loading c:/program files/swipl/library/lists ...
> 
> Term: load_file(done(1,file(c:/program files/swipl/library/lists,c:/program files/swipl/library/lists.pl),compiled,lists,0.015625,111))
> Kind: silent
> Lines: [~|~t~*+ - [1],~w-[c:/program files/swipl/library/lists], ~w-[compiled], into ~w-[lists], ~2f sec, ~D clauses-[0.015625,111]]
> 
> c:/program files/swipl/library/lists compiled into lists 0.02 sec, 111 clauses
> 
> Term: load_file(done(0,file(print_message_lines_example,c:/users/groot/print_message_lines_example.pl),compiled,user,0.015625,2))
> Kind: silent
> Lines: [~|~t~*+ - [0],~w-[print_message_lines_example], ~w-[compiled], ~2f sec, ~D clauses-[0.015625,2]]
> 
> print_message_lines_example compiled 0.02 sec, 2 clauses
> 
> Term: query(yes([],true,[]-[]))
> Kind: query
> Lines: [ansi(truth(true),true.,[]),~N-[]]
> 
> true.
> 
> ```

* * *

An example that prints informational messages using unit test.

Directory: `C:/Users/Groot` (You can change the directory as needed).  
File: `print_message_lines_example.pl`

```prolog
user:message_hook(Term, Kind, Lines) :-
    format('Term: ~w~nKind: ~w~nLines: ~w~n~n',[Term,Kind,Lines]),
    print_message_lines(current_output,kind(Kind),Lines),
    nl.

:- begin_tests(message_hook).

:- use_module(library(lists)).

test(reverse) :-
        reverse([a,b], [b,a]).

:- end_tests(message_hook).

```

Note: In the example run below, the informational messages are not generated when the code is loaded, the informational messages are generated for run\_tests/0.

> **Example run (Click triangle to expand)**
>
> ```prolog
> Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.28-20)
> ...
> ?- [informational_message_example].
> Term: autoload(user:begin_tests/1,c:/program files/swipl/library/plunit)
> Kind: silent
> Lines: [autoloading ~p from ~w-[user:begin_tests/1,c:/program files/swipl/library/plunit]]
> 
> autoloading user:begin_tests/1 from c:/program files/swipl/library/plunit
> 
> Term: load_file(start(1,file(c:/program files/swipl/library/plunit,c:/program files/swipl/library/plunit.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[1],~w-[c:/program files/swipl/library/plunit], ...]
> 
> Loading c:/program files/swipl/library/plunit ...
> 
> Term: load_file(done(1,file(c:/program files/swipl/library/plunit,c:/program files/swipl/library/plunit.pl),compiled,plunit,0.015625000000000028,280))
> Kind: silent
> Lines: [~|~t~*+ - [1],~w-[c:/program files/swipl/library/plunit], ~w-[compiled], into ~w-[plunit], ~2f sec, ~D clauses-[0.015625000000000028,280]]
> 
> c:/program files/swipl/library/plunit compiled into plunit 0.02 sec, 280 clauses
> 
> Term: autoload(plunit:must_be/2,c:/program files/swipl/library/error.pl)
> Kind: silent
> Lines: [autoloading ~p from ~w-[plunit:must_be/2,c:/program files/swipl/library/error.pl]]
> 
> autoloading plunit:must_be/2 from c:/program files/swipl/library/error.pl
> 
> Term: load_file(start(2,file(c:/program files/swipl/library/error.pl,c:/program files/swipl/library/error.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[2],~w-[c:/program files/swipl/library/error.pl], ...]
> 
> Loading c:/program files/swipl/library/error.pl ...
> 
> Term: load_file(done(2,file(c:/program files/swipl/library/error.pl,c:/program files/swipl/library/error.pl),compiled,error,0.015625,90))
> Kind: silent
> Lines: [~|~t~*+ - [2],~w-[c:/program files/swipl/library/error.pl], ~w-[compiled], into ~w-[error], ~2f sec, ~D clauses-[0.015625,90]]
> 
> c:/program files/swipl/library/error.pl compiled into error 0.02 sec, 90 clauses
> 
> Term: autoload(plunit:option/3,c:/program files/swipl/library/option.pl)
> Kind: silent
> Lines: [autoloading ~p from ~w-[plunit:option/3,c:/program files/swipl/library/option.pl]]
> 
> autoloading plunit:option/3 from c:/program files/swipl/library/option.pl
> 
> Term: load_file(start(2,file(c:/program files/swipl/library/option.pl,c:/program files/swipl/library/option.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[2],~w-[c:/program files/swipl/library/option.pl], ...]
> 
> Loading c:/program files/swipl/library/option.pl ...
> 
> Term: load_file(done(2,file(c:/program files/swipl/library/option.pl,c:/program files/swipl/library/option.pl),compiled,swi_option,0.0,42))
> Kind: silent
> Lines: [~|~t~*+ - [2],~w-[c:/program files/swipl/library/option.pl], ~w-[compiled], into ~w-[swi_option], ~2f sec, ~D clauses-[0.0,42]]
> 
> c:/program files/swipl/library/option.pl compiled into swi_option 0.00 sec, 42 clauses
> 
> Term: load_file(start(1,file(library(lists),c:/program files/swipl/library/lists.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[1],~p-[library(lists)], ...]
> 
> Loading library(lists) ...
> 
> Term: load_file(done(1,file(library(lists),c:/program files/swipl/library/lists.pl),compiled,lists,0.0,111))
> Kind: silent
> Lines: [~|~t~*+ - [1],~p-[library(lists)], ~w-[compiled], into ~w-[lists], ~2f sec, ~D clauses-[0.0,111]]
> 
> library(lists) compiled into lists 0.00 sec, 111 clauses
> 
> Term: autoload(plunit:ord_intersection/3,c:/program files/swipl/library/ordsets.pl)
> Kind: silent
> Lines: [autoloading ~p from ~w-[plunit:ord_intersection/3,c:/program files/swipl/library/ordsets.pl]]
> 
> autoloading plunit:ord_intersection/3 from c:/program files/swipl/library/ordsets.pl
> 
> Term: load_file(start(2,file(c:/program files/swipl/library/ordsets.pl,c:/program files/swipl/library/ordsets.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[2],~w-[c:/program files/swipl/library/ordsets.pl], ...]
> 
> Loading c:/program files/swipl/library/ordsets.pl ...
> 
> Term: load_file(done(2,file(c:/program files/swipl/library/ordsets.pl,c:/program files/swipl/library/ordsets.pl),compiled,ordsets,0.0,88))
> Kind: silent
> Lines: [~|~t~*+ - [2],~w-[c:/program files/swipl/library/ordsets.pl], ~w-[compiled], into ~w-[ordsets], ~2f sec, ~D clauses-[0.0,88]]
> 
> c:/program files/swipl/library/ordsets.pl compiled into ordsets 0.00 sec, 88 clauses
> 
> Term: autoload(plunit:maplist/3,c:/program files/swipl/library/apply.pl)
> Kind: silent
> Lines: [autoloading ~p from ~w-[plunit:maplist/3,c:/program files/swipl/library/apply.pl]]
> 
> autoloading plunit:maplist/3 from c:/program files/swipl/library/apply.pl
> 
> Term: load_file(start(2,file(c:/program files/swipl/library/apply.pl,c:/program files/swipl/library/apply.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[2],~w-[c:/program files/swipl/library/apply.pl], ...]
> 
> Loading c:/program files/swipl/library/apply.pl ...
> 
> Term: load_file(done(2,file(c:/program files/swipl/library/apply.pl,c:/program files/swipl/library/apply.pl),compiled,apply,0.0,75))
> Kind: silent
> Lines: [~|~t~*+ - [2],~w-[c:/program files/swipl/library/apply.pl], ~w-[compiled], into ~w-[apply], ~2f sec, ~D clauses-[0.0,75]]
> 
> c:/program files/swipl/library/apply.pl compiled into apply 0.00 sec, 75 clauses
> 
> Term: autoload(plunit:include/3,c:/program files/swipl/library/apply.pl)
> Kind: silent
> Lines: [autoloading ~p from ~w-[plunit:include/3,c:/program files/swipl/library/apply.pl]]
> 
> autoloading plunit:include/3 from c:/program files/swipl/library/apply.pl
> 
> Term: autoload(plunit_message_hook:end_tests/1,c:/program files/swipl/library/plunit)
> Kind: silent
> Lines: [autoloading ~p from ~w-[plunit_message_hook:end_tests/1,c:/program files/swipl/library/plunit]]
> 
> autoloading plunit_message_hook:end_tests/1 from c:/program files/swipl/library/plunit
> 
> Term: load_file(done(0,file(informational_message_example,c:/users/groot/informational_message_example.pl),compiled,user,0.03125000000000003,9))
> Kind: silent
> Lines: [~|~t~*+ - [0],~w-[informational_message_example], ~w-[compiled], ~2f sec, ~D clauses-[0.03125000000000003,9]]
> 
> informational_message_example compiled 0.03 sec, 9 clauses
> 
> Term: query(yes([],true,[]-[]))
> Kind: query
> Lines: [ansi(truth(true),true.,[]),~N-[]]
> 
> true.
> 
> ?- run_tests.
> Term: autoload(user:run_tests/0,c:/program files/swipl/library/plunit)
> Kind: silent
> Lines: [autoloading ~p from ~w-[user:run_tests/0,c:/program files/swipl/library/plunit]]
> 
> autoloading user:run_tests/0 from c:/program files/swipl/library/plunit
> 
> Term: toplevel_goal(user:run_tests,[])
> Kind: silent
> Lines: [Unknown message: ~p-[toplevel_goal(user:run_tests,[])]]
> 
> Unknown message: toplevel_goal(user:run_tests,[])
> 
> Term: autoload(plunit:option/2,c:/program files/swipl/library/option.pl)
> Kind: silent
> Lines: [autoloading ~p from ~w-[plunit:option/2,c:/program files/swipl/library/option.pl]]
> 
> autoloading plunit:option/2 from c:/program files/swipl/library/option.pl
> 
> Term: autoload(plunit:debug/3,c:/program files/swipl/library/debug)
> Kind: silent
> Lines: [autoloading ~p from ~w-[plunit:debug/3,c:/program files/swipl/library/debug]]
> 
> autoloading plunit:debug/3 from c:/program files/swipl/library/debug
> 
> Term: load_file(start(1,file(c:/program files/swipl/library/debug,c:/program files/swipl/library/debug.pl)))
> Kind: silent
> Lines: [~|~t~*+Loading -[1],~w-[c:/program files/swipl/library/debug], ...]
> 
> Loading c:/program files/swipl/library/debug ...
> 
> Term: load_file(done(1,file(c:/program files/swipl/library/debug,c:/program files/swipl/library/debug.pl),compiled,prolog_debug,0.015625,48))
> Kind: silent
> Lines: [~|~t~*+ - [1],~w-[c:/program files/swipl/library/debug], ~w-[compiled], into ~w-[prolog_debug], ~2f sec, ~D clauses-[0.015625,48]]
> 
> c:/program files/swipl/library/debug compiled into prolog_debug 0.02 sec, 48 clauses
> 
> Term: plunit(begin(message_hook))
> Kind: informational
> Lines: [PL-Unit: ~w -[message_hook],flush]
> 
> % PL-Unit: message_hook 
> Term: plunit(begin(message_hook:reverse,c:/users/groot/informational_message_example.pl:26,rational_trees))
> Kind: silent
> Lines: [Unknown message: ~p-[plunit(begin(message_hook:reverse,c:/users/groot/informational_message_example.pl:26,rational_trees))]]
> 
> Unknown message: plunit(begin(message_hook:reverse,'c:/users/groot/informational_message_example.pl':26,rational_trees))
> 
> Term: plunit(end(message_hook:reverse,c:/users/groot/informational_message_example.pl:26,rational_trees))
> Kind: silent
> Lines: [Unknown message: ~p-[plunit(end(message_hook:reverse,c:/users/groot/informational_message_example.pl:26,rational_trees))]]
> 
> Unknown message: plunit(end(message_hook:reverse,'c:/users/groot/informational_message_example.pl':26,rational_trees))
> 
> Term: plunit(progress(message_hook,reverse,passed))
> Kind: information
> Lines: [at_same_line,(.)-[],flush]
> 
> .
> Term: plunit(end(message_hook))
> Kind: informational
> Lines: [at_same_line, done]
> 
> done
> 
> Term: plunit(summary(plunit{blocked:0,failed:0,failed_assertions:0,passed:1,sto:0}))
> Kind: silent
> Lines: [Unknown message: ~p-[plunit(summary(plunit{blocked:0,failed:0,failed_assertions:0,passed:1,sto:0}))]]
> 
> Unknown message: plunit(summary(plunit{blocked:0,failed:0,failed_assertions:0,passed:1,sto:0}))
> 
> Term: plunit(fixme(0,0,0))
> Kind: informational
> Lines: []
> 
> % 
> 
> Term: plunit(all_passed(1))
> Kind: informational
> Lines: [test passed]
> 
> % test passed
> 
> Term: query(yes([],true,[]-[]))
> Kind: query
> Lines: [ansi(truth(true),true.,[]),~N-[]]
> 
> true.
> 
> ```

* * *

* * *

Notes:

* * *

One would think that if the hook is asserted then assert/1 would be used to assert message\_hook/3, typically asserta/2 is used to capture the reference to the asserted clause.

The reason that temporary installed hooks use

```prolog
setup_call_cleanup(
	asserta(HookTerm, Ref),
	ProtectedCode,
	erase(Ref))

```

Is because this makes it trivial to remove exactly the added clause. If we use [retract/1](https://www.swi-prolog.org/pldoc/doc_for?object=retract/1), it may retract another clause that happens to unify with the one you just added. It may also leave a choice point. Using [erase/1](https://www.swi-prolog.org/pldoc/doc_for?object=erase/1) guarantee we have the right clause without any search and without unwanted choice points. ([ref](https://swi-prolog.discourse.group/t/wiki-discussion-using-message-hook-3/4430/2))

* * *

SWI-Prolog is written in C and low level Prolog constructs such as a clause are actually C structures ([struct clause](https://github.com/SWI-Prolog/swipl-devel/blob/984bb191bb1c989d4fc930f558ae0906bfbbc339/src/pl-incl.h#L1343-L1361)).

A side benefit of having the reference is that you can use it with certain predicates like clause\_property/2.

* * *

For more clarification on the differences between static and dynamic predicates with SWI-Prolog see this other [reply](https://discourse.swi-prolog.org/t/from-dynamic-to-static-predicates-and-vice-versa/1009/4?u=ericgt) by Jan W.
