Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Quo Vadis Modules: How about abstract/1 ?

225 views
Skip to first unread message

janb...@easel.ch

unread,
Jun 11, 2018, 5:08:35 PM6/11/18
to
OO-Prologs have a long tradition. Chris Moss once handed
me a copy of his book Prolog++. I still have it, I got
it in August 1994, when there was even no Logtalk yet.

Chris Moss, Prolog++: The Power of Object-Oriented and Logic Programming
https://en.wikipedia.org/wiki/Prolog%2B%2B

Of course the goal of any OO system is to make virtual
calls effortless. Otherwise you shouldn't even touch making
an OO system. This has to do that without an effortless virtual

call, many OO typical programming patterns cannot be used.
For example visitor pattern etc.. Such patterns are often
solved Prolog-ish in different ways. But if you solve it

in another way, and if you don't use virtual calls, why
use Logtalk at all. Doesn't make any sense at all. You
can use modules and reexport or use_module to

share code. You also have in the ISO core standard
the following feature:

... have to look it up, either in core or module,
a predicate can be in a state that it is half defined,
i.e. it exists but has no clauses, and throws an
error if invoked ...

Looking at the many modifiers that Java has I
noticed that Logtalk already implements public/1,
private/1 and protected/1.

I do not yet have protected/1. But I got the idea to
implement abstract/1 just now. One could do what some of
the Logtalk prototypes or who knows what do. One could

for example make a pure abstract module as follows:

:- module(arith, []).
:- abstract add/3.
:- abstract sub/3.
:- abstract neg/2.
...

The effect would be that such a half backed predicate
is created, I have already an internal predicate for that,
that can create such predicates:

sys_neutral_predicate(I):
If no predicate has yet been defined for the predicate indicator I, defines a corresponding neutral predicate.
http://www.jekejeke.ch/idatab/doclet/prod/en/docs/05_run/10_docu/02_reference/07_theories/01_kernel/03_body.html

What I do not yet have is an "abstract" attribute of a predicate.
But taking into account this "abstract" attribute, I could adapt
the current style check for modules,

that looks for unimplemented predicates. And maybe I could
also adapt the predicate lookup. This would satisfy some
of the Logtalk software engineering appeal.

In the end I would have both performance and
software engineering appeal.

Even this "abstract" attribute would come very handy for
my Java class auto loader. I could also assign the attribute
to auto loaded classes and members, if they have it already.

Maybe I should do the "abstract" attribute first, and the
"protected" modifier attribute later. Ha Ha. Can be used for
a lot more, already found in the Logtalk univers by

other names. But for example in Java interface classes,
are just classes where all the members are by default
"abstract" and "public". So such things could be also done.

I have actually some use cases for this scenario:
- It serves as a documentation tool, other than
no predicate declared, its abstractly declared.
- It helps in making the code robust, other error
than simply predicate undefined
- It helps in debugging the code, other error than
simply predicate undefined.

Although its not really a contribution to speed. Its a
contribution to make the OO system more complete, and map
some OO patterns, OO practice to the OO system.

The next step would be to allow a modifier for the
module declaration, for example, as such:

:- abstract module(arith, []).

Then term objects and/or proxy objects from the module
arith would not anymore be allowed. Etc.. Etc..

But please note: This would again be based on the native
module system. So that the end-user doesn't have to learn
anything new, execpt the modifiers.

burs...@gmail.com

unread,
Jun 12, 2018, 6:55:09 AM6/12/18
to
Further brain storming: The visibility modifiers are possibly
also a further factor in a discussion about the pros-and cons
of Logtalk {}/1 wrap and of ISO core module wrapless plain

predicates. Here are some observation:
- If plain predicates, their lookup, also respectes visibility
modifiers, then private plain predicates would not be lookek-
up,not be found.

So the preservation of Logtalk against wrapless ISO plain
predicates inside modules is void for private user predicates,
they would be anyway not visible.

- Further if a user predicate is marked public, as I said, if
we allow visibility modifiers also for plain predicates, and
it is marked public.

This could be indicative that the end-user **wants** that it
gets looked up as a plain predicate. But possibly we now
touch a sceanrio where truth maintanence would be needed.

- What I dunno yet, is what package private should mean
for plain predicates. So far it meant inside the same file
name package, but this would prevent **patching**,

So I guess I should make package private mean for
all user modules, and then again the Logtalk preservation
would be void, such predicates would also not be seen inside
a non-user, since a named module would have a different package.

Maybe I should really change the same package check this
way, and give user predicates a little bit more visibility when
package private, but this would not leak then into named modules.

Interesting.... But it requires that you have public/1, private/1,
etc.. modifiers also for plain code! Which is availabkle in Jekejeke
Prolog, the modifiers also work for plain code.

burs...@gmail.com

unread,
Jun 12, 2018, 6:55:48 AM6/12/18
to
My current package visibility is done by this code:

I am using the file name and not the module name,
because I offer this feature also for unnamed modules.

/**
* <p>Check whether this source has the same package as another source.</p>
*
* @param fst The first source, not null.
* @param snd The second source, not null.
* @return True if the two sources share the same package, otherwise false.
*/
public static boolean samePackage(AbstractSource fst, AbstractSource snd) {
https://github.com/jburse/jekejeke-devel/blob/master/jekrun/headless/jekpro/model/molec/OperatorSearch.java#L528

burs...@gmail.com

unread,
Jun 12, 2018, 6:58:05 AM6/12/18
to
I guess I should redo my code. I found a use-case
for using the module name instead of the file path,
for package visibility. Module names can be flat

or hierarchical. If hierarchical module names are
avaibale, a same package check can work as follows.
For two hierarchical module names as follows:

<package1>/<name1>

<package2>/<name2>

Same package means <package1> = <package2>. Now how
does this help code patching? You can use it, in case
you want to do the following:
- Code patching:
- Assume you have a ZIP with some Prolog code,
but in one little package packageX, you want to
patch one little moduleY.

- In Java, I guess one way to do this, is just add
an additional ZIP to the class path, which has
packageX/moduleY patched.

- To have package visibility still working you
need to make the visibility check based on
the synthetic module name, not on the path.

- Why not on the path? Because the path would
tell two different ZIPs, and not the same package.
So the new packageX/moduleY would not be callable.

burs...@gmail.com

unread,
Jun 12, 2018, 8:07:56 AM6/12/18
to
Further brainstorming/brainwriting: The discussion is
very broad, {}/1 versus non-{}/1, multiple implementation
of an interface, meta-predicate declarations, etc..

Here is a nice example of multiple implementation of
the same interface pattern. That only works half way,
but it works already sufficiently I guess, across

different Prolog systems. The idea is to use this
pattern for multiple implementations of the same
interface:

File interface:
:- module(interface, []).

File implementation1:
:- module(implementation1, []).
:- reexport(interface).

File implementation2:
:- module(implementation2, []).
:- reexport(interface).

All that was used was modern :- module/2, as already
found in many Prolog systems, and reexport/1, which is
also found in many Prolog systems, but also defined by ISO:

ISO/IEC 13211-2 First edition 2000-06-01
6.2.4.4 Module interface directive reexport/1

j4n bur53

unread,
Jun 12, 2018, 8:10:21 AM6/12/18
to
I made on purpose a test, which is possibly out of
reach of Logtalk, since it has to do with operators.
So I put an operator (++)/2 into the interface.

SWI-Prolog can do it partially. It cannot do it fully,
since it uses meta_predicate semantics for modules.
The rexport/1 is respected during consult file,

hence during the read_term there:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.15)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- assertz(user:prolog_file_type(p, prolog)).
true.

?-
ensure_loaded('C:\\Projects\\Jekejeke\\Prototyping\\experiment\\other\\prolog2\\fareast\\logtalk\\implementation1.p').
++(foo,bar)
true.

?-
ensure_loaded('C:\\Projects\\Jekejeke\\Prototyping\\experiment\\other\\prolog2\\fareast\\logtalk\\implementation2.p').
foo++baz
true.

But what doesn't work is the reverse, the write_term. This has
to do that the SWI-Prolog module system is meta_predicate driven.
This means calls and so on work. But term writing has no clue

at all about modules. The second write works, since ensure_loaded/1
polutes the user namespace. I made my own test with sys_auto_load/1,
I do not know currently whats the SWI-Prolog equivalent to sys_auto_load/1,

but I can make more demonstrate that the (++)/2 operator is properly in
its own namespace. This is not the real issue for SWI-Prolog, I guess
it has the (++)/2 operator also properly in its own namespace:

Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland
?-
sys_add_path('file:/C:/Projects/Jekejeke/Prototyping/experiment/other/prolog2/fareast/logtalk/').
Yes

?-
sys_auto_load('file:/C:/Projects/Jekejeke/Prototyping/experiment/other/prolog2/fareast/logtalk/implementation1.p').
foo++bar
Yes

?-
sys_auto_load('file:/C:/Projects/Jekejeke/Prototyping/experiment/other/prolog2/fareast/logtalk/implementation2.p').
foo++baz
Yes

?- X = foo ++ bak.
Error: Superfluous token.
X = foo ++ bak.
^

I do not know what can be done to fix the writing in case of SWI-Prolog.
Some write option? My expectation: A write inside a module should do
the right thing automatically.

I uploaded some screenshots, in case you don't believe me. I put
the little Prolog text of interface, implementation1 and implementation2
also on the same gist:

https://gist.github.com/jburse/98796d20e58bbd6d5474dad5135b5bff#gistcomment-2617329

burs...@gmail.com schrieb:

burs...@gmail.com

unread,
Jun 12, 2018, 1:26:25 PM6/12/18
to
More brainwriting:

Maybe the distinction should be made between semantic modelling,
and OO programming. For OO programming, for example if only
single inheritance is needed, its evident that the reexport/1 directive

builds a function table, and in the case of single inheritance, you
can easily turn this function table, into a virtual function table lookup
and use the module as class name for instances.

But in the case multiple inheritance, maybe one would anyway
use RDF, OWL, Description Logics, etc.. whatever, where its more
common to use logical inferences,

also in RDF, OWL, Description Logics, etc.. you might have
forward chaining, which would give you truth maintenance, if
you desire so. These systems again are more specialized

to also return meta information about their own objects. The
requirements for OO programming and semantic modelling
are slightly different in my opinion. What works for semantic

modelling doesn't necessary work for OO programing. Anyway,
I wont bother you anymore. For every problem the right tool.
In my opinion Logtalk is neither fish nor bird. It tries a balancing

act between semantic modelling and OO programming, but
in my opinion for sure harms OO programming. For OO
programming the most important is performance of

virtual methods and this kind. Java had in the past a couple
of patents which guarded their aproaches. From Python
we have PEPs with some technology. OO programming

languages is a total different turf which you need to approach
natively, otherwise you don't produce something useful...

burs...@gmail.com

unread,
Jun 12, 2018, 1:30:41 PM6/12/18
to
That Logtalk is a brain child of semantic modelling
is seen in this early paper. Its just GOFAI
frames/slotes/facets:

Logtalk: Object-Oriented Programming in Prolog (1994)
by Paulo Moura, Ernesto Costa
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.48.2295

Thats not how you do an OO-system nowadays. Thats
like the first hurdle, of getting clear **what**
is in the meta model of the OO-system.

But then... you need to invent.

burs...@gmail.com

unread,
Jun 12, 2018, 1:32:06 PM6/12/18
to
You need to invent:

For example the goal of an OO-system to deliver
meta information is much more limited. You could provide
some reflection, which can be useful to discover services

etc.. But typically you don't bother providing bidirectional
predicates for meta information, that tell you everything
about the OO-system for all directions.

If you want an analysis of such data, you can for
example use in Java javadoc. Which does extract from
source code on its own a meta model of the program

and provide grouping in its output along diverse
axis etc.. Its just a separate tool, not directly married
at runtime with the OO system.

P.S.: Technically Java javadoc shares some of
the token scanner and parser of Java javac.
Basically they share tools.jar from the Java distribution.

But its really a separate tool. Thats probably one criteria
for the distinction between an OO-system and semantic
modelling. Logtalk might have the idea, that such a restriction

doesn't exist. But every restriction that is willfully lifted,
should not sacrifice performance. For an OO-system this
is really the holy grail. No performance, no OO-system.

I have a lot of example where this is extremly important,
for example computer algebra, deep learning, auto diff, etc...
No performance, no computer algebra, no deep learning,

no auto diff, etc... Without performance, with the usually
OO programming patterns how you program these things,
these things simple don't work anymore...

janb...@easel.ch

unread,
Jun 14, 2018, 8:12:55 PM6/14/18
to
Hi Jan W.,

You invented already OO via ISO modules. Maybe you never
tried it. But it seems to work, exactly as I suggest to use
reexport/1 for inheritance.

I am not taking my PythonStyleCall, but your DictStyleCall.
It is documented here. In your DictStyleCall the receiver
is always the but last argument, and you also assume a
last argument because you only think about functions:

<module>:<name>(Arg1, ..., +Dict, -Value)
http://www.swi-prolog.org/pldoc/man?section=ext-dict-user-functions

So lets make an inheritance example:

File subject.pl:

:- module(subject, [name/2]).
M.name() := N :-
N is M.name.

File person.pl:

:- module(person, []).
:- reexport(subject).

And here is the result:

?- X = person{name:123}.name().

X = 123.


Works perfectly, or did I miss something. The only difference to my
OO-system, is that the PythonStyleCall can be used for both predicates
and functions, respectively the PythonStyleCall doesn't care what
mode the predicate has. You simply put the receiver in the first argument.

Then my OO-system didn't sacrifice ISO core standard compatibiity.
I didn't change consing, i.e. ('.')/2 is still the consing because I use
(::)/2 for message sending. Also in the PythonStyleCall you don't
need (:=)/2 to define a method, neither () in a call.

So my PythonStyleCall is less intrusive to the ISO core standard,
than your DictStyleCall. But its the same idea, as you have documented
in the link above, to use ordinary ISO module standard (:)/2 operator
for message dispatch.

Best Regards

Am Dienstag, 12. Juni 2018 19:32:06 UTC+2 schrieb burs...@gmail.com:
> You need to invent:

janb...@easel.ch

unread,
Jun 14, 2018, 8:51:32 PM6/14/18
to
We do not have dict proper in my system, but we can
simulate some of the dict functionality, and get
the same result:

?- person(name,123)::name(X).
X = 123

I uploaded all the test sources, showing that inheritance
works, to Gist. Proof of concept for SWI-Prolog and
my system. There are also some screenshots:

reexport/1 for inheritance in SWI-Prolog
https://gist.github.com/jburse/98796d20e58bbd6d5474dad5135b5bff#gistcomment-2620313

The operator (::)/2 can also do the dict functionality,
since for a term object which is a receiver, when extracting
the module from the given receiver term object, the arity

of the receiver term object is irrelevant. So I can also
pass arbitrary long dicts as a key value pairs coded
in the arguments of compound. But I do not have a

dict syntax. But basically the (::)/2 operator from my
system, can do the same as your (.)/2 operator. But my
(::)/2 operator does not involve any term expansion. Its

an ordinary builtin predicate. What I wonder is whether Logtalk
would support dicts in anyway, or whether it has already
such a term object data structure?

Disclaimer: I hope my SWI-Prolog and inheritance
as reexport/1 testing is correct, and the result is not
some artefact of the user context.

janb...@easel.ch

unread,
Jun 15, 2018, 8:52:52 AM6/15/18
to
I assume Pythonesk OO is not very well known,
so I expand again.

oncerning what you wrote, you would need to define
what you mean by class context, and what you want to
do with it. In both PythonCallStyle and DictCallStyle,

you have the class of the receiver available from the
receiver, and you can do further message sending to
the receiver just by ordinary message sending.

In both PythonCallStyle and DictCallStyle the self is
just a formal parameter you can give any name you
want. In your DictCallStyle examples you use M.

Python typically uses "self", but its just an ordinary
formal parameter of a routine (or a function pointer).
Here is an example in your DictCallStyle setting calling self.

To illustrate my point I renamed your M to Self, its
based on your M here:

M.multiply(F) := point{x:X, y:Y} :-
X is M.x*F,
Y is M.y*F.

http://www.swi-prolog.org/pldoc/man?section=ext-dict-user-functions

To show some self calling, I blowed up the example
and accesed x and y by extra functions insted by the dict
accessor:


Self.multiply(F) := point{x:X, y:Y} :-
X1 = Self.x(), X is X1*F,
Y1 = Self.y(), Y is Y1*F.

Self.x() := X :-
X is Self.x.

Self.y() := Y :-
Y is Self.y.

Here is the reult when you run it:


Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.15)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- X = point{x:1, y:2}.multiply(2).
X = point{x:2, y:4}.

Thats the same in Python. self is just a function formal
parameter (and of course also actual parameter), which
could also give other names.

In my system I adopted the Python approach. Your
Dict approach has a different argument order and is
not directly compatible with the Python approach.

Here is the Python approach described:

Python decided to do methods in a way that makes the instance to
which the method belongs be passed automatically, but not received
automatically: the first parameter of methods is the instance the
method is called on.
https://stackoverflow.com/a/2709832/502187

And here is that you can choose the name of self by yourself:

That makes methods entirely the same as functions, and
leaves the actual name to use up to you (although self is the
convention, and people will generally frown at you when you use
something else.) self is not special to the code, it's just
another object.
https://stackoverflow.com/a/2709832/502187

Thats a tremendous simplification. For automatic passing you
provide an operator, like in my system its the (::)/2 operator.
But automatic receiving you don't need anything.

The programmer just uses any name he likes for self. And
in PythonCallStyle its the first argument. In DictCallStyle its
effectively the last but one argument, but

you introduced (:=)/2. The (:=)/2 is not really necessary.
Especially if you would switch to PythonCallStyle since then
self is anyway the first argument, you get a nice reading.

If you would use PythonCallStyle you could also bind
foreign libraries more easily. The PythonCallStyle makes also
the FFI more easily. I use the PythonCallStyle to invoke

Java foreign functions that are virtual methods.

j4n bur53

unread,
Jun 15, 2018, 8:54:51 AM6/15/18
to
For self sending you just use the receiver variable name,
that you can decide on your own. Works like a charm.

I have made a picture of the SWI-Prolog run, and also
uploaded the point.pl source on Gist:

https://gist.github.com/jburse/98796d20e58bbd6d5474dad5135b5bff#gistcomment-2620758

Works also in my system analogously:

?- point(x,1,y,2)::multiply(2,X).
X = point(x,2,y,4)


The self sending is inside the multiply method. You need
to look at the source code on Gist.

But its all implement Pythonesk.

janb...@easel.ch schrieb:

Julio Di Egidio

unread,
Jun 15, 2018, 9:02:08 AM6/15/18
to
On Friday, 15 June 2018 14:52:52 UTC+2, janb...@easel.ch wrote:

> I assume Pythonesk OO is not very well known,
> so I expand again.

What's the point of doing OO on top of Prolog? Moreover, partitioning of code,
as with modules, isn't per se OO: it exists since more or less the invention of
structured languages. OTOH, the peculiarity and strength of the logical paradigm
(vs the imperative on a side and functional on the other) is...?

Julio

janb...@easel.ch

unread,
Jun 15, 2018, 11:42:11 AM6/15/18
to
Logtalk is doing OO on top of Prolog. It doesn't
use the ISO module system. My proposal suggests
using the ISO module system.

So its kind of doing OO inside a Prolog system,
and not on top a Prolog system. You can still
combine it with clause indexing.

In Python style, you can do the following:

graph(Self, zurich, munich, ..) :- ...
graph(Self, munich, dusseldorf, ..) :- ...

In Python style you can return multiple values
at once, if you have such a call pattern. You
could use the OO to implement some of

RDF partitioning of graphs. Etc.. Etc.. Thats
currently not my motiviation. One motivation
I had was binding to Java. Still exploring

what can be done.

burs...@gmail.com

unread,
Jun 15, 2018, 2:53:33 PM6/15/18
to
Maybe the problem is that nobody takes
the ISO core module standard seriously,
and even expects that it contains some

useful building blocks. Ok I am a little
lazy to reread it, but I guess I will do
it in the next days. Here is my

claim about the ISO core module standard,
which fits perfectly well together with
Pythonesk style method clauses:

Lets say sig(N) is the export list of each
module N. Then tran_sig(N) is the visible
predicates list (see ISO core module standard)

in each module. It has the following algorithm

tran_sig(N) :
Res := sig(N)
for each reexport(K) of N
Res := Res u tran_sig(K)
return Res

Ok, if I have time I will try to verify that.
I am curious what wording the ISO module
standard is using, where it exactly makes

a more formal definition, and whether he
leaves some stuff open, implementation defined
and/or implementation specific.

The document is:

ISO/IEC 13211-2
First edition 2000-06-01

I am working on it...

burs...@gmail.com

unread,
Jun 20, 2018, 4:25:05 AM6/20/18
to
Besides a abstract/1 directive, on my wishlist
I also find a final/1 directive. Like the abstract
directive, which has its correspondence by the

absract modifier in Java, the final directive
would work similarly like the corresponding
final modifier in Java. So for example without

the final/1 directive we would be allowed to do:

:- module(person, [show/1]).
:- reexport(subject).

:- override show/1.
show(Self) :-
...
subject:show(Self)
...

Thus overriding show/1, and inside show/1 call
super, via directly refering to the super class.
Now if subject had been defined with final/1 directive:

:- module(subject, [show/1]).

:- final show/1.
show(Self) :-
...

The the Prolog module loader would not accept
the override anymore. Since the predicate that is
overridden, is marked final. The final modifier
would prevent overriding.

Historical Note: I don't know the exact history
of a final modifier. Java has it. Possibly already
in its version 1.0. Also Telesript had it, its
name was sealing. I find:

Elaborating upon inheritance
A class can be a mix-in rather than a flavor.
A mix-in cannot have instances. Every immediate
subclass of a mix-in is a subclass of a class
the mix-in designates as its anchor. The anchor or
its anchor, recursively, is a flavor.

A class or feature can be sealed. A sealed class
cannot have user-defined immediate subclasses. A
sealed feature cannot be implemented by userdefined
subclasses of the class that defines it. A class is
sealed by itself. A feature is sealed by a class that
defines or inherits an implementation of it.

A class or feature can be abstract rather than concrete.
An abstract class cannot have instances. Hence the
class and its implementation superclasses need not
collectively implement all features that the class
defines or inherits. An abstract feature cannot be
implemented by the class that defines it.

Notes.
• Flavors provide single inheritance, mix-ins a limited
form of multiple inheritance. Informally, flavors act as
nouns, mix-ins as adjectives.
• A flavor is either abstract or concrete. A mix-in
is effectively abstract.

Telescript Language Reference - October 1995, General Magic
http://bitsavers.informatik.uni-stuttgart.de/pdf/generalMagic/Telescript_Language_Reference_Oct95.pdf

A lot of this ontology is present in initial Java. The
Java equivalent to mix-ins is interfaces I guess. And
sealing is the aforementioned final modifier. The Java class
loader uses sealing in another sense. Packages can be sealed.

burs...@gmail.com

unread,
Jun 20, 2018, 4:34:10 AM6/20/18
to
We still find enthusiams for platforms similar
like the telescript platform. Maybe not in all
respect but some common themes can be identified.

Anyway congratulations to this prototype:

Pure Web Prolog = Pure Prolog + RPC - Torbjörn Lager, 2018
"Imagine a dialect of Prolog with processes and
mailboxes and send and receive – all the means
necessary for powerful concurrent and distributed
programming. Alternatively, think of it as a dialect
of Erlang with logic variables, backtracking search
and a built-in database of facts and rules – the
means for logic programming, knowledge representation
and reasoning. Also, think of it as a web logic
programming language. This is what Web Prolog
is all about."
https://github.com/Web-Prolog/swi-web-prolog

What I would like to add as a last remark here: The
two best kept secrets of Prolog, reexport/1 as ISA-A
and a simple (::)/2 could be a nice addition here. Maybe
the rpc itself could be viewed as (::)/2,

like the RMI in Java is implemented this way, you
just need to have some stub objects that can communicate
remotely. But RMI in Java has a very bad reputation.
Their messages require compatible Java class signatures.

But we might think of more flexible solutions. What
I like in the reexport/1 as ISA-A and (::)/2 approach
is that the language need not be typed. All we have
to do is to have some module names that can be looked

up, maybe at compile time or maybe only at runtime.
The (::)/2 operator is translated to the (:)/2 operator.
So we don't have types, but the above example shows
nevertheless the modules exhibit a kind of signature,

namely their exported predicates. And based on this
signature, we could add modifiers like abstract/1,
final/1 etc.. etc.. And refine the task of the Prolog
text loader and also of the truth maintenance.

burs...@gmail.com

unread,
Jun 26, 2018, 6:49:45 AM6/26/18
to
Lets say our aim is differently than Logtalk
parametric objects. Our aim is more to have
Java abstract/concrete pattern.

Here is a part of such an example hierarchy, the fragment
of the whole hierarchy, there is more stuff but
in separate hierarchies actually:

element
/ \
/ \
/ \
/ \
/ fraction*
ring
/ | \
/ | \
/ | \
variable* polynom* ordered
/ | \
/ | \
integer* rational* radical*

https://github.com/jburse/jekejeke-devel/tree/master/jekmin/headless/jekmin/frequent

Only the leaves, here marked by an asterix * have
term objects. The other classes do not have term objects.
But this currently not expressed in the code.

Maybe we should first head for modifiers, that express
that something is a leave and something is not a leave.
Maybe even a modifier that enforces such a property

of a module. For such a modifier we could adopt the
Java final modifier on the class level, and allow it
for modules. It would then be forbidden that the module

is object of a reexport/1. Unfortunately knowadays
Google search delivers me only nonsense when I search for
the abstract/concrete pattern, but there should be

also papers, dunno what, maybe from old OOPSLA. I
already wrote that with this approach more setters
and getters might be needed, since there are no

term objects for the abstract classes anymore, and they
also get no parameter passed to them, by some projection
from the subclass parametric object to the class parametric

object. So what is this setter/getter stuff versus this
parameters all about? Well Martin Odersky and Matthias Zenger
say about the difference:

Scalable Component Abstractions - ‎2005
Martin Odersky EPFL, Matthias Zenger Google Switzerland GmbH
2.1 Abstract Type Members
An important issue in component systems is how to abstract
from required services. There are two principal forms
of abstraction in programming languages: parameterization
and abstract members. The first form is typical for functional
languages, whereas the second form is typically used
in object-oriented languages. Traditionally, Java supports
parameterization for values, and member abstraction for operations.
The more recent Java 5.0 with generics supports
parameterization also for types.
Scala supports both styles of abstraction uniformly for
types as well as values. Both types and values can be parameters,
and both can be abstract members. The rest of
this section gives an introduction to object-oriented abstraction
in Scala and reviews at the same time a large part of its
type system. We defer a discussion of functional type abstraction
(aka generics) to the appendix, because this aspect
of the language is more conventional and not as fundamental
for composition in the large.
http://lampwww.epfl.ch/~odersky/papers/ScalableComponent.pdf

So we would head to the more object orientation
typical abstract memmber (=setter/getter) approach,
than to the parameter (=Logtalk) approach.

It seems that Logtalk has adopted some approach that
stems from functional programming. This is Ok, it
might lead to seamingly easier declarativity.

But in my opinion, for a practical reasons, and
what the benchmarks show, one can easily go with
the abstract/concrete pattern and not loose anything.

Am Mittwoch, 20. Juni 2018 10:34:10 UTC+2 schrieb burs...@gmail.com:


burs...@gmail.com

unread,
Jun 26, 2018, 7:15:31 AM6/26/18
to
Because in this Prolog variant of the Java
abstract/concrete pattern, the abstract classes
would rather correspond to interfaces.

At least since they have no term object associated,
there would not already define some object state
via some fields. But they are a hybrid of the

usual Java interfaces and the Java abstract classes.
Since in Java abstract classes there are methods
allowed, which we still do allow, only we make

no gurantees about the layout of some fields of
the object. This means in the case of multiple
inheritance, which we allow for reexport/1 usages,

the hybrids of usual Java interfaces and Java
abstract classes would need to be as powerful as
the new Jave default methods. But still we don't

account for some fields in the abstract part of
the taxonomy. If needed, inside the abstract part of
taxonomy, everything is done with setters and getters.

This is already what Paulo Moura instisted for with
his "with" solution, which is a form of setter. So
although Paulo Moura can provide a getter-less solution

for his parametric objects, he doesn't have a setter-less
solution so far. Maybe Logtalk could also evolve a setter-less
solution for its parametric objects,

but so far what he insisted for with his "with" solution,
his parametric objects were getter-less but on the
other hand setter-full. If below in the hierarchy

some parametric object would be in the case of Logtalk,
to poor end-user would need to populate the whole hierarchy
with setters. In our approach we view the matter from

the other side. The leaves natural have the term objects,
and not necessarely need setters and getters. Only if really
some abstract service is designed down the leaves, some

common functionality, then it might be the case that the
hierarchy needs to be populated with additional setters
and getters. But by code inspection, one can easily

verify for the CAS hierarchy, that we didn't need any
setters and getters. Since the leaves have the term objects
and there, as already explained, we can use unification.

So lets make a small example of the design patter:

What we wouldn't do:

integer(X)
\
rational(X,Y)

Instead we would do:

ordered
/ \
integer(X) rational(X,Y)

So maybe the color point example was a little bit misleading
in this respect. But the CAS example is a larger hierarchy
and it has a different design flavour. If I have time

I will compare this hierarchy and code with Log-Nonsense-Talk
and lets see what the performance will be.

burs...@gmail.com

unread,
Aug 4, 2018, 7:06:52 PM8/4/18
to
One of the ideas of OO-systems is that ultimately
every thing looks like a nail, and the OO-programming
paradigma is the hammer.

This idea can be expanded to a lot of things, including
for example RPC calls. Akka, Actors, Erlang can be viewed
under the OO-programmimg paradigma.

A further niche that can be explored this way, and gets
possibly a little bit more explored in the future, by
projects such as this one:

JEP 191: Foreign Function Interface
http://openjdk.java.net/jeps/191

Is the following idea: A foreign function call can be
seamlessly integrated so that there is no difference between
a call in the present language and a foreign call.

This leads to polyglott languages and things like that.
Current endeavours are for example GraalVM, etc.. and already
the many languages that share a JVM potentially could

seamlessly interact without RPC. What could Prolog do
in this respect? Further pursue Log-Nonsense-Talk? Here
is my guess, it all boils down to pursue ISO module

standard and a robust reference data type:

Static Java Calls:
The ISO module standard module operator (:) is used
for static calls. Constructors can be treaded as static
calls with the special method name new.

Dynamic Java Calls:
Dynamic Java method calls are done by our Pythonesk
message sending operator (::)/2 which is again based
on the ISO module standard.

Reference Datatype:
Our Prolog reference data type is used whenever a Java
class instance is demanded. If the Java class instance
implements the Comparable interface it can be even used
in our Prolog (@<)/2, (@>)/2, etc.. lexical comparison.

This can be combined with a Java class auto loader, that
automatically generates a synthetic Prolog modules for
the execution at runtime. The synthetic Prolog modules

contain automatically generated forreign function
entries and overloading dispatchers. Here is a little
example, taking a screen capture:

capture_screen(FileName) :-
java/awt/'Toolkit':getDefaultToolkit(Toolkit),
Toolkit::getScreenSize(ScreenSize),
java/awt/'Rectangle':new(ScreenSize, ScreenRectangle),
java/awt/'Robot':new(Robot),
Robot::createScreenCapture(ScreenRectangle, Image),
java/io/'File':new(FileName, File),
javax/imageio/'ImageIO':write(Image, 'png', File).

See also:
https://plus.google.com/+JekejekeCh/posts/2m2gUex8xEd

What needs to be done more? Well the current Java class
auto loader maps Java methods to deterministic Prolog
predicates. What one would like to have in the future might

be for example:

- If a Java method returns an enumerator/iterator,
this should be automatically mapped to a non-deterministic
Prolog predicate.
- If a Java method demands an array or map, we should
be allowed to pass Prolog lists or Prolog dicts for
convenience.
- If a Java method returns something that amounts to
a tupple it could give a Prolog predicate with
multiple output argument positions.
- What else?

BTW: Here is a corresponding feature request for Tau Prolog:
https://github.com/jariazavalverde/tau-prolog/issues/27#issuecomment-410483321

janb...@easel.ch

unread,
Sep 13, 2018, 9:53:29 AM9/13/18
to
The below picture shows the hierarchy we used in
the CAS. Now Logtalk developer Paulo Moura offered
his servies, lets see whether we can cut through
a smaller example:

Paulo Moura be careful before you offer services
in the following form "You can also simply ask.".
This requires two things:
- You need to invest time, here I am asking something
new from another thread
- You need to answer the question that was asked,
and not something else

I am asking something else from another thread,
because the solution of the other thread is closer

to what Samer wants. Samer wrote:

"you can’t write truly polymorphic predicates as above."

In object oriented programming, you can write
kind of polymorphic methods. So this is the context,
nothing extra ordinary, just something in the present

context. So the question and the focus for your
service public in the spirit of your "You can also simply
ask.", would be, without changing the topic now.

Can you show a Logtalk solution for this problem:

floats:

X.add(Y) := Z :- Z is X + Y.
X.mul(Y) := Z :- Z is X * Y.

vector:
X.add(Y) := Z :- maplist(plus, X, Y, Z).

plus(X, Y, Z) :- Z is X+Y.
X.mul(Y) := Z :- maplist(times(Y), X, Z).

times(X, Y, Z) :- Z is X*Y.

For the full function on dicts solution here:

https://groups.google.com/d/msg/swi-prolog/V-SJW_syu8E/8nND3VTxBwAJ

What is the Logtalk code solution, and
what is the Logtalk Prolog generated code?

Am Donnerstag, 13. September 2018 13:34:50 UTC+2 schrieb Paulo Moura:
> > At the moment its not clear what your code
> >
> > does, and whether it has anything to do with my example.
> > For example if the code had really a "this", they the
> > call from dynamic to stattic would be, thats how you call
> >
> > so called plain code:
> >
> > {maplist(plus, X, Y, Z)}
> >
> > but instead I see something like:
> >
> > apply:maplist(times(X), Y, Z).
> >
> > So I guess its either plain-plain, or the non-plain-non-plain.
> > Neither is what my example did.
>
> I long lost track of how many times I tried to explain to you
> the role of the {}/1 control construct. You claim that Logtalk
> is difficult to understand while blatantly ignoring its
> documentation. The rebuttal to your never-ending bogus
> rants is in the user and reference manuals. In plain sight.
> You know, reading instead of guessing. You can also simply ask.

(single mail reply to several mails)
https://groups.google.com/d/msg/swi-prolog/cUDGgAju5dw/Tt_1rAVmCAAJ


Am Dienstag, 26. Juni 2018 12:49:45 UTC+2 schrieb burs...@gmail.com:

burs...@gmail.com

unread,
Sep 13, 2018, 10:55:48 AM9/13/18
to
I also uploaded main2.pl, which has the shorter:

interpolate(K1, X1, X2, Y) :-
K2 is 1-K1,
Y = X1.mul(K1).add(X2.mul(K2)).

Which poses some extra challenges for the function
expansion, to get it correctly translated. The
translation of the above code reads as follows:

SWI-Prolog 7:

̀ ?- listing(interpolate/4).
interpolate(A, B, C, G) :-
D is 1-A,
'.'(B, mul(A), E),
'.'(C, mul(D), F),
'.'(E, add(F), H),
G=H.

Jekejeke Prolog 1.3.0:

?- listing(interpolate/4).
interpolate(K1, X1, X2, Y) :-
K2 is 1-K1,
'.'(X1, mul(K1), A),
'.'(X2, mul(K2), B),
'.'(A, add(B), C),
Y = C.

For more information see:

Preview: No hands polymorphism functions on Prolog dicts. (Jekejeke)
https://plus.google.com/+JanBurse/posts/igDMVE2zkjE

The example is again a "no hands" example, we still
fully rely only on the ISO module standard for dispatch.
We might do a further test with local modules as well.

In the present solution the different datatypes each
occupy a module file. With local modules it would be
possibly to pack everything into one Prolog text.

Locale modules were not conceived as part
of the ISO module standard.

janb...@easel.ch

unread,
Sep 13, 2018, 11:09:44 AM9/13/18
to
Ha Ha, Paulo Moura is definitively a complete
moron and doesn't know what he is doing:

Corr.:
everything around Logtalk, and that it cannot take any technical
critique. I am also not interested in some infantile Logtalk games,

Am Donnerstag, 13. September 2018 17:03:23 UTC+2 schrieb Proof Easel:

Why do you write "You can also simply ask." if you don't mean
it? Anyway, I can do the example myself in Logtalk, and also
list the produced Prolog code myself as well, even if I need

to hack the SWI-Prolog 7 adapter for this purpose. There is no
need to rely on somebody who is up to some cat and mouse game.
This only proves my brainwashing intransparency claim with

everything around Logtalk, and that it can take any technical
critique. I am also not interested in some infantile Logtalk games,
who is a groupie of Logtalk and who is not a groupie of Logtalk,

and doesn't deserve attention. Thats just not professional, and
shows your mental immaturity and that you have something
to hide. Period.

Am Donnerstag, 13. September 2018 16:47:15 UTC+2 schrieb Paulo Moura:
> On 13 Sep 2018, at 14:45, Proof Easel <janb...@easel.ch> wrote:
>
> Paulo Moura be careful before you offer services
> in the following form "You can also simply ask.".
>
> Too late for *you*. Sure, you can simply ask. But you
> will no longer get any answers. After calling Logtalk a
> fraud any leftover goodwill is gone and you're out of
> free support. You're also out of payed support or any
> other form of support offered by me. If Samer is curious
> about polymorphism in Logtalk, I'm sure is perfectly
> capable of asking himself.
>
> -----------------------------------------------------------------
> Paulo Moura
> Logtalk developer
https://groups.google.com/d/msg/swi-prolog/cUDGgAju5dw/AFptpoVwCAAJ

burs...@gmail.com

unread,
Sep 30, 2018, 7:15:45 AM9/30/18
to
I am currently working on "Leantalk", which comes
with some reading about JDK 9, JDK 10, JDK 11, etc..
and their new deep reflection and all the new

accessibility that comes by their new "module"
concept, which is something like a package
conglomerate. There was already an interesting

find. Just looking across the brim of Java, I
found a specification of C#. Do they already
have such a "module" concept. Now I am confused.

But it seems there is much more than the usual
private, public, protect modifiers. C# has
additional modifiers:

internal
protected internal

Standard ECMA-334 - C# Language Specification
5th edition (December 2017)
https://www.ecma-international.org/publications/standards/Ecma-334.htm

An alternative name for "internal" and "protected internal"
could be also found. These are the following visibility
properties, example for a field:

public bool IsAssembly { get; }
https://docs.microsoft.com/de-de/dotnet/api/system.reflection.fieldinfo.isassembly

public bool IsFamilyAndAssembly { get; }
https://docs.microsoft.com/de-de/dotnet/api/system.reflection.fieldinfo.isfamilyandassembly

The documentation says:

IsAssembly: Gets a value indicating whether the potential
visibility of this field is described by Assembly;
that is, the field is visible at most to other types
in the same assembly, and is not visible to derived
types outside the assembly.

IsFamilyAndAssembly: Gets a value indicating whether the
visibility of this field is described by FamANDAssem;
that is, the field can be accessed from derived classes,
but only if they are in the same assembly.

Somehow since I have recently introduced hierarchical
knowledge bases into Jekejeke Prolog, I am doomed to such
issues. A base knowledge base and a sub knowledge base
can be viewed as an assembly, maybe.

So in the module "func", from a base knowledge base, I
can access sub knowledge bases. This will not be an issue
since the next release of Jekejeke Prolog, 1.3.1 will
hopefull adopt the call-site of the dot notation.

But for other common services we might want to
seal assemblies. So that it gets more clear what is
exported as a whole from an assembly and what not.
This could be an interesting new modifier, also for

a Prolog system. Logtalk has already adopted modifiers
like public. I did the same for Jekejeke Prolog. The
protected modifier is not yet implemented in my system.
But if the system has a notion of assembly, one

could also implement further modifiers, such as
"internal" and "protected internal". In the case of
hierarchical knowledge bases, as currently present
in the later Jekejeke Prolog releases the parent

child relation between knowledge bases could serve
as a the link that determines the "protected internal"
visibility. Or "protected internal" means something
else, its only "protected" and then "internal".

The JDK 9, JDK 10, JDK 11, ... on the other hand seems
to have a more declarative way of describing such
assembly level visibility. Not sure. Have to check.
Do they have new modifiers on the member level?

To be continued...

burs...@gmail.com

unread,
Sep 30, 2018, 7:24:05 AM9/30/18
to
Such visibility seems to be also available
in Xamarin. How popular is Xamarin?

Stackoverflow:

- Questions tagged [xamarin]: 33,207 questions

- Questions tagged [prolog]: 9,629 questions

As of today, Sunday 30.09.2018

burs...@gmail.com

unread,
Oct 12, 2018, 10:39:34 PM10/12/18
to
In another post "Will Logtalk ever fly?" I have
demonstrated how vital modifiers are for generating
efficient code for object oriented programs.

But I have also demonstrated how Logtalk miserably
fails when it comes to tools. Its debugger is practically
not usable. Further the generated code can be

simulated by Pythonesk calls. It might be even the case
that Pythonesk calls are more flexible and transparent than
Logtalk. Like when using call/n etc..

But there are more issues with Logtalk. Here is a
demonstration. Jekejeke Prolog modifiers are fool proof,
they are also part of the Pythonesk methods.

Jekejeke Pythonesk Methods:

?- deter:rev(_,[1,2,3,4,5,6,7,8,9,10],[],X).
Error: Undefined or inaccesible predicate deter2:rev/4.
deter2:rev/4

But in Logtalk the modifiers fly away after compiling
and after loading the code is a big pile in user land:

Logtalk Transpiler Code:

?- '$deter#0.rev#3'([1,2,3,4,5,6,7,8,9,10],[],X,_).
X = [10, 9, 8, 7, 6, 5, 4, 3, 2|...].

So it would be still useful to have innovation among
Prolog systems implementing the ISO module system and
writing the unwritten chapters, because:

- Logtalk tools don't work, they are too
slow. Example the debugger, it is >200x
times slower.

- Logtalk code is not safe, the modifiers
disappear in the generated code. And all
the code lands in user land and becomes
freely executable.

- Logtalk generated code can be also manually
coded by Pythonesk methods. The native
module system could be reused.

- Pythonesk methods would be also more
transparent, and more ammenable to
call/n. Will make some examples soon.

To be continued...

Mostowski Collapse

unread,
Jun 4, 2020, 3:02:29 AM6/4/20
to
There are new ideas around how to handle modules.
My system has a big drawback, its not able to
allow modules off the class path.

So a module declaration:

:- module(foo, []).

Requires that foo is found on the class path.
Its even worse. If the module has a package
declaration again things dont work off the class path.

So a package and a module declaration:

:- package(library(bar)).
:- module(foo, []).

Requires that bar/foo is found on the class path.

So what is the solution to this mess?

Mostowski Collapse

unread,
Jun 4, 2020, 3:12:30 AM6/4/20
to
The solution sketch reads as follows. The
path lookup mechanism already searches relative
to a module that is consulted.

Many Prolog systems do that but not all. SWI-Prolog
does it and we do it as well. So the new idea is to
validate a module name, be searching relative

to the module. So a module declaration:

:- module(foo, []).

Would have the following new requirements:

a) foo is found relative to the current module path
b) and the resulting path is the same as the current module path

But here comes the core new idea. Namely if the
module has a package declaration, then search should
be done in parent directories relative to the

current module path. The package declaration would
not anymore need library() in it, and for each simple
file name segment in the package delaration we would

search inside a parent of the current module path.
This would be a enhancement of the search mechanism
which is compatible with SWI-Prolog since this

enhancement is only effective when there is a package
declaration, and SWI-Prolog does not have package
declarations inside modules. So the new idea is to

validate a package path and a module name, be searching
relative to the package parent of the module. Whereby
package declaration doesn't need library() anymore.

So a package and module declaration:

:- package(bar).
:- module(foo, []).

Would have the following new requirements:

a) bar/foo is found relative to the parent of the current module path
b) and the resulting path is the same as the current module path

This would even allow to make self-contained
collections of package-ified modules. Possibly
all the use_module/1 can be done without

library() then as well. What we then should
also allow is a use_package/1 without library().
Not yet sure what would be the requirements for the later.

Mostowski Collapse

unread,
Jun 4, 2020, 3:40:33 AM6/4/20
to
I have recently also added to my system SWI-Prolog
packs. It turns out improving my package and module
validation and enhancing the search,

would also have benefits to SWI-Prolog packs. Currently
I have an ugly version mechanism, that adds the versioned
SWI-Prolog pack name to the class path.

The mechanism is expensive, since it is probing each
versioned SWI-Prolog pack name, cause a slow-down in
class path lookup linear multiplier with the number of

activated SWI-Prolog packs. But we can view a SWI-Prolog pack
as a self-contained collection of non-package-ified
and package-ified modules. With the new validation

and enhancement we wouldn't need the version search
mechanism anymore. All we need to have is an entry to
the main module. But for this purpose it would be

enough to add a few use_package/1 directives including
the version, removing a lot of burden from the
class path search. Since the use_package/1 search

mechanism is cheaper than the current ugly version
mechanism. It would not anymore blow up the search.
What is open whether we would add the use_package/1

to user or to system. It is not that our user pseudo
module results in an everywhere import like in SWI-Prolog.
So we probably would need to add it to the

system pseudo module, which has this semantic, allowing
then cross SWI-Prolog pack calls again as well.

Mostowski Collapse

unread,
Jun 13, 2020, 4:05:15 PM6/13/20
to
Ha Ha, the relative path thingy, is already an
obstacle in some Prolog systems concerning
ensure_loaded/1. In SWI-Prolog relative paths

are resolved against the current module. But
for example CxProlog, although it has ensure_loaded/1,
it cannot do the same resolution:

CxProlog version 0.97.5

[main] ?- ensure_loaded('<path>\\cxprolog.p').
{ERROR (open/3): No such file 'suite.p'.}
% File '<path>\\cxprolog.p' consulted, 0 sec 1480 bytes
yes

cd/1, chdir/1 or working_directory/2 do also not
work. Looks again that just loading Prolog texts turns
into a painful experience.

Mostowski Collapse

unread,
Jun 13, 2020, 4:19:15 PM6/13/20
to
But CxProlog has an Ok performance.
Not like GNU Prolog but also not that
far away. For my standard micro benchmark

I get this result:

CxProlog 0.97.5: 4'799 ms
GNU Prolog 1.4.5: 3'826 ms

If there were a pre-built new version
Windows EXE for CxProlog I would also test this.
But did only test the above version.

Ike Schroder

unread,
Jun 13, 2020, 4:55:03 PM6/13/20
to
Mostowski Collapse wrote:

> But CxProlog has an Ok performance.
> Not like GNU Prolog but also not that far away. For my standard micro
> benchmark I get this result:
> CxProlog 0.97.5: 4'799 ms GNU Prolog 1.4.5: 3'826 ms
> If there were a pre-built new version Windows EXE for CxProlog I would
> also test this. But did only test the above version.

PLease stope using windoze, if you are not covidXp upgrade vaccination
ready, asking a question like that. You have to vaccinate upgrade
covid95, covidXp, covid7, covid8.1, covid10 and so on, in this order.

Mostowski Collapse

unread,
Jun 13, 2020, 5:14:50 PM6/13/20
to
Was using Windoze 10. I was refering to the version
of CxProlog, a Windows EXE for CxProlog. Is there a
newer Window EXE for CxProlog around? Was using 0.97.5.

What is Matsunaga's Prolog? Its from here:

Why is racklog so inefficient?
https://groups.google.com/d/msg/racket-users/iJwzoBCs0ao/vr_APWc0AAAJ

Is there new interest in WAM?

Mostowski Collapse

unread,
Jun 14, 2020, 6:59:28 AM6/14/20
to
The problem is how implement ensure_loaded/1 really.
Assume for example I have a soft link:

/Projects --> /opt/Projects

What should be the result of:

:- ensure_loaded('/Projects/foo.pl').
:- ensure_loaded('/opt/Projects/foo.pl').

But first things first. Will do the package thing
first, and then look at canonical paths again.
Canonical paths, but I have the feeling some

hardening could be appropriate, and may some
optimization here and then. Do we need them
always? I started using non-canonical paths in

few places, since they dont require OS calls.
Making a path canonical usually requires OS calls,
like resolving a soft link.

Am Samstag, 13. Juni 2020 22:05:15 UTC+2 schrieb Mostowski Collapse:

Mostowski Collapse

unread,
Jun 16, 2020, 11:48:55 AM6/16/20
to
How about abstract/1? How about synchronized/1?
At least Logtalk pioneered a synchronized/1
directive for a predicate property.

Jan W. hinted on SWI-Prolog discourse that this
synchronized/1 directive is a little limited, like
it executes the predicate as once/1.

I don’t know how Logtalk implemented synchronized.
The keyword itself does not imply that some choice
points are removed. There is nothing that would

prevent Logtalk from implementing synchronized this way:

with_mutex_nondet(Mutex, Goal) :-
setup_call_cleanup(
mutex_lock(Mutex),
Goal,
mutex_unlock(Mutex)).

Mostowski Collapse

unread,
Jun 16, 2020, 12:02:32 PM6/16/20
to
But a distinct mark of monitors is not only
that it has a critical region, there is also
wait() and notify() inside the critical region.

But it seems to be a current limitation of Logtalk,
that it indeed cuts away the choice point, and wait()
and notify() are also missing.

Besides using setup_call_cleanup/3, one could also
use try_call_finally/3. With the later the critical
region would be released in a exit port and re-aqcuired
in a redo port.

Whereas the former only releases the critical region
in a deterministic exit port. Concerning wait() and notify(),
a further more general feature of monitors would be
condition variables.

So one could wait() and notify() on a particular condition
variable, and a monitor can have multiple condition variables.
Brinch Hansen and Hoare developed the monitor concept

in the early 1970s. What Logtalk has is thread_wait() and
thread_notify(), but it seems this addresses only some
thread queue. And not addressing some particular monitor
or some particular monitor condition variable.

What Logtalk delivers is somehow bound by what its backends
can currently deliver.

Mostowski Collapse

unread,
Jun 16, 2020, 12:11:17 PM6/16/20
to
A synchronized/1 directive could be a Swiss
army knife for concurrent programming. It would
allow a novice programmer to quickly write some
code with critical regions, not talking care

about more fine points of multi-threaded programming.
I guess a Prolog system that has a tabling/1 directive
could implement a synchronized/1 directive similarly
as a predicate wrapper. What SWI-Prolog would allow,

that synchronized can be recursively called.
It seems iits mutex is reentrant, I just see:

?- mutex_lock(foo).
true.

?- mutex_lock(foo).
true.

?- mutex_unlock(foo).
true.

?- mutex_property(foo, X).
X = alias(foo) ;
X = status(locked(main, 1)).

?- mutex_unlock(foo).
true.

?- mutex_property(foo, X).
X = alias(foo) ;
X = status(unlocked)

But the question is, what should be the monitor.
In Java a static method chooses the surrounding
class as a monitor. The Prolog equivalent would
be a module. Not sure what this means.

Mostowski Collapse

unread,
Jun 27, 2020, 7:30:22 AM6/27/20
to
Will SWI-Prolog repeat the conceptual errors of
Logtalk? In Logtalk there is not a single thread
primitive that can take another object as argument.

Java is a little extreme in that every object
can be a monitor. And classes are also objects.
This solves all problems. In a Prolog system such

as SWI-Prolog an atom may play a similar role
like a Java object. So a further alternative might
be that this would be allowed:

my_predicate :-
synchronized(my_module, ...).

This would have some meta-programming advantage,
like you could code something for a module
argument M inside a library:

my_predicate(M) :-
synchronized(M, ...).

This would again give the programmer more power.
A power that also lacks Logtalk since none
of its thread primitives have an object argument.

On the other hand in Java you can surely write
libraries that obtain and release locks
even on classes.

Mostowski Collapse

unread,
Jun 27, 2020, 7:46:45 AM6/27/20
to
One could view this as a new trench war about
some Prolog philosophy. But the advantages of
not conflating where a lock comes from and the

lock API itself is simple to demonstrate. Just
remember the concept of lock level from databases.
Since release 1.4.4 of Jekejeke Prolog I have

visible predicate level locks, which can be retrieve
via predicate_property/2. This is more fine grained
than module level locks. Here is an example.

The lock is not an intrinsic Java lock,
but a lock from a library:

:- dynamic foo/1.

?- predicate_property(foo/1, X), write(X), nl, fail; true.
sys_readwrite_lock(0rdbf4fcd)

This is used in the shared tabling prototype, to
synchronize the cache. It gives a more fine grained
locking with less contention. But a module_property/2

could also return a lock on module level. But
generally these lock factories are not conflated
with the lock API itself.

Currently the predicate property is only a lock,
but I could consider pairing it with a condition
variable and making it a monitor. This is something

new this pairing, and I am grateful for watching
the SWI-Prolog attempts. But of course, SWI-Prolog
is free to do, what ever it thinks is right.

Mostowski Collapse

unread,
Jun 27, 2020, 8:19:35 AM6/27/20
to
Disclaimer: Logtalk could still safe its head,
by for example allowing this here:

Object::threaded_wait(Pattern)

But I just did a GitHub search, I didn't find any
example of this. It could be that this is missing
because of some Old School precautions. For example

Java gives usually the following linter warning:

- Reports synchronization on a local variable or
parameter. It is very difficult to guarantee
correctness when such synchronization is used.

It may be possible to improve code like this
by controlling access through e.g. a synchronized
wrapper class, or by synchronizing on a field.

I think the warning is based on this common
programming errors:

Programmer forgot to mention the monitor in wait, etc..:
--------------------------------------------------------

synchronized (M) {
...
wait(); /* error here */
...
}

Programmer forgot to mention the monitor in synchronized:
--------------------------------------------------------

synchronized (this) { /* error here */
...
M.wait();
...
}

Not a severe collateral damage.

Mostowski Collapse

unread,
Jun 27, 2020, 8:23:40 AM6/27/20
to
A third programming error, monitor variable is not final:

Programmer overrides monitor variable:
--------------------------------------

synchronized (moni) {
...
moni = moni2; /* error here */
...
moni.wait();
...

Mostowski Collapse

unread,
Jun 27, 2020, 8:33:31 AM6/27/20
to
Most of these errors cannot happen in Prolog,
for various reasons, namely:

1) Programmer forgot to mention the monitor in wait, etc..:
Programmer forgot to mention the monitor in synchronized:
---------------------------------------------------------
If you are not using predicates with to much implicits,
or if you are not usingg Logtalk, like the original
synchronized/2 and wait/2, most likely you

get a singleton variable error:

synchronized(M, (
...
wait(N), /* singleton variable error because of typo */
... )).

2) Programmer overrides monitor variable:
---------------------------------------------------------
This is also unlickely to happen in Prolog, unless
you use Picat loops, since a variable gets a value
once, there is hardly a chance to change it.

LoL

Mostowski Collapse

unread,
Jul 24, 2020, 12:36:13 PM7/24/20
to
Surprise, surprise. My current Prolog module
proxies, that can act as Java classes, cannot
deal with default methods.

Was testing with:

public interface InterfaceDog {

default String barking() {
return "woof";
}

default void bark() throws IOException {
String voice = barking();
Writer wr = (Writer) Interpreter.getInter().
getProperty("sys_cur_output");
wr.write(this + " says " + voice + ".\n");
wr.flush();
}

}

The problem is that the Java proxy class implements
the default interface methods as well and delegates
them to the proxy handler.

So whats the solution?

Mostowski Collapse

unread,
Jul 24, 2020, 12:39:14 PM7/24/20
to
Or whats the problem? Well the problem is
the situation when the Prolog proxy module
does not implement a predicate, and therefore

indicates it wants to inherit a particular
method. Currently the proxy handler executes
a non existing Prolog proxy module, and

unless before default methods, it would fetch
an abstract interface method, and throw an
error. But now it will fetch a default method.

Unfortunately it will invoke this method
with late binding, which will result in a vicious
circle, because the proxy class invocation

handler is called again.

Mostowski Collapse

unread,
Jul 24, 2020, 12:45:12 PM7/24/20
to
So basically the problem is the invokevirtual,
and a solution would be a invokespecial. Up
to JDK 1.6 there were not many possibities

to call an invokespecial. The usual Method.invoke()
does late binding and therefore a invokevirtual. But
interestingly JDK 1.7 has invokespecial

through method handles. Such a method handle
can be created as follows:

MethodHandles.Lookup lookup = IMPL_LOOKUP;
special = lookup.unreflectSpecial(method, method.getDeclaringClass());

And then get invoked as follows:

special.bindTo(proxy).invokeWithArguments(args);

All we need now to do, is created different
executors inside the proxy invocation handler.
Executors for the old interface methods which

work unchanged, and new executors for default
methods. This executore will additionally perform
a kind of current_predicate/1 for further evidence

that a method was not overwritten.

Mostowski Collapse

unread,
Jul 24, 2020, 2:38:23 PM7/24/20
to
BTW: Java code examples now make use of getInter().
This is experimental new method. Before hand I
assume that a foreign function might simply

have an Interpreter parameter, in case it
needs something from the Interpreter. But if
we look at all the common Interfaces from

Java, they obviously don't have an Interpreter
parameter. So there is now this static method,
which uses a little of thread context

to figure out the current interpreter.
See also this blog:

Preview: getInter() convenience for object oriented Prolog. (Jekejeke)
https://gist.github.com/jburse/3e48104808582eaa5ad0e725132fad81#gistcomment-3390119

Mostowski Collapse

unread,
Jul 24, 2020, 2:42:00 PM7/24/20
to
But getInter() only works if we are already
executing inside the Prolog interpreter.
But there are situations where this is

not the case. Now I wonder whether a
getKnow() would be also possible. Some
kind of reverse lookup from some class

loader object. I have such a reverse lookup
already somewhere, but it additionally
requires a knowledge base root,

and then the whole knowledge base hierarchy
is searched. But a JVM could house multiple
knowledge base roots. So maybe

replace this code by something new, and
also provide getKnow() sooner or later.

Mostowski Collapse

unread,
Jul 25, 2020, 12:10:43 PM7/25/20
to
Ok, prototype was successful. I guess the years and
years of discussing LogNonsenseTalk pays off. invokespecial
is used under the hood of LogNonsenseTalk.

The new Java class is ExecutorDefault. A link to Github
is found in my recent blog. But now something else.
How do we give state to a Java to Prolog proxy?

Previous to release 1.4.5 we supported InterfaceSlots.
But InterfaceSlots is not general enough. So the new
interface for stateful Java to Prolog proxy is now:

public interface InterfacePivot {

/**
* <p>Retrieve the value.</p>
*
* @return The value.
*/
AbstractTerm value();

/**
* <p>Set the value.</p>
*
* @param data The value.
*/
void set_value(AbstractTerm data);

}

Its the same pivot idea that now forms the basis
of bags, aggregates, sequence and tabling. The
interface is now auto-detected and there is

only one proxy constructor now.

Mostowski Collapse

unread,
Jul 25, 2020, 12:18:36 PM7/25/20
to
A state interface, even if its fully abstract,
works astonishingly smooth with some non-abstract
default interface methods. The new Java default

interface methods are not some hack, they support
proper object orientation, the method dispatch works
besides inheritance/overriding.

I already was redoing the dog example, now with stateful:

public interface InterfaceDog extends InterfacePivot {

default String barking() {
return "woof";
}

default void bark() throws IOException {
String voice = barking();
Writer wr = (Writer) Interpreter.getInter().
getProperty("sys_cur_output");
wr.write(value() + " says " + voice + ".\n");
wr.flush();
}

}

This is now the last example07 from the advanced
tutorial. Compare to example06 what changed was
the extends InterfacePivot and the use of a self

call value() in the default interface method
bark(). Testing shows that everything works as
expected, if this dog interface is implemented

by a class that also provides the pivot interface,
as expected the dog becomes a face, we can use
value() to retrieve a name.

What then will be demonstrated how our Java to Prolog
proxy do automatically give state, by providing a stateful
proxy object when the pivot interface is detected.

Mostowski Collapse

unread,
Jul 26, 2020, 6:36:52 AM7/26/20
to
There are some interresting possibility through
the new invokespecial via MethodHandles. What
did not yet work in my system,

was doing a super call to an auto loaded interface
or super class. The problem is basically that all
auto loaded interface or super class predicate

registrations use Method and not MethodHandle. And
the make an invoke virtual. So wenn we use a qualified
call, we do not end up in the interface or class but

again in self. Also default methods could give an
other spin to proxy state. Namely we could implement
proxy strate access and modification directly

inside the corresponding interface, like in this sketch:

public interface InterfacePivot {

default AbstractTerm value() {
ProxyState = (ProxyState) Proxy.getInvocationHandler(this):
return ... retrieve from proxy state ...
}

default void set_value(AbstractTerm data);
ProxyState = (ProxyState) Proxy.getInvocationHandler(this):
... set to proxy state ...

Mostowski Collapse

unread,
Jul 26, 2020, 6:47:33 AM7/26/20
to
If predicate registered non-abstract methods would
already do an invoke special, our proxy invocation
handler code would even get more simpler.

We wouldn't need anymore a special executor, since
the found predicate registration of a default method
would already do the job. Similarly for an abstract

method, the predicate registered method could
directly throw an existence error. All the late binding
would work along the ISO module lookup and inheritance

through reexport. What is not yet clear how the
rest of auto loading is affected, espessially the
collation of overloaded Java methods into a single

Prolog predicate, when there are super definitions
already around, and some of these are abstract.
In the worst case we need message sending inside

the overloaded branching code, or alternatively
fork predicate registrations indo special and virtual.
Have to check whats going on right now.

Mostowski Collapse

unread,
Jul 26, 2020, 6:58:48 AM7/26/20
to
Last but not least, are MethodHandles also awailable
on the Android Platform. It seems with API level 26
(Oreo 2017) method handles are also part of the

Android platform. What I don't know yet whether some
lookup issues have been fixed in Android. Especially
looking up specials from interfaces is nasty,

and varies between JDK versions.

See also:

Non-abstract methods in interfaces
https://openjdk.java.net/jeps/274

Mostowski Collapse

unread,
Jul 26, 2020, 11:37:20 AM7/26/20
to
Ok, here is a new idea to simplify matters.
Could introduce foreign_special/3 directive
besides a foreign/3 directive.

:- foreign(indicator, class, method).
Will invoke the found method via invokevirtual.
:- foreign_special(indicator, class, method).
Will invoke the found method via invokespecial.

Could then adapt the auto loader, such that uses
foreign_special/3 instead foreign/3. I could then
rollback what I did for proxy, because

the special call respectively existence error,
is now delegated to the auto loaded interface.
To shield the end-user from the more delicate

foreign_special/3 could put it into the module
"score", which unlike the module "foreign" is not
preloaded, and usually imported by auto loaded

Java classes. This could be fun und would allow
a proxy Prolog module to call super methods etc..
And default methods would be called via fallback.

Meanwhile what has been implemented as of
now for default methods:

Preview: InterfacePivot convenience for object oriented Prolog. (Jekejeke)
https://gist.github.com/jburse/c34d6501e574a7f7b4a22749e480628b#gistcomment-3391839

Mostowski Collapse

unread,
Jul 28, 2020, 6:57:10 PM7/28/20
to
Ok, its done. There is now a new directive foreign_special/3.
And so far regression testing didn't show some problems,
and further we can now indeed do a super call into

a default method, that is a non-abstract interface member,
while inside a proxy object. Woa! As an example added
a module "chihuahua". An agressive little dog, that

simply barks two times:

% barking(+Dog, -Atom)
:- override barking/2.
barking(Self, Voice2) :-
example06/'InterfaceDog':barking(Self, Voice),
atom_split(Voice2, ' ', [Voice, Voice]).

LoL

See also:
Preview: foreign_special/3 convenience for object oriented Prolog. (Jekejeke)
https://gist.github.com/jburse/784567d5738aa271a7ce2847546936ad#gistcomment-3395511

Mostowski Collapse

unread,
Jul 28, 2020, 7:35:02 PM7/28/20
to
Admittedly, got a little obsessed with these Prolog
driven proxy objects. Was even thinking about
implementing rational numbers this way, that

would be more first class citizen. The idea
here would be that rational numbers would
implement the Java class Number. But since

Number is a Java class and not a Jave interface,
the usual proxy objects from the JDK cannot
do it. They can only enhance an interface, but

not a class. Would need to go CGLIB for enhancing
for example the Java class Number.

Enhancer e = new Enhancer();
e.setClassLoader(myClassLoader);
e.setSuperclass(SomeConcreteClass.class);
e.setCallback(new MethodInterceptor() {
Etc...

creating Java Proxy instance for a class type?
https://stackoverflow.com/a/14277664/502187

But I could nevertheless do the Java class
Number thingy for rational numbers. Only not
in Prolog, but with a little bit more Java

programming. :-( :-)

Mostowski Collapse

unread,
Jul 29, 2020, 6:51:43 AM7/29/20
to
An interesting turn of events from foreign_special/3
was that stateful proxy is now directly implemented
in the corresponding Java interface.

This is made possibly through default methods,
the new JDK 1.8 feature we are now beginning to support.
The implementation of InterfacePivot now reads as follows:

public interface InterfacePivot {

default AbstractTerm value() {
ProxyPivot state = (ProxyPivot) Proxy.getInvocationHandler(this);
return state.value();
}

default void set_value(Interpreter inter, AbstractTerm data) {
ProxyPivot state = (ProxyPivot) Proxy.getInvocationHandler(this);
state.set_value(data, inter.getEngine());
}

}

What would be more interesting, if we could have
a multitude of different statefull interfaces.
Whereas a statefull interface can currently decide

on his own to retrieve its state via Proxy.getInvocationHandler()
and decide on its own to then do a cast to
for example ProxyPivot in the above example.

We do not yet have a generic and extensible
way to create a statefull instance of a proxy
object. This is still hard coded.

Mostowski Collapse

unread,
Jul 29, 2020, 7:06:32 AM7/29/20
to
Also the java Proxy class only delivers a
Proxy.getInvocationHandler() and not a Proxy.setInvocationHandler().
So we cannot mingle with the invocation handler,

and upgrade it after the Proxy was created.
The invocation handler is parameter to the
Proxy constructor and it is currently hard

coded where ProxyHandler or ProxyPivot is passed
to the Proxy constructor. But there is some
pattern behind it. Even ProxyPivot shares

a ProxyHandler. For statefull proxies we decided
that the state is a little go inbetween, and
the state then does delegate to the ProxyHandler.

This means proxypivot itself is only:

public final class ProxyPivot implements InvocationHandler {
private ProxyHandler handler;

/* some statefull stuff */

/* go inbetween */

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return handler.invoke(proxy, method, args);
}

}

But somehow other designs could be also possible,
if we where for example to reduce the footprint
of ProxyHandler, we could implement ProxyPivot

as a subclass of ProxyHandler. Also we might want
to cache the constructor for a proxy
somewhere else than in the ProxyHandler.

Mostowski Collapse

unread,
Aug 6, 2020, 9:49:58 AM8/6/20
to
The JDK 1.8 has not only introduced default methods
inside interfaces. It also introduced static methods
inside interfaces,

Some regression testing shows that this also works.
I guess this worked already before, but we never
explicitly tested it. Here is calling a static

method inside an interface via the Java classes
auto loader of our Prolog system:

Jekejeke Prolog 4, Runtime Library 1.4.5

?- java/util/'Comparator':reverseOrder(X).
X = 0r2b872d57

To access something static we can use a qualified
call instead of message sending.

We were thinking about using a static method inside
an interface to create a stateful invocation handler
from a stateless invocation handler.

Mostowski Collapse

unread,
Aug 6, 2020, 10:07:22 AM8/6/20
to
So what we had in mind was something like a
signature in an interface:

public interface InterfaceXXX {

static Object create() {
...
}
}

This could create the stateful handler.
But it seems that although static methods
inside interfaces were introduced in

JDK 1.8, not all of JDK 1.8 did follow
the new introductuon. If we inspect such
an InterfaceXXX and check the static flag

of the methods, we get:

clazz=interface jekpro.tools.proxy.InterfaceXXX
...
methods[1]=public static java.lang.Object
jekpro.tools.proxy.InterfaceXXX.create(), static=true
...

Then in JDK 1.8.0_261 for the proxy,
this is wrongly turned into non-static:

clazz=class com.sun.proxy.$Proxy0
...
methods[1]=public final boolean
com.sun.proxy.$Proxy0.equals(java.lang.Object), static=false
methods[2]=public final java.lang.String
com.sun.proxy.$Proxy0.toString(), static=false
methods[3]=public final int
com.sun.proxy.$Proxy0.hashCode(), static=false
methods[4]=public final java.lang.Object
com.sun.proxy.$Proxy0.create(), static=false
...

Its seems to have been fixed for example in JDK 11.0.8,
in that the static member is not anymore added to the proxy:

clazz=class com.sun.proxy.$Proxy0
...
methods[1]=public final boolean
com.sun.proxy.$Proxy0.equals(java.lang.Object), static=false
methods[2]=public final java.lang.String
com.sun.proxy.$Proxy0.toString(), static=false
methods[3]=public final int
com.sun.proxy.$Proxy0.hashCode(), static=false
...

Also looking up the new JDK 1.8 static methods is more
restricted for interfaces. The design decision of Java
was that static methods are not found in superinterfaces.

So we postpone using a signature for stateful proxy
detection since the possible problems are little overwhelming.
Also there might be other roads to make stateful proxies

more generatic, like a class parameter in the constructor predicate.

Mostowski Collapse

unread,
Aug 8, 2020, 3:30:39 PM8/8/20
to
Ok its done. Default methods are now also
supported on the Android platform. A lot
of hurdles, for example proguard with:

-target 1.6

strips down an interface from its default
methods. So the output of proguard was this
degenerated interface:

public interface InterfacePivot {
AbstractTerm value();
void set_value(Interpreter var1, AbstractTerm var2);
}

What did work was using a different code
target. We were first hesitant whether a higher
target will also work for the Android platform.

But it seems that from Android 24 on default
methods are also supported:

-target 1.8

See also:
Preview: default method support on the Android platform. (Jekejeke)
https://gist.github.com/jburse/784567d5738aa271a7ce2847546936ad#gistcomment-3409620

Mostowski Collapse

unread,
Aug 20, 2020, 5:38:11 PM8/20/20
to
Interesting find, SWI-Prolog doesn't like MRO,
unlike Python, which is fond on fumbling with MRO:
https://realpython.com/python-super/#method-resolution-order

But step by step. There was a post on SWI-Prolog discourse
with an attempt at listing every import as super.
Calling every import “super” would be probably a
misnomer. “super” is usally used for generalization/
specialization, which is defined in UML as:

Generalization
A generalization relationship indicates that a
specialized (child) model element is based on a
general (parent) model element. Although the parent
model element can have one or more children, and any
child model element can have one or more parents,
typically a single parent has multiple children. In
UML 2.0, several classes can constitute a
generalization set of another class. Generalization
relationships appear in class, component, and use-case diagrams.
https://www.ibm.com/support/knowledgecenter/SS8PJ7_9.5.0/com.ibm.xtools.modeler.doc/topics/rreltyp.html

Specialization would happen for example by overriding
a parent method by a child. But if you use the use_module/1
directive in a Prolog module, the imported predicates are
even not visible outside of the child, when invoking the
child module explicitly.

This only happens if you use reexport/1. So what would be
more appropriate to describe the relationship established
through use_module/1 would be a so called uses relationship:

Usage
A usage relationship is a dependency relationship in which
one model element requires the presence of another model
element (or set of model elements) for its full implementation
or operation. The model element that requires the presence
of another model element is the client, and the model
element whose presence is required is the supplier. Although
a usage relationship indicates an ongoing requirement, it
also indicates that the connection between the two model
elements is not always meaningful or present.
https://www.ibm.com/support/knowledgecenter/SS8PJ7_9.5.0/com.ibm.xtools.modeler.doc/topics/rreltyp.html

So if you can determine whether an import is a use_module/1
or reexport/1 you could tag these relationships as “Usage”
and “Generalization”.

Mostowski Collapse

unread,
Aug 20, 2020, 5:40:09 PM8/20/20
to
This also now shows a problem of implementing a
super message sending. A super message sending
if there is only one “Generalization” relationship
can be translated to:

p :-
<super>:q.

But if there are multiple “Generalization” relationships,
like in multi-inheritance, what should the meaning be?
Some conjunction or some disjunction?

/* and broadcast */
p :-
<super1>:q, ..., <super2>:q.
/* or broadcast */
p :-
<super1>:q; ...; <super2>:q.

The “and broadcast” respectively “or broadcast” terminology
I just invented based on SICStus Prolog 3.5 predicates
and_cast/2 and or_cast/2. What you could do is use your
usual MRO (method resolution order) and just pick the
first of the many “Generalization” relationships. Using
the MRO (method resolution order) means also to look
at “Generalization” relationships with a further predicate
indicator parameter.

In SWI-Prolog multiple inheritance is even not possible,
there is a warning since SWI-Prolog doesn’t want to
disambiguate by some MRO, rather inform the end-user.
You need to use except/1, so that in the end you could
decide on a single <super> for each predicate indicator.

Mostowski Collapse

unread,
Aug 20, 2020, 6:33:43 PM8/20/20
to
In our system we could adopt the Python MRO
approach. A corresponding search is already
implemented while doing the override check.

We could facilitate a super module call, when
we would be able to integrate it which our call-
site predicate lookup cache. This cache would
not only provide the necessary

speed, but also allow truth maintenance, in
that the cache is invalidated if dependent modules
change. Currently the cache is capable of. The
super call would need the new caching of only

doing reexport lookup:

qualified call declared lookup reexport lookup
qualified assert declared lookup
super call reexport lookup

the super call could be detected by a new super
pseudo module. Similar like the user pseudo module,
this would fit into the qualified call framework,

and only require a change where a qualified call
is resolved only once before caching. So we can
spend arbitrary time in detecting a super pseudo

module call, it would not hurt to have a further
decision branch in the code, this is just cached
value computation.

Mostowski Collapse

unread,
Aug 21, 2020, 4:25:12 AM8/21/20
to
Understanding object oriented programming language
design is infinitely hard. A lot of misconceptions
can emerge, like super needs a self notion.
Just recall where super is needed: In overriding
a method and nevertheless calling the original
methd, a method that is imported into the
current context.

So I didn’t need any focusing on “self”. The self
is irrelevant in a super call. If you write super.method()
in a program, it refers to super from the calling
context not from the self, the self can be any subclass
from the current context, and is ignored in determining
which method is to be called. The class of the self
can be far down in the inheritance hierarchy, not
allowing to determine the super.

All that is relevant is the method resolution order
(MRO) in the current context. A predicate has a
property exported/0, besides imported_from/1. EricGT
code only collected the imported_from/1 predicate property,
and didn’t look at the exported/0 property.

I guess by looking also at the exported/0 property, he
could determine whether the predicate stems from a
use_module/1 or reexport/1, and therefore tag the
relationship as either “Uses” or “Generalization”.
Most programming languages resolve super only for
“Generalization”, and do not involve the “Uses”
relationship in resolving super.

Mostowski Collapse

unread,
Aug 21, 2020, 4:29:28 AM8/21/20
to
Here is a little test, confirming that the
predicate property exported/0 works. The predicate
member/2 is exported from the Prolog module lists,
whereas the predicate member_/3 is not exported
from the Prolog module lists:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.5)

?- predicate_property(lists:member(_,_), X), write(X), nl, fail; true.
...
exported
...
?- predicate_property(lists:member_(_,_,_), X), write(X), nl, fail; true.
...

The above doesn’t yet show use_module/1 and
reexport/1 difference. But we can do a use_module/1
for testing in the toplevel and will not find a
export/0 predicate property:

?- use_module(library(lists)).
true.

?- predicate_property(member(_,_), X), write(X), nl, fail; true.
...
imported_from(lists)
...

But if we do reexport/1 we will find an export/0
predicate property for member/2:

?- reexport(library(lists)).
true.

?- predicate_property(member(_,_), X), write(X), nl, fail; true.
...
exported
imported_from(lists)
...

Mostowski Collapse

unread,
Aug 21, 2020, 4:50:02 AM8/21/20
to
Because super calls don’t depend on the self,
the Java virtual machine can translate them
to invokespecial. Fun fact, early in the
evolution of the Java virtual machine, the
instruction was even called invokenonvirtual(*).

The now called invokespecial is used for
initializers, private methods and super calls.
With Java 1.8 it can be also reflectively invoked
via MethodHandles. A self is not needed for some
late binding. But it took Java 20 years to even
provide MethodHandles (Java 1.8 was published 2014).

MethodHandles are useful when implementing
interpretive languages on top of the Java virtual
machine, like for example Groovy(**). MethodHandles
might nevertheless perform some type checks, like
assuring the invariant that self is sub class
of the current context.

(*) invokenonvirtual
https://stackoverflow.com/a/8950564

(**) Groovy
https://de.wikipedia.org/wiki/Groovy
0 new messages