Fork me on GitHub
#datomic
<
2020-11-19
>
joshkh13:11:10

nil is meant to be allowed in heterogenous tuples, right? for example, let's say i have a tuple like this: [:db.type/ref :db.type/ref] and nil in the second value {:person/parents [123456 nil]} i get an exception when i untuple and bind on the nil value

(d/q '{:find  [?person ?parent-a-name]
       :in    [$]
       :where [
               [?person :person/parents ?parents-tuple]
               [(untuple ?parents-tuple) [?parent-a ?parent-b]]
               [?parent-a :person/name ?parent-a-name]
               [?parent-b :person/name] ;<-- throws exception
               ]}
     db)
Execution error (NullPointerException) at datomic.core.db/asserting-datum (db.clj:-1).
null
clojure.lang.ExceptionInfo: processing clause: [?parent-b :parent/name], message:  #:cognitect.anomalies{:category :cognitect.anomalies/incorrect, :message "processing clause: [?parent-b :parent/name], message: "}

kschltz19:11:27

@U0GC1C09L I'm afraid you can't have nil there

kschltz19:11:10

If I'm not mistaken the value just would not be there

kschltz19:11:24

{:parents [123456]}

joshkh19:11:17

that makes sense to me. do you know if that is the official stance? i am allowed to both transact and pull nil values. as for binding i would have expected the query to not unify instead of throw an exception

kschltz20:11:40

I believe you get that exception because theres actually a value (nil), which makes the whole hting unify but it wont comply to your clause :person/name

kschltz20:11:34

That would be my guess

joshkh20:11:39

fair enough 🙂

joshkh20:11:05

just a funny observation: when retracting an entity referenced in a tuple, the tuple retrains the entity db/id even after the target has been retracted. that feels equally strange to me but for other reasons.

kschltz20:11:12

Not sure why, but I think if you look at it like independent datoms, kinda makes sense. Its not like a component, where you retract the mother entity and the child follows along. But you have a fair point

joshkh21:11:17

also from Jaret on the forums (at least regarding homogenous tuples) > Additionally you may be interested in knowing that, `nil` is a legal value for any slot in a tuple. This facilitates using tuples in range searches, where `nil` sorts lowest. https://forum.datomic.com/t/tuple-with-single-item-fails-transaction/1690

😮 3
joshkh21:11:00

maybe i'll make an ol' posteroo on the forums

kschltz21:11:06

I hope Jaret get a raise soon enough, he's always the one to respond my tickets xD

joshkh21:11:02

Jaret and Marshall both do a great job of putting up with my bs 😎

kschltz21:11:41

couldn't say it better

joshkh21:11:26

(in case someone from Cognitect reads the thread, i've posted the question here: https://forum.datomic.com/t/nil-value-in-heterogeneous-tuple-throws-a-nullpointerexception/1693)

😄 3
favila22:11:39

I think this is just a mismatch between datalog unification and how tuples are handled. Since this is a composite attribute, consider reading the source attribute value instead of the composite

favila22:11:05

(I’ve often wished for composite attributes to have a “not nillable” option, so that they are not asserted unless all values are present)

joshkh09:11:48

i don't think this is a composite tuple though. this is a heterogenous tuple.

favila13:11:14

Heterogeneous tuples cannot contain refs

joshkh15:11:27

hmm, i don't doubt what you're saying.. maybe i'm just confused here. i thought this is a heterogeneous tuple (from the schema in the forum post above):

{:db/ident       :person/parents
 :db/valueType   :db.type/tuple
 :db/tupleTypes  [:db.type/ref :db.type/ref]
 :db/cardinality :db.cardinality/one}
which allows refs, and works with transactions and pulls. are you saying that hetero tuples shouldn't contain refs, rather than cannot contain refs?

favila13:11:04

they shouldn’t, and I thought they could not

favila13:11:12

if you read the docs, they make no mention of this

favila13:11:44

also conceptually, it’s bad: ref values are supposed to be managed by datomic--this is no different than putting a long into a tuple

favila13:11:27

with composite tuples, it knows what assertion it’s denormalized from; here, there is no support. and you can’t use lookup refs or keywords or tempids to reference these

favila13:11:33

I’m wrong though, :db.type/ref is lised as a scalar type

favila13:11:04

I am pretty sure it wasn’t the last time I read this--maybe a change? Anyway, it still seems like a bad idea

favila13:11:28

but if you really need to do it, queries needs to be defensive against nils

favila13:11:05

[(!= ?x nil)] immediately might work, [(some? ?x)] should definitely work.

joshkh16:11:36

hey favila, both of your solutions worked. thanks. in my case i'm storing some rankings in tuples...

{:race/finishers [[0 sally-ref coach-1-ref]
                  [1 bob-ref nil]
                  [2 jane-ref coach-2-ref]]}
of course the alternative (and more verbose) solution is to have separate ranking entities that store all of the context (the race, the people involved, and a rank), but as an experiment i thought tuples might be an interesting solution. in my example i don't see why storing references in tuples seems like a bad idea.