I get this strange behaviour with e/amb and a when statement:
(let [e (e/amb 1 2 nil)]
(when e
(println :e e)))
This prints:
:e 2
:e nil
:e 1
:e 2
:e nil
:e 1
I know, that e/amb puts things in superposition.
Anyway it looks odd, that
a) the when branch is executed with nil values
b) everything is executed twice
I would expect to see this:
:e 2
:e 1
Is this a bug or the intended behaviour?the current behavior in this case is less than obvious. To understand consider inlining the local value
(when (e/amb 1 2 nil)
(println :e (e/amb 1 2 nil)))you can achieve what you desire with e/for
(e/for [e (e/amb 1 2 nil)]
(when e
(println :e e)))
Now there's 3 branches with a single value and the world makes sense again.
We certainly aim to improve this at some point. The reason we haven't yet is we don't hit this case, usually we e/for over our ambs anywayah I see. thanks for the explanation π e/for works fine.
π¦
https://github.com/theronic/eacl v6.1 now yields sub-millisecond performance when enumerating 1k of 800k permissioned entities in pages of 50 results, backed by Datomic:
β’ EACL is a https://en.wikipedia.org/wiki/Relationship-based_access_control authorization library based on https://authzed.com/spicedb, built in Clojure and backed by Datomic.
β’ Here is a https://x.com/PetrusTheron/status/1996344248925294773 of EACL used from an Electric Clojure v3 application with real-time enumeration of permissioned resource via eacl/lookup-resources. This demo showcases iterative counting with some Missionary machinery on top of Electric (thx @dustingetz!) for more responsive counts when reducing over ~800k resources (enabled by cursor-based pagination in eacl/count-resources).
β’ EACL is ideally suited to Electric Clojure, esp. for real-time menu population with permissioned entities.
β’ You can read the rationale behind EACL on http://eacl.dev.
β’ There is still plenty of room for improvement: I expect expect another 2x improvement when v7 lands, which has a tighter data model backed by heterogenous tuples.
β’ v6.1 introduces no breaking changes or data model changes, so these performance improvements will land on main soon.
π€£ @petrus unmistakably a fellow South African πΏπ¦
Our home grown system is certainly going to grind to a halt at a certain scale but that will be a nice problem to have π I'm going to check it all of this out, it looks super interesting
This is awesome. I wish I could justify using it at my place.
@jatkin whatβs stopping you? And what are you currently using? If you need fine-grained authorization, the main trade-offs are some Spice features and whether you want to start off using an external AuthZ system like SpiceDB, which I guarantee will be costlier to implement correctly syncing for (because I did it). With EACL, you retain the optionality to sync to an external system later when you need more scale. One consideration is whether you want a central authz system for external consumption - at work, we are likely to just dedicate some Datomic Peers to that.
It's not on the roadmap, we just built our own authZ system and integrated it, and that's not my part of the app. It's not a dig at EACL at all - I just can't use it right now π.
tell me about your authz system?
It's ReBAC* but using typical datomic queries, not any indexes. Our pathom system ties into it extensively, as does our UI toolkit *ReBAC with some slight modifications
whatβs your target scale / performance? the first version of EACL was implemented with recursive Datalog rules but it was wayyy too slow despite aggressive optimization, and could not handle all the grounding cases. bear in mind the query engine is eager, so you canβt paginate efficiently at all or return stable sort order without materializing the entire graph on each call, so be sure to benchmark. Iβd be curious about your data model
I'm afraid I can't get into too much more detail, since I don't actually fully understand my own system here lol. @donavan you may find this interesting. (Donavan wrote our system).
if you have a finite set of known resource types, it is feasible to maintain queries for all lookups, but it will still be slow for large results sets and esp. intermediate graph hops that grow the search space. Calling (take N) on d/q still materialises the full result set, so memory can be an issue EACLβs secret sauce is cursor-based pagination with lazy parallel deduplication over terminal indices + optimized tuples (esp. in upcoming v7)