Re: handling state the database way

Paulo Moura <[email protected]>
Newsgroups gmane.comp.ai.prolog.swi
Message-ID <[email protected]>
On 16/02/2014, at 22:26, Richard A. O'Keefe <[email protected]> wrote:

> 
> On 15/02/2014, at 7:28 AM, Abdallah, Samer wrote:
> [To paraphrase:] Why can't I *see* the structure?
> 
> May I suggest a module?
> 
> First draft:
> 
> :- module(single_fact, [
>    initialise/2,
>    update/2,
>    finalise/1
>   ]).
> :- meta_predicate
>    update(+, 2).
> 
> :- dynamic store/2.
> 
> initialise(Key, Datum) :-
>    retractall(store(Key,_)),
>    assert(store(Key, Datum)).
> 
> update(Key, Updater) :-
>    retract(store(Key, Old)),
>    !, /* green cut */
>    (   call(Updater, Old, New) -> F = true
>    ;   New = Old, F = fail
>    ),
>    assert(store(Key, New)),
>    F == true.
> 
> finalise(Key) :-
>    retractall(store(Key,_)).
> 
>> 
>> 	:- dynamic some_pred/1.
>> 	update(Event) :-
>> 		retract(some_pred(OldState)),
>> 		update_something(Event,OldState,NewState),
>> 		assert(some_pred(NewState)).
>> 
>> 	initialise :
>> 		retractall(some_pred(_)),
>> 		assert(some_pred( <Initial state> )).
> 
> This becomes:
> 
> 	initialise :-
> 	    single_fact:initialise(<<key>>, <<initial state>>).
> 
> 	update(Event) :-
> 	    single_fact:update(<<key>>, update_something(Event)).
> 
>> 
>> Obviously, one could write a library to do this, but I think there might be
>> benefit in performance, atomicity and control over backtracking behaviour
>> that might come from it being integrated at a lower level, like flag/3.
> 
> Yes, but the library stage comes *first*.

The design idea behind the "single_fact" module centralizes (for an application) the handling of mutable data.  This can be both an advantage (a single place to hold the mutable data) and a disadvantage (multiple modules using this module must be careful to use different keys). This makes "single_fact" more like a *prototype* solution than an ideal *library* solution. As a library solution it comes with a bias towards a single central, global store.

Logtalk provides a bit more flexible library solution by using a category instead. A Logtalk category is a fine-grined unit of code reuse that can be (virtually) imported by any object. Using the "single_fact" module suggested predicates, we can define:

:- category(single_fact).

	:- public([
		initialize/2,
		update/2,
		finalize/1
	]).

	:- private(store/2).
	:- dynamic(store/2).

	initialise(Key, Datum) :-
   		retractall(store(Key,_)),
   		assert(store(Key, Datum)).

	...

:- end_category.

Looks similar but there are key semantic differences. Categories are used for defining new objects object by composition but without code duplication, no matter how many objects import a single category. But more interesting in this case is that each importing object will have its own store, independent of the stores of other objects that also import the category. The retractall/1 and assert/1 calls above retract and assert to the importing object private store. Thus, no object using this category can clash with the keys used by other objects in the same application.

It's recommended that the "single_fact" interface not be exposed by the objects importing it? No problem, We can simply write:

:- object(component_foo,
	imports(private::single_fact)).

Logtalk enforces encapsulation, so a component_foo::update(Key, Datum) will generate a permission error.

But what if the best solution for an application is really to have a single central store? No problem:

:- object(central_store,
	imports(single_fact)).

:- end_object.

As category interfaces add to the interface of the objects importing them, we can simply write from other places in the application e.g.

	initialise :-
	    central_store::initialise(<<key>>, <<initial state>>).

	update(Event) :-
	    central_store::update(<<key>>, update_something(Event)).

Thus, a Logtalk category library solution copes without bias with both central stores and individual stores.

> By the way, there's a proposal for adding mutable variables to
> ISO Prolog, relevant to this.

WG17 have been discussing mutable variables forever.

>  I am afraid that after printing
> a copy of the proposal and skimming it, I hurled it into the
> nearest paper recycling bin in horror and disgust at the very
> idea.  But if Prolog _is_ to end up with green worms wriggling
> behind its eyes (see Stross's Laundry series for the key to
> this metaphor) it would be well if they were the *same* green
> worms.
> 
>> 
>> What do you think? Is it the case that the cost of doing unification on the
>> state means that it is not worth the small gain of making it a built-in?
> 
> The cost of unification is unlikely to be high.
> What counts more is how expensive everything *else* the applications
> are doing.  And really, the only way to find out is to start with a
> simple library module and do some profiling.
> 
> I will say that any Prolog program that spends a lot of its time
> in the single_fact: module will be in desperate need of
> restructuring.  Or possibly of rewriting in Visual Basic.NET.

The trouble is often with porting applications (without going for a major restructuring in the process).

Cheers,

Paulo

-----------------------------------------------------------------
Paulo Moura
Logtalk developer

Email: <mailto:[email protected]>
Web:   <http://logtalk.org/>
-----------------------------------------------------------------
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.