Path: utzoo!attcan!utgpu!watmath!iuvax!rutgers!bellcore!wind!sdh From: sdh@wind.bellcore.com (Stephen D Hawley) Newsgroups: comp.sys.mac Subject: Re: Real Multifinder Message-ID: <17421@bellcore.bellcore.com> Date: 17 Aug 89 14:33:59 GMT References: <46100321@uxe.cso.uiuc.edu> <1989Aug15.001507.14552@sj.ate.slb.com> <24626@iuvax.cs.indiana.edu> <3576@internal.Apple.COM> <1989Aug16.175351.24310@sj.ate.slb.com> Reply-To: sdh@wind.UUCP (Stephen D Hawley) Organization: Bellcore, Morristown, NJ Lines: 105 In article <1989Aug16.175351.24310@sj.ate.slb.com> enk@slcs.slb.com (Edan Kabatchnik) writes: > Granted, (parts of) UNIX should be done away with. But, there is a >superior form to the main event loop: callbacks (found in X and Xerox >Artificial Intelligence Workstations from which the Macintosh developed its >user interface.) Instead of having to dispatch on every possible event in the >main event loop, one establishes a hook that is automatically called when an >event takes place. Yes, and no. Callbacks are not superior, they are only different. Keep in mind that you have to do one of 2 things: 1) make hooks for every possible call back routine in every combination. Set up all these vectors (in pascal, this will be particularly painful without an initialized static data type), and then go. --or-- 2) Make a well thought out set of call back functions that are grouped by types (like window events, controls, etc) and force the call back routines to check a parameter for an action to be taken. The first is painful at best, the second is exactly the same as the event loop. The only difference is that you have taken the dispatcher away from the user and put it somewhere else. Think about it, when an event happens, it would have to be sent through a function that picks a function pointer from a vector of call back routines and executes it. This is exactly equivalent to having the all-too famous: switch(myEvent.what) { case ... } Each case corresponds to a component of the vector of call back routines. I do not think that either is superior at this level, only different. Consider the following code: #define N_EVENTS 16 /* from inside mac */ #define EVER (;;) extern int no_op(); typedef int (*FUNCPTR)(); static FUNCPTR vector[N_EVENTS] = { no_op, no_op, no_op, no_op, no_op, no_op, no_op, no_op, no_op, no_op, no_op, no_op, no_op, no_op, no_op, no_op }; int no_op(evt) eventRecord *evt; { /* should a no_op return anything? */ return(0); } SetEventCallBack(evt, func) int evt; FUNCPTR func; { vector[evt] = func; /* record new callback */ } FUNCPTR GetEventCallBack(evt) int evt; { return(vector[evt]); /* return old callback */ } SetNullEvent(evt) int evt; { SetEvent(evt, no_op); /* set a no_op */ } DoEvents() { EventRecord evt; for EVER { /* infinite loop is no problem, * just leave the program with a call to * ExitToShell(). */ if (GetNextEvent(everyEvent, &evt)) { /* * Since the evnt codes go from 0-15, use * that as an index into the vector, and * execute. */ (*(vector[evt.what]))(&evt); /* * pass in the event so the callback knows * what happened. */ } } } Ok. Now you have code to do all you events will callbacks. There is NO significant difference. All you're doing is factoring out the switch statement, and forcing yourself to write all the code to do calls to SetCallBack() and GetCallBack(). The work isn't reduced, its just changed. Steve Hawley sdh@flash.bellcore.com "Up is where you hang your hat." --Jim Blandy, computer scientist