This leads to no where if you want to have
real objects, namely objects that are based
on generalization and specialization of their
classes, and where the classes somehow define
the state of the object instances.
I was mentioning the setter/getter for this
reason. If you interchange A-B-C with s(A,B,C)
you might spare some unification. But if for
example a fourth property appreas, lets say
bar, you have to rewrite all four setters/
getters:
read(Read) --> self(s(Read,_,_,_)).
write(Write) --> self(s(_,Write,_,_)).
foo(Foo) --> self(s(_,_,Foo,_)).
bar(Bar) --> self(s(_,_,_,Bar)).
But what if the read and write setter/getter
was not defined by you but by someone else
in another module which is sealed, i.e. you
cannot modify. You can still hope that you
are allowed to override read and write. But
this is also not guaranteed.
So basically, if you can assure that the state
is only subject to single inheritance you
might want to meet an old fried, namely the
arg/3 predicate. Just use:
read(Read) --> self(Self), arg(1, Self, Read).
write(Write) --> self(Self), arg(2, Self, Write).
You can then freely add:
foo(Foo) --> self(Self), arg(3, Self, Foo).
bar(Bar) --> self(Self), arg(4, Self, Bar).
The only problem here, is that arg/3 doesn't work
when Self is not yet a compound. So you would need
to be more careful when you created the Self object
the first time, and for example have a new method,
in the class where only read and write is defined,
the new method would do:
new --> functor(Self, s, 2), self(Self).
In the class where also foo and bar are defined,
the class would override the new method, and define
it as follows, whereas I don't see yet how DCG
could model overriding:
new --> functor(Self, s, 4), self(Self).
I think for Prolog, since it doesn't have an institutionalized
OO system, the above are just programming patterns. So
that the following paper does a right discussion:
Programming Patterns for Logtalk Parametric Objects,
Paulo Moura, 2011
http://cracs.fc.up.pt/sites/default/files/c2011_pm_inap.pdf
The problem with an OO institutionalization is then that
there is quite a design space, and decisions that might
have been taken 10-20 years ago or so, might not be optimal.
In as far as DCG will persist here, I am not yet clear about.
For OO you would need to have generalization and specialization
as well. This goes into the calling mechanism of object sending.
In DCG the calling mechanism of a non-terminal is simply
extending it by the two input and output parameters. So
calling a non-terminal is primarily independent of the
given input and output parameters.
The input and output parameters only add to the arity but
the predicate name is the same as already seen in the DCG
phrase. But for object sending, a solution to the generalization
and specialization problem, is a form of late binding. I
don't know how complicated the mechanism is in Logtalk at
the moment.
My current proposable from Jekejeke is stupid simple, just
use the ISO module system to resolve the actual predicate name.
So the (::)/2 operator is simply defined as follows:
Receiver::Message :-
Message =.. [MessageName|Args],
functor(Receiver, Class, _),
Goal =.. [MessageName,Reciever|Args],
Class:Goal.
This is the pythonesk approach and the lua approach, and under
the hood also used in Java. In Java when a method is resolved
you get a method handle which has a method name and a declaring
class. The Class:Goal will resolve MessageName in the same
way and execute the Goal in the declaring class.
So following the rexport chain the find the declaring class,
every Prolog module system that implements the ISO module
standard should be able to do that. So no need for a bloathed
Logtalk OO system, we can directly work on top of the ISO
module system. Nevertheless there is a lot of work ahead:
- The (::)/2 is only the beginning, it is the head start
for the OO system
- We still need to find solutions that ease the definition
of method heads and method bodies, should we adopt
Logtalks {}/1 and Logtalks ^^/1 and Logtalks ::/1
or are there other solutions possible.
- We still need to find solutions that ease the definition
of properties should we adopt Logtalks parametric
objects or are there orther solutions possible.
All these decisions will lead to an institutionalization
of OO programming patterns, that are already available in
pure Prolog with an ISO module system. Everything that is done
is mapped to pure Prolog in some way or another, an example
beeing (::)/2 which has a pure Prolog definition.
But most likely the resulting language will be much more
dynamic than Logtalk. For example the head start (::)/2
already shows that anything dynamic is delegate to the ISO
module system. If the ISO module system can reload modules
at runtime, fine, the OO system will also be able to reload
classes at runtime.
Similarly there is no need to have a OO-system in the form
of a kind of compiler, that transforms Prolog texts. The
solutions to the methods and properties problems, can mostlikely
easily solved with term expansion. So that the OO-system will
be highly dynamic, no need for some clumsy command line control.
Just use your ordinary Prolog as usually, plus the definition
of (::)/2 and the other definitions.
Bye
Markus Triska schrieb: