## 4.13 Declaring predicates properties

This section describes directives which manipulate attributes of predicate definitions. The functors dynamic/1, multifile/1 and discontiguous/1 are operators of priority 1150 (see op/3), which implies the list of predicates they involve can just be a comma separated list:

    :- dynamic
            foo/0,
            baz/2.

On SWI-Prolog all these directives are just predicates. This implies they can also be called by a program. Do not rely on this feature if you want to maintain portability to other Prolog implementations.

[ISO]dynamic :PredicateIndicator, \ldots
  Informs the interpreter that the definition of the predicate(s) may change during execution (using assert/1 and/or retract/1). In the multi-threaded version, the clauses of dynamic predicates are shared between the threads. The directive thread_local/1 provides an alternative where each threads has its own clause-list for the predicate. Dynamic predicates can be turned into static ones using compile_predicates/1.
compile_predicates(:ListOfNameArity)
  Compile a list of specified dynamic predicates (see dynamic/1 and assert/1) into normal static predicates. This call tells the Prolog environment the definition will not change anymore and further calls to assert/1 or retract/1 on the named predicates raise a permission error. This predicate is designed to deal with parts of the program that is generated at runtime but does not change during the remainder of the program execution.40The specification of this predicate is from Richard O'Keefe. The implementation is allowed to optimise the predicate. This is not yet implemented. In multi-threaded Prolog however, static code runs faster as it does not require synchronisation. This is particularly true on SMP hardware.
[ISO]multifile :PredicateIndicator, \ldots
  Informs the system that the specified predicate(s) may be defined over more than one file. This stops consult/1 from redefining a predicate when a new definition is found.
[ISO]discontiguous :PredicateIndicator, \ldots
  Informs the system that the clauses of the specified predicate(s) might not be together in the source file. See also style_check/1.
public :PredicateIndicator, \ldots
  Instructs the cross-referencer that the predicate can be called. It has no semantics.41This declaration is compatible to SICStus. In YAP, public/1 instructs the compiler to keep the source. As the source is always available in SWI-Prolog, our current interpretation also enhanced the compatibility to YAP.
index(+Head)
  Index the clauses of the predicate with the same name and arity as Head on the specified arguments. Head is a term of which all arguments are either `1' (denoting `index this argument') or `0' (denoting `do not index this argument'). Indexing has no implications for the semantics of a predicate, only on its performance. If indexing is enabled on a predicate a special purpose algorithm is used to select candidate clauses based on the actual arguments of the goal. This algorithm checks whether indexed arguments might unify in the clause head. Only atoms, integers and compound terms are considered. Compound terms are indexed on the combination of their name and arity. Indexing is very useful for predicates with many clauses representing facts.

  Due to the representation technique used at most 4 arguments can be indexed. All indexed arguments should be in the first 32 arguments of the predicate. If more than 4 arguments are specified for indexing only the first 4 will be accepted. Arguments above 32 are ignored for indexing.

  Indexing as specified by this predicate uses a quick but linear scan. Without explicit specification the system uses an algorithm depending on the structure of the first argument and number of clauses, In particular, for predicates that can be indexed on the first argument and have many clauses, the system will use an automatically resizing hash-table to provide access time independent from the number of clauses.42SWI-Prolog indexing is no longer state-of-the-art. Better schemas for multi-argument as well as indexing inside compound terms are known. We hope to integrate this in future versions. If---for example---one wants to represents sub-types using a fact list `sub_type(Sub, Super)' that should be used both to determine sub- and super types one should declare sub_type/2 as follows:

      :- index(sub_type(1, 1)).

      sub_type(horse, animal).
      ...
      ...

  Note that this type of indexing makes selecting clauses much faster but remains linear with respect to the number of clauses, while hashing as described with hash/1 provides constant access time. See also hash/1 and term_hash/2.

hash(+Head)
  Index the given predicate by hashing on the first argument. This is done by default on any predicate with more than 5 clauses having a first argument that can be indexed and at most two that can not be indexed. On dynamic predicates the hash-table is resized as the number of clauses grows, providing roughly constant-time access regardless of the number of clauses predicates that can be indexed on the first argument. See also index/1, term_hash/2 and predicate_property/2.