Question about Datalog rules with multiple bodies

Dear all,

From the Learn XTDB Datalog Today session on Rules we learn that, when multiple rules are defined, “[s]ubsequent rule definitions will only be used if the ones preceding it aren’t satisfied”.

Now, here’s a query example adapted from a concrete situation:

(q '{:find [name]
       :where [[student :enrollment-per-period/student-id _]
               (preferred-name student name)]
       :rules [[(preferred-name ?person ?preferred-name) ;; (1)
                [?person :enrollment-per-period/social-name ?preferred-name]
                (not [(clojure.string/blank? ?preferred-name)])]
               [(preferred-name ?person ?preferred-name) ;; (2)
                [?person :enrollment-per-period/social-name ?social-name] ;; (3)
                [(clojure.string/blank? ?social-name)] ;; (4)
                [?person :enrollment-per-period/given-name ?preferred-name]]]
       :order-by [[name :asc]]})

The idea is that the first rule defined at (1) would pick the case when a student has a social name. The second rule at (2) would serve the other cases, when the student has no social name (a blank field). Everyone in the database has given names.

I believed that the statements at (3) and (4) would be logically redundant and unnecessary. To my surprise, though, in cases where the student has a social name, if I don’t add these lines to the second rule, I’ll end up picking the same student twice, both with her given name and her social name.

Could someone please help me understand?

EDIT: The 1.x Language Reference, quoted below, states that multiple rule bodies are similar to or-join legs. I suppose, then, that the description in Learn XTDB Today is incorrect.

Multiple rule bodies may be defined for a single rule name (i.e. using matching rule heads) which works in a similar fashion to an or-join . Rules and or-join both execute internally as non-lazy subqueries whose results are unified (and potentially cross-joined) with the tuples in the outer query.

(I also note in passing the subsection on Bound arguments, according to which the rules would preferably be stated as (preferred-name [?person] ?preferred-name).)

I can see that the or-join behaviour was an implementation decision. But isn’t this design for rules somewhat limiting for cases like the one exemplified above, because of the need to specify exclusion conditions for every rule? I verify that according to its documentation, Datomic implements rules differently, as a logical or (which makes them similar to Prolog rules, in contrast to XTDB’s implementation).

Hey @brunocbr apologies for the confusion here - I can confirm that wording
was erroneously copied and included (by me) from the original Learn Datalog Today text. I’ll make sure it is removed/changed soon! I’m not sure it’s actually an accurate statement for how Datomic works in any case (perhaps someone can confirm).

The behaviour of rules you’re seeing reflects the (more) declarative semantics of XTDB’s Datalog, where user-supplied orderings are entirely ignored and rules can generate new tuples (and not just be used as predicates), but I believe a “logic OR” is still a valid interpretation of how XTDB behaves.

It is definitely a trade-off of ~procedural ordering vs. declarative constraints. I would say XTDB behaves more like Prolog.