http://wiki.commonjs.org/wiki/Events/A
Kris Kowal
Here's an even more brain-dead proposal just in case you guys want
less specified.
http://wiki.commonjs.org/wiki/Events/B
Kris Kowal
Kris Kowal
--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.
I sought to simplify where possible, so omitted some things that
probably would exist in practice but are not strictly necessary.
These include a getSignal(name) method on Emitters, and ways to
enumerate the existing signals or signal names. These don't actually
need to be observable to an outsider. We could add them, but I don't
think they'd be missed in a first pass. A way to "dismiss" a signal
is a complicated issue and beyond the scope of what I want to argue
about for a 1.0.
> - What happens if an exception is raised processing a signal, with respect
> to signal propagation
I don't have a prescription for anything special.
> - Does it make sense to throw new require("events").stopPropagation rather
> than invoking an instance method?
It could.
> - Does it make sense to call them signals? When I say signals, I think
> POSIX signals. How about "events"?
There are similarities to signals. They could conceivably be called
"slots". I prefer "Signal", and don't think it really gets in the way
of distinguishing them from POSIX signals. These could be thought of
as a high-level API corresponding vaguely to the same concept in POSIX
"interrupt" signals. One of the proposals I mention has an "event"
object, which…
> - Should we look at making these compatible with DOM events?
…supports the stopPropagation and cancelDefault API of the W3C Event
object. In DOM events, these are passed as the only argument to an
observer, but I find that gets in the way of creating Emitters that
forward their own methods to "signals" with the respective names. I
find that it's much more handy to forward the "emit" arguments to the
observers.
Kris Kowal
Oh. Yes.
Kris Kowal
> On Wed, Feb 3, 2010 at 4:31 PM, Kris Kowal <kris.ko...@cixar.com> wrote:
Kris, could you give a quick overview or a sample of using these. I'm
not familiar with the role of Signal.
Also, what are you proposing as the lead option A or B?
-mob
--
Thanks,
Kris
On 2/3/2010 5:31 PM, Kris Kowal wrote:
--
Thanks,
Kris
'Signal' already has a technical meaning in a context not too distant
from this (UNIX) that we shouldn't conflict with.
What about http://www.w3.org/TR/DOM-Level-2-Events/ ?
On Feb 5, 1:01 pm, George Moschovitis <george.moschovi...@gmail.com>
wrote:
> > What abouthttp://www.w3.org/TR/DOM-Level-2-Events/?
>
> yeah, why not reusing this?
>
> -g.
That is very browser / DOM centric. It doesn't look like it was
designed with server-side in mind. Most of the event types don't apply
and event propagation is less important when you don't have a DOM.
-mob
On Feb 5, 1:44 pm, Dean Landolt <d...@deanlandolt.com> wrote:
> On Fri, Feb 5, 2010 at 4:32 PM, mob <m...@embedthis.com> wrote:
>
> > On Feb 5, 1:01 pm, George Moschovitis <george.moschovi...@gmail.com>
> > wrote:
> > > > What abouthttp://www.w3.org/TR/DOM-Level-2-Events/?
>
> > > yeah, why not reusing this?
>
> > > -g.
>
> > That is very browser / DOM centric. It doesn't look like it was
> > designed with server-side in mind. Most of the event types don't apply
> > and event propagation is less important when you don't have a DOM.
>
> XHR is browser-specific too but it makes a great low-level HTTP client
> interface that *every* ssjs platform will likely implement eventually.
> WebWorkers, WebSockets, the whole compliment of new web platform APIs --
> these may have been designed for the browser but they provide us with specs
> we don't have to (can't, really) bikeshed. DOM Events have a familiar style,
> why should they be any different?
>
> That's not to say they *should* be used, or would even be useful -- just
> that we shouldn't dismiss them lightly.
Agree, we should not dismissing it lightly. However, that spec is a
not a small spec or API. There are lots of methods and properties.
IMHO: For a low level, fast eventing API, it seems to heavy with lots
of unnecessary baggage. Baggage that add value in the browser, but is
baggage elsewhere.
We could just adopt portions of it, but that seems to lose the benefit
of using it in the first place. Given the choice, I prefer what Kris
has proposed.
-mob
OK, but perhaps we should reuse names and conventions (even though,
personally, I prefer Kris' names)
-g.
~Daniel Friesen (Dantman, Nadir-Seen-Fire) [http://daniel.friesen.name]
In order to have a nice decoupling of concerns, I too had a need for a callback system. Since there wasn't one in CommonJS at the time, I created one myself. That's my vested interest here :-)
I started out calling this concepts simply "callbacks" and "events", but after few iterations against real-world use cases from the rest of our codebase, I finally settled on the more generic "extension point". For easy review, I put the JSDoc output of my implementation at <http://dl.dropbox.com/u/362958/commonjs/extensionPoints.html>. I provided examples in the API docs.
Now, it is very similar to your Events/B proposal: my concept of "extension point" maps fairly good to your concept of "signal" although I don't even bother reifying the signal into a proper JS object. My "defineMultiExtensionPoint" API allows for construction of an extension point on an object - it is a named function on the object that acts as your Signal.observe(); a place where you can register observer callbacks. The result of invocation of "defineMultiExtensionPoint" is a function that when invoked acts as your Signal.emit(). The benefit of this is that this emit() is not globally available to anyone who can see a reified Signal - it is an anonymous function returned to the caller who creates the extension point, and it's the caller's decision whether to share it or keep it to itself. Isolates better - in your model, someone who sees a reified Signal can't be prevented from invoking emit() even when it has no business to do it.
Also, my design purposefully doesn't allow interference between the callbacks registered at a signal[*] - a callback should be able to observe the events regardless of what other callbacks registered at the same signal do. Allowing otherwise calls for trouble - you're creating a non-local behavioral dependency, in my eyes that's no better than passing state in global variables.
For that reason, no mechanism for stopping the propagation is included and the observers shouldn't be dependent on their invocation order. In my philosophy, if you have a dependency in observers (say,observer B depends on observer A), then probably the A observer should itself have a signal, and have the dependent observer B register with it, instead of with the same signal that A registered with. Then A can decide whether it wants to raise an event on its own signal or not.
What is further significant for me is that my equivalent to Signal.emit() will return an array of return values of each callback when invoked. This indeed is what distinguishes an "extension" from an "event listener" - it is bidirectional, and the entity calling emit() can inspect the return values and act on them. That's why my preferred terminology is "extension point", not "signal".
So, to reiterate key points, in my solution:
* Signal is not reified as an object (I see no benefit to it); it's just a pair of functions
* Signal.emit() is only available to the creator of the Signal (encapsulation)
* observer functions registered through Signal.observe() can't interfere with each other (encapsulation)
* Signal.emit() will return an array of the return values of all observers (which transforms them from unidirectional observers into bidirectional extensions, a more powerful concept)
Attila.
[*] Well, except if a callback throws something, but I intend to also take care of that and just ignore any throws. Alternatively, the thrown objects could be returned too as normal return values, with some indication that they were thrown, not returned.
--
twitter: http://twitter.com/szegedi
weblog: http://constc.blogspot.com
home: http://www.szegedi.org
http://wiki.commonjs.org/wiki/Events/C
Kris Kowal
http://wiki.commonjs.org/wiki/Events/A
Kris Kowal
Most of the links in that doc are 404 :(
Ah. JSDoc generated them all with assumption that files reside in a "symbols" directory, so relative links are all constructed as "../symbols/". I fixed that now by adding an additional "symbols" directory: <http://dl.dropbox.com/u/362958/commonjs/symbols/extensionPoints.html>
Thanks and apologies,
Attila.
>
> --
> http://codebad.com/
In the DOM Level 2 Events doc, Emitter is called EventTarget. I think
it is a better name because it
doesn't strictly emit the event, but dispatches it.
http://www.w3.org/TR/DOM-Level-2-Events/idl-definitions.html
--
Jonas Pfenniger (zimbatm) <jo...@pfenniger.name>
I've been under the impression that "emit", "dispatch", and "fire"
were synonyms. NodeJS picked "emit" and I think it's a good choice.
What is the distinction between emission and dispatch?
I am confused by EventTarget; it clearly bears an analogous API to
Events/A/NameEmitter, but since it is the "source" of events, I do not
think "target" is a good name.
However, choosing good names may be irrelevant if we choose to adopt
DOM2 event name conventions. Here's a reasonable subset of the DOM 2
API. I think it's obviously insufficient and awkward, but if someone
would like to patch it up, please do.
http://wiki.commonjs.org/wiki/Events/D
Kris Kowal
I agree, the method name is good and all those names are good synonyms.
My argument is over the name of the class that holds that method (see below).
> I am confused by EventTarget; it clearly bears an analogous API to
> Events/A/NameEmitter, but since it is the "source" of events, I do not
> think "target" is a good name.
Yes, it is only a name change (bikeshed). I undestand your point of view, but
I don't agree that it's the EventBikeshed object that emits the event. In my
mental model, it is the line of code that calls the emit() methods.
I guess it depends on your mental model. Let me take a simple example to
lighten up my point:
1. var ev = new EventTarget();
2. ev.observe("something", callback);
// ...
X. ev.emit("something", event)
From my point of view, the emitter, is the line (X.) of code, that
calls `ev.emit`.
`ev` receives that event and dispatches it to the registered callbacks. This is
why I think EventTarget is a good name.
Another argument is that EventEmitter also could be named EventObserver,
because it is in-between and holds both functions. Best is to give it
a third name
that doesn't convey neither emit neither observe.
> However, choosing good names may be irrelevant if we choose to adopt
> DOM2 event name conventions. Here's a reasonable subset of the DOM 2
> API. I think it's obviously insufficient and awkward, but if someone
> would like to patch it up, please do.
>
> http://wiki.commonjs.org/wiki/Events/D
Maybe it is best to start with a list of things we want, and see if
DOM2 fits or not.
Especially, it would be useful to discuss things like ; is emit()
synchronous and
what happens if a callback throws an error.
No, Emitter/NameEmitter is confusing.
-g.
var dispatcher = getOrCreateDispatcher("our_dispatcher");
var mo = new Object();
mo.myTower = function (data) {
/* maybe do something with data??? */
dispatcher.broadcast(data);
}
dispatcher.createBroadcaster("event_name", mo.myTower);
// In another scope
var data = {/* some properties */};
var dispatcher = getOrCreateDispatcher("our_dispatcher");
dispatcher.observe("event_name", data, function handler(data) { /*do
something with data*/ });
In the first scope, where the emitter is defined with
dispatcher.createBroadcaster(), the mo.myTower() method will get
passed the data object from the the other scope by the dispatcher.
### I like this better for several reasons:
1. The data object passed around in this example may be an instance of
a abstract data type class defined elsewhere in the program with all
the good stuff that a type system can bring to a complex program.
This also has advantages for better communication between scopes or
threads where using reference pointers may not be a good idea. An
implementation could permit the data object to include references to
functions, or it could strip them out, or serialize it, depending on
the security and concurrency requirements.
2. The use of a string identifier for a dispatcher decouples it from
the direct reference pointer, which would be really handy for
concurrent programs. Also, from a security point of view, the string
name of a dispatcher could be a randomly generated opaque string to
prevent other programs from connecting to secure dispatchers just by
knowing the name.
3. I really loath the "new" operator in JavaScript.
-- Kris Walker
(How many Krises with a "K" can be on one mailing list???)
Can you make an example with a fake HTTPClient implementation ? I
don't see how you can listen to two instances separately.
Also, I don't understand your point on security. If you don't want an
"external" (I guess in a browser?) program to get access to your data,
isn't it easier to share a reference to an object directly ?
I like that this approach is simple, but you wouldn't be able to
polymorphically intercept:
myObject.click.listen(…);
In the same way you could intercept:
myObject.observe('click', …);
At least until proxies make it to the language.
However, creating a click method should be easy. I think I provided
such a mechanism in a revision of the proposals, but suffice it to:
myObject.click = myObject.emitter("click");
I have seen the need to do this in the real world, both in Narwhal and
Node. I've also seen the need to "observe" the "observe" method.
We can pore over the names later; I presume that observe/listen,
emit/fire, emitter/event are not germane. If they are, we can start
that process sooner than later.
Kris Kowal
> I've also seen the need to "observe" the "observe" method.
My earlier post may have seemed a little convoluted, but I also see a
use for a slightly richer events API that could be used in conjunction
with promises and concurrency.
For example -- In my current implementation, a browser extension with
extended privileges, I am using what I call "channels" to communicate
securely between privileged and unprivileged code. In addition, some
of the privileged code is accessing native code as well. In this
case, opening a channel from JavaScript should return a standardized
event handling interface.
Sometimes I send a message and expect a specific response. I don't
want to observe all the responses to a particular named event, only a
response to the the request I sent.
Events should be a representational state transfer mechanism between
processes.
// various constructors that might return an event dispatcher.
var dispatcher;
dispatcher = openChannel();
dispatcher = Mutex();
dispatcher = navigationButtons();
// send a 1 time event request (we may get a reply depending on the
implementation)
var promise = dispatcher.send("named_event", dataObject);
promise.then(callback, errback);
// observe all events of type "named_event"
var observer = dispatcher.observe("named_event" dataObject);
observer.then(callback, errback);
I'm finding lots of uses in for passing the dataObject in both
directions. Also, note that a call to send() gives back a promise,
which is totally different than an observer. The state machine of a
promise is directional -- it can only move state from incomplete ->
complete or error, while an observer does not maintain state.
-- Kris Walker
I think that our interests are aligned, and furthermore that any of
the proposals above provide a suitable foundation for the construction
of promises. I did an experiment to that effect in Narwhal, where I
started with setTimeout or enqueue as the only engine-specific
component, and from there grew out anonymous event emitter objects
with events, then built named-event emitter objects on top of that,
and then built promises on top of named-event emitters with a
polymorphic override to the emitter code to guarantee monotonic state
advancement.
I apologize that the code is a bit convoluted in terms of OO style
because one of the other goals was to use ES5 methods to guarantee
that recipients could not use promises as a subversive communication
channel, and yet still have some sharable constructor code:
http://github.com/kriskowal/narwhal/blob/master/lib/events.js
Kris Kowal
It seems in the case of promises that they may be better represented
as a subclass of an Emitter/Observable object. At least, that is what
I'm taking away from events.js in Narwhal.
Up to this point, in my implementation, a single named event may
return a promise. This implicitly defines it as a one time, "single
serving" event. However, allowing an event constructor to return a
promise like this don't seem to fit very neatly into the direction the
spec is going, since returning an observable object from an observable
object does not make sense. Maybe I should decouple it and create a
different subclass for one time events and communication channels?