Hook predicates and static binding - incompatible?

Prolog compatibility woes and feedback that is not compiler specific

Moderator: Paulo Moura

Post Reply
Parker
Posts: 33
Joined: Wed Feb 27, 2008 2:51 pm

Hook predicates and static binding - incompatible?

Post by Parker » Mon Oct 20, 2008 4:31 pm

I'd like to use static binding for category predicates called from an object - ie switch from :: to :. However, I use a hook object to allow compatibility across different prolog systems and have run into a problem.

Here is the loader. An object test should use predicates from category utils. But utils has predicates affected by hook.

Code: Select all

:- initialization(
        (logtalk_load([hook]),
         logtalk_load([utils],[reload(skip),hook(hook)]),
	 logtalk_load([test],[events(on),xmldocs(off)])
        )). 
All the code compiles fine if the call to the category predicate is with ::. But when the call is with : object test is giving me an existence error:

Code: Select all

    compiling object test... 
        ERROR!    existence_error(procedure, yap_flag(counter, _G9647, 0))
                  in clause: test:- :yap_flag(counter, _G9647, 0)
                  above line: 7
Is this because I'm not using these features correctly or could it be they're not compatible?

Cheers,
Parker

Paulo Moura
Logtalk developer
Posts: 470
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Hook predicates and static binding - incompatible?

Post by Paulo Moura » Mon Oct 20, 2008 7:18 pm

Hi Parker!

Nice to ear from you again.
Parker wrote: I'd like to use static binding for category predicates called from an object - ie switch from :: to :. However, I use a hook object to allow compatibility across different prolog systems and have run into a problem.
Note that, while the :/1 control construct allows the use of static binding when calling imported category predicates, the semantics of the control constructs ::/2 and :/1 are different. The first uses predicate (declaration and definition) lookups starting in "self" while the later uses predicate lookups starting in "this" and restricted to the imported categories. Switching from ::/2 to :/1 is not a problem as long as the predicate is not being redefined in a descendant object.
Parker wrote: Here is the loader. An object test should use predicates from category utils. But utils has predicates affected by hook.

Code: Select all

:- initialization(
        (logtalk_load([hook]),
         logtalk_load([utils],[reload(skip),hook(hook)]),
	 logtalk_load([test],[events(on),xmldocs(off)])
        )). 
All the code compiles fine if the call to the category predicate is with ::. But when the call is with : object test is giving me an existence error:

Code: Select all

    compiling object test... 
        ERROR!    existence_error(procedure, yap_flag(counter, _G9647, 0))
                  in clause: test:- :yap_flag(counter, _G9647, 0)
                  above line: 7
Is this because I'm not using these features correctly or could it be they're not compatible?
I guess you're defining clauses for goal_expansion/2 in your hook object. You need to add a clause for :/1 goals. The same for ::/1 goals. For example:

Code: Select all

goal_expansion(::Goal, ::ExpandedGoal) :-
    nonvar(Goal),    % sanity check for prevening endless loops
    goal_expansion(Goal, ExpandedGoal).

goal_expansion(:Goal, :ExpandedGoal) :-
    nonvar(Goal),    % sanity check for prevening endless loops
    goal_expansion(Goal, ExpandedGoal).

goal_expansion(..., ...).
I'm surprised that your code works for ::/1 calls but it's hard to explain without seeing your hook code.

Hope this helps. Let me know if the solution above solves your problem. Cheers,

Paulo
Paulo Moura
Logtalk developer

Parker
Posts: 33
Joined: Wed Feb 27, 2008 2:51 pm

Re: Hook predicates and static binding - incompatible?

Post by Parker » Fri Oct 24, 2008 2:18 pm

Paulo Moura wrote: Nice to ear from you again.
Likewise!
Is this because I'm not using these features correctly or could it be they're not compatible?
Ooops. It's my fault. I missed out the category import so the existence error was perfectly correct. With that corrected, it appears to work fine.
Paulo Moura wrote: I guess you're defining clauses for goal_expansion/2 in your hook object. You need to add a clause for :/1 goals. The same for ::/1 goals. For example:

Code: Select all

goal_expansion(::Goal, ::ExpandedGoal) :-
    nonvar(Goal),    % sanity check for prevening endless loops
    goal_expansion(Goal, ExpandedGoal).

goal_expansion(:Goal, :ExpandedGoal) :-
    nonvar(Goal),    % sanity check for prevening endless loops
    goal_expansion(Goal, ExpandedGoal).

goal_expansion(..., ...).
I'm surprised that your code works for ::/1 calls but it's hard to explain without seeing your hook code.
The hook code doesn't specifically address ::/1 calls. BTW, the code should look familiar to you :wink:

Code: Select all

    hook((Head :- Body), [(Head :- TBody)]) :-
        conjunction(Body, TBody).

    conjunction((Goal1; Goal2), (TGoal1; TGoal2)) :-
        !,
        conjunction(Goal1, TGoal1),
        conjunction(Goal2, TGoal2).
    conjunction((Goal1 -> Goal2), (TGoal1 -> TGoal2)) :-
        !,
        conjunction(Goal1, TGoal1),
        conjunction(Goal2, TGoal2).
    conjunction(\+ (Goal, Goals), \+ (TGoal, TGoals)) :-
        !,
        conjunction(Goal, TGoal),
        conjunction(Goals, TGoals).
    conjunction((Goal, Goals), (TGoal, TGoals)) :-
        !,
        conjunction(Goal, TGoal),
        conjunction(Goals, TGoals).
    conjunction(\+ Goal, \+ TGoal) :-
        !,
        transform(Goal, TGoal).

    conjunction(Goal, TGoal) :-
        transform(Goal, TGoal).

    % replace bb_put/2 with true
    transform(bb_put(_,_),true) :- !.

    % replace bb_get/2 with true
    transform(bb_get(_,_),true) :- !.

    % replace number_atom/2 with true
    transform(number_atom(_,_),true) :- !.

    transform(Goal, Goal).

    goal_expansion(bb_put(_,_),true).
    goal_expansion(bb_get(_,_),true).
    goal_expansion(number_atom(_,_),true).
Paulo Moura wrote: Hope this helps. Let me know if the solution above solves your problem. Cheers,
Paulo
Thanks Paulo. Curiously, preliminary testing shows no noticeable speed improvement for my code. Perhaps there are no :/1 calls on the critical path (although I doubt this). Is it possible static binding is not being used for some reason? To test this I compared compiled code when switching from ::/1 to :/1 and the calls to $lgt_send_to_self_nv are removed, which seems to be correct. I suppose I was over-optimistic about the improvement. However my results are consistent with your benchmarks (c2 vs c1) here http://logtalk.org/performance.html

Running Logtalk: 2.32.2 on SWI 5.6.57

Cheers,
Parker,

FYI: reply notification is not working on this forum even when subscribed to a topic - just in case you didn't know.

Paulo Moura
Logtalk developer
Posts: 470
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Hook predicates and static binding - incompatible?

Post by Paulo Moura » Fri Oct 24, 2008 3:21 pm

Parker wrote: The hook code doesn't specifically address ::/1 calls. BTW, the code should look familiar to you :wink:

Code: Select all

    hook((Head :- Body), [(Head :- TBody)]) :-
        conjunction(Body, TBody).

    conjunction((Goal1; Goal2), (TGoal1; TGoal2)) :-
        !,
        conjunction(Goal1, TGoal1),
        conjunction(Goal2, TGoal2).
    conjunction((Goal1 -> Goal2), (TGoal1 -> TGoal2)) :-
        !,
        conjunction(Goal1, TGoal1),
        conjunction(Goal2, TGoal2).
    conjunction(\+ (Goal, Goals), \+ (TGoal, TGoals)) :-
        !,
        conjunction(Goal, TGoal),
        conjunction(Goals, TGoals).
    conjunction((Goal, Goals), (TGoal, TGoals)) :-
        !,
        conjunction(Goal, TGoal),
        conjunction(Goals, TGoals).
    conjunction(\+ Goal, \+ TGoal) :-
        !,
        transform(Goal, TGoal).

    conjunction(Goal, TGoal) :-
        transform(Goal, TGoal).

    % replace bb_put/2 with true
    transform(bb_put(_,_),true) :- !.

    % replace bb_get/2 with true
    transform(bb_get(_,_),true) :- !.

    % replace number_atom/2 with true
    transform(number_atom(_,_),true) :- !.

    transform(Goal, Goal).

    goal_expansion(bb_put(_,_),true).
    goal_expansion(bb_get(_,_),true).
    goal_expansion(number_atom(_,_),true).
Why do you need the conjunction/2 predicate? It should be enough to simply define clauses for goal_expansion/2 in your hook object. Logtalk automatically calls goal_expansion/2 for every goal in the body of object (and category) predicate clauses. Am I missing something?
Parker wrote: Thanks Paulo. Curiously, preliminary testing shows no noticeable speed improvement for my code. Perhaps there are no :/1 calls on the critical path (although I doubt this). Is it possible static binding is not being used for some reason? To test this I compared compiled code when switching from ::/1 to :/1 and the calls to $lgt_send_to_self_nv are removed, which seems to be correct. I suppose I was over-optimistic about the improvement. However my results are consistent with your benchmarks (c2 vs c1) here http://logtalk.org/performance.html

Running Logtalk: 2.32.2 on SWI 5.6.57
Logtalk 2.32.2 is 3 months old. The latest stable release (2.33.2) gives you some nice improvements and new features including a new debugger feature that you requested long ago.

I assume that you're compiling the categories in a separate logtalk_load/2 call using the reload(skip) option before the calls that load the objects that import the category. The actual improvement depends on the amount of work your category predicates are performing. If this work is significant (performance-wise), the overhead of dynamic binding (when using ::/2 to call the category predicates) becomes negligible.

To check that static binding is doing its magic, check the generated Prolog files for your objects. The category predicates should be being called directly.

Btw, SWI-Prolog 5.7.x seems to be getting stable enough for daily use. It should provide a nice speed boost for your application.
Parker wrote: FYI: reply notification is not working on this forum even when subscribed to a topic - just in case you didn't know.
Yes, email notifications seem to not be working. Again. Meantime, the most reliable way to get notified is to subscribe to this forums RSS feed. For Logtalk development news and ticket updates subscribe to the RSS feeds on http://trac.logtalk.org/.

Cheers,

Paulo
Paulo Moura
Logtalk developer

Paulo Moura
Logtalk developer
Posts: 470
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Hook predicates and static binding - incompatible?

Post by Paulo Moura » Sun Nov 09, 2008 12:03 am

Paulo Moura wrote: Yes, email notifications seem to not be working. Again. Meantime, the most reliable way to get notified is to subscribe to this forums RSS feed. For Logtalk development news and ticket updates subscribe to the RSS feeds on http://trac.logtalk.org/.
The problem with email notifications should hopefully be solved now. Nevertheless, subscribing to the RSS feeds is still recommended, both for keeping tabs in the forums and on Logtalk development.

Cheers,

Paulo
Paulo Moura
Logtalk developer

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest