Logtalk is actually the famous Object Oriented Prolog available today. Paulo made it available as a pack , so installation should be very simple.
Modules are not suitable for orientation of objects. They are more like namespaces, but without nesting. In addition, the ISO standard is a bit of a contradiction.
SWI-Prolog v7 introduced dicts , an extension that at least handles the historical problem of the language and provides accessible โfieldsโ, by name and syntax for โmethodsโ. But still, no inheritance ...
change
I have added a small example of object orientation in SWI-Prolog here. This is the evolution of my test application for creating family trees.
By comparing the sources of genealogy.pl, you can evaluate how the latest version uses the module specifier and not the directive: - multifile, and then can work with several trees.
You can see that the calling module is passed by the building code of the graph, and have optional or mandatory predicates that are called by the module qualification:
make_rank(M, RPs, Rp-P) :- findall(G, M:parent_child(P, G), Gs), maplist(generated(M, Rp, RPs), Gs).
optional predicates must be called as
... catch(M:female(P),_,fail) -> C = red ...
Note that predicates are not exported by applicative modules. By exporting them, AFAIK disrupts the orientation of the object.
===========
Another, perhaps more trivial, example of object orientation is the pqGraphviz_emu module, where I created a simple mental replacement of system level objects.
I will explain: pqGraphviz is a tiny layer - written in Qt - above the Graphviz library. Graphviz - albeit in C - has an object-oriented interface. Indeed, the API allows you to create appropriate objects (graphs, nodes, links), and then assign attributes to them. My layer is trying to keep the API most similar to the original. For example, Graphviz creates a node with
Agnode_t* agnode(Agraph_t*,char*,int);
I wrote using the C ++ interface
PREDICATE(agnode, 4) { if (Agnode_t* N = agnode(graph(PL_A1), CP(PL_A2), PL_A3)) return PL_A4 = N; return false; }
We exchange pointers, and I set up the Qt metatep tool to handle input ... but since the interface is pretty low, I usually have a tiny middle layer that provides a more applicative look, and this middle level interface called from genealogy.pl:
make_node(G, Id, Np) :- make_node(G, Id, [], Np). make_node(G, Id, As, Np) :- empty(node, N0), term_to_atom(Id, IdW), N = N0.put(id, IdW), alloc_new(N, Np), set_attrs(Np, As), dladd(G, nodes, Np).
In this snippet you can see an example of SWI-Prolog v7 dicts:
... N = N0.put(id, IdW), ...
The memory allocation scheme is processed in allocator.pl.