| Did you know ... | Search Documentation: |
| Printing from libraries |
Libraries should not use format/3
or other output predicates directly. Libraries that print informational
output directly to the console are hard to use from code that depend on
your textual output, such as a CGI script. The predicates in section
4.11 define the API for dealing with messages. The idea behind this
is that a library that wants to provide information about its status,
progress, events or problems calls print_message/2.
The first argument is the
level. The supported levels are described with print_message/2.
Libraries typically use informational and warning,
while libraries should use exceptions for errors (see throw/1, type_error/2,
etc.).
The second argument is an arbitrary Prolog term that carries the information of the message, but not the precise text. The text is defined by the grammar rule prolog:message//1. This distinction is made to allow for translations and to allow hooks processing the information in a different way (e.g., to translate progress messages into a progress bar).
For example, suppose we have a library that must download data from the Internet (e.g., based on http_open/3). The library wants to print the progress after each downloaded file. The code below is a good skeleton:
download_urls(List) :-
length(List, Total),
forall(nth1(I, List, URL),
( download_url(URL),
print_message(informational,
download_url(URL, I, Total)))).
The programmer can now specify the default textual output using the rule below. Note that this rule may be in the same file or anywhere else. Notably, the application may come with several rule sets for different languages. This, and the user-hook example below are the reason to represent the message as a compound term rather than a string. This is similar to using message numbers in non-symbolic languages. The documentation of print_message_lines/3 describes the elements that may appear in the output list.
:- multifile
prolog:message//1.
prolog:message(download_url(URL, I, Total)) -->
{ Perc is round(I*100/Total) },
[ 'Downloaded ~w; ~D from ~D (~d%)'-[URL, I, Total, Perc] ].
A user of the library may define rules for message_hook/3. The rule below acts on the message content. Other applications can act on the message level and, for example, popup a message box for warnings and errors.
:- multifile user:message_hook/3.
message_hook(download_url(URL, I, Total), _Kind, _Lines) :-
<send this information to a GUI component>
In addition, using the command line option -q, the user can disable all informational messages.
Many messages refer to a predicate. Rather than formatting the
predicate indicator yourself, use the grammar rules below. They are
defined in the system module $messages and are declared
public, i.e., they must be called with an explicit module
qualification. Using them makes the reference consistent with the
messages of the system: the predicate indicator is written using the
code style class and, if the source location of the
predicate is known, it becomes a hyperlink to its definition on
terminals that support this (see section
2.5 and the Prolog flag
hyperlink_term). This works for predicates defined in C as well,
provided the system can resolve the address of the implementing
function.
prolog:message(no_such_predicate(PI)) -->
[ 'There is no ' ],
'$messages':predicate_reference(PI).
////// notation. Options:
auto (default), hide or show.
Using
auto, the module qualification is removed if it is user,
system or a system internal module.false, do not create a hyperlink. Default is true.code.true, add a tag that indicates the kind of the
predicate. Default is false. This is intended for messages
that list candidate predicates, one per line.//iso, built_in, foreign,
library(Name), module(Module), user
or
undefined. This is the classification used by the
tag(true) option above. Fails if Spec does not
denote a predicate.