Ah. Sorry. My misunderstanding. I went looking for the Effects.tick replacement in 0.17+ and only found AnimationFrame.
Mark On Sun, Dec 11, 2016 at 10:32 PM Janis Voigtländer < [email protected]> wrote: > Mark, wow, a lot of material. I’m not able to digest all of it right now. > But something quick I want to say, because I have the impression that there > is a misunderstanding about the current state of tick batching support. > > > This: > > > > > Since I wasn’t proposing to get rid of subscriptions and since this > functionality is covered through subscriptions, my proposal arguably > doesn’t cause a problem. > > > > > baffles me. I’m not sure what you mean by “this functionality is covered > through subscriptions”. Tick batching wasn’t covered through signals (the > closest predecessors of subscriptions), and isn’t covered through > subscriptions (or at all!) right now. > > > Specifically and relatedly, concerning this: > > > > > The special behavior for tick wasn’t particularly documented for the 0.16 > Effects module and isn’t really documented for the 0.17+ AnimationFrame > module. > > > > > I should clarify that the tick batching trick as existed in the 0.16 > Effects module is *not implemented* for Elm 0.17+. Apparently since gamey > stuff is not anymore in Elm’s focus, Evan didn’t bring the “first ever > effect manager” over to the new world when effect managers as such became a > thing. > > > (Did I indicate previously that tick batching as existed before is a thing > currently in core or other 0.17/0.18 packages? I don’t think so. I was > only bringing it up as a thing that can be done with effect managers and > benefits from, maybe even is absolutely dependent on, having separate > concepts of Task and Cmd. To decide about maintaining that latter stance, > will require digesting your material more fully.) > > > > > 2016-12-11 21:26 GMT+01:00 Mark Hamburg <[email protected]>: > > Since I wasn't proposing to get rid of subscriptions and since this > functionality is covered through subscriptions, my proposal arguably > doesn't cause a problem. But that's just getting through the loophole of > this specific example to dodge this particular case, so let me see if I can > get straight what the special property is that we need to preserve if we > were still trying to implement a tick command in the same manner of the > 0.16 tick effect. (It's worth noting as a side note that in 0.16, all > effects other than tick were tasks, so obviously tasks are close to > covering the role of commands — née effects — but tick may point to extra > wrinkles.) I'm not going to assume a constraint by the current task > implementation, but any revised implementation has to have a clear behavior > in conjunction with the existing task APIs since its those APIs that make > tasks an attractive alternative to commands. > > The special behavior for tick wasn't particularly documented for the 0.16 > Effects module and isn't really documented for the 0.17+ AnimationFrame > module. Am I correct that the concern is that when the animation frame > "arrives": > > > 1. We run all of the update functions before actually calling the view > function; and > 2. Any tick effects that result from those updates will be batched > together for the next animation frame > > Was there anything else that I'm missing? > > The first point means that any implementation is going to have to be built > in conjunction with the Elm runtime since coordinating with the call of the > view function requires knowledge of when and how the view function gets > run. But since the whole point of this is to coordinate with the view > function that shouldn't be surprising nor is it particularly odd. It does > mean that my simple example using port tasks wouldn't work because it > wouldn't enjoy that coordination, but extra requirements add extra > implementation details. > > So, what we want is that we can divide time up with a series of animation > frame events and at each animation frame event, we want to start a new > epoch for collecting tick effects, run the updates driven by all effects > collected for the previous epoch, and then do the view rendering. A naive > implementation will just keep listening for all animation frames. A more > sophisticated implementation will take steps to shutdown that observation > when it is no longer necessary. > > The vague handwaving in the above is seemingly around what it means to say > "run the updates driven by all effects collected for the previous epoch". > In particular, how does this interact with task chains built using andThen, > etc.? I am going to make a distinction between two ways to specify > successor computation on a task. In one case with map the results or the > error coming from the task to produce a new result or error. In the other, > we map the results or the error coming from the task to produce a new task. > I would argue that the first category is what leads to actual messages for > the model. The second can be viewed as making no changes to the model but > queueing new task executions. > > So, how could this work in a task-based scenario? I'm going to speak of > tasks initiating and resolving to distinguish between when they have code > invoked v when they deliver values. > > When a tick task initiates, it adds itself to the set of tick task > executions for the current tick epoch. > > When we receive an animation frame call, we do the following: > > 1. We grab the contents of the tick epoch set and reset the set to > empty > 2. For each of the tick executions in the tick epoch set grabbed in > (1), we resolve the execution using the current time. This means running > down the network of tasks chained onto the executions. For cases where we > map the result or error to a new result or error, we do so and keep working > down the chain. For cases where we map the result or error to a new task, > we queue that task for execution. > 3. We execute the view function. > > In this way, we deliver all of the updates that are simply dependent on > the tick event or a mapping thereof while initiating any further > computations that were waiting for the tick event. > > The other piece of concern is how task queueing works and when tasks get > to execute. I would probably go for a structure on the task queue in which > it is also divided into epochs. We process all of the tasks within an > epoch. Any tasks produced during this processing as a result of andThen, > etc. go in the next epoch. All tasks produced during an update go in the > current epoch which we process at the end of the update. This design keeps > chains of tasks from blocking other update processing. We could go further > and pull tasks generated by tasks off of a queue that executes even more > incrementally. The key point is that all of the tasks from an update get > initiated immediately following the update and tasks initiated from other > tasks happen as we have time to process them. > > In the case of ticks, this means that a tick task that initiates a chain > will execute immediately following the update but a tick task that is > initiated from some other task might get run at an arbitrary later time. > (How arbitrary determines whether we can do things like write Task.tick > |> Task.andThen (always Task.tick) in order to wait two ticks as opposed > to at least two ticks.) > > To make animation frame updates as efficient as possible, we probably also > want to avoid draining the task-initiated task queue until after the view > function is run. That's not critical to the semantics but it could matter > for performance. > > Now, maybe I've missed some other detail that matters, but as I've said > the documentation for both Effects.tick and AnimationFrame is relatively > thin on detailed semantics and requirements. But if I've gotten the > concerns right, then I believe the above shows how a task-based system > could do what is called for here. Am I missing something? I know I'm > handwaving through some of the execution machinery, but my intuition from > writing lots of promise systems in Lua says that this sort of structure > would work. > > Mark > > On Sat, Dec 10, 2016 at 10:20 PM, Janis Voigtländer < > [email protected]> wrote: > > > > In the case of ticks, what I gather from a read through of the code that > it does is guarantee that all of the tick requests placed between animation > frame strobes will all be delivered at the next animation frame strobe. Is > that a correct read? > > > > > Yes, that is a correct read. But no, I don’t think that your post shows > the same can be done with tasks instead of commands. The reason is, as > previously mentioned, the existence of andThen for tasks. And your “P.S.” > does not address this, because you are not there considering what the real > complication with andThen is. The complication is not whether a tick task > involved in two andThen chains is run once or twice, the complication is > how to deal with the “continuations” in those two chains. Let’s look at > this with some example: > > > In the Effects/Cmd world, using ticks would be like this: > > > > > > 1. At some point, a command tick tagger1 reaches the runtime system, > where tagger1 : Time -> Msg for Msg being the program’s message type. > The runtime system will not do anything at that point, except for > registering in some internal state that a tick request was issued, and that > the tagger to use for it is tagger1. So essentially, the runtime > system (specifically, the effect manager) at that point stores the function > tagger1 in some list. > > 2. At some point after that, but before the next animation frame > happens, a command tick tagger2 reaches the runtime system. At that > point, the effect manager adds the function tagger2 to said internal > list. > > 3. Some time later, the next animation frame is due. So the runtime > system looks at its internal list, sees that there are [tagger1, > tagger2], takes the current time stamp t, evaluates msg1 = tagger1 t > and msg2 = tagger2 t, and passes msg1 and msg2 to the program’s update > function one after the other *but without any intermediate view > rendering*. If the update function creates additional > effects/commands, the ones created from the calls of update with msg1 > and msg2 are batched (so that actually the grouping together of > updates will propagate to the future). > > > > > What about in your hypothetical world in which no Cmd abstraction exists, > but instead tick has type Task Never Time? Now instead of just using tick > with functions of type Time -> Msg, tick can be used in task chains, like tick > |> andThen cont with cont : Time -> Task Never Msg. Let’s look at such a > scenario: > > > > > > 1. At some point, a task tick |> andThen cont1 reaches the runtime > system, where cont1 : Time -> Task Never Msg. As above, the runtime > system shouldn’t do anything at that point, except for registering in its > internal state that there is this tick request and what to do when it > eventually becomes active. The difference to above is that now instead of > storing a function Time -> Msg for later use, the system has to store > a function Time -> Task Never Msg. Fine enough. > > 2. At some point after that, but before the next animation frame > happens, a task tick |> andThen cont2 reaches the runtime system, > where cont2 : Time -> Task Never Msg. Again, the effect manager should > simply add that to the internal list of open tick requests. > > 3. Some time later, the next animation frame is due. Now what? The > runtime system knows that two tick requests are open. So of course it takes > the current time stamp t and passes it to the two functions stored in > its internal list. But instead of getting some msg1 : Msg and msg2 : > Msg as above, it now gets some task1 = cont1 t : Task Never Msg and task2 > = cont2 t : Task Never Msg. So *unlike above*, the strategy now cannot > be to pass the relevant two messages to the program’s update function > while ensuring that no view rendering happens in between (which was the > whole point of tick batching in the animation scenario). Because those > messages are simply not available right now. What is available are two > tasks that when run will eventually return with messages (maybe after some > http requests or whatever). So the runtime system can now fire off > task1 and task2, but there is no way to tell when they will return, > and certainly no assumption can be made that they will return still before > the view rendering that is supposed to happen right now because we have an > animation frame just due. In consequence, the whole point of tick batching > is lost. We don’t get to ensure that groups of update calls get > performed “atomically” without intermediate view rendering. > > > > > What do you think about the above? To me, it means that in the “just > tasks” world tick batching as in the “separate tasks and commands” world is > not possible (with the same quality). > > > > > > > > > > > > -- > > > You received this message because you are subscribed to the Google Groups > "Elm Discuss" group. > > > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > > > For more options, visit https://groups.google.com/d/optout. > > > > > > > > > > > > -- > > > You received this message because you are subscribed to the Google Groups > "Elm Discuss" group. > > > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > > > For more options, visit https://groups.google.com/d/optout. > > > > > > > > > > > > -- > > > You received this message because you are subscribed to the Google Groups > "Elm Discuss" group. > > > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > > > For more options, visit https://groups.google.com/d/optout. > > > -- You received this message because you are subscribed to the Google Groups "Elm Discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
