Module_property/2 - include property for super

Internally (C code) SWI-Prolog modules have several properties. (ref)

Many of the module properties are accessible via Prolog with module_property/2.

One of the internal properties that is not accessible via Prolog is the list of supers.

Should supers should be added to module_property/2?

I can’t think of a reason not to add the property supers, but then again I don’t understand SWI-Prolog at the C code.

Here is some code to create the relationships between modules by using predicate_property/2 that I am expecting should be similar to what a super property for module would return.

After reply by Jan W. added section for import_module/2.

:- module(module_tools,[
        init/0,
        list_uses/1,
        list_imports/1,
        compare/0
    ]).

:- use_module(library(persistency)).

:- persistent
    uses(super:atom,module:atom),
    imports(module:atom,import:atom).

:- initialization(db_attach('module.journal', [])).

add_uses(Super,Module) :-
    (
        uses(Super,Module), !
    ;
        assert_uses(Super,Module)
    ).

init_uses :-
    forall(
            predicate_property(Super:_, imported_from(Module)),
            add_uses(Super,Module)
        ).

list_uses(uses(Super,Module)) :-
    uses(Super,Module).

add_imports(Module,Import) :-
    (
        imports(Module,Import), !
    ;
        assert_imports(Module,Import)
    ).

init_imports :-
    forall(
            (
                current_module(Module),
                import_module(Module,Import)
            ),
            add_imports(Module,Import)
        ).

list_imports(imports(Module,Import)) :-
    imports(Module,Import).

init :-
    init_uses,
    init_imports.

compare :-
    missing_imports,
    missing_uses.

missing_imports :-
    list_uses(uses(A,B)),
    (
        list_imports(imports(A,B))
    ->
        true
    ;
        format('Missing import: ~w, ~w~n',[A,B])
    ),
    fail.
missing_imports.

missing_uses :-
    list_imports(imports(A,B)),
    (
        list_uses(uses(A,B))
    ->
        true
    ;
        format('Missing uses: ~w, ~w~n',[A,B])
    ),
    fail.
missing_uses.

Example usage.

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

?- working_directory(_,'C:/Users/Groot/Documents').
true.

?- ['module tools'].
true.

?- init.
true.

?- list_uses(Uses).
Uses = uses(prolog_source, system) ;
Uses = uses(prolog_source, prolog_operator) ;
Uses = uses(prolog_source, '$expand') ;
...

?- list_imports(Imports).
Imports = imports(prolog_source, system) ;
Imports = imports(swi_option, system) ;
Imports = imports(prolog_operator, system) ;
...

?- compare.
...
Missing import: prolog_metainference, lists
Missing import: prolog_metainference, apply
Missing uses: prolog, user
Missing uses: pce_expansion, user
...

If you want to look at the journal file created by library persistency remember that you have to execute halt. first. Also the code will hold a lock on the file while the code is running.

The internal notion of a super module is the same as what is accessible through import_module/2. What you are doing seems more related to library(prolog_xref) or gxref/0.

I’m not really against exposing import_module/2 also through module_property/2, although this and its related default_module/2 are non-deterministic and that isn’t ideal the module_property/2 api.

1 Like

Thanks. I will check this out and add a variation to my sample code if it proves useful.


Yes. I am starting to experiment with gxref/0 more, but it doesn’t have all of the functionality I would like. Granted when someone first learns to use a tool and the way they eventually use it can be quite different, that might be the case.

For example if I drag library(system) or library(lists) onto the canvas area then right click the following options appear

image

but for me clicking on Show exports or Show imports does nothing.

I am on Windows 10.

While I can run X-Windows with WSL 2 on Windows 10, currently enabling X-Windows with WSL 2 grinds the system to a near halt and becomes impractical to use.


The specific need is to do an inheritance of predicates similar to Object-Oriented. The predicates are for the BNF for rfc5234, rfc3986, and rfc7230 which each extend from the previous and thus inheritance. However unlike inheritance, some of the predicates will not replace the ones in the preceding rfc but work along side them, think multi-clause predicate.

I experimented with oo.pl from here but then realized that it is not the call stack (prolog frame) that I should be traversing, but the hierarchy of the modules.

Anyway the only way to know if what I seek is doable is to just try it.

Indeed, seems broken. Double clicking shows the proper dependencies, so this seems more a GUI issue.

Not sure I get this. Surely though, a module import never extends a predicate. The only way to do that is to add a clause calling the super. So, assume we have s:p/1 and t:p/1 and t:p/1 should be extended with s:p/1 we get in t:

p(1).
p(2).
...
p(X) :- s:p(X).

That makes two of us.

It is hard to explain where one is going when one is not sure about where one needs to go.

Yes.

It seems that to solve my specific problem I have a few choices.

  1. Duplicate code. This works and was done by creating a single module with all of the predicates needed for each RFC. This essentially was done by taking the preceding RFC and duplicating the code then adding the new predicates. Thus each RFC required a new and unique module.

  2. Use multifile/1. In one of the ways I did get the code working was to use multifile/1 for some of the predicates, but while I understand what I did and why, trying to write that up for a Wiki article or something requires an in-depth explanation of parsing, inheritance, Prolog, etc, that I would run away in horror if I read it and never use it.

  3. Abandon the module system. I have considered making predicates that replace use_module/1,2 with something like inherit_module/1,2 but that is not even a correct conveyance of the what needs to be done. In all my years of using inheritance with OO, I don’t recall the notion of something like multi-clause predicates being used with inheritance. Especially when on of the clauses would be in one module and the other would be in another module.

  4. Manage the exports and imports by hand and use Module:Predicate where necessary. This also came to rely on needing multifile/1 to work, thus turned out not to be a separate solution.

  5. A variation on oo.pl. This is the one I am working on now that needs super.

  6. Using expand_term/2 or similar. A future option as a plan B, or to be used with another option if it is to complex to explain in a Wiki article.


This is closest to what seems to be the correct path and thus the need for knowing the super. I still don’t see all of the potential problems so will just write the code and hopefully it will work as expected.

Thanks. :slightly_smiling_face:

In fact, the code was designed not to include imports and exports from libraries in the dependency view as it quickly gets a mess. Should work fine on your own modules.

1 Like

Besides import/export, SWI-Prolog modules can inherit in a different way. That is realised by import_module/2 and predicates from the same manual section. It implies that if a predicate is not defined the system examines the import modules one-by-one and when found, auto-imports the definition. A module can have multiple import modules (rarely used). You can form a lattice of import modules, etc.

This is not proper OO. There is no notion of self and also no real notion of super, so a module cannot wrap its general notion of super, it can only wrap the implementation from a known concrete module. You can achieve some stuff using the module transparent notion, but that is more hacking than anythng else.