hoplon

The :hoplon: ClojureScript Web Framework - http://hoplon.io/
2020-07-12T18:55:23.291100Z

i have been doing some thinking and prototyping around something i'd love feedback/thoughts on

2020-07-12T18:56:29.292300Z

a couple years ago i had a discussion with micha about fusing cells and values, based on the insight that cells mostly contain maps

2020-07-12T18:56:50.292700Z

and most formula code looked pretty much like relational queries if you squinted

2020-07-12T18:57:15.293200Z

but because the formulas are opaque functions, cells aren't aware of relationships between the formula code and changes to the value, if any

2020-07-12T18:57:38.293800Z

so we rely on clojure.core/= here to propagate change. the problem is formulas might run based on some change, but produce the same result

2020-07-12T18:57:53.294100Z

granted, propagation will stop there

2020-07-12T18:59:17.294700Z

so lately i have been noodling around with an in-memory datalog-esque model

2020-07-12T18:59:49.295400Z

you have a db of triples that you can query with datalog, but he twist is, you register queries with a callback and your callback is invoked when your query results change

2020-07-12T19:00:29.296200Z

this arrangement leverages the fact that a datalog query embodies a view into the db, and so when data goes in or is removed, we know exactly which queries will be affected, and thus need to be rerun

2020-07-12T19:01:31.297100Z

so there is still the data-based diffing, but less general, restricted to datalog

2020-07-12T19:02:07.297800Z

my original idea was for registered query callbacks to receive diffs of results, so they could choose to accumulate data themselves

2020-07-12T19:02:20.298200Z

in the context of hoplon, a diff about aparticular entity being added or removed could be used to make a precise dom modification

2020-07-12T19:03:16.298900Z

anyway, would love to hear any thoughts on this general scheme, particularly if others have been experimenting with datalog + hoplon in any way, such as via datascript ( i remember maybe @mynomoto did some of this in the past?)

phronmophobic 2020-07-12T19:17:45.305200Z

this isn't exactly the same scheme, but maybe it's close enough to be relevant. I've been experimenting with a macro that can keep track of how values are derived. for example:

(let [state  {:todos
              [{:complete? false
                :description "first"}
               {:complete? false
                :description "second"}
               {:complete? true
                :description "third"}]}
      todos (:todos state)
      my-views (for [todo todos]
                 (hstack
                  (checkbox (:complete? todo))
                  (textarea (:description todo))))]
  (apply vstack my-views))
in this example, the macro can modify the checkbox call so that it not only knows that it receiving true/false, but also that the value is derived from the path [state :todos (nth i) :complete?] . it might sound like keeping track of how values are derived wouldn't work very well, but like you noted, access in clojure is fairly uniform and consists mostly of nth, get, keyword access, and a few others.

phronmophobic 2020-07-12T19:19:58.306200Z

> but because the formulas are opaque functions, cells aren't aware of relationships between the formula code and changes to the value, if an so if the cells analyzed the code within the cell, then you might be able to automatically derive the relationships and have more efficient change/update tracking

2020-07-12T19:20:29.306800Z

right i think that's exactly what the datalog scheme is

2020-07-12T19:20:34.307Z

except the analysis is of datalog and not clj

2020-07-12T19:21:27.308700Z

maybe analyzing a clj(s) subset would have the same affordances and come more naturally tho

2020-07-12T19:21:36.308900Z

i can definitely see the appeal

phronmophobic 2020-07-12T19:26:22.310200Z

rather than datascript, I use specter under the hood which has its own query language

phronmophobic 2020-07-12T19:27:05.311100Z

in theory, you could have the same code as above and have it use datascript or specter under the hood without changing the code.

2020-07-12T21:30:49.314800Z

@alandipert Yeah, I did some experiments but never used on a production app. I just used a cell instead of a atom when creating the datascript database. For the toy project I was experimenting with perf was never a problem but it could be as every query ran again on every database change.

2020-07-12T21:32:38.316500Z

If the query has a way to know if it should or not run again based on what changed on the database that would be awesome. I was experimenting with some indirection to run less queries and use those in several places but that as all the things has trade-offs.

2020-07-12T21:33:31.317100Z

the observation i feel might be helpful is just that, whenever a new fact comes in, if no query refers to any eav of the fact, then no query need run

2020-07-12T21:34:30.317600Z

anyway thanks much for the ideas folks, i'll keep playing with it and report back if i have any interesting results

2020-07-12T21:48:18.319200Z

The way that datalog works it would be interesting to check if you could use different formula cells for each step of filters on queries. That way as soon as a filter returns the same results as before it would stop propagation.

2020-07-12T21:50:02.320300Z

But that would cause more queries to run when the db change but less work keeping track of when a query should run again.

2020-07-12T21:57:50.321400Z

Ignore what I just suggested, it doesn't work for multiple reasons. If the query needs to run it probably has to run as a whole.