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 <mhamburg...@gmail.com>:

> 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 <
> janis.voigtlaen...@gmail.com> 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 elm-discuss+unsubscr...@googlegroups.com.
>> 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 elm-discuss+unsubscr...@googlegroups.com.
> 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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to