Fork me on GitHub
#vrac
<
2021-09-26
>
Vincent Cantin03:09:52

In Vrac, the implementation will also use "canonical paths" which are paths without any entity reference inside. It's basically a path which you could use in (get-in app-db path)

phronmophobic03:09:59

so if you have a model where the same logical entity might show up in multiple places, is it the db's job to make sure updates to a logical entity get propagated?

phronmophobic03:09:41

that's more or less what I've been thinking, but I haven't found a db with the right API

Vincent Cantin03:09:01

By "same logical entity in multiple place", you mean multiple copies of the same data, or multiple references to the same data?

phronmophobic03:09:15

I probably phrased it poorly. The UI typically works based off the denormalized data from a query and it's probably stored in a normalized form

phronmophobic03:09:47

I responded before I read your #2 from above. I think follow. Is it correct to say that a schema for the data model will be required so that you can tell whether a reference is an entity reference?

Vincent Cantin03:09:10

I am thinking of 2 different ways to make it work: 1. Make the user list all the keys which will always point to entities, a.k.a. "tagged relations" 2. Use a special data type for representing a reference to an entity. <-- that the approach which I am using in my PoC.

Vincent Cantin03:09:55

The solution 2. avoids having to specify a schema manually.

Vincent Cantin03:09:22

oh wait ... I am not sure if I did it that way ... I kind of forgot already.

Vincent Cantin03:09:22

The Id type acts as an id and a reference at the same time, depending on where it is used.

phronmophobic03:09:06

right, but it doesn't seem like it would uncommon to need to refer to a property of an entity

phronmophobic03:09:45

like if you have a checkbox, it could be toggling the :todo/complete? property of a todo item and you would need a reference to that property for the checkbox

Vincent Cantin03:09:10

It would be referenced via its path in the db, something like [:entities (Id. xxx) :todo/complete?]

phronmophobic03:09:07

oh, so the component would at some point need to do (get some-entity (Id. entity-id))

Vincent Cantin03:09:09

Not explicitly (not visible for the user), but the implementation, yes.

phronmophobic03:09:49

> Not explicitly (not visible for the user), but the implementation, yes. I'm not sure I follow

Vincent Cantin04:09:26

I just mean "yes" 🙂

phronmophobic04:09:15

yea, if you don't have entities, the key-path works great. It's still unclear to me what the best approach is for handling a data model with entities: • require a schema • components required to know which keys are references • try to support both • something else

Vincent Cantin04:09:39

In my case, I have entities, no schema, and a special data type to represent references.

phronmophobic04:09:08

isn't that a form of "components required to know which keys are references"

phronmophobic04:09:28

not that it's a bad thing

phronmophobic04:09:01

just trying to see what trade-off others are trying and how they feel

Vincent Cantin04:09:45

> isn't that a form of "components required to know which keys are references" It's not. The component doesn't know anything. The only thing he knows is to follow a path.

phronmophobic04:09:19

so where does the special reference type get inserted?

Vincent Cantin04:09:48

They are not in the path. They are in the data pointed by the path.

phronmophobic04:09:14

so it's in the db?

Vincent Cantin04:09:28

Yes, and it's totally dynamic

phronmophobic04:09:38

what's the difference between that and having a schema?

Vincent Cantin04:09:41

schemas are static vs. data driven is dynamic

Vincent Cantin04:09:05

For the user, no schema might mean less work.

Vincent Cantin04:09:04

Both approach can be supported by the framework, I think.

phronmophobic04:09:18

I could see that working for an existing reference

phronmophobic04:09:27

how would a new reference be added?

Vincent Cantin04:09:37

The only part which would need to change would be the function which follows a path to retrieve some data.

phronmophobic04:09:18

for example, you have list of todo-items and each todo item is a reference. when you add a new todo, it's the "effect handler"'s job to create the reference?

Vincent Cantin04:09:45

> how would a new reference be added? with-id is a function which turns an hashmap into an entity. https://github.com/green-coder/vrac-simple-sample/blob/master/src/vrac/reframe.cljc#L8-L9

Vincent Cantin04:09:52

from that entity, you can get a reference to it using (:vrac.db/id my-entity)

Vincent Cantin04:09:27

Let's move the discussion back to the channel

👍 1
phronmophobic03:09:26

the main issue is illustrated when you have a dynamic component like a tabbed pane. The selected tab is part of the data and you don't know what data you need to show until you've already queried a subset of the data (ie. each tab will have different data and you don't know which data will be needed for the current render until you know which tab is selected)

phronmophobic04:09:14

so all the effect handlers would need to know which keys are references?

Vincent Cantin04:09:13

The effect handlers contains the logic of how to change the app-db. When we are not using a schema, the code in the handler also have to know when to use a reference instead of just the data.

phronmophobic04:09:01

I'm still not sure which options I like best. One thing I've noticed is that it's really nice to have an entity-less data model for testing components in isolation, but you usually want an actual db when integrating a full UI. Having generic effect handlers can help.

phronmophobic04:09:36

There's also generic components like date* pickers, and list views that ideally shouldn't care

Vincent Cantin04:09:56

Reusable & generic components like a date picker or would normally not dispatch their own events, they would dispatch events provided by their parent.

phronmophobic04:09:59

well, the event system in membrane works different than what you're probably used to and no one is dispatching events, but generic components like date pickers do have default handlers

Vincent Cantin04:09:03

in that case, you can have a schema where the user provides a list of qualified keywords which will always refer to entities.

Vincent Cantin04:09:00

But that won't solve all your problems, if you default handler have to dissoc data and does not know if the data is just fields in an entity or the entity itself.

phronmophobic04:09:03

why wouldn't the schema handle that?

Vincent Cantin04:09:28

When working on Clojure values, you can just dissoc. On a db it's different, you need to say if you delete a link to an entity or if you also want to delete the entity. The schema won't answer this question. If the code in the default handler of your date picker answer this question, it means it is aware of where the entities are.

Vincent Cantin04:09:01

One solution would be that it answers that question, regardless of the kind of data it deals with. In other word, it would say something like dissoc or dissoc-delete for the operations to be done on the data.

phronmophobic05:09:45

right, if you write* the code using that operation, it would work in either context

phronmophobic05:09:56

in the non-entity db context, it would just be a dissoc

Vincent Cantin05:09:43

Now I remember that I run into that in April and I forgot.

Vincent Cantin04:09:03

> For example, you have list of todo-items and each todo item is a reference. when you add a new todo, it's the "effect handler"'s job to create the reference? Yes

👍 1
Vincent Cantin05:09:23

I might add support for a schema (i.e. the user lists the keyword relations pointing to entities) in Vrac, for the users who need it.

Vincent Cantin07:09:49

@smith.adriane inside:

(defui counter [{:keys [num]}]
  (horizontal-layout
   (on :mouse-down (fn [[mouse-x mouse-y]]
                     [[::counter-increment $num]])
       (ui/button "more!"))
   (ui/label num)))
If I understand correctly, the view passes the reference $num to the event. Does it mean that the view has to know when to pass the reference vs. pass the value?

phronmophobic07:09:28

it passes both, the defui macro takes care of passing the extra reference info

phronmophobic07:09:07

it's a bit of an implementation detail, but every function defined using defui has a special key in it's meta data. the defui macro will look at every function call within the body and automatically include the extra info when calling a function that has the special meta data

phronmophobic07:09:09

and to pass the extra info, every defui is required to except a single map as its argument

phronmophobic07:09:03

It was initially meant to be a temporary experiment, but it seems to work surprisingly well in practice

Vincent Cantin07:09:36

What I mean is: does the user sometime passes num and sometimes passes $num ?

phronmophobic07:09:39

you mean when calling counter or for effects?

phronmophobic07:09:58

when calling counter, the user will only ever pass num and $num will be passed implicitly

Vincent Cantin07:09:03

when creating the effect

phronmophobic07:09:14

for effects, it will depend

Vincent Cantin07:09:52

In Vrac, the user would types num all the time, it means passing the reference. The effect handler would be the one to know if it needs the reference or the value.

phronmophobic07:09:18

you can always get the value from the reference, but not always the other way around

Vincent Cantin07:09:19

It means that the view does not have to know how the effect handler works

phronmophobic07:09:28

that's something I would have to think more about. The effect is supposed to reflect the intent of the user. I'm not sure whether describing the intent of the user should differentiate between a reference or the value

phronmophobic07:09:14

and some arguments are clearly not values references

phronmophobic07:09:55

that's an interesting point though

phronmophobic07:09:32

when you implement an effect, do you say which args are values vs refs? can you get both?

phronmophobic08:09:29

for an intent like [:toggle $bool], it doesn't make sense unless $bool is a reference. for an intent like [:add-to-counter $counter 42], the argument 42 is a literal and no reference exists. I'm trying to think of an example where the difference between a reference or a value would be an implementation detail.

phronmophobic08:09:12

it's also getting a little late here, so my 🧠 might not be working 100%

Vincent Cantin08:09:41

I have the same goal of trying to deduct which one to use, based on how the effect handler is implemented. I am not sure if it is always possible to deduct it. In the worst case, the user can explicitely write something like (ref counter) when he wants to use the reference inside the effect handler. That's an area which will need clarification in Vrac.

Vincent Cantin08:09:20

In this simple case, color is a reference and new-color ... it depends what it is, it could be a ref or a value.

Vincent Cantin08:09:12

new-color is a value, I think

phronmophobic08:09:27

I guess the question I was trying to ask is if the reference/value difference should be specified by the effect itself and not the implementation. The benefit of specifying it as part of the effect is that you can catch errors earlier

phronmophobic08:09:48

since passing a value when a ref is required is an error

phronmophobic08:09:19

additionally, I like the idea of being able to provide different implementations for effects depending on the context (eg. testing, debugging, different uses cases, etc)

phronmophobic08:09:54

so having ref vs value as part of the effect definition might be helpful (or hurtful)

Vincent Cantin08:09:08

> since passing a value when a ref is required is an error but passing a ref all the time means no error 🙂

phronmophobic08:09:14

but you can't: [:add-to-counter $counter 42]. 42 is not referencable

Vincent Cantin08:09:33

ah, you are right