[xinf] Events counter-proposal

hank williams hank777 at gmail.com
Sun Jul 9 15:21:57 CEST 2006


Dan,

Congrats. This seems to be quite cool. I must admit I dont fully understand
the new "object instead of string" thing so I have a few questions
(primarily relating to my haXe ignorance), but I do get the basic idea and
it sounds just right. Binding is possible easily and it does indeed provide
type safety.

It would really be nice if the compiler could automatically check for any
event conflicts within a project, and or produce a list (I had suggested XML
but I realize it doesnt have to be, though it would provide a way of
allowing the entire event to travel, and not just the name conflict
checking) which would allow the conflict checking to transend an individual
swf. For example, I will be using a combination of haXe and AS3 and I would
love to be able to work across the platforms (including bound code) and to
have my events move seamlessly.

But none of that should effect what you are talking about. Any additions
would/could be separate from the design you describe.

Regarding my questions,

1. what does this mean:

        public var name(default,null) :String;

what are default and null and just how do they get used.

2. did you really mean this:

    class MouseEvent extends Event<MouseEvent> {

This seems like a recursive definintion, but I am not sure.

Again, great work.

Hank

On 7/9/06, daniel fischer <dan at f3c.com> wrote:
>
>
> hi all,
>
> after a lot of thinking and shifting things back and forth, i've
> finally come up with a proposal for the Event model that i hope
> satisifies all. I had nearly given up, settling for either a compromise
> in-between, or going for two-different-models-at-the-same-time. But
> going thru the discussions again, i found this little hint from
> Nicolas: http://xinf.org/pipermail/xinf/2006-June/000107.html .
>
> The trick is to use Type Parameters for functions. I didn't know this
> was possible until recently. I've tried and extended Nic's hint, and
> the result seems to be "DOM-like Events with haXe type safety". How
> does it sound like?
>
> I'm attaching a "complete" example, but let me go thru the basics first.
>
> 1) Instead of "pure strings" as event identifiers, we're using Objects
> of type EventType<T>:
>
>     class EventType<T> {
>         public var name(default,null) :String;
>         public function new( name:String ) {
>             this.name = name;
>         }
>         public function toString() {
>             return name;
>         }
>     }
>
> you should note that these do have a "name". That name should be
> globally unique (in theory, this could be checked with some static
> list, maybe only if some compile flag like -D assureUniqueEvents is
> given).
>
>
> 2) There is a (type-parameterized) basic Event class, it's main (here:
> only) feature is the event's type:
>
>     class Event<T> {
>         public var type(default,null) : EventType<T>;
>
>         public function new( t ) {
>             type = t;
>         }
>     }
>
>
> 3) A concrete Event class looks like this:
>
>     class MouseEvent extends Event<MouseEvent> {
>         static public var MOUSE_DOWN
>                  = new EventType<MouseEvent>("mouseDown");
>         static public var MOUSE_UP
>                 = new EventType<MouseEvent>("mouseUp");
>         public var x:Int;
>         public var y:Int;
>         public var button:Int;
>
>         public function new( _type:EventType<MouseEvent>,
>                 _x:Int, _y:Int, _button:Int ) {
>             super(_type);
>             x=_x; y=_y; button=_button;
>         }
>     }
>
> we're also defining some event types here-- it seems good to have them
> in this class, but they could be anywhere.
>
>
> 4) An EventDispatcher keeps a list of (rather: a hashtable of lists of)
> event listener functions, EventDispatcher will likely be an interface
> (it is a simple implementation in the attached example), providing some
> well-known functions:
>
>     interface EventDispatcher {
>         function addListener<T>( type:EventType<T>, h:T->Void) :Void;
>         function removeListener<T>( type:EventType<T>, h:T->Void) :Bool;
>         function dispatchEvent<T>( e :Event<T> ) :Void;
>     }
>
>
> this is pretty much all there is to it. The clever use of type
> parameters (all credits to Nicolas) assures that you cannot register a
> wrong handler function. Here's the common usage pattern:
>
>     p.addListener( MouseEvent.MOUSE_DOWN, function(e:MouseEvent) {
>         // do something.
>     });
>     p.dispatchEvent( new MouseEvent(MouseEvent.MOUSE_DOWN,10,10,1));
>
>
> you can neither register a wrong handler function:
>
>     // err: "KeyboardEvent->Void should be MouseEvent->Void"
>     p.addListener( MouseEvent.MOUSE_DOWN, function(e:KeyboardEvent) { });
>
> nor create a wrong event:
>
>     // err: "EventType<KeyboardEvent> should be EventType<MouseEvent>"
>     new MouseEvent( KeyboardEvent.KEY_DOWN, 10, 10, 1 );
>
>
> Some more notes:
>
> - *Inside* the EventDispatcher, there is little typesafety; but the
> function interface assures proper use. Of course it's easy to
> circumvent the typesafety (that is easy in all haXe-- see "untyped"),
> but for "normal" usage, this will IMHO be just fine.
>
> - Should you wish, you can do a "generic" handler function that can
> validly be registered to any event type:
>
>     public static function testHandler<T>( e:Event<T> ):Void {
>         trace("Generic EventHandler: "+e.type );
>     }
>     p.addListener( MouseEvent.MOUSE_DOWN, testHandler );
>
>
> - the "automatic delegate creation" pitfall remains- this will not work:
>
>     public static function testHandler<T>( e:Event<T> ):Void {
>         trace("Generic EventHandler: "+e.type );
>     }
>     p.addListener( MouseEvent.MOUSE_DOWN, testHandler );
>     p.removeListener( MouseEvent.MOUSE_DOWN, testHandler );
>
>   but this will:
>
>     public static function testHandler<T>( e:Event<T> ):Void {
>         trace("Generic EventHandler: "+e.type );
>     }
>     var handler = testHandler;
>     p.addListener( MouseEvent.MOUSE_DOWN, handler );
>     p.removeListener( MouseEvent.MOUSE_DOWN, handler );
>
>   i see no way around this, but it's not too bad a pitfall either.
>
>
> In the attached Test.hx, i've added a "bubbles" flag to EventType
> denoting wether events of this type should bubble or not, and a
> "stopped" property/stopPropagation function to Event for obvious
> reasons. EventDispatcher is a class (includes implementation), but
> should probably be an Interface first, and some kind of
> "SimpleEventDispatcher" class, really. I'm also doing some more test
> event types- KeyboardEvent and GenericEvent. Note that the
> GenericEvent-type used (SOME_EVENT) is not declared in the GenericEvent
> class-- there's no need to do so, if you prefer otherwise.
>
>
> I'm pretty happy with this solution as it seems to provide "best of
> both worlds" - you can rather simply add typesafe events and handler
> functions, but you can also handle events abstractly if you wish.
> Your comments are very appreciated, if the xinf list can
> agree on this, i'll of course also post it to the haXe list.
>
> There is (at least) one open issue left- is the order of event
> listeners relevant? Probably yes, and EventListener should provide a
> way to register listeners with specific priorities... What'cha think?
>
> It seems Nicolas is on holiday- so we have some time to discuss before
> he overthrows everything again :)
>
> -dan
>
> --
> http://0xDF.com/
> http://iterative.org/
>
>
>
> --
> xinf is not flash
> http://xinf.org/
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://xinf.org/pipermail/xinf/attachments/20060709/980aa88d/attachment-0001.htm 


More information about the xinf mailing list