\libdoc{record}{Access named fields in a term}
\label{sec:lib:record}

The library \pllib{record} provides named access to fields in a record
represented as a compound term such as \exam{point(X, Y)}. The Prolog
world knows various approaches to solve this problem, unfortunately with
no consensus. The approach taken by this library is proposed by Richard
O'Keefe on the SWI-Prolog mailinglist.

The approach automates a technique commonly described in Prolog
text-books, where access and modification predicates are defined for
the record type. Such predicates are subject to normal import/export as
well as analysis by cross-referencers. Given the simple nature of the
access predicates, an optimizing compiler can easily inline them for
optimal preformance.

A record is defined using the directive \index{record/1}\predref{record}{1}.  We introduce the
library with a short example:

\begin{code}
:- record point(x:integer=0, y:integer=0).

        ...,
        default_point(Point),
        point_x(Point, X),
        set_x_of_point(10, Point, Point1),

        make_point([y(20)], YPoint),
\end{code}

\noindent
The principal functor and arity of the term used defines the name and
arity of the compound used as records.  Each argument is described using
a term of the format below.

\begin{quote}
\bnfmeta{name}[:\bnfmeta{type}][=\bnfmeta{default}]
\end{quote}

In this definition, \bnfmeta{name} is an atom defining the name of the argument,
\bnfmeta{type} is an optional type specification as defined by \index{must_be/2}\predref{must_be}{2} from
library \pllib{error}, and \bnfmeta{default} is the default initial value.  The
\bnfmeta{type} defaults to \const{any}.  If no default value is specified the
default is an unbound variable.

A record declaration creates a set of predicates through
\jargon{term-expansion}.  We describe these predicates below.  In this
description, \bnfmeta{constructor} refers to the name of the record (`point'
in the example above) and \bnfmeta{name} to the name of an argument (field).

\begin{itemlist}
    \item [default_\bnfmeta{constructor}(-Record)]
Create a new record where all fields have their default values. This is
the same as \mbox{make_\bnfmeta{constructor}([], Record)}.

    \item [make_\bnfmeta{constructor}(+Fields, -Record)]
Create a new record where specified fields have the specified values and
remaining fields have their default value.  Each field is specified as
a term \bnfmeta{name}(\bnfmeta{value}).  See example in the introduction.

    \item [make_\bnfmeta{constructor}(+Fields, -Record, -RestFields)]
Same as make_\bnfmeta{constructor}/2, but named fields that do not appear in
\arg{Record} are returned in \arg{RestFields}. This predicate is
motivated by option-list processing.  See library \pllib{option}.

    \item [\bnfmeta{constructor}_\bnfmeta{name}(Record, Value)]
Unify \arg{Value} with argument in \arg{Record} named \bnfmeta{name}.%
	\footnote{Note this is not called `get_' as it performs
		  unification and can perfectly well instantiate the
		  argument.}

    \item [\bnfmeta{constructor}_data(?Name, +Record, ?Value)]
True when \arg{Value} is the value for the field named \arg{Name}
in \arg{Record}.  This predicate does not perform type-checking.

    \item [set_\bnfmeta{name}_of_\bnfmeta{constructor}(+Value, +OldRecord, -NewRecord)]
Replace the value for \bnfmeta{name} in \arg{OldRecord} by \arg{Value} and unify
the result with \arg{NewRecord}.

    \item [set_\bnfmeta{name}_of_\bnfmeta{constructor}(+Value, !Record)]
Destructively replace the argument \bnfmeta{name} in \arg{Record} by
\arg{Value} based on \index{setarg/3}\predref{setarg}{3}.  Use with care.

    \item [nb_set_\bnfmeta{name}_of_\bnfmeta{constructor}(+Value, !Record)]
As above, but using non-backtrackable assignment based on \index{nb_setarg/3}\predref{nb_setarg}{3}.
Use with \emph{extreme} care.

    \item [set_\bnfmeta{constructor}_fields(+Fields, +Record0, -Record)]
Set multiple fields using the same syntax as make_\bnfmeta{constructor}/2, but
starting with \arg{Record0} rather than the default record.

    \item [set_\bnfmeta{constructor}_fields(+Fields, +Record0, -Record, -RestFields)]
Similar to set_\bnfmeta{constructor}_\index{fields/4}\predref{fields}{4}, but fields not defined by
\bnfmeta{constructor} are returned in \arg{RestFields}.

    \item [set_\bnfmeta{constructor}_field(+Field, +Record0, -Record)]
Set a single field specified as a term \bnfmeta{name}(\bnfmeta{value}).
\end{itemlist}

\begin{description}
    \predicate{record}{1}{+Spec}
The construct \exam{:- record Spec, ...} is used to define access to
named fields in a compound. It is subject to term-expansion (see
\index{expand_term/2}\predref{expand_term}{2}) and cannot be called as a predicate. See
\secref{lib:record} for details.
\end{description}
