These are chat archives for jdubray/sam

1st
Jul 2016
Edward Mulraney
@edmulraney
Jul 01 2016 15:38
@jdubray how would you define the list of "allowed actions" for a component? just run state function to work out current state, then map current states to an array of allowed actions?
is that too coupled?
Jean-Jacques Dubray
@jdubray
Jul 01 2016 15:39
yes, this is kind of standard state machine semantics
Edward Mulraney
@edmulraney
Jul 01 2016 15:40
i suppose youre right, that's how we would wire a standard state machine and is much safer
i like that idea really
Jean-Jacques Dubray
@jdubray
Jul 01 2016 15:40
In simple cases, the "allowed" action are in the view (via V = f(M))
so you don't need to add another check
However, in some cases, things can get quite complex, then it's a very good structure to reason about incoming events/intents/actions
that is because you have a stable application state
each time you get a new application state, you can compute that list
When you implement a dispatcher, then, it's a really quick check.
As I mentioned too, you can also check the "allowed proposals"
that is not standard state machine semantics, this is more advanced, because of the way you structure the application state mutation (proposer / acceptor)
but still, being able to validate allowed proposals is a big benefit too when you need it
These semantics are missing in Meteor for instance, which makes it really hard to reason about your code.
That's the problem really once you get the factoring wrong, all these questions become very hard to solve on a case by case basis.
The big advantage of focusing on what's allowed is that there is no "memory" to it. You just consider the current application state, you don't need to know how you got there.
Jean-Jacques Dubray
@jdubray
Jul 01 2016 15:45
Things like Sagas have a memory effect, they tell you X is allowed, because it is the way we coded it
Fred Daoud
@foxdonut
Jul 01 2016 18:44
@jdubray I discovered what I think is a flaw in my data flow sequence. I have propose -> accept -> render view -> nap. I think that should be propose -> accept -> nap -> render view. If nap triggers an automatic action, no sense in re-rendering the view between the first propose and the subsequent propose triggered by nap. Do you agree?
Jean-Jacques Dubray
@jdubray
Jul 01 2016 18:46
Logically, it is after, you reached the current application state which needs to be rendered.
the next-action could take seconds, hours, days to present its data to the model
You may introduce an optimization where the rendering is "on hold" such that you wait for the second reactive loop (next-action) to complete before you trigger the render.
This is something I have contemplated implementing the SAFE middleware, but that decision is on a case by case basis. Logically the next action is a "fire and forget" event and the state representation needs to be rendered.
Fred Daoud
@foxdonut
Jul 01 2016 18:49
You raise a good point, though, what if next-action takes long. Maybe it is better to leave it after. I think my mistake was to put in next-action something, as you had pointed out, that should have been in a single "Step".
Jean-Jacques Dubray
@jdubray
Jul 01 2016 18:50
As I said before, I believe my interpretation of TLA+ seems to be ok, you can always introduce well defined optimizations, but it has to be for a purpose, not to change the semantics of the pattern/TLA+
Feel free to question the semantics, I don't want to shut down any discussion, but I would prefer that we distinguish the "true" semantics vs optimizations.
Fred Daoud
@foxdonut
Jul 01 2016 18:52
Yes, well said. I think nap needs to remain after, otherwise it does change the semantics of an action.
Jean-Jacques Dubray
@jdubray
Jul 01 2016 18:54
Optimizations are always expressed in context: if you are implementing scenario A, then you can use optimization O(A). You are not breaking any semantics, just taking a well identified, but not general, short cut.
Fred Daoud
@foxdonut
Jul 01 2016 19:20
I'm wondering if it might make sense to call nap() before re-rendering, where nap() might synchronously make another propose. Synchronously (part of the same function call), it would be in the same Step. If it is asynchronous, the Step ends and the propose made asynchronously is a new Step.
I don't know if that makes any sense, or if it's better to just reason that if something is part of the same Step, it should be in the model within a single propose.
Jean-Jacques Dubray
@jdubray
Jul 01 2016 19:23
I would argue that "synchronous" nap() are part of the model. There is no reason (other than purity) to initiate the action outside the model.
If you are interested in some result "synchronously" that means that you are still in the critical section (i.e. in the model).
So there is no need to "nap" in that case
Fred Daoud
@foxdonut
Jul 01 2016 19:29
Agreed. Thank you JJ!
Jean-Jacques Dubray
@jdubray
Jul 01 2016 19:37
you could still factor your code with an "internal" nap to keep it clean, but logically you are still in the model. The Application State is not ready to be shared.
Fred Daoud
@foxdonut
Jul 01 2016 19:38
That makes sense :thumbsup:
Jean-Jacques Dubray
@jdubray
Jul 01 2016 19:56
Incidentally, if you look at the fishing game I published last week, there is a nap function where I count the number of fishes caught on mouse up, you can't really see that this is what's happening.