# Use\_module not importing all predicates

**URL:** <https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019>\
**Category:** Help!\
**Created:** [March 16, 2020, 12:27pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019 "2020-03-16T12:27:26Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![maren](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/maren/32/6605_2.png) [@maren](https://swi-prolog.discourse.group/u/maren)\
**Post date:** [March 16, 2020, 12:27pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/1 "2020-03-16T12:27:27Z")

</div>

I’m working on a relatively large prolog project. The amount of files has grown so much that I’d like to reorder the code a bit. So i thought of the following plan:

- group all existing source files into separate directories.
- have a single source file for each directory which re-exports all predicates in that directory through `reexport/1`.
- modify all `use_module` directives so that they use the high-level reexporting module, rather than the smaller submodules inside the directories.

Unfortunately, after having done this refactor, things stop working, and I get lots of ‘Undefined procedure’ errors for predicates that should actually be resolvable. Funnily, reconsulting files containing predicates that error actually makes the problem go away.

I have no idea what is going wrong. I tried creating a minimal example where I create some toy modules that import and reexport, but can’t seem to recreate the problem.

Does this problem sound familiar to anyone? Does anyone have any idea what would cause a module to not find predicates in its dependencies on first consult, but then find them anyway on second consult?

This happens on 8.0.3.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 16, 2020, 1:00pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/2 "2020-03-16T13:00:25Z")

</div>

To find what is going wrong I’d use the inspection predicates such as module\_property/2, predicate\_property/2 and source\_file\_property/2. I see no reason why this could not work. But, reexport/1,2 was added as part of the YAP/SWI portability issue to recreate the yap library from the SWI-Prolog one or the other way around.

Adding a load module that imports libraries from some sub application is not uncommon, but after that you typically only have to export a limited number of predicates that are of interest to the remainder of the system. The rest are internal interfaces.

If you just want to have access to a large collection of predicates without much typing I doubt this is the way to go. If these predicates follow a naming schema that is sufficiently unique to avoid conflicts I’d consider using use\_module/1 to the `user` module to make all predicates available or turn these libraries into _autoload libraries_.

I’ve seen big projects, but never really experienced the need for using reexport the way you want to do. Typically each module still needs a quite limited number of predicates from other modules. Many larger applications also use some publish/subscribe way for communication between fairly independent subcomponents. See library(broadcast).

---

<div class="post-metadata">

**Author:** ![maren](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/maren/32/6605_2.png) [@maren](https://swi-prolog.discourse.group/u/maren)\
**Post date:** [March 16, 2020, 1:11pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/3 "2020-03-16T13:11:19Z")

</div>

The goal is very much to just export a minimal api from each module eventually. The reexport stuff is temporary, and I hoped it’d let me get away with restructuring the files first, before determining what exactly the outer api is that I’ll have to export. Unfortunately, I then ran into this issue.

---

<div class="post-metadata">

**Author:** ![rob](https://avatars.discourse-cdn.com/v4/letter/r/838e76/32.png) [@rob](https://swi-prolog.discourse.group/u/rob)\
**Post date:** [March 16, 2020, 1:59pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/4 "2020-03-16T13:59:08Z")

</div>

@jan If you’re curious, you can reproduce it by cloning terminus-server, checkout to the #hub branch and run “./start.pl test”. You need the terminus\_store pack though.

---

<div class="post-metadata">

**Author:** ![michaelby](https://avatars.discourse-cdn.com/v4/letter/m/b3f665/32.png) [@michaelby](https://swi-prolog.discourse.group/u/michaelby)\
**Post date:** [March 16, 2020, 3:02pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/5 "2020-03-16T15:02:50Z")

</div>

Just a thought after a quick look at the code: have you tried doing

```
:- reexport('foo/bar').

```

instead of

```
:- reexport(foo/bar).

```

?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 16, 2020, 3:48pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/6 "2020-03-16T15:48:12Z")

</div>

That makes sense. You can figure out the dependencies by loading the still working branch and run `?- gxref.` (requires xpce installed).

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 16, 2020, 3:49pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/7 "2020-03-16T15:49:50Z")

</div>

Might give it a try, but I’m traveling and only have a small laptop that doesn’t make development easy :(.

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [March 16, 2020, 4:25pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/8 "2020-03-16T16:25:11Z")

</div>

The bug seems to be in the processing of `use_module/1` directives. The module `init` contains the directive:

```prolog
:- use_module(core(triple)).

```

In turn, the module `triple` definition is:

```prolog
:- module(triple, [
              update/5 % we're explicitely exporting this so it can be excluded elsehwere
          ]).
:- reexport([triple/base_type,
             triple/casting,
             triple/database_utils,
             triple/iana,
             triple/literals,
             triple/temp_graph,
             triple/terminus_bootstrap,
             triple/triplestore,
             triple/turtle_utils,
             triple/upgrade_db
            ]).

```

After loading the application, we get:

```nohighlight
?- module(init).
true.

init: ?- predicate_property(update(_,_,_,_,_), P).
P = interpreted ;
P = visible ;
P = static ;
P = imported_from(triplestore) ;
P = file('/home/pmoura/terminus-server/core/triple/triplestore.pl') ;
P = line_count(264) ;
P = number_of_clauses(1) ;
P = number_of_rules(1) ;
P = last_modified_generation(23984) ;
P = defined.

init: ?- predicate_property(terminus_instance_name(_), P).
false.

```

But the `terminus_instance_name/1` predicate is exported from module `terminus_bootstrap`, whose predicates are reexported by module `triple`:

```prolog
:- module(terminus_bootstrap,[
              terminus_instance_name/1,
              terminus_schema_name/1,
              terminus_inference_name/1,
              ...

```

I.e. the bug seems to be that the processing of `use_module/1` directives is looking into the second argument of the `module/2` directive for the imported module but ignoring the predicates exported via `reexport/1` directives in the same module. We arrive to the same conclusion if we use `gxref`. I can also reproduce the `gxref` results by using Logtalk’s diagrams tool to generate a xref diagram for the module `init` (the tool uses `library(prolog_xref)` when running on SWI-Prolog).

Calls to `module_property/2`, however, don’t seem to be affected by this bug:

```prolog
?- module_property(triple, exports(L)).
L = [terminus_inference_name/1, subject_id/3, nb_remove_triple/4, id_triple_addition/4, terminus_instance_name/1, update/5, head/2, predicate_id/3, ... / ...|...].

```

Hope this helps.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 16, 2020, 4:52pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/9 "2020-03-16T16:52:04Z")

</div>

> [@pmoura](#):
>
> I.e. the bug seems to be that the processing of `use_module/1` directives is looking into the second argument of the `module/2` directive for the imported module but ignoring the predicates exported via `reexport/1` directives in the same module.

I’ll never say something can’t be true, but use\_module/1 uses the exported property (or, the same data as the exported property uses). I.e., use\_module/1 and use\_module/2 load the file if not loaded. The /2 version next imports the given predicates (if they are exported, otherwise still, but with a warning). The /1 version looks at the exported predicates, but at the module structure itself, not from the module/2 header.

```prolog
:- module(r, [r/0]).
r :- writeln(r).

```

```prolog
:- module(q, [q/0]).
:- reexport(r).
q :- writeln(q).

```

```prolog
:- module(p, [p/0]).
:- use_module(q).

p :- q, r.

```

Saved into `r.pl`, `q.pl` and `p.pl` and loaded as `swipl p.pl` gives a properly working p/0 predicate.

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [March 16, 2020, 4:58pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/10 "2020-03-16T16:58:30Z")

</div>

How do you explain then:

```prolog
init: ?- predicate_property(terminus_instance_name(_), P).
false.

```

The module `init` calls the `terminus_instance_name/1` predicate from one of its own local predicates.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 16, 2020, 5:03pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/11 "2020-03-16T17:03:45Z")

</div>

I don’t know. I’ll try to have a look, but with my equipment here that is a bit hard. Does the minimal example not cover your claim? My claim is that at least in principle, reexported predicates behave the same as normally exported ones. I don’t have much clue why this specific predicate seems to escape this logic.

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [March 16, 2020, 5:07pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/12 "2020-03-16T17:07:11Z")

</div>

I also failed so far to find a minimal example that reproduces the reported problem.

But another interesting finding: if we modify the `core/api/init.pl` file as:

```prolog
:- use_module(core(triple)).
:- use_module(core(triple), [terminus_instance_name/1]). % added

```

We get:

```nohighlight
pmoura@ubuntu18:~/terminus-server$ ./start.pl test
Warning: /home/pmoura/terminus-server/core/api/init.pl:11:
	import/1: triple:terminus_instance_name/1 is not exported (still imported into init)

```

But, as mentioned before, this is inconsistent with:

```prolog
?- module_property(triple, exports(L)).
L = [terminus_inference_name/1, subject_id/3, nb_remove_triple/4, id_triple_addition/4, terminus_instance_name/1, update/5, head/2, predicate_id/3, ... / ...|...].

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 16, 2020, 5:26pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/13 "2020-03-16T17:26:13Z")

</div>

Enabling verbose loading (`?- set_prolog_flag(verbose_load, true).` gives a hint: ask.pl, which is using this terminus\_instance\_name/1 seems indirectly loaded from core/triple. It seems we are dealing with a case of cyclic module dependencies. use\_module/1,2 should handle this correctly, but possibly reexport doesn’t.

Hopefully this gives a clue to @rob.

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [March 16, 2020, 5:50pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/14 "2020-03-16T17:50:53Z")

</div>

Still, if the root cause is `reexport/1` not handling cyclic module dependencies, it’s still puzzling that `module_property/2` is returning all the expected exports.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 16, 2020, 8:20pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/15 "2020-03-16T20:20:43Z")

</div>

> [@pmoura](#):
>
> it’s still puzzling that `module_property/2` is returning all the expected exports.

My guess is that the exports are used before they are complete. Will figure out later with a nice big machine and even more importantly a big screen.

---

<div class="post-metadata">

**Author:** ![maren](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/maren/32/6605_2.png) [@maren](https://swi-prolog.discourse.group/u/maren)\
**Post date:** [March 18, 2020, 9:07am UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/16 "2020-03-18T09:07:17Z")

</div>

We’ve now switched to re-exporting all imported predicates. This works, though it’s not the prettiest.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 18, 2020, 10:48am UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/17 "2020-03-18T10:48:26Z")

</div>

> [@maren](#):
>
> This works, though it’s not the prettiest.

I understand it is an intermediate step. Note that there are plenty of tools in SWI-Prolog to compute the actually used dependencies. Any of these tools can make mistakes as Prolog allows constructing goals that are completely non-tracktable. Should be a good approximation though and if there is a good test suite it shouldn’t be too hard to fix the few possible omissions.

---

<div class="post-metadata">

**Author:** ![PaulBrownMagic](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/paulbrownmagic/32/211_2.png) [@PaulBrownMagic](https://swi-prolog.discourse.group/u/PaulBrownMagic)\
**Post date:** [March 19, 2020, 12:32am UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/18 "2020-03-19T00:32:26Z")

</div>

I’ve had the same experience maybe a year ago or so, using header like files with reexports. Also couldn’t get to the bottom of it or produce a toy example recreating it. Ended up with a big refactor, I think back then I tried using broadcast as an interface between “modules”, but that got refactored out too.

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [March 20, 2020, 9:45am UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/19 "2020-03-20T09:45:53Z")

</div>

> [@maren](#):
>
> We’ve now switched to re-exporting all imported predicates. This works, though it’s not the prettiest.

Even with those changes, I still see broken imports. For example:

```plaintext
$ swilgt start.pl
...
?- module_property(util, P).
P = class(user) ;
P = file('/Users/pmoura/terminus-server/core/util.pl') ;
P = line_count(1) ;
P = exports([terminus_schema_path/1, decimal/3, dateTime/11, time/8, truncate_list/4, exhaust/1, digit/3, ... / ...|...]) ;
P = exported_operators([op(601, xfx, @), op(601, xfx, ^^), op(920, fy, *), op(700, xfy, <>)]) ;
P = program_size(2448) ;
P = last_modified_generation(13327).

```

I then apply Logtalk tools, which compile the TerminusDB modules as objects, **which does not modifying in any way those modules** , and I get:

```plaintext
?- {loader}.
...
?- module_property(util, P).
P = class(user) ;
P = file('/Users/pmoura/terminus-server/core/util.pl') ;
P = line_count(1) ;
P = exports([terminus_schema_path/1, decimal/3, dateTime/11, time/8, truncate_list/4, exhaust/1, digit/3, ... / ...|...]) ;
P = exported_operators([op(601, xfx, @), op(601, xfx, ^^)]) ;
P = program_size(2448) ;
P = last_modified_generation(13327).

```

Notice the difference? Two of the `util` module exported operators are no longer reported.

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [March 20, 2020, 2:32pm UTC](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019/20 "2020-03-20T14:32:50Z")

</div>

> [@pmoura](#):
>
> Notice the difference? Two of the `util` module exported operators are no longer reported.

Followup. Managed to isolate what’s causing this operator bug. When compiling the `util` module as an object, the resulting Prolog file is loaded using the goal `load_files(Path, [derived_from(Source)| Options])`. Here, `Source` is the path to the module file (`'/Users/pmoura/terminus-server/core/util.pl'`) while `Path` is the plain Prolog file generated by the Logtalk compiler. If I remove the `derived_from(Source)` option, the bug no longer occurs. Thus, the handling of the `derived_from /1` option seems to be causing the followup call to `module_property/2` to report an empty list of exported operators. Hope this helps.

[Next page](https://swi-prolog.discourse.group/t/use-module-not-importing-all-predicates/2019.md?page=2)
