Observing state and changes (was: Re: Specifying the association with an online timing service)

Hi Ingar,

On 2015-06-09 16:35, Ingar Mæhlum Arntzen wrote:
>
> Hi Francois and all.
>
> Your post on association between timing objects and timing providers
> opens the floor for several discussions (by intention I suspect :) ).
>
> I'll try to highlight one issue here, and leave others for later.
>
>  From the programmer perspective, it is quite tedious to have to wait
> for an object to reach some state of readiness, before you can start to
> use it.
>
> In this perspective, it would be nice if timing objects may be
> intantiated/generated up front as "empty shells", yet allowing
> application handlers to be safely registered immediately. As
> bootstrapping is finalized, the "empty shells" are filled up, and events
> are being emitted as expected - causing application code to start executing.
>
> The requirement to provide this guarantee would have to be reflected in
> the spec somehow. I'm not sure how though - maybe there is some
> precedence in other event interfaces?

Yes. In my example:

  var timing = new TimingObject(provider);
  timing.onopen = runWhenReady;

My implicit assumption is that the TimingObject constructor would always 
return an instance in the "connecting" state (is that what you call an 
"empty shell"?) and that transition to the "open" state would always 
happen in a following execution task (in a next "tick" in other words), 
so that attaching event listeners after instance creation would always work.

That guarantee should indeed be written explicitly in the spec. This can 
be done using "queue a task" as defined in HTML5:
http://www.w3.org/html/wg/drafts/html/master/webappapis.html#queue-a-task

A good concrete example here would be the WebSockets API:

[[
When the WebSocket connection is established, the user agent must *queue 
a task* to run these steps:
  [...]
  5. Fire a simple event named open at the WebSocket object.
]]
http://www.w3.org/TR/websockets/#feedback-from-the-protocol

Thanks to "queue a task" in the above excerpt, the "open" event will 
always fire after the current execution task is over, so you can create 
a WebSocket instance, start listening to the "open" event, and you know 
you will always catch the transition to "open".

Conversely, when the spec does not use "queue a task" before "fire an 
event", it means that the event is to be dispatched synchronously.


>
> Related to this, there is one more detail for the event interface that
> Njål and I would like to propose.
>
> Quite often in Web interfaces, you need to check whether an event has
> already been emitted or not. For instance, consider the "onopen" event.
> To be sure of correctness you often end up with code like this
>
> if (is_open()) {
>    do_your_thing ();
> } else {
>    onopen = function () {do_your_thing();}
> }
>
> Francois, you have a very similar example in your example code in this
> thread.
>
> Now, this may not look like much of an inconvenience, but it adds up.
> This may have to be done for multiple event types, and again recursively
> in higher-level api's that depend on underlying events.
> In my experience, it quickly gets difficult to reason about correctness
> as well as tracking down bugs. These scenarios may even lead to nasty
> effects such as event duplication or reordering.
>
> This problem also generalizes to "observing" or visualizing any object
> that has state and may be subject to modification.
>
> // visualize the state of an object
> var state = o.get_state();
> visualize(state);
> // attach handler for future state changes
> o.on("change", function () {
>     var state = o.get_state();
>     visualize(state);
> })
>
> We have successfully avoided this complexity (for the event consumer) by
> a subtle change in the eventing api. Basically we are shifting the
> responsibility for sorting this out from the event consumer (examples
> above) to the event source. So, when an event consumer attaches a
> handler, the event source is responsible for sending an initial event
> with the current state, before any subsequent event.

I don't disagree but... it seems that the current consensus among 
implementers is that attaching an event listener should not trigger any 
side effect, and thus requiring the user agent to send an initial event 
when an event handler is attached is (currently, at least!) considered 
bad practice.


[...]
> Again, I'm not sure how to include this in the spec. Ideally, if this
> pattern was documented in some specific EventListenerInterface we could
> simply reference that - but I suspect it is not?

Right, since this is considered an anti-pattern right now, I do not 
think that there exists a spec that uses it.
>
> Also, to explain the (slightly more complex) logic of the event source,
> we could provide some sample code if needed.

It is worthwhile to document the pattern, provide sample code, and show 
how it improves the situation.

Are there use cases that cannot be done without it? If yes, that could 
provide a good reason to shake things up. If not, I would make that 
fight in parallel to the development of the CG specs.

Francois.

Received on Thursday, 11 June 2015 10:18:42 UTC