#200 broken modules

wrong answer
open
nobody
None
2
2013-09-03
2013-08-07
Michael Kifer
No

I ran into the following broken behavior:

Three tiny files (attached):

m1

:- export foo/1.
foo(1).

m2

fact(m1:foo(abc)).

m3

?- [m1].
test(X) :- G = (m1:foo(X)), load_dyn(m2), fact(G1), G=G1.

I am testing here if m1:foo/1 from m2.P is the same as m1:foo/1 from m3.P.

If you ask ?- test(X) then you get a no -- they are not the same.
The culprit here is

?- [m1].

which somehow imports foo/1 into usermod and changes the meaning of G = (m1:foo(X)).
If you delete ?- [m1]. in m3.P then the query test(X) returns X=abc, i.e., the two m1:foo/1's are the same functor.

I think this is a serious bug that makes XSB modules very hard to use reliably for meta programming.

I could possibly understand the rationale there might have been if I were using straight foo/1 instead of m1:foo/1 But with m1:foo I am clearly stating that my intent is to construct foo/1 in module m1.
So, I am not sure what XSB is doing here.

Discussion

  • The problem is your expectation of the meaning of the syntax of mod:foo(X). This is just a term, like any other. Functor symbols are in modules, so foo/1 can be in different modules, and in your case, by thinking carefully of how modules are assigned to functor symbols, we see that in one case the functor symbol foo/1 of m1:foo(X) is in m1, and in the other it is in usermod. So these two terms are not syntactically identically, and unification fails.

    The syntax mod:foo(X) is treated in a particular way in certain predicates. Predicates that manage predicates (like call/n, assert, retract, ...) treat the syntax mod:foo(X) to mean foo(X) with foo/1 in module mod (regardless of what module f/1 in that term actually happens to be in.) So mod:foo(X) is treated specially by certain predicates that take predicates as arguments. If you want to compare whether two modified calls would actually be the same, you could write an explicit comparison predicate as:

    same_call(Mod1:Goal1,Mod1:Goal2) :-
        machine:term_new_mod(Mod1,Goal1,Call1),
        machine:term_new_mod(Mod1,Goal2,Call2),
        Call1 = Call2.