..
   This file is part of Logtalk <https://logtalk.org/>  
   Copyright 1998-2020 Paulo Moura <pmoura@logtalk.org>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


.. _objects_objects:

Objects
=======

The main goal of Logtalk objects is the encapsulation and reuse of
predicates. Instead of a single database containing all your code,
Logtalk objects provide separated namespaces or databases allowing the
partitioning of code in more manageable parts. Logtalk is a *declarative
programming language* and does not aim to bring some sort of new dynamic
state change concept to Logic Programming or Prolog.

Logtalk, defines two built-in objects, :ref:`user <apis:user/0>` and
:ref:`logtalk <apis:logtalk/0>`, which are described at the end of this
section.

.. _objects_kind:

Objects, prototypes, classes, and instances
-------------------------------------------

There are only three kinds of encapsulation entities in Logtalk:
*objects*, *protocols*, and *categories*. Logtalk uses the term *object*
in a broad sense. The terms *prototype*, *parent*, *class*, *subclass*,
*superclass*, *metaclass*, and *instance* always designate an object.
Different names are used to emphasize the *role* played by an object in
a particular context. I.e. we use a term other than object when we want
to make the relationship with other objects explicit. For example, an
object with an *instantiation* relation with other object plays the role
of an *instance*, while the instantiated object plays the role of a
*class*; an object with a *specialization* relation with other object
plays the role of a *subclass*, while the specialized object plays the
role of a *superclass*; an object with an *extension* relation with
other object plays the role of a *prototype*, the same for the extended
object. A *stand-alone* object, i.e. an object with no relations with
other objects, is always interpreted as a prototype. In Logtalk, entity
relations essentially define *patterns* of code reuse. An entity is
compiled accordingly to the roles it plays.

Logtalk allows you to work from standalone objects to any kind of
hierarchy, either class-based or prototype-based. You may use single or
multiple inheritance, use or forgo metaclasses, implement reflective
designs, use parametric objects, and take advantage of protocols and
categories (think components).

.. _objects_prototypes:

Prototypes
~~~~~~~~~~

Prototypes are either self-defined objects or objects defined as
extensions to other prototypes with whom they share common properties.
Prototypes are ideal for representing one-of-a-kind objects. Prototypes
usually represent concrete objects in the application domain. When
linking prototypes using *extension* relations, Logtalk uses the term
*prototype hierarchies* although most authors prefer to use the term
*hierarchy* only with class generalization/specialization relations. In
the context of logic programming, prototypes are often the ideal
replacement for modules.

.. _objects_classes:

Classes
~~~~~~~

Classes are used to represent abstractions of common properties of sets
of objects. Classes provide an ideal structuring solution when you want
to express hierarchies of abstractions or work with many similar
objects. Classes are used indirectly through *instantiation*. Contrary
to most object-oriented programming languages, instances can be created
both dynamically at runtime or defined in a source file like other
objects.

.. _objects_defining:

Defining a new object
---------------------

We can define a new object in the same way we write Prolog code: by
using a text editor. Logtalk source files may contain one or more
objects, categories, or protocols. If you prefer to define each entity
in its own source file, it is recommended that the file be named after
the object. By default, all Logtalk source files use the extension
``.lgt`` but this is optional and can be set in the adapter files.
Intermediate Prolog source files (generated by the Logtalk compiler)
have, by default, a ``_lgt`` suffix and a ``.pl`` extension. Again, this
can be set to match the needs of a particular Prolog compiler in the
corresponding adapter file. For instance, we may define an object named
``vehicle`` and save it in a ``vehicle.lgt`` source file which will be
compiled to a ``vehicle_lgt.pl`` Prolog file (depending on the
:term:`backend compiler <backend Prolog compiler>`, the names of the
intermediate Prolog files may include a directory hash).

Object names can be atoms or compound terms (when defining parametric
objects, see below). Objects, categories, and protocols share the same
name space: we cannot have an object with the same name as a protocol or
a category.

Object code (directives and predicates) is textually encapsulated by
using two Logtalk directives: :ref:`directives_object_1_5` and
:ref:`directives_end_object_0`. The most simple object will be one
that is self-contained, not depending on any other Logtalk entity:

::

   :- object(Object).
       ...
   :- end_object.

If an object implements one or more protocols then the opening directive
will be:

::

   :- object(Object,
       implements([Protocol1, Protocol2, ...])).
       ...
   :- end_object.

An object can import one or more categories:

::

   :- object(Object,
       imports([Category1, Category2, ...])).
       ...
   :- end_object.

If an object both implements protocols and imports categories then we
will write:

::

   :- object(Object,
       implements([Protocol1, Protocol2, ...]),
       imports([Category1, Category2, ...])).
       ...
   :- end_object.

In object-oriented programming objects are usually organized in
hierarchies that enable interface and code sharing by inheritance. In
Logtalk, we can construct prototype-based hierarchies by writing:

::

   :- object(Prototype,
       extends(Parent)).
       ...
   :- end_object.

We can also have class-based hierarchies by defining instantiation and
specialization relations between objects. To define an object as a class
instance we will write:

::

   :- object(Object,
       instantiates(Class)).
       ...
   :- end_object.

A class may specialize another class, its superclass:

::

   :- object(Class,
       specializes(Superclass)).
       ...
   :- end_object.

If we are defining a reflexive system where every class is also an
instance, we will probably be using the following pattern:

::

   :- object(Class,
       instantiates(Metaclass),
       specializes(Superclass)).
       ...
   :- end_object.

In short, an object can be a *stand-alone* object or be part of an
object hierarchy. The hierarchy can be prototype-based (defined by
extending other objects) or class-based (with instantiation and
specialization relations). An object may also implement one or more
protocols or import one or more categories.

A *stand-alone* object (i.e. an object with no extension, instantiation,
or specialization relations with other objects) always plays the role of
a prototype, that is, a self-describing object. If we want to use classes
and instances, then we will need to specify at least one instantiation
or specialization relation. The best way to do this is to define a set
of objects that provide the basis of a reflective system [Cointe87]_,
[Moura94]_. For example:

::

   % avoid the inevitable unknown entity warnings as in a
   % reflective system there will always be references to
   % an entity that will be defined after the reference

   :- set_logtalk_flag(unknown_entities, silent).


   % default root of the inheritance graph
   % predicates common to all objects

   :- object(object,
       instantiates(class)).
       ...
   :- end_object.


   % default metaclass for all classes
   % predicates common to all instantiable classes

   :- object(class,
       instantiates(class),
       specializes(abstract_class)).
       ...
   :- end_object.


   % default metaclass for all abstract classes
   % predicates common to all classes

   :- object(abstract_class,
       instantiates(class),
       specializes(object)).
       ...
   :- end_object.

Note that with these instantiation and specialization relations,
``object``, ``class``, and ``abstract_class`` are, at the same time,
classes and instances of some class. In addition, each object inherits
its own predicates and the predicates of the other two objects without
any inheritance loop problems.

When a full-blown reflective system solution is not needed, the above
scheme can be simplified by making an object an instance of itself, i.e.
by making a class its own metaclass. For example:

::

   :- object(class,
       instantiates(class)).
       ...
   :- end_object.

We can use, in the same application, both prototype and class-based
hierarchies (and freely exchange messages between all objects). We
cannot however mix the two types of hierarchies by, e.g., specializing
an object that extends another object in this current Logtalk version.

Logtalk also supports public, protected, and private inheritance. See
the :ref:`inheritance <inheritance_scope>` section for details.

.. _objects_parametric:

Parametric objects
------------------

Parametric objects have a compound term as identifier where all the
arguments of the compound term are variables. These variables, the
*object parameters*, can be instantiated when sending or as a consequence
of sending a message to the object, thus acting as object parameters. The
object predicates can then be coded to depend on those parameters, which
are logical variables shared by all object predicates. When an object state
is set at object creation and never changed, parameters provide a better
solution than using the object's database via asserts. Parametric objects
can also be used to associate a set of predicates to terms that share a
common functor and arity.

In order to give access to an object parameter, Logtalk provides a
:ref:`methods_parameter_2` built-in local method:

::

   :- object(foo(_Bar, _Baz, ...)).

       ...
       bar(Bar) :-
           parameter(1, Bar).

       baz :-
           parameter(2, Baz),
           baz(Baz),
           ... .

An alternative solution is to use the built-in local method
:ref:`methods_this_1`. For example:

::

   :- object(foo(_Bar, _Baz, ...)).

       ...
       baz :-
           this(Name(_, Baz, ...)),
           baz(Baz),
           ... .

Both solutions are equally efficient as calls to the methods ``this/1``
and ``parameter/2`` are usually compiled inline into a clause head
unification. The drawback of this second solution is that we must check
all calls of ``this/1`` if we change the object name. Note that we can't
use these method with the message sending operators
(:ref:`control_send_to_object_2`, :ref:`control_send_to_self_1`, or
:ref:`control_call_super_1`).

A third alternative to access object parameters is to use
:term:`parameter variables <parameter variable>`. Although parameter variables
introduce a concept of entity global variables, their unique syntax,
``_ParameterName_``, avoids conflicts and makes them easily recognizable. For
example:

::

   :- object(foo(_Bar_, _Baz_, ...)).

       ...
       bar(_Bar_).

       baz :-
           baz(_Baz_),
           ... .

Note that using parameter variables doesn't change the fact that entity parameters
are logical variables. Parameter variables simplify code maintenance by allowing
parameters to be added, reordered, or removed without having to specify or update
parameter indexes.

When storing a parametric object in its own source file, the convention
is to name the file after the object, with the object arity appended.
For instance, when defining an object named ``sort(Type)``, we may save
it in a ``sort_1.lgt`` text file. This way it is easy to avoid file name
clashes when saving Logtalk entities that have the same functor but
different arity.

Compound terms with the same functor and with the same number of
arguments as a parametric object identifier may act as *proxies* to a
parametric object. Proxies may be stored on the database as Prolog facts
and be used to represent different instantiations of a parametric object
identifier. Logtalk provides a convenient notation for accessing proxies
represented as Prolog facts when sending a message:

::

   ..., {Proxy}::Message, ...

In this context, the proxy argument is proved as a plain Prolog goal. If
successful, the message is sent to the corresponding parametric object.
Typically, the proof allows retrieving of parameter instantiations. This
construct can either be used with a proxy argument that is sufficiently
instantiated in order to unify with a single Prolog fact or with a proxy
argument that unifies with several facts on backtracking.

.. _objects_finding:

Finding defined objects
-----------------------

We can find, by backtracking, all defined objects by calling the
:ref:`predicates_current_object_1` built-in predicate with a
unbound argument:

.. code-block:: text

   | ?- current_object(Object).
   Object = logtalk ;
   Object = user ;
   ...

This predicate can also be used to test if an object is defined by
calling it with a valid object identifier (an atom or a compound term).

.. _objects_creating:

Creating a new object in runtime
--------------------------------

An object can be dynamically created at runtime by using the
:ref:`predicates_create_object_4` built-in predicate:

.. code-block:: text

   | ?- create_object(Object, Relations, Directives, Clauses).

The first argument should be either a variable or the name of the new
object (a Prolog atom or compound term, which must not match any
existing entity name). The remaining three arguments correspond to the
relations described in the opening object directive and to the object
code contents (directives and clauses).

For example, the call:

.. code-block:: text

   | ?- create_object(
            foo,
            [extends(bar)],
            [public(foo/1)],
            [foo(1), foo(2)]
        ).

is equivalent to compiling and loading the object:

::

   :- object(foo,
       extends(bar)).

       :- dynamic.

       :- public(foo/1).
       foo(1).
       foo(2).

   :- end_object.

If we need to create a lot of (dynamic) objects at runtime, then is best
to define a metaclass or a prototype with a predicate that will call
this built-in predicate to make new objects. This predicate may provide
automatic object name generation, name checking, and accept object
initialization options.

.. _objects_abolishing:

Abolishing an existing object
-----------------------------

Dynamic objects can be abolished using the :ref:`predicates_abolish_object_1`
built-in predicate:

.. code-block:: text

   | ?- abolish_object(Object).

The argument must be an identifier of a defined dynamic object,
otherwise an error will be thrown.

.. _objects_directives:

Object directives
-----------------

Object directives are used to set initialization goals, define object
properties, to document an object dependencies on other Logtalk
entities, and to load the contents of files into an object.

.. _objects_initialization:

Object initialization
~~~~~~~~~~~~~~~~~~~~~

We can define a goal to be executed as soon as an object is (compiled
and) loaded to memory with the :ref:`directives_initialization_1`
directive:

::

   :- initialization(Goal).

The argument can be any valid Prolog or Logtalk goal, including a
message to other object. For example:

::

   :- object(foo).

       :- initialization(init).
       :- private(init/0).

       init :-
           ... .

       ...

   :- end_object.

Or:

::

   :- object(assembler).

       :- initialization(control::start).
       ...

   :- end_object.

The initialization goal can also be a message to *self* in order to call
an inherited or imported predicate. For example, assuming that we have a
``monitor`` category defining a ``reset/0`` predicate:

::

   :- object(profiler,
       imports(monitor)).

       :- initialization(::reset).
       ...

   :- end_object.

Note, however, that descendant objects do not inherit initialization
directives. In this context, *self* denotes the object that contains the
directive. Also note that by initialization we do not necessarily mean
setting an object dynamic state.

.. _objects_dynamic:

Dynamic objects
~~~~~~~~~~~~~~~

Similar to Prolog predicates, an object can be either static or dynamic.
An object created during the execution of a program is always dynamic.
An object defined in a file can be either dynamic or static. Dynamic
objects are declared by using the :ref:`directives_dynamic_0` directive in the
object source code:

::

   :- dynamic.

The directive must precede any predicate directives or clauses. Please
be aware that using dynamic code results in a performance hit when
compared to static code. We should only use dynamic objects when these
need to be abolished during program execution. In addition, note that we
can declare and define dynamic predicates within a static object.

.. _objects_documentation:

Object documentation
~~~~~~~~~~~~~~~~~~~~

An object can be documented with arbitrary user-defined information by
using the :ref:`directives_info_1` directive:

::

   :- info(List).

See the :ref:`documenting_documenting` section for details.

.. _objects_include:

Loading files into an object
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The :ref:`directives_include_1` directive
can be used to load the contents of a file into an object. A typical usage
scenario is to load a plain Prolog file into an object thus providing a
simple way to encapsulate its contents. For example, assume a ``cities.pl``
file defining facts for a ``city/4`` predicate. We could define a wrapper
for this database by writing:

::

   :- object(cities).

       :- public(city/4).

       :- include(dbs('cities.pl')).

   :- end_object.

The ``include/1`` directive can also be used when creating an object
dynamically. For example:

.. code-block:: text

   | ?- create_object(cities, [], [public(city/4), include(dbs('cities.pl'))], []).

.. _objects_object_aliases:

Declaring object aliases
~~~~~~~~~~~~~~~~~~~~~~~~

The :ref:`directives_uses_1` directive can be used to declare object aliases.
The typical uses of this directive include shortening long object names,
working consistently with specific parameterizations of parametric objects,
and simplifying experimenting with different object implementations of the
same protocol when using explicit message sending.

.. _objects_relationships:

Object relationships
--------------------

Logtalk provides six sets of built-in predicates that enable us to query
the system about the possible relationships that an object may have with
other entities.

The :ref:`predicates_instantiates_class_2_3` built-in predicates can be
used to query all instantiation relations:

.. code-block:: text

   | ?- instantiates_class(Instance, Class).

or, if we also want to know the instantiation scope:

.. code-block:: text

   | ?- instantiates_class(Instance, Class, Scope).

Specialization relations can be found by using the
:ref:`predicates_specializes_class_2_3` built-in predicates:

.. code-block:: text

   | ?- specializes_class(Class, Superclass).

or, if we also want to know the specialization scope:

.. code-block:: text

   | ?- specializes_class(Class, Superclass, Scope).

For prototypes, we can query extension relations using with the
:ref:`predicates_extends_object_2_3` built-in predicates:

.. code-block:: text

   | ?- extends_object(Object, Parent).

or, if we also want to know the extension scope:

.. code-block:: text

   | ?- extends_object(Object, Parent, Scope).

In order to find which objects import which categories we can use the
:ref:`predicates_imports_category_2_3` built-in predicates:

.. code-block:: text

   | ?- imports_category(Object, Category).

or, if we also want to know the importation scope:

.. code-block:: text

   | ?- imports_category(Object, Category, Scope).

To find which objects implements which protocols we can use the
:ref:`predicates_implements_protocol_2_3` and
:ref:`predicates_conforms_to_protocol_2_3` built-in predicates:

.. code-block:: text

   | ?- implements_protocol(Object, Protocol, Scope).

or, if we also want to consider inherited protocols:

.. code-block:: text

   | ?- conforms_to_protocol(Object, Protocol, Scope).

Note that, if we use a unbound first argument, we will need to use the
:ref:`predicates_current_object_1` built-in predicate to ensure that the
entity returned is an object and not a category.

To find which objects are explicitly complemented by categories we can
use the :ref:`predicates_complements_object_2` built-in predicate:

.. code-block:: text

   | ?- complements_object(Category, Object).

Note that more than one category may explicitly complement a single
object and a single category can complement several objects.

.. _objects_properties:

Object properties
-----------------

We can find the properties of defined objects by calling the built-in
predicate :ref:`predicates_object_property_2`:

.. code-block:: text

   | ?- object_property(Object, Property).

The following object properties are supported:

``static``
   The object is static
``dynamic``
   The object is dynamic (and thus can be abolished in runtime by
   calling the :ref:`predicates_abolish_object_1` built-in predicate)
``built_in``
   The object is a built-in object (and thus always available)
``threaded``
   The object supports/makes multi-threading calls
``file(Path)``
   Absolute path of the source file defining the object (if applicable)
``file(Basename, Directory)``
   Basename and directory of the source file defining the object (if
   applicable)
``lines(BeginLine, EndLine)``
   Source file begin and end lines of the object definition (if
   applicable)
``context_switching_calls``
   The object supports context switching calls (i.e. can be used with
   the :ref:`control_context_switch_2` debugging control construct)
``dynamic_declarations``
   The object supports dynamic declarations of predicates
``events``
   Messages sent from the object generate events
``source_data``
   Source data available for the object
``complements(Permission)``
   The object supports complementing categories with the specified
   permission (``allow`` or ``restrict``)
``complements``
   The object supports complementing categories
``public(Predicates)``
   List of public predicates declared by the object
``protected(Predicates)``
   List of protected predicates declared by the object
``private(Predicates)``
   List of private predicates declared by the object
``declares(Predicate, Properties)``
   List of :ref:`properties <grammar_entity_properties>` for a predicate declared by the object
``defines(Predicate, Properties)``
   List of :ref:`properties <grammar_entity_properties>` for a predicate defined by the object
``includes(Predicate, Entity, Properties)``
   List of :ref:`properties <grammar_entity_properties>` for an object multifile predicate that are defined
   in the specified entity (the properties include
   ``number_of_clauses(Number)``, ``number_of_rules(Number)``, and
   ``line_count(Line)`` with ``Line`` being the begin line of the
   multifile predicate clause)
``provides(Predicate, Entity, Properties)``
   List of :ref:`properties <grammar_entity_properties>` for other entity multifile predicate that are
   defined in the object (the properties include
   ``number_of_clauses(Number)``, ``number_of_rules(Number)``, and
   ``line_count(Line)`` with ``Line`` being the begin line of the
   multifile predicate clause)
``alias(Predicate, Properties)``
   List of :ref:`properties <grammar_entity_properties>` for a :term:`predicate alias` declared by the object
   (the properties include ``for(Original)``, ``from(Entity)``,
   ``non_terminal(NonTerminal)``, and ``line_count(Line)`` with ``Line``
   being the begin line of the alias directive)
``calls(Call, Properties)``
   List of :ref:`properties <grammar_entity_properties>` for predicate calls made by the object (``Call``
   is either a predicate indicator or a control construct such as
   ``::/1-2`` or ``^^/1`` with a predicate indicator as argument; note
   that ``Call`` may not be ground in case of a call to a control
   construct where its argument is only know at runtime; the properties
   include ``caller(Caller)``, ``alias(Alias)``, and
   ``line_count(Line)`` with both ``Caller`` and ``Alias`` being
   predicate indicators and ``Line`` being the begin line of the
   predicate clause or directive making the call)
``updates(Predicate, Properties)``
   List of :ref:`properties <grammar_entity_properties>` for dynamic predicate updates (and also access
   using the ``clause/2`` predicate) made by the object (``Predicate``
   is either a predicate indicator or a control construct such as
   ``::/1-2`` or ``:/2`` with a predicate indicator as argument; note
   that ``Predicate`` may not be ground in case of a control construct
   argument only know at runtime; the properties include
   ``updater(Updater)``, ``alias(Alias)``, and ``line_count(Line)`` with
   ``Updater`` being a (possibly multifile) predicate indicator,
   ``Alias`` being a predicate indicator, and ``Line`` being the begin
   line of the predicate clause or directive updating the predicate)
``number_of_clauses(Number)``
   Total number of predicate clauses defined in the object at compilation
   time (includes both user-defined clauses and auxiliary clauses generated
   by the compiler or by the :ref:`expansion hooks <expansion_expansion>`
   but does not include clauses for multifile predicates defined for other
   entities or clauses for the object own multifile predicates contributed
   by other entities)
``number_of_rules(Number)``
   Total number of predicate rules defined in the object at compilation
   time (includes both user-defined rules and auxiliary rules generated
   by the compiler or by the :ref:`expansion hooks <expansion_expansion>`
   but does not include rules for multifile predicates defined for other
   entities or rules for the object own multifile predicates contributed
   by other entities)
``number_of_user_clauses(Number)``
   Total number of user-defined predicate clauses defined in the object
   at compilation time (does not include clauses for multifile predicates
   defined for other entities or clauses for the object own multifile
   predicates contributed by other entities)
``number_of_user_rules(Number)``
   Total number of user-defined predicate rules defined in the object at
   compilation time (does not include rules for multifile predicates defined
   for other entities or rules for the object own multifile predicates
   contributed by other entities)
``debugging``
   The object is compiled in debug mode
``module``
   The object resulted from the compilation of a Prolog module

When a predicate is called from an ``initialization/1`` directive, the
argument of the ``caller/1`` property is ``:-/1``.

Some of the properties such as line numbers are only available when the
object is defined in a source file compiled with the
:ref:`source_data <flag_source_data>` flag turned on.

The properties that return the number of clauses (rules) report the
clauses (rules) *textually defined in the object* for both multifile and
non-multifile predicates. Thus, these numbers exclude clauses (rules)
for multifile predicates *contributed* by other entities.

.. _objects_built_in:

Built-in objects
----------------

Logtalk defines some built-in objects that are always available for any
application.

.. _objects_user:

The built-in pseudo-object ``user``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The built-in :ref:`user <apis:user/0>` pseudo-object virtually contains all
user predicate definitions not encapsulated in a Logtalk entity (or a Prolog
module for backends supporting a module system). These predicates are
assumed to be implicitly declared public. Messages sent from this
pseudo-object, which includes messages sent from the top-level interpreter,
generate events when the default value of the :ref:`events <flag_events>`
flag is set to ``allow``. Defining complementing categories for this
pseudo-object is not supported.

With some of the :term:`backend Prolog compilers <backend Prolog compiler>`
that support a module system, it is possible to load (the) Logtalk
(compiler/runtime) into a module other than the pseudo-module *user*. In
this case, the Logtalk pseudo-object *user* virtually contains all user
predicate definitions defined in the module where Logtalk was loaded.

.. _objects_logtalk:

The built-in object ``logtalk``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The built-in :ref:`logtalk <apis:logtalk/0>` object provides
:ref:`message printing <printing_messages>` predicates,
:ref:`question asking <printing_questions>` predicates,
:ref:`debug and trace event <debugging_events>` predicates, predicates for
accessing the internal database of loaded files and their properties, and
also a set of low-level utility predicates normally used when defining hook
objects. Consult its API documentation for details.
