2.5 Other Integration Approaches
2.5.2 Code Generation, Querying and Transformation Libraries
forming object-oriented code from within a logic language [42, 43, 118]. Most of them have similar features to Soul, but do not attempt to provide integration support from the object-oriented language perspective. Furthermore, the fea- tures from the logic language perspective are focused on meta-programming but are difficult to use for something else (e.g., to symbiotically call object-oriented routines from the logic side).
There are also generative approaches making use of quasiquotation that are employed to generate foreign language code, not necessarily object-oriented, from a logic program [142].
2.6 Multi-Paradigm Languages
A multi-paradigm language combines concepts from different programming paradigms in one single language. This has the advantage that no integra- tion approach is required between distinct languages, since concepts belonging to different paradigms coexist in the same language.
An example of an object-oriented language providing support for logic pro- gramming features is Oz [116].
Examples of logic languages also supporting object-oriented features are Log- talk [96, 95], Flora [146], SICStus Objects [53] and O’CIAO [113].
In the rest of this section we give an overview of Logtalk, which can be considered as a representative example among the existing approaches. Log- talk is also used as one of the underlying building blocks of our approach. Therefore, it is referenced in several chapters of this dissertation.
Logtalk
Logtalk supports both prototype-based or class-based hierarchies [128, 6], even in the same application. The first-order Logtalk entities are objects,
protocols and categories. Since we make use of certain Logtalk artefacts to
implement the components of our approach, we provide a short overview of them in this section.
Logtalk Objects
Objects serve as encapsulation units for predicates, thus providing namespaces allowing the separation of code in manageable units.
In Logtalk, the term object is used in a broad sense to denote a prototype,
parent, class, subclass, superclass, metaclass and an instance.
Object names can be atoms or compound terms. A Logtalk object is tex- tually defined by means of the directives: object/1-5 and end_object/0.
Code snippet 2.32 illustrates a declaration of an object named hello_object. The public/1 directive on line 3 declares the greet/0 predicate as part of the object’s public interface (i.e., it can be called from any object). Other possible access modifier directives are private/1 (i.e., it can be called only from the container object) and protected/1 (i.e., it can be called by the container object or by the container’s descendants). The implementation of the predicate greet /0 (line 4) just shows on the screen the Hello World message.
1 :- object ( hello_object ). 2
3 :- public ( greet /0).
4 greet :- write ( Hello World ). 5
6 :- end_object .
Sending Messages to Objects
In Logtalk, a message to an object can be sent using the ::/2 operator. Therefore, we could write hello_object::greet to send the message greet to the object hello_object.
If the message is not declared for the object an exception will be thrown. If the message is declared, but not defined, the message will simply fail (closed
world assumption [56]).
Parametric Objects
When an object name is a compound term, it is referred to as a parametric
object [97]. Code snippet 2.33 shows an alternative implementation of the pre-
vious object this time using the compound hello_object/1 as its name. The implementation of the greet/1 predicate (lines 4–7) refers to the first param- eter of the object by means of the parameter/2 predicate (line 6). Afterwards this parameter is shown on the screen (line 7).
1 :- object ( hello_object ( _Name )). 2 3 :- public ( greet /0). 4 greet :- 5 write ( Hello ), 6 parameter (1, Name ), 7 write ( Name ). 8 9 :- end_object .
Snippet 2.33: Declaring a Logtalk parametric object.
Prototypes
Prototypes are either self-defined objects or objects that are defined as exten- sions to other objects, their parent prototypes. With prototypes, there is no distinction between abstractions and concrete examples of these abstractions, as we have with classes and instances. Therefore, prototype semantics is simpler as there is only one possible relation between objects (extension), while with classes and instances we have to deal with both instantiation and specialisation relations.
For example, the hello_object/1 parametric object shown in code snippet 2.33 can play the role of a prototype. Then, an object talkative_hello_object /1 can extend it as shown in code snippet 2.34, line 2. In this example, the greet/0 predicate first delegates to its inherited definition (line 5) and then shows additional text on the screen (line 6).
1 :- object ( talkative_hello_object ( _Name ), 2 extends ( hello_object ( _Name ))).
3
4 greet :-
5 ^^ greet ,
6 write ( . How are you ? ). 7
8 :- end_object .
Snippet 2.34: Declaring a Logtalk parametric object.
Classes
A class is a role played by a Logtalk object. In other words, there is no class keyword specifying that an object is a class. Instead, an object is considered a class or an instance if it, respectively, specialises (code snippet 2.35) or instan- tiates (code snippet 2.36) another object (that would be playing the role of a class).
1 :- object ( object ,
2 specializes ( class )). 3
4 % predicates common to all instances of the class
5
6 :- end_object .
Snippet 2.35: Object specializing a class.
1 :- object ( object ,
2 instantiates ( class )). 3
4 % predicates common to all instances of the class
5
6 :- end_object .
Snippet 2.36: Object instantiating a class.
If an object plays the role of a class, it declares and possibly defines predicates for its instances.
Protocols
Protocols enable separation between interface and implementation. They are equivalent to the notion of interfaces in languages such as Java.
A protocol can only contain predicate declarations concerning a single func- tionality. In Logtalk, a protocol can be implemented by several objects and an object can implement several protocols. A Logtalk protocol is defined using of the directives protocol/1-2 and end_protocol/0, as demonstrated in code snippet 2.37. 1 :- protocol ( hello_protocol ). 2 3 :- public ( greet /0). 4 5 :- end_protocol .
Snippet 2.37: Declaring a Logtalk Protocol.
Both objects and categories can implement a protocol, as shown in code snippets 2.38 and 2.39.
1 :- object (Object , 2 implements ( hello_protocol )). 3 4 greet :- ... 5 ... 6 :- end_object .
Snippet 2.38: An object implementing a Logtalk protocol.
1 :- category (Object , 2 implements ( hello_protocol )). 3 4 greet :- ... 5 ... 6 :- end_object .
Snippet 2.39: A category implementing a Logtalk protocol.
When a protocol is implemented by an object (or a category; described next), the definition of all its declared methods is not mandatory. When an object receives as a message a predicate declared by a protocol where such predicate has been left undefined the message will fail. This is because Logtalk im- plements a closed world assumption, where the absence of a definition implies failure. This is contrary to an object receiving an unrecognised message, where in this case an error will be thrown.
Categories
Logtalk also supports categories, which are fine-grained units of code reuse and can be seen as a dual concept of protocols that can contain both predicate declarations and definitions. As protocols, categories should describe a single functionality. The concept of categories is similar to the concept of mixins [8] and “provide a way to encapsulate a set of related predicate declarations and definitions that do not represent an object and that only make sense when composed with other predicates” [99]. Categories can be (virtually) imported by any object, independently of the roles that object plays (e.g., prototypes or classes). A category cannot be used as a stand-alone object, i.e., it cannot be the target of a Logtalk method invocation.
An example of a simple category declaration is shown in code snippet 2.40. As the example shows, a category is defined using the directives category/1-2 and end_category/0. 1 :- category ( hello_category ). 2 3 :- public ( greet /0). 4 greet :- 5 parameter (1, Name ), 6 write ( Name ). 7 8 :- end_category .
The syntax for importing a category into an object is shown in code snippet 2.41. 1 :- object (Object , 2 imports ( hello_category )). 3 ... 4 :- end_object .
Snippet 2.41: An object importing a Logtalk category.
Logtalk Portability
One advantage of Logtalk in comparison with other alternatives is its wide portability across Prolog implementations. For a description of Logtalk other features we refer to the Logtalk documentation [99, 98, 94].