Logtalk user manual
Objects
Contents > User Manual > 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 does not aim to bring some sort of new dynamic state change concept to Logic Programming or Prolog.

In Logtalk, the only pre-defined objects are the built-in objects `user` and `logtalk`, which are described at the end of this section.

## 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).

### 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.

### 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.

## 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.

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: `object/1-5` and `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(Protocol)).
        ...
    :- end_object.

An object can import one or more categories:

    :- object(Object,
        imports(Category)).
        ...
    :- end_object.

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

    :- object(Object,
        implements(Protocol),
        imports(Category)).
        ...
    :- 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) is always compiled as 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 [Cointe 87, Moura 94]. For example:

    :- object(object,               % default root of the inheritance graph
        instantiates(class)).       % predicates common to all objects
        ...
    :- end_object.

    :- object(class,                % default metaclass for all classes
        instantiates(class),        % predicates common to all instantiable classes
        specializes(abstract_class)).
        ...
    :- end_object.

    :- object(abstract_class,       % default metaclass for all abstract classes
        instantiates(class),        % predicates common to all classes
        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.

## Parametric objects

Parametric objects have a compound term for name instead of an atom. This compound term usually contains free variables that 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 parameters, Logtalk provides the `parameter/2` built-in local method:

    :- object(Functor(Arg1, Arg2, ...)).

        ...

        Predicate :-
            ...,
            parameter(Number, Value),
            ... .

An alternative solution is to use the built-in local method `this/1`. For example:

    :- object(foo(Arg)).

        ...

        bar :-
            ...,
            this(foo(Arg)),
            ... .

Both solutions are equally efficient because the runtime cost of the methods `this/1` and `parameter/2` is negligible. 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 (`::/2`, `::/1`, or `^^/1`).

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.

## Finding defined objects

We can find, by backtracking, all defined objects by calling the `current_object/1` built-in predicate with a non-instantiated variable:

    | ?- current_object(Object).

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).

## Creating a new object in runtime

An object can be dynamically created at runtime by using the `create_object/4` built-in predicate:

    | ?- 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 instance, the call:

    | ?- 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.

## Abolishing an existing object

Dynamic objects can be abolished using the `abolish_object/1` built-in predicate:

    | ?- abolish_object(Object).

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

## 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.

### Object initialization

We can define a goal to be executed as soon as an object is (compiled and) loaded to memory with the `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.

### 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 `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.

### Object documentation

An object can be documented with arbitrary user-defined information by using the `info/1` directive:

    :- info(List).

See the documenting Logtalk programs section for details.

### Loading files into an object

The `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 database into an object thus providing a simple way to encapsulate it. 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(includes(databases('cities.pl'))).

    :- end_object.

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

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

## 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 built-in predicates `instantiates_class/2` and `instantiates_class/3` can be used to query all instantiation relations:

    | ?- instantiates_class(Instance, Class).

or, if we want to know the instantiation scope:

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

Specialization relations can be found by using either the `specializes_class/2` or the `specializes_class/3` built-in predicates:

    | ?- specializes_class(Class, Superclass).

or, if we want to know the specialization scope:

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

For prototypes, we can query extension relations with the `extends_object/2` or the `extends_object/3` built-in predicates:

    | ?- extends_object(Object, Parent).

or, if we want to know the extension scope:

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

In order to find which objects import which categories we can use the built-in predicates `imports_category/2` or `imports_category/3`:

    | ?- imports_category(Object, Category).

or, if we want to know the importation scope:

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

To find which objects implements which protocols we can use the `implements_protocol/2-3` and `conforms_to_protocol/2-3` built-in predicates:

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

or, if we also want inherited protocols:

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

Note that, if we use a non-instantiated variable for the first argument, we will need to use the `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 `complements_object/2` built-in predicate:

    | ?- complements_object(Category, Object).

Note that more than one category may explicitly complement a single object.

## Object properties

We can find the properties of defined objects by calling the built-in predicate `object_property/2`:

    | ?- 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 `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 `<</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 properties for a predicate declared by the object
`defines(Predicate, Properties)`
  List of properties for a predicate defined by the object
`includes(Predicate, Entity, Properties)`
  List of properties for an object multifile predicate that are defined in the specified entity (the properties include `number_of_clauses(Number)` and `line_count(Line)` with `Line` being the begin line of the multifile predicate clause)
`provides(Predicate, Entity, Properties)`
  List of properties for other entity multifile predicate that are defined in the object (the properties include `number_of_clauses(Number)` and `line_count(Line)` with `Line` being the begin line of the multifile predicate clause)
`alias(Predicate, Properties)`
  List of properties for a 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 properties for predicate calls made by the object (`Call` is either a predicate indicator or a control construct such as `^^/1` with a predicate indicator as argument; note that `Call` may not be ground when the control construct is `::/2` and the object argument is only know at runtime; the properties include `caller(Caller)` and `line_count(Line)` with `Caller` being a predicate indicator and `Line` being the begin line of the predicate clause or directive making the call)
`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 expansion hooks)
`number_of_user_clauses(Number)`
  Total number of user-defined predicate clauses defined in the object at compilation time

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

## Built-in objects

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

### The built-in pseudo-object user

Logtalk defines a built-in, pseudo-object named `user` that virtually contains all user predicate definitions not encapsulated in a Logtalk entity. These predicates are assumed to be implicitly declared public. Messages sent from this pseudo-object, which includes messages sent from the top-level interpreter, always generate events. Defining complementing categories for this pseudo-object is not supported.

### The built-in object logtalk

Logtalk defines a built-in object named `logtalk` that provides structured message printing mechanism predicates, structured question asking predicates, debugging event 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.

The following predicates are defined:

`expand_library_path(Library, Path)`
  Expands a file specification in library notation to a full operating-system path.
`loaded_file(Path)`
  Returns the full path of a currently loaded source file.
`loaded_file_property(Path, Property)`
  Returns a property for a currently loaded source file. Valid properties are `basename/1`, `directory/1`, `flags/1` (explicit flags used when the file was loaded), `text_properties/1` (list, possibly empty, whose possible elements are `encoding/1` and `bom/1`), `target/1` (full path for the Prolog file generated by the compilation of the loaded source file), `modified/1` (time stamp that should be treated as an opaque term but that may be used for comparisons), `parent/1` (parent file, if it exists, that loaded the file), and `library/1` (library name when there is a library whose location is the same as the loaded file directory).

`compile_aux_clauses(Clauses)`
  Compiles a list of clauses in the context of the entity under compilation. This method is usually called from `goal_expansion/2` hooks in order to compile auxiliary clauses generated for supporting an expanded goal. The compilation of the clauses avoids the risk of making the predicate whose clause is being goal-expanded discontiguous by accident.

`entity_prefix(Entity, Prefix)`
  Converts an entity identifier into its internal prefix or an internal prefix into an entity identifier.

`compile_predicate_heads(Heads, Entity, TranslatedHeads, ContextArgument)`
  Compiles a predicate head or a list of predicate heads in the context of the specified entity or in the context of the entity being compiled when `Entity` is not instantiated.
`compile_predicate_indicators(PredicateIndicators, Entity, TranslatedPredicateIndicators)`
  Compiles a predicate indicator or a list of predicate indicators in the context of the specified entity or in the context of the entity being compiled when `Entity` is not instantiated.
`decompile_predicate_heads(TranslatedHeads, Entity, EntityType, Heads)`
  Decompiles a compiled predicate head or a list of compiled predicate heads returning the entity, entity type, and source level heads. Requires the entity to be currently loaded.
`decompile_predicate_indicators(TranslatedPredicateIndicators, Entity, EntityType, PredicateIndicators)`
  Decompiles a compiled predicate indicator or a list of compiled predicate indicators returning the entity, entity type, and source level predicate indicators. Requires the entity to be currently loaded.

`execution_context(ExecutionContext, Entity, Sender, This, Self, MetaCallContext, Stack)`
  Allows constructing and accessing execution context components.

`print_message(Kind, Component, Term)`
  Prints a message term after converting it into a list of tokens using the `message_tokens//2` hook non-terminal. When the conversion fails, the message term itself is printed.
`print_message_tokens(Stream, Prefix, Tokens)`
  Prints a list of message tokens to the specified stream and prefixing each line with the specified prefix.
`print_message_token(Stream, Prefix, Token, Tokens)`
  Hook predicate, declared multifile and dynamic, allowing the default printing of a token to be overridden.
`message_tokens(Term, Component)`
  Hook non-terminal, declared multifile and dynamic, allowing the translation of a message into a list of tokens for printing.
`message_prefix_stream(Kind, Component, Prefix, Stream)`
  Hook predicate, declared multifile and dynamic, allowing the definition of line prefix and output stream for messages.
`message_hook(Term, Kind, Component, Tokens)`
  Hook predicate, declared multifile and dynamic, allowing the overriding the default printing of a message.

`trace_event(Event, EventExecutionContext)`
  Hook predicate, declared multifile and dynamic, for handling trace events generated by the execution of source code compiled in debug mode. The Logtalk runtime calls all defined handlers using a failure-driven loop. Thus, care must be taken that the handlers are deterministic to avoid potential termination issues.
`debug_handler_provider(Provider)`
  Multifile predicate for declaring an object that provides a debug handler. There can only be one debug handler provider loaded at the same time. The Logtalk runtime uses this hook predicate for detecting multiple instances of the handler and for better error reporting.
`debug_handler(Event, EventExecutionContext)`
  Multifile predicate for handling debug events generated by the execution of source code compiled in debug mode.

To use these predicates, simply send the corresponding message to the `logtalk` object.