# Backtracking cannot see predicates changes when retract/assertz itself

**URL:** <https://swi-prolog.discourse.group/t/backtracking-cannot-see-predicates-changes-when-retract-assertz-itself/5417>\
**Category:** Discussion\
**Tags:** discussion, database\
**Created:** [May 21, 2022, 4:41pm UTC](https://swi-prolog.discourse.group/t/backtracking-cannot-see-predicates-changes-when-retract-assertz-itself/5417 "2022-05-21T16:41:44Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![chansey97](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chansey97](https://swi-prolog.discourse.group/u/chansey97)\
**Post date:** [May 21, 2022, 4:41pm UTC](https://swi-prolog.discourse.group/t/backtracking-cannot-see-predicates-changes-when-retract-assertz-itself/5417/1 "2022-05-21T16:41:44Z")

</div>

I did an experiment about retract/1 or assertz/1.

See following program:

```prolog
:- dynamic test/1.

update(X) :-
  test(X),
  format("update ~w~n", [X]),  
  ( X=2
  -> format("update X=2 ~n"), retract(test(3))
  ; format("update X=/=2 ~n"), true
  ),
  listing(test/1).

```

and query:

```prolog
?- assertz(test(1)),
   assertz(test(2)),
   assertz(test(3)),
   update(X).
update 1
update X=/=2 
:- dynamic test/1.

test(1).
test(2).
test(3).

X = 1 ;
update 2
update X=2 
:- dynamic test/1.

test(1).
test(2).

X = 2 ;
update 3
update X=/=2 
:- dynamic test/1.

test(1).
test(2).

X = 3.

```

Intuitively, the fact `test(3)` should be retracted when `X=2`, but why it still do backtracking for `test(3)` ? It should terminate when `X=2`, is that right?

I found some clues in [SWI-Prolog Manual](https://www.swi-prolog.org/pldoc/man?section=update), but I’m not sure if it’s related:

> Traditionally, Prolog systems used the _immediate update view_ : new clauses became visible to predicates backtracking over dynamic predicates immediately, and retracted clauses became invisible immediately.

> Starting with SWI-Prolog 3.3.0 we adhere to the _logical update view_ , where backtrackable predicates that enter the definition of a predicate will not see any changes (either caused by [assert/1](https://www.swi-prolog.org/pldoc/man?predicate=assert/1) or [retract/1](https://www.swi-prolog.org/pldoc/man?predicate=retract/1)) to the predicate.

Does it mean that in old Prolog system the above example would terminate when `X=2`? If so, is it possible to get the old behavior in current SWI-Prolog?

Thanks.

---

<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:** [May 23, 2022, 7:01am UTC](https://swi-prolog.discourse.group/t/backtracking-cannot-see-predicates-changes-when-retract-assertz-itself/5417/2 "2022-05-23T07:01:48Z")

</div>

It is true that the result you see is the consequence of the _logical update view_. And no, there is no way to get the old _immediate update view_ using the dynamic database.

You’ll need to reconsider your design at a somewhat higher level. If you want help it would help if you share your overall aim.

---

<div class="post-metadata">

**Author:** ![chansey97](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chansey97](https://swi-prolog.discourse.group/u/chansey97)\
**Post date:** [June 15, 2022, 2:52pm UTC](https://swi-prolog.discourse.group/t/backtracking-cannot-see-predicates-changes-when-retract-assertz-itself/5417/3 "2022-06-15T14:52:32Z")

</div>

> [@jan](#):
>
> You’ll need to reconsider your design at a somewhat higher level. If you want help it would help if you share your overall aim.

The aim is that I’d like to simulate [Entity\_component\_system (ECS)](https://en.wikipedia.org/wiki/Entity_component_system) in Prolog.

My current workaround is that

1. Introduce the `iter_entity/1`, the game loop traverse `iter_entity/1` instead of `entity/1`.

2. During a frame, structural changes impact `entity/1` instead of `iter_entity/1`. P.s. The structural changes are creating/deleting entities, adding/removing components to an entity.

3. At the end of frame, clean `iter_entity(EID)` and copy `entity(EID)` to `iter_entity(EID)`.

See the following program.

```prolog
:- dynamic iter_entity/1, entity/1, component/3.

entity(1).
entity(2).
entity(3).
entity(4).

component(1, position, vec(1,1)).
component(1, health, 100).
component(1, speed, 5).
component(1, bounds, 1).

component(2, position, vec(2,2)).
component(2, health, 200).
component(2, speed, 10).
component(2, bounds, 2).

component(3, position, vec(3,3)).
component(3, health, 300).
component(3, speed, 15).
component(3, bounds, 3).

component(4, position, vec(4,4)).
component(4, health, 400).
component(4, speed, 20).
component(4, bounds, 4).

iter_entity(1).
iter_entity(2).
iter_entity(3).
iter_entity(4).

query_entity_components(EID) :-  
 format("query_entity_components ~w~n", [EID]),
 forall(component(EID, K, V), format("component(~w, ~w, ~w)~n", [EID, K, V])).

query_all :-  
 format("query_all~n"),
 forall(entity(EID), format("entity(~w)~n", [EID])),
 forall(component(EID, K, V), format("component(~w,~w,~w)~n", [EID, K, V])).

game_update(FrameID) :-   
 system_A_update(FrameID),
 retractall(iter_entity(_)),
 forall(entity(EID), assertz(iter_entity(EID))).

system_A_update(FrameID) :-
 forall(iter_entity(EID), ignore((entity(EID), system_A_update_entity(FrameID, EID)))).

system_A_update_entity(FrameID, EID) :- 
 format("system_A_update_entity FrameID=~w EID=~w~n", [FrameID, EID]),           
 query_all,
 %% In frame 1, when entity(2) update, remove entity(3), 
 %% then the entity(3) will become invisible immediately!
 %% For example, unit_2 kill unit_3.
 ( FrameID=1, EID=2
 -> retract(entity(3)),
     retractall(component(3, _)),
     query_all     
 ; true
 ).

```

The `entity/1` represents entities, the `component/3` represents components, `system_A_update` represents a system, the `game_update` will be called in the game main loop.

The design is that

1. When adding an entity during a frame, the entity can be only queried and modified in the current frame, but it cannot be called in `system_A_update_entity/2`. It will be called in the next frame.
2. When removing an entity during a frame, the entity will become invisible immediately.

It seems reasonable.

Do you have any suggestions? Thanks.

Some tests:

> **?- game\_update(1).**
>
> ```prolog
> ?- game_update(1).
> system_A_update_entity FrameID=1 EID=1
> query_all
> entity(1)
> entity(2)
> entity(3)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> system_A_update_entity FrameID=1 EID=2
> query_all
> entity(1)
> entity(2)
> entity(3)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> query_all
> entity(1)
> entity(2)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> system_A_update_entity FrameID=1 EID=4
> query_all
> entity(1)
> entity(2)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> true.
> 
> ```

> **?- game\_update(1), game\_update(2),.**
>
> ```prolog
> ?- game_update(1), game_update(2).
> system_A_update_entity FrameID=1 EID=1
> query_all
> entity(1)
> entity(2)
> entity(3)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> system_A_update_entity FrameID=1 EID=2
> query_all
> entity(1)
> entity(2)
> entity(3)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> query_all
> entity(1)
> entity(2)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> system_A_update_entity FrameID=1 EID=4
> query_all
> entity(1)
> entity(2)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> system_A_update_entity FrameID=2 EID=1
> query_all
> entity(1)
> entity(2)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> system_A_update_entity FrameID=2 EID=2
> query_all
> entity(1)
> entity(2)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> system_A_update_entity FrameID=2 EID=4
> query_all
> entity(1)
> entity(2)
> entity(4)
> component(1,position,vec(1,1))
> component(1,health,100)
> component(1,speed,5)
> component(1,bounds,1)
> component(2,position,vec(2,2))
> component(2,health,200)
> component(2,speed,10)
> component(2,bounds,2)
> component(3,position,vec(3,3))
> component(3,health,300)
> component(3,speed,15)
> component(3,bounds,3)
> component(4,position,vec(4,4))
> component(4,health,400)
> component(4,speed,20)
> component(4,bounds,4)
> true.
> 
> ```

---

<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:** [June 15, 2022, 3:35pm UTC](https://swi-prolog.discourse.group/t/backtracking-cannot-see-predicates-changes-when-retract-assertz-itself/5417/4 "2022-06-15T15:35:00Z")

</div>

> [@chansey97](#):
>
> It seems reasonable.

Glad you think so 🙂 Update semantics can be tricky. Making clauses visible on a backtracking predicate would require any call to a dynamic predicate to succeed with a choice point as it is always possible the user adds a clause. SWI-Prolog does allow you to check whether a predicate was modified using predicate\_property/2 with the `last_modified_generation` property. You can also use prolog\_listen/2 to listen to changes of a predicate and act on it immediately.

> [@chansey97](#):
>
> ` forall(iter_entity(EID), ignore((entity(EID), system_A_update_entity(FrameID, EID)))).`

This seems reasonable, although I’d write it as below. The ignore/1 will cause calls to system\_A\_update\_entity/2 to fail without the whole thing failing.

```prolog
   forall(iter_entity(EID),
          ( iter_entity(EID)
          -> system_A_update_entity(FrameID, EID)
          ; true
          ))

```

Note that in recent versions you can declare a predicate should succeed exactly once using det/1. That makes debugging a lot quicker 🙂

---

<div class="post-metadata">

**Author:** ![chansey97](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chansey97](https://swi-prolog.discourse.group/u/chansey97)\
**Post date:** [June 16, 2022, 7:56pm UTC](https://swi-prolog.discourse.group/t/backtracking-cannot-see-predicates-changes-when-retract-assertz-itself/5417/5 "2022-06-16T19:56:46Z")

</div>

Thanks ❤.

I read the paper “A framework to specify database update views for Prolog” by Egon Boerger and Bart Demoen today. In that paper the authors introduced 4 different update views (i.e. _minimal_, _logical_, _immemediate_ and _maximal_) and argued that the most attractive view is the _minimal_ view, which is exactly the entity update semantics used in my game. That is interesting!

BTW, the authors also mentioned the following papers:

1. Efficient Implementation of a Defensible Semantics for Dynamic PROLOG Code by T. Lindholm, R.A. O’Keefe.

2. Cut and Paste - Defining the impure primitives of Prolog by C. Moss.

3. An analysis of Prolog database views and their uniform implementation by E. Boerger, D. Rosenzweig.

but I cannot find them on the Internet.

Do you (or anyone) have these papers?

I’d like to take a look at them.

Thanks.
