TweetFollow Us on Twitter

AppleEvents, Mops
Volume Number:8
Issue Number:4
Column Tag:Jörg's Folder

Mops & More Apple Events

Mops is improved, again and more LS Fortran Apple Events

By Jörg Langowski, MacTutor Regular Contributing Author

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Two themes this month: first, the OOPS Forth lovers among you will appreciate that Michael Hore has again improved his MOPS system (see also V7#9); we are at version 2.1 now. Second, we’ll continue a little our experiments with Apple Events; this time with some more examples in LS Fortran.

MOPS 2.1

Not even half a year after the announcement of Mops 2.0, I received a new diskette from Australia with Michael Hore’s newest release of MOPS, version 2.1. Again, he has added a whole stock of new things, and I only hope that the word will spread that this is probably one of the best high level programming systems on the Mac. Many systems that you pay a lot of money for get much less support from its developers than MOPS, which is free.

I wish MOPS many users, and wouldn’t actually be surprised if it went commercial one day. Up to now you can get it from me at langowski@frembl51.bitnet, though. I’ll also try again and post it on sumex-aim.stanford.edu, although they don’t seem to receive my mailings somehow. The compacted MOPS system is 800 K long, so we can’t put it on the source code disk.

Here’s Michael’s letter and the release notes (edited somewhat):

Dear Jörg,

Thanks for a great writeup of Mops in the Sept. MacTutor! I’ve only got one complaint-now I’m surely going to get enquiries from non-Neon users and all kinds of people, so I really ought to write a manual! Horrors!!! (Seriously though, I’ve already started on it. I think I can reasonably assume some knowledge of Forth, and start from there. Maybe in another few months it’ll be ready. Maybe.)

Well, time never stands still, so here’s release 2.1. Sorry, but after your CtlWind example, what have I gone and done but altered the handling of windows with controls!! Would you believe it was a complete coincidence. I’ve introduced the “view” concept, similar to MacApp and TCL, so now controls belong to views, and views belong to windows. The changeover is very straightforward, though, and I think will make it much easier in the long run to put all kinds of things in windows. We don’t have fully automatic handling of scrolling yet, but that should come. The other big change is that classes can now be exported from Modules. All the changes are listed in the “Mops 2.1 release notes” file.

The other big news is that I’m isolated no longer! CompuServe is now in Australia, so anyone can now send email to me at [100033,3164]. I think I’ll have an InterNet address in the new year, too.

Michael Hore, PO Box 821, Nhulunbuy, NT 0881, Australia

[Parts of the release notes follow]

Classes can be exported from modules

Yes, it’s true! You can now define a class in a module, include the class name in the imports list, and instantiate objects of that class anywhere. In fact in the Mops system itself, we are now handling windows, menus and dialogs this way. All the methods of the class are in effect exported along with the class name; you don’t have to take any special action, apart from putting the class name in the imports list, and taking care with action handlers (see below). Whenever you send a message to an exported class, the module will be invoked automatically.

Naturally this has some performance implications. There is a fair amount of overhead involved in invoking a module. You can reduce this to some extent by locking the module over a number of calls (this is true for ordinary exported words as well). But if message execution for a particular class is really time-critical, it would really best to leave the class in the main dictionary. Where exported classes are most useful is for those classes that depend heavily on Toolbox calls for most of their methods (such as windows, menus and dialogs). Toolbox calls are generally much slower than Mops module invocations, so the extra time penalty of putting the class into a module won’t be significant.

Now for the point about action handlers. If the class is defined in module 1, let’s say, and if it is instantiated in another module, module 2, and if this object has action handlers which are also words from the module 2 (rather than in the main dictionary), you will need to declare these action handlers with a new syntax :a .... ;a (pronounced “colon A” and “semi A”) instead of : ... ; . This is because these action handlers will probably be invoked from the class implementation, in module 1, which amounts to a “back-door” entry to module 2. As I have pointed out in the main documentation file, this is a big no-no. But any word declared with the :a ... ;a syntax avoids this problem.

This is a rather subtle condition, so it is probably best simply to declare all action handlers with the :a ... ;a syntax no matter what-it won’t hurt. There is no performance penalty. In fact, :a definitions in the main dictionary compile identical code to normal definitions. And if you use :a definitions routinely, then it is always obvious if a word is an action handler. And this way, whenever you move class definitions into modules, you won’t run into the above problem.

Here are the technical details for those who are interested. An action handler is either in the main dictionary or a module. If it’s in a module, module 2 let’s say, the object using it must also be in module 2 (otherwise you would get a “Can’t store a module address outside the module” error when you tried to install the action handler in the object).

The problem comes up if the class implementation is in another module, say module 1. When a method (in module 1) invokes the action handler, A5 (modBase) will still be set up for module 1, and so will be wrong for the action handler (in module 2). So :a definitions, at the start, first push A5 on to the return stack, then set A5 to the correct value for the current module. This is done by PC-relative addressing, so it makes no assumptions about the previous value of A5. Then at the end of the definition (or if EXIT is done), the previous A5 value is popped back from the return stack.

Note that the overhead is only a few machine instructions. But if the :a word is compiled in the main dictionary, these extra instructions are unnecessary and are omitted, so there is no penalty at all. This is a blatantly undisguised attempt to encourage use of the :a syntax for all action handlers no matter where they are, which will minimize problems with moving class implementations into modules.

CallBefore and CallAfter

This is a new feature which has been in my “coming attractions” list, and has now arrived. It is a bit complex to explain, but if you don’t need this feature, ignore it. It is entirely optional, but can be really useful in some situations.

We have wanted to provide a bit more flexibility in the way a subclass overrides a method. Up to now, it could either override or not. If it did, it could possibly call the Super version of the method within the new definition, but that was all. A superclass had no way of limiting what a subclass may do. So now, along with other languages such as Flavors and Eiffel, we provide a superclass with the power to limit the extent to which a subclass may override a method, basically by allowing the provision of code which must be executed BEFORE the subclass’s version of the method executes, and code which must be executed AFTER the subclass’s method has finished. These pieces of code can do things like check that certain constraints haven’t been violated, or do some other obligatory setting up and winding up housekeeping.

The best way do describe this feature is by means of a real-life example-this code is extracted from class Window (now in the file WindowMod.txt):

/* 1 */

private
:m  SETUP_DRAW:
 get: fPrect\ Save fPrect as it might get changed
 ^base  call BeginUpdate   ;m

:m  WINDUP_DRAW:
 ^base  call EndUpdate
 put: fPrect   ;m\ Restore fPrect

callFirst setup_draw:
callLastwindup_draw:

public
:m  DRAW: (draw): self   ;m

Drawing to a window in response to an update event requires certain housekeeping chores to be done at the beginning and the end. Rather than require them to be repeated

in every window subclass that overrides Draw:, we move them into two private methods, Setup_draw: and Windup_draw:. Then we use the callFirst and callLast syntax to specify that these methods are to be called (as messages to Self) before and after Draw: , respectively. Whenever Draw: is redefined in a window subclass, Setup_draw: and Windup_draw: are executed at the beginning and the end, so that the housekeeping code doesn’t need to be repeated (and you can even forget what it is, if you want to).

Note that the CallFirst and CallLast declarations always apply to the next method declared. You can actually use these declarations more than once, as long as all the CallFirsts come before the CallLasts. A subclass may add methods to the CallFirst and CallLast list of any method (thus, the subclass doesn’t need to know if there are already CallFirst or CallLast declarations in existence for a method it is overriding).

There is no need for CallFirst or CallLast messages to be private, although we have done it in this example. But it wouldn’t really make much sense to call them directly from the outside world.

The order of execution is significant. All entries on the CallFirst list are called in order from the beginning to the end. Thus the CallFirst entries specified by the highest superclass get executed first. This is exactly what you would expect, given the hierarchical nature of Mops code.

But notice carefully, that the same logic applied to the CallLast list means that the entries specified by the highest superclass should get executed last. So what we do is execute the entries in the CallLast list from the end backwards. The entries are put on the list simply in the order they are declared, but they will be executed in the reverse order.

A CallFirst or CallLast method is executed as an early-bound message to Self. All stack parameters and results will be as they are for the method to which the CallFirst/CallLast is being applied. If this “main” method uses the named parameters syntax, then at the time any CallFirst method is invoked these parameters will still be on the stack. Thus the CallFirst method is free to use the named parms syntax itself, as long as it pushes the parms back on the stack when it finishes-otherwise the main method would find its parameters had mysteriously disappeared!

I probably shouldn’t say this. But there is a way to override a CallFirst/CallLast. Forth programmers are notoriously anarchic, and may resent a superclass autocratically decreeing that certain things must take place at the beginning and end of the method they are about to write. (Even if they wrote the superclass themselves. Especially if they wrote it themselves.) Well... the entries on the CallFirst/CallLast lists are simply the hashed forms of the selector names. The binding isn’t actually done until the main method is compiled, at which time the hashed selectors are grabbed and used to insert calls to Self at the appropriate places. So... if, earlier in the class, you have declared a method with the same name as a CallFirst or CallLast method declared in a superclass, the normal method lookup process will find this new method first, and it will be called instead! Now forget you ever read this. Thanks.

MacApp, TCL, and windows with controls

I have been looking at both MacApp and TCL, since these are undoubtedly destined to become the “mainstream” OOP systems on the Mac. I plan to progressively incorporate various ideas from these into Mops. This, I hope, can be done entirely by the addition of new classes, rather that the alteration or replacement of anything there already. Well having said that, I’m going to have to say that I really hope that the following change will be a rare exception!

This change involves the handling of controls within windows, and it unfortunately may affect some existing code. I am really sorry about that, but I think the change is a definite improvement, and will simplify the implementation of windows with complex controls. Anyway the changes to existing code ought to be fairly mechanical.

MacApp and TCL both have the philosophy that anything that can appear on the screen is a “view”, and views may be hierarchical-views may contain any number of subviews. Thus it is straightforward to have a window with scroll bars which can contain a little rectangle of scrolling text with its own separate scroll bars. Also multiple panes in windows can work along similar lines.

So what we now have in Mops, is a new class, View, which logically comes between a window and its controls. Controls now no longer belong directly to a window as such, but they belong to a view, and views belong to windows.

The new window class which supports views is Window+ (in the Toolbox Classes folder). This class replaces CtlWind. Each window+ object has one special view which corresponds to the whole content area of the window; we call this the ContView. The address of this view is passed to a Window+ object when NEW: is called, and otherwise the view doesn’t need any special initialization. Controls work exactly as they always did, except that where you used to pass a window address to various methods of controls, you now pass a view address.

Thus if you already have a CtlWind, it can be changed over to the new scheme quite easily. The CtlWind becomes a Window+. Declare a view, and add that view’s address to the parameters passed to NEW: on the window+. Then all the messages you send to your controls need to have the view passed instead of the former CtlWind. Here is an example (from InstlMod.txt):

BEFORE:

vScroll VS1
vScroll VS2

CtlWind IWIND

: INSTALL
 wRect “  “ dlgWind true false  new: iWind
 180 15 48 iWind  new: vs1  180 85 48 iWind  new: vs2
 etc.

AFTER:

vScroll VS1
vScroll VS2

window+ IWIND
view    IVIEW

: INSTALL
 wRect “  “ dlgWind true false  iView  new: iWind
 180 15 48 iView  new: vs1  180 85 48 iView  new: vs2
 etc.

I have also added a new “Scroller” class, which is a subclass of View, and makes it easier to add scroll bars to a rectangular area. It’s not really complete yet, but may be worth a look. If you use a Scroller as the ContView of a Window+, then when you resize the window the scroll bars automatically do the right thing. In the next Mops release I expect to be able to enhance Scroller along the lines of the Panorama idea in TCL, where Scroller will automatically handle scrolling of its subviews, whenever they take up a larger area than the Scroller view itself.

When you execute the Draw: method on a view, the clip region will have been set to the bounding rectangle for the view, and the coordinate origin will have been changed so that the top left corner of this rectangle is at (0, 0). Both MacApp and TCL do something very similar, so I guess it’s a good idea. Also, it was easy. This whole thing is achieved in Mops with just a few lines of code in the View class, thanks to the CallFirst and CallLast feature.

I hope soon to give some thought to the “command” class in MacApp which makes “Undo” so straightforward, and also to the idea of a command hierarchy as implemented by both MacApp and TCL, in which various classes in turn can have a shot at an incoming command. I expect something in this area will turn up in the next Mops release.

Bugs fixed

There was a bug involving Install, when the installed application used fWind. This window wasn’t being properly initialized when the application was called, and wouldn’t appear on the screen. This is now fixed.

There was a very subtle bug involving indexed ivars not being properly set up in certain particular situations. This is now fixed too.

I also found and fixed a couple of obscure bugs involving optimization of floating point code (i.e., with UseFPU? set True).

I have just found that the Debug command generates a system error 28 when running in virtual memory mode in System 7. I won’t delay this release, especially as I am just about to go on holidays, but hope to fix this in the next release. If you need to use Debug, do it in real mode. If you aren’t using System 7 yet, this won’t affect you.

[end of release notes - letter continues]

MOPS - the fastest high-level language for the Mac?

I think I might have been underselling the performance of Mops. I was very interested in the April MacTutor article by Jonathan Bell, “Beat the Optimizer!” Now people who want to use a high-level language but are primarily interested in number-crunching performance generally use Fortran. Jon documents some extensive speed testing on floating-point matrix multiplication using Language Systems Fortran, both optimized and unoptimized, and also using hand-coded assembler. So I thought this might be a good chance to see how the performance of Mops stacks up.

Jon’s article gives all the details about matrix multiplication, so I won’t repeat it here. Anyway, the main bit of code that we are interested in for performance purposes is the innermost of the three nested DO loops. For the multiplication of matrices A and B to give result matrix C, Jon gives this loop as

 DO K = 1, M
 SUM = SUM + A(I,K) * B(K,J)
 END DO

This loop goes over a row of A and a column of B and the eventual value of SUM is assigned to C(I,J).

This loop involves a floating multiplication and a floating add, as well as array indexing calculations. Jon shows how LS Fortran optimization levels 2 and 3 move the indexing calculations out of the loop to improve performance.

Now for some philosophy. No self-respecting Forth programmer would write the equivalent of the above code. As Jon points out, successive accesses to matrices A and B are a constant distance (or “stride”) apart (although different for A and B). In Forth, where lean and mean is the order of the day, the programmer, not the compiler, would have the responsibility for writing code that exploits this fact (which isn’t really very hard). It shouldn’t be the job of a Forth compiler to improve terrible code!

Still, to be quite fair, and to avoid accusations of cheating, I did it both ways in Mops. I wrote a matrix class, and included ROW: and COL: methods. These return a start address, a limit address and a “stride”, ready for a DO loop over the row or column. Using these methods, the inner loop becomes

(don’t need the limit here )

i col: B -> stride -> Baddr drop

Alimit Aaddr

do i f@ Baddr f@ f* ++> %sum

stride ++> Baddr

12 +loop

(Aaddr, Alimit, Baddr and stride are all local variables. %sum is a floating local. The stride value for a matrix row in Mops is always 12, so this value is used to step through a row of the A matrix. The stride for a column of the B matrix is obtained from the col: B call.)

Doing a straight conversion from Fortran, without using the new methods, we have

 m 0 do
 k i  at: A   i j  at: B   f*  ++> %sum
 loop

Now for the results. I have a IIsi with FPU, so Jon’s results for an SE/30 are comparable if we allow for the difference in clock speeds (16 Mhz for the SE/30, 20 Mhz for the IIsi). Accordingly I have scaled my results by 20/16 to get figures which should compare meaningfully with Jon’s SE/30 results.

There are three sets of results. Mops has a value FPU? which is set True by the startup code if an FPU is present. If we set this flag False, even with an FPU present, we force Mops to call SANE for all floating operations.

Here are Jon’s SE/30 results for SANE, with Mops underneath. Times are average times, in seconds, for a 500 * 500 matrix multiply.

total calcs overhead

LSF1 26.283 21.773 4.510

LSF2 22.755 21.653 1.102

Mops(normal) 26.99 23.35 3.64

Mops(slow) 35.22 23.38 11.85

The Mops results aren’t as good as LSF here, but it was handicapped. If we leave the FPU? flag alone, Mops finds at startup that there is an FPU, and sets the flag True. The Mops FP routines for the common operators test this flag and bypass SANE if it is True. This gives a second set of results which doesn’t really correspond to any of Jon’s, since LS Fortran doesn’t apparently have this feature. But we can see that bypassing SANE is well worth doing:

total calcs overhead

Mops(normal) 9.92 6.28 3.64

Mops(slow) 18.34 6.50 11.85

Note that this is code which will run on any Mac, since the presence of the FPU is determined on the fly. Even the simple-minded, “slow” version is faster than LSF2, and the “normal” version is more than twice as fast. The “overhead” came out the same as in the previous test, which is good, because it ought to.

The third set of results for Mops is obtained by setting another value, UseFPU? to True. This produces code which utilizes the FPU in line, with some optimization, and so corresponds to the LSF -mc68882 option.

Here are the results:

total calcs overhead

LSF1 3.998 2.182 1.817

LSF2 2.873 2.158 0.715

Assembly 1.355 1.192 0.163

Mops(normal) 1.62 1.26 0.35

Mops(slow) 11.81 1.09 10.72

The “calcs” figure in the last line is definitely underestimated-it is difficult to isolate the “overhead” meaningfully, so I just fetched the floating values to the stack and then dropped them, a process which would overestimate the overhead in most situations. With the FPU being used directly, the calculations are so fast that the error is magnified by comparison.

Anyway the main point to note is that the “normal” Mops times are almost twice as good as LSF2, and very competitive with hand-coded assembly. This is largely because Mops detects sequences of FP operations and leaves the intermediate results in the FPU’s registers. Also FP named local variables and parameters are assigned to FPU registers (up to 6). Moving floating values to and from the FPU is fairly slow, and Mops tries to avoid it if it can. Looking at the generated machine code, the time penalty as compared with assembly is largely in the DO loop operations rather than in the FP instructions. Even this overhead could be reduced by using a FOR ... NEXT loop.

I’m now going to make the outrageous assertion that provided normal Forth philosophy is followed, Mops produces faster code than any other high-level language for the Mac. Would anybody like to prove me wrong?

End of Michael’s letter. If only C wasn’t so much in fashion, this could be one of the most widely used languages on the Mac. Really.

Example 1: MOPS’ matrix methods

\ Matrix timing test.  Nov 91.

need     floating point

\  Usage:   50 100  dimension   Fmatrix MM

    0     value    ROWDIM
    0     value    COLDIM

: DIMENSION
            -> colDim   -> rowDim
            colDim  rowDim  *  ;


:class   FMATRIX         super{  Farray  }

            var      #rows
            var      #cols
            var      rowLength
            var      colLength

:m  #ROWS:    get: #rows   ;m
:m  #COLS:      get: #cols   ;m

:m  ^ELEM:  { row col \ temp - addr }
            row  get: #cols  *  col +   ^elem: super   ;m

:m  AT:             ^elem: self  f@   ;m

:m  TO:             ^elem: self  f!   ;m

:m  ROW:  { row - limit start stride }           
                        \ Sets up for a DO over the row.
            row  get: rowLength *   idxBase +     \ addr
            get: rowLength  bounds           \ ( limit addr )
            12   ;m                                                                                    \ stride

:m  COL:  { col - limit start stride }  
                        \ Sets up for a DO over the column.
            col 12 *  idxBase +    \ addr
            get: colLength  bounds             \ ( limit addr )
            get: rowLength   ;m                             \ stride

:m  PUTROW:  \ ( 1st ... last  row - )
            row: self   drop  ( we know stride is 12 )
            swap   12 -
            do   i  f!   -12 +loop   ;m

:m  PRINTROW:  { row - }
            row  row: self    drop
            ?do   i f@ 10 e.r   12 +loop    ;m

:m  PRINTCOL:  { col \ stride - }
            col  col: self   -> stride
            ?do   i f@  10 e.r  cr   stride +loop    ;m

:m  PRINT:
            get: #rows  0
            ?do   i printRow: self  cr   loop   ;m

:m  CLASSINIT:
            rowDim  put: #rows   colDim  put: #cols
            get: #cols 12 *  put: rowLength   
            get: #rows  get: rowLength *   put: colLength
            classinit: super   ;m

;class

5 3 dimension  Fmatrix         FF

objPtr A          class_is  Fmatrix
objPtr B         class_is  Fmatrix
objPtr C          class_is  Fmatrix

: DIMSCHK  { l m n - }
            #rows: B        m         <>
            l  #rows: C     <>
            n  #cols: C      <>
            or  or  
abort” Wrong operand dimensions for matrix multiply”   ;


: MXMPY  { m1 m2 m3 \
                                     l m n  Aaddr Alimit Baddr stride %sum - }
            m1 -> A   m2 -> B   m3 -> C
            #rows: A  -> l   #cols: A  -> m   #cols: B  -> n
            l m n  dimsChk
            l  0  do
                        i row: A  drop   -> Aaddr  -> Alimit
                        n  0  do
                                    0.0 -> %sum
                                    i col: B  -> stride  -> Baddr  drop
                                    Alimit  Aaddr
                                    do        i  f@  Baddr f@   f*  ++> %sum
                                                stride ++> Baddr
                                    12 +loop
                                    %sum   j i to: C
                        loop
            loop   ;

: DUMMY  { m1 m2 m3 \
                                     l m n  Aaddr Alimit Baddr stride %sum - }
            m1 -> A   m2 -> B   m3 -> C
            #rows: A  -> l   #cols: A  -> m   #cols: B  -> n
            l m n  dimsChk
            l  0  do
                        i row: A  drop   -> Aaddr  -> Alimit
                        n  0  do
                                    0.0 -> %sum
                                    i col: B  -> stride  -> Baddr  drop
                                    Alimit  Aaddr
                                    do
            \          i f@   Baddr f@   f2drop
            \ Note: omit this line entirely for UseFPU? True test,
            \ otherwise overhead figure is artificially high.
                                                stride ++> Baddr
                                    12 +loop
                                    %sum   j i to: C
                        loop
            loop   ;

: SLOWMPY  { m1 m2 m3 \ l m n %sum - }
            m1 -> A   m2 -> B   m3 -> C
            #rows: A  -> l   #cols: A  -> m   #cols: B  -> n
            l m n  dimsChk
            l  0  do
                        n  0  do
                                    0.0 -> %sum
                                    m 0 do
                                                k i  at: A   i j  at: B   f*  ++> %sum
                                    loop
                                    %sum   j i to: C
                        loop
            loop   ;

: SLOWDUMMY  { m1 m2 m3 \ l m n %sum - }
            m1 -> A   m2 -> B   m3 -> C
            #rows: A  -> l   #cols: A  -> m   #cols: B  -> n
            l m n  dimsChk
            l  0  do
                        n  0  do
                                    0.0 -> %sum
                                    m 0 do
                                                k i  at: A   i j  at: B   f2drop
                                    loop
                        



            %sum   j i to: C
                        loop
            loop   ;

3 5 dimension  fmatrix  matA
5 3 dimension  fmatrix  matB
3 3 dimension  fmatrix  matC

-2.0 -7.0 -4.0 8.0 1.0        0  putRow: matA
-3.0 0.0 -1.0 0.0 -9.0        1  putRow: matA
0.0 -1.0 -8.0 -9.0 -3.0      2  putRow: matA

-1.0 3.0 -2.00  putRow: matB
4.0 -1.0 1.0  1  putRow: matB
9.0 -4.0 -8.02  putRow: matB
-5.0 0.0 -3.03  putRow: matB
6.0 3.0 -6.0  4  putRow: matB

0.0      fvalue  TOTAL
0.0      fvalue  OVERHEAD
0.0      fvalue  CALCS
0.0      fvalue  SLOWTOTAL
0.0      fvalue  SLOWOVERHEAD
0.0      fvalue  SLOWCALCS

: MATINIT        \ ( mat - )
            -> A
            #rows: A  0
            do
                        #cols: A  0
                        do
                                    i j +  >float  j i to: A
                        loop
            loop   ;

: TICKSglobal Ticks  @  ;

: .RESULTS      \ ( flt - )
            fdup  6  f.r  6 spaces
            20.0  f*  16.0 f/   .” scaled: “  6  f.r   cr  ;

: TIMER  { mx1 mx2 mx3 - }
            mx1 matinit   mx2  matinit
            ticks
            10 0 do   mx1  mx2  mx3  mxmpy   loop
            ticks  swap -  >float  600.0 f/  -> total
            ticks
            10 0 do   mx1  mx2  mx3  dummy   loop
            ticks  swap -   >float  600.0 f/  -> overhead
            total  overhead  f-  -> calcs
            ticks
            10 0 do   mx1  mx2  mx3  slowmpy   loop
            ticks  swap -  >float  600.0 f/  -> slowtotal
            ticks
            10 0 do   mx1  mx2  mx3  slowDummy   loop
            ticks  swap -  >float  600.0 f/  -> slowoverhead
            slowTotal  slowOverhead  f-  -> slowCalcs
            .” Total         “  total  .results
            .” Calcs       “  calcs  .results
            .” Overhead”  overhead  .results
            .” Slow total”  slowTotal  .results
            .” Slow calcs”  slowCalcs  .results
            .” Slow overhead”  slowOverhead  .results  ;

50 50 dimension  fmatrix  SOURCE
50 50 dimension  fmatrix  RESULT

Adding more Apple Events to Fortran code

At the end, I would like to show you how to use more than the four required ‘built-in’ Apple Events in Language Systems Fortran. The high level event support in the Fortran run time system contains the subroutine F_SendEvent, which will send an ‘aevt’ class Apple Event, and takes three parameters: the first is the four character event ID, ‘EVT1’ or ‘EVT2’ in our case, the second is the name of the target application that the event is sent to, and the third specifies an optional file name. There are some predefined target application names: ‘*browse’ specifies that the target process should be selected with the PPC browser (the ‘Select a program to link to:’ dialog), ‘*lastbrowse’ means that the last process selected with the browser is the target, and ‘*sender’ sends the event to the process that last sent an ‘odoc’ event to this application.

There are some limitations; you can not (for the moment, I hope this will change) use an event class other than ‘aevt’, and you cannot send any data with the event, except for specifying a file name in the third parameter. But because this name is converted by the sending routine into a ‘file system specifier’, this has to be the name of a real-existing file, you cannot just send any character string here (I tried this to add data to the Apple event - no luck).

In order to receive an Apple Event other than one of the four required ones, you have to install a new event handler for it. The main program in example 2 does just this - installs the event handlers via the AEInstallEventHandler function and sets up a new menu with two items which correspond to the two subroutines that send the two types of events. When one of the menu items is selected, you can choose a target process with the PPC browser and the event will be sent to it. If you try to send an event to yourself, you’ll notice something funny: the program will seem to hang for a while and then finally report an error message, but the receive message will also be printed! This is because the event has been posted OK and will be eventually taken by the program, but only on the next passage through its main event loop. Now, because F_SendEvent uses a send mode that waits for the event to have arrived at its target until a timeout, the receipt of the event will never be acknowledged. The send routine waits patiently until it times out (about a minute), then returns with an error message, which will be displayed in the output window together with the message that is printed by the receiving routine. When you make a duplicate of the AEMenu program (on the source code disk) and launch both the original and the copy, sending messages between the two programs works fine.

Actually, this should have been an example on distributed processing. What I wanted to show was how you can split up a lengthy operation, such as multiplication of large matrices, into chunks that can be processed independently and later be assembled to a final result. This requires that you can send data with the event, have that processed by the other program (possibly on another machine), and have the result sent back to you. Sorry, but my exploration have not come that far yet because the generic Apple Event send routine that I wanted to write always broke down on me. An Apple Event is such a complex data structure that it is hard to see where you’ve made a mistake when the send routine returns with an error message. In other words, Apple Events are hard to debug; if someone out there knows a good utility that can be used to debug Apple Events, I’d appreciate to know about it. Until then, I’ll work on a more extended high level event example. The idea of doing distributed processing through Apple Events is really intriguing. You might imagine little ‘math routine servers’ turning as background processes on Macintoshes on some network; when these machines are not used for heavy calculations, like when someone is just typing text into the machine like I am doing right now, these servers can be used by other machines on the network to help doing their number crunching. I am convinced that a large percentage of the raw power of big computer installations is contained in the workstations on user’s desks, and these machines are not being used most of the time. Distributed processing may help in channeling some of that power.

Example 2: Adding new Apple Events in Fortran

!!M Inlines.f
!!G AEvent.finc
c
c
 program AEMenu

 implicit none
 
 external action1, action2, AE1, AE2
 integer*2 err
 
 err = AEInstallEventHandler (%val(‘aevt’),
 1 %val(‘EVT1’),%val(%loc(AE1)),
 2 %val(int4(0)),%val(int2(0))) 
 if (err. ne. 0) then
 type *,’Error installing first Apple event, 
 1 result code = ‘,err
 end if
 err = AEInstallEventHandler (%val(‘aevt’),
 1 %val(‘EVT2’),%val(%loc(AE2)),
 2 %val(int4(0)),%val(int2(0))) 
 if (err. ne. 0) then
 type *,’Error installing second Apple event, 
 1 result code = ‘,err
 end if
 
 call AddMenuItem (‘AE menu’,’action1’,action1)
 call AddMenuItem (‘AE menu’,’action2’,action2)
 
 end

 subroutine action1
 implicit none
 
 integer*2 err,F_SendEvent
 external F_SendEvent
 
 err = F_SendEvent (‘EVT1’,’*browse’,0)
 type *,’Sent EVT1. Error code = ‘,err
 
 return
 end

 subroutine action2
 implicit none
 
 integer*2 err,F_SendEvent
 external F_SendEvent
 
 err = F_SendEvent (‘EVT2’,’*browse’,0)
 type *,’Sent EVT2. Error code = ‘,err
 
 return
 end
 
 integer*2 function 
 1 AE1(theAppleEvent,reply,%val(handlerRefCon))
 record /AppleEvent/ theAppleEvent
 record /AppleEvent/ reply
 integer*4 handlerRefCon
 
 type *,’Event 1 received’
 
 AE1 = 0! noErr
 return
 end

 integer*2 function 
 1 AE2(theAppleEvent,reply,%val(handlerRefCon))
 record /AppleEvent/ theAppleEvent
 record /AppleEvent/ reply
 integer*4 handlerRefCon
 
 type *,’Event 2 received’
 
 AE2 = 0 ! noErr
 return
 end
 

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Live Home 3D Pro 3.6.2 - $49.99
Live Home 3D Pro is powerful yet intuitive home design software that lets you build the house of your dreams right on your Mac, iPhone or iPad. It has every feature of Live Home 3D, plus some... Read more
RapidWeaver 8.2 - Create template-based...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
Opera 60.0.3255.109 - High-performance W...
Opera is a fast and secure browser trusted by millions of users. With the intuitive interface, Speed Dial and visual bookmarks for organizing favorite sites, news feature with fresh, relevant content... Read more
DEVONthink Pro 3.0beta2 - Knowledge base...
DEVONthink Pro is your essential assistant for today's world, where almost everything is digital. From shopping receipts to important research papers, your life often fills your hard drive in the... Read more
Tunnelblick 3.7.9 - GUI for OpenVPN.
Tunnelblick is a free, open source graphic user interface for OpenVPN on OS X. It provides easy control of OpenVPN client and/or server connections. It comes as a ready-to-use application with all... Read more
Carbon Copy Cloner 5.1.9 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
Dropbox 73.4.118 - Cloud backup and sync...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keeps them up-to-date between systems... Read more
Postbox 6.1.18 - Powerful and flexible e...
Postbox is a new email application that helps you organize your work life and get stuff done. It has all the elegance and simplicity of Apple Mail, but with more power and flexibility to manage even... Read more
Wireshark 3.0.2 - Network protocol analy...
Wireshark is one of the world's foremost network protocol analyzers, and is the standard in many parts of the industry. It is the continuation of a project that started in 1998. Hundreds of... Read more
BetterTouchTool 2.856 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom... Read more

AFK Arena guide - Everything you need to...
Ok, so if you're like me, you've been playing (and sometimes waiting) your way through AFK Arena, only to learn there's a lot more to it than there appears on the surface. There's guilds, a PvP arena, and all sorts of other systems and game modes... | Read more »
Explore an epic fantasy world in MMORPG...
Webzen have just announced the official launch date for its stunning MMORPG ‘MU Origin 2’ which will arrive for iOS and Android on May 28th. It will be the second spinoff from the classic PC-based MU Online, and it looks to further refine the... | Read more »
Solar Explorer: New Dawn guide - Tips an...
Solar Explorer: New Dawn is a lunar lander game that really ratchets the intensity up to 11. With all of the asteroids flying around as you fly around at seemingly breakneck speeds, it can be easy to feel overwhelmed bythe whole thing. | Read more »
The Dalaran Heist - How Hearthstone...
I am someone who wrote Hearthstone off a while ago. It was hard not to try and stick with it. The game has incredible production values and a core of really great talent working on the game continuously to keep it feeling fresh and fun (full... | Read more »
Steam Link App - Everything You Need to...
Steam Link has finally released for iOS! That’s right, you can play your epic backlog of PC games on the go now. Well… sort of. While the Steam Link app was announced seemingly ages ago, it only got actual approval for release last night. Check out... | Read more »
Pre-register now for endless superhero r...
Talking Tom Hero Dash is set to take the ever-popular Talking Tom and Friends franchise in a brand new direction as it opens pre-registration to players worldwide. Not only does it promise to be a beautifully rendered, fast-paced, action-packed... | Read more »
AFK Arena - Guild Wars guide
Ok, so if you're like me, you've been playing (and sometimes waiting) your way through AFK Arena, only to learn there's a lot more to it than there appears on the surface. There's guilds, a PvP arena, and all sorts of other systems and game modes... | Read more »
Superhero-themed Talking Tom Hero Dash i...
One of the exciting releases that we’re looking forward to is Talking Tom Hero Dash, an upcoming superhero-themed runner created by Outfit7. This new game is an action-packed endless runner that takes you on an epic adventure to assemble the... | Read more »
Kingdom Rush Vengeance Update Guide 2 -...
Kingdom Rush: Vengeance just got updated once again to add more content to the game. This addition, called The Frozen Nightmare, adds three new levels, five new enemies, two new heroes, and some new achievements. | Read more »
Save the world with SCIENCE in the upcom...
Previous versions of space colonization game TerraGenesis encouraged you to explore the galaxy and settle its planets. The eagerly-awaited 5.0 update will try to smash them to bits. Yep, with a new "world killers" setting, you can unleash... | Read more »

Price Scanner via MacPrices.net

12″ 1.2GHz MacBooks on sale for $999, $300 of...
Amazon has current-generation 12″ 1.2GHz Retina MacBooks on sale for $300 off Apple’s MSRP. Shipping is free: 12″ 1.2GHz Space Gray MacBook: $999.99 $300 off MSRP 12″ 1.2GHz Silver MacBook: $999.99 $... Read more
Here’s how to save $200 on Apple’s new 8-Core...
Apple has released details of their Education discount associated with the new 2019 15″ 6-Core and 8-Core MacBook Pros. Take $200 off the price of the new 8-Core model (now $2599) and $150 off the 15... Read more
Price drops! 2018 15″ 2.2GHz 6-Core MacBook P...
Amazon has dropped prices on clearance 2018 15″ 2.2GHz 6-Core Touch Bar MacBook Pros by $300 with models now available for $2099. These are the same models sold by Apple in their retail and online... Read more
Apple drops prices on 2018 13″ 2.3GHz Quad-Co...
Apple has dropped prices on Certified Refurbished 2018 13″ 2.3GHz 4-Core Touch Bar MacBook Pros with prices now starting at $1489. Apple’s one-year warranty is included, shipping is free, and each... Read more
Apple drops prices on 2018 Certified Refurbis...
Apple has dropped prices on clearance 2018 15″ 6-Core Touch Bar MacBook Pro, Certified Refurbished, with models available starting at only $1999. Each model features a new outer case, shipping is... Read more
Price drops! Clearance 2018 13″ Quad Core Mac...
Amazon has dropped prices on 2018 13″ Apple Quad-Core MacBook Pros with models now available for $250 off original MSRP. Shipping is free. Select Amazon as the seller, rather than a third-party, to... Read more
How Much Is ‘Solace’ Of Mind Worth When Buyin...
COMMENTARY: 05.22.19- Smartphone cases give us peace of mind by providing ample protection for such a fragile gadget and the sky’s the limit as far as choices go with a plethora of brands, styles,... Read more
Get a 13″ Touch Bar MacBook Pro for the lowes...
Apple has Certified Refurbished 2017 13″ 3.1GHz Dual-Core i5 Touch Bar MacBook Pros available starting at $1439, ranging up to $390 off original MSRP. Each MacBook features a new outer case, shipping... Read more
Apple adds new 15″ 8-Core MacBook Pro to line...
Apple has added a new 15″ MacBook Pro to its lineup featuring a 9th generation 2.3GHz 8-Core Intel i9 processor, 16GB of RAM, a 512GB SSD, and a Radeon Pro 560X with 4GB of GDDR5 memory for $2799.... Read more
21″ 2.3GHz iMac available for $999 at B&H...
B&H Photo has the 2018 21″ 2.3GHz Apple iMac on sale for $100 off MSRP. This is the same model offering by Apple in their retail and online stores. Shipping is free: – 21″ 2.3GHz iMac (MMQA2LL/A... Read more

Jobs Board

Best Buy *Apple* Computing Master - Best Bu...
**690427BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000860-Charlottesville-Store **Job Description:** **What Read more
*Apple* Mobile Master - Best Buy (United Sta...
**696430BR** **Job Title:** Apple Mobile Master **Job Category:** Store Associates **Location Number:** 001012-Bismarck-Store **Job Description:** **What does a Best Read more
Manager - *Apple* Team - SHI International...
…opportunity available in the Hardware & Advanced Solutions Department as the Manager of the Apple Team The Manager must be familiar with all aspects of Apple Read more
Best Buy *Apple* Computing Master - Best Bu...
**696375BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000203-North Austin-Store **Job Description:** **What does a Read more
Geek Squad *Apple* Master Consultation Agen...
**696286BR** **Job Title:** Geek Squad Apple Master Consultation Agent **Job Category:** Services/Installation/Repair **Location Number:** 000172-Rivergate-Store Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.