For Programmers: Free Programming Magazines  


Home > Archive > Prolog > March 2005 > The meaning of module overriding syntax mod:goal in different Prologs









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author The meaning of module overriding syntax mod:goal in different Prologs
brianh@metamilk.com

2005-02-26, 3:58 pm

Hi - I am wondering if there is any existing Prolog implementation
similar to SWI Prolog, which keeps track of a conversion module which
is used to determine how terms are converted into predicates for
call/1, assert/1 etc so that there is no need for meta predicate
argument declarations (and the associated dependency problems when
recompiling individual modules), but where the syntax mod:goal means
"look-up goal in module mod but keep the current conversion module" ie
so you could always qualify every call to a different module using the
:/2 syntax to avoid having to import predicates into a module (which
creates a rather unworkable flat namespace amongst all the modules you
might ever need to import)

Also I'd be interested to hear if anyone has had any experience with
hierarchical modules or file-free implementations (eg like Smalltalk,
where you only need to think about the objects/classes etc and the
system takes care of storing them somewhere, or Java, where the
physical path to the file for a class is determined by where the class
is in its hierarchy)

Brian Hulley

2005-02-28, 8:58 am

Thanks - this does exactly what I meant.
The "conversion module" is just the same as the ECLiPSe "caller module"
except that instead of the compiler creating a new predicate with an
extra argument, the caller module is maintained in a WAM register (just
like there are registers for the program counter, heap top etc), and
predicates which you'd declare as tool predicates in ECLiPSe are
declared module_transparent, meaning that the body of their clauses
doesn't change the value of this register.

Thus example WAM code for a normal (ie non-transparent) predicate in
module def would be something like:

normal :- allocate
context_module def
a, call def:a/0
context_module def
b, call def:b/0
context_module def
deallocate
c. execute def:c/0

whereas WAM code for a module_transparent (tool) predicate calltwice(X)
would be:

calltwice(X) :- allocate
get_context
get_var Y1, A0
call(X), metacall
context_env
put_value Y1,A0
call(X). metaexecute

where get_context stores the current value of the conversion module
register in the first environment cell, and context_env copies the
value in the first env cell into the conversion module register.

Using this technique there is a slight runtime overhead for modules but
the great advantage is that you can always compile a clause without
knowing anything at all about the predicates it is calling.

Cheers, Brian.

Brian Hulley

2005-02-28, 3:59 pm

I should have pointed out that the above WAM code relates to a Prolog
implementation that I am creating and has nothing to do with SWI-Prolog
(I don't know how module transparency is implemented in SWI-Prolog),
although I am indebted to SWI-Prolog for the concept of module
transparency.

Jan Wielemaker

2005-02-28, 3:59 pm

On 2005-02-28, Brian Hulley <brianh@metamilk.com> wrote:
> whereas WAM code for a module_transparent (tool) predicate calltwice(X)
> would be:
>
> calltwice(X) :- allocate
> get_context
> get_var Y1, A0
> call(X), metacall
> context_env
> put_value Y1,A0
> call(X). metaexecute
>
> where get_context stores the current value of the conversion module
> register in the first environment cell, and context_env copies the
> value in the first env cell into the conversion module register.
>
> Using this technique there is a slight runtime overhead for modules but
> the great advantage is that you can always compile a clause without
> knowing anything at all about the predicates it is calling.


This is -but you knew- exactly why SWI-Prolog introduced this
technique. I'm not sure I still like it though. One of the
divantages are predicates that require multiple terms to be
translated to predicates, a common example is a transparent predicate
that needs to assert something (in its own module). Another common
problem is that some modules come scattered with transparent
predicates to have the meta-arguments arrive at the right place, where
the meta-predicate approach only requires the entry-point to be declared.

For short, carrying the meta-information in the argument leads to
cleaner code but compilation becomes dependent on what you call, while
using the notion of caller/context module sometimes leads to ugly code
and/or many declarations.

Bart Demoen once told me a name-based module system similar to XSB solves
most of these problems while avoiding the problems normally associated
with name-based module systems. I've never studied this.

Given that these days Quintus, SICSTus, CIAO, YAP, GNU-Prolog and
SWI-Prolog (more?) share more or less the same module system, I'm
very reluctant to change anything. In these module systems
foo:assert(bar) asserts bar in module foo.

B.t.w. I've written substantial Prolog programs and never had problems
importing things. Very rarely I've used :- use_module/2 to import only
the things I need to avoid a conflict. I'm more worried about the flat
module namespace. I've seen conflicts due to people using very common
names as module-name (e.g. find, file, prove, search, ...).

--- Jan


Brian Hulley

2005-02-28, 3:59 pm

Thanks - I'll have a look into XSB as well.

Most of my programming experience is with large programs in C++, where
I've got used to the fact that you have several libraries, each with
its own namespace, containing a set of classes which in turn contain
the actual methods. Therefore there is always at least 2 levels
(library name and class name) between the global top-level namespace
and the namespace where all methods for a particular class are defined.

In C++, I always qualify a class in a different library with the
library name, since I find it makes the code much clearer: you can
immediately tell which sub system you are dealing with, and also means
you never need to worry about name clashes. This is why I like the idea
of mod:goal keeping the current context.

Of course, there is no special reason why the :/2 operator has to be
used, and in fact I was wondering whether it might at some point be
possible to resurrect the humble full stop ( :-)) from its current
oblivion as the list cons functor (which doesn't need such a nice
symbol since it already has the [] notation), or use a symbol such as /
or :: so that the functionality could be provided without interfering
with the de-facto standard for :/2.

Having had experience in the computer games industry with an enormous
bug-ridden C++ program that people had been writing for over 5 years
without using libraries or namespaces, the idea of only having a flat
module namespace to organise a corresponding Prolog project is not very
appealing to me either.

ptarau@yahoo.com

2005-02-28, 3:59 pm

The Jinni 2005 Prolog compiler reuses the module notation to implement
a very general, compile time OO layer, supporting cyclical multiple
inheritance. Please take a look at

http://www.binnetcorp.com/download/...iUserGuide.html

for more details.

Paul Tarau
BinNet Corp.

P.S. As Jinni classes use separate symbol tables I guess the class
system is quite close to an "atom-based module system" for Prolog. Note
also that code spaces for classes are also separated - this allows
Jinni (which is multi-threaded) to be used as a container for multiple
independed applications running in the same process.

Brian Hulley

2005-02-28, 3:59 pm


ptarau@yahoo.com wrote:
> The Jinni 2005 Prolog compiler reuses the module notation to

implement
> a very general, compile time OO layer, supporting cyclical multiple
> inheritance. Please take a look at
>
> http://www.binnetcorp.com/download/...iUserGuide.html
>


Thanks - that system does look neat. One question: when the guide says

"Code inheritance is handled at compile time - through a special
ocompile/1 command which reinterprets include directives like
:[<file>] as inheritance from other Prolog files/classes. Classes are
compiled on the fly, at the first use of a class or creation of a new
instance."

does this mean that you would first compile a class file using
ocompile/1 which would create some internal representation of it in the
database which is then further compiled on first use at runtime? ie a 2
step compilation process? Or does the system use ocompile/1 at runtime?

Cheers - Brian.

ptarau@yahoo.com

2005-03-01, 3:59 pm

Jinni's ocompile/1 acts like Java's dynamic loading - but, like with
any Prolog - compilation included! A class is directly compiled to a
code area in memory, when a first instance is created - the code is
than shared by all other instances - which can keep their state in a
per-class and a per-instance dynamic database as well as in class and
instance variables.

Cheers,

Paul Tarau

Brian Hulley

2005-03-01, 8:58 pm

Thanks for the explanation - I'd been puzzling about how late binding
could be achieved for a hierarchical system and compile on first use
seems a very elegant solution.

Brian.

pmoura@di.ubi.pt

2005-03-02, 3:58 am


Brian Hulley wrote:

> Thanks for the explanation - I'd been puzzling about how late binding
> could be achieved for a hierarchical system and compile on first use
> seems a very elegant solution.


Actually, late/dynamic binding and just-in-time compiling is easier to
implement than static binding. With late-binding you can compile an
entity in your hierarchical system (object, module, ...) disregarding
its ancestors. Later, when you use an entity feature for the first time
(e.g. a predicate through message sending) you can compile or cache the
corresponding call in order to greatly improve further calls. This is a
common solution for OOP languages and extensions implementing dynamic
binding. You can search the web for "JIT compiling" for further
informations.

Cheers,

Paulo

Brian Hulley

2005-03-02, 8:58 pm

pmoura@di.ubi.pt wrote:

> binding. You can search the web for "JIT compiling" for further
> informations.


Thanks for pointing that out. In my resulting "travels" through the web
I came across an interesting discussion, at

http://lambda-the-ultimate.org/node/view/489

which has reversed the direction of my thoughts back to a non-modular
system, to keep the numinosity of Prolog with a pure flat predicate
space, eliminating all module complications, and avoiding a built-in
"this language is a poor relation of a proper OO language" assumption.

(While the LtU discussion was a bit negative w.r.t. OOP, I am only
taking the positive aspects from it ie Prolog *in its own right* is
already a great language, which can, when required, cleanly support all
OOP concepts via your Logtalk source-transformation system for
example.)

As an alternative to modules, I'm planning to add support in the
development environment for global source code transformations by
allowing atoms of the form a.b.c (without quotes) so that sub systems
of predicates could easily be renamed as necessary (this avoids
premature reification of the domain (into modules) and supports the
concept of "numinosity" which, as far as I can tell, is a unique
feature of pure Prolog...)


Brian.

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com