Review: the APL*PLUS III GUI
In the last issue of Vector and in other APL rags too numerous to mention Manugistics announced APL*PLUS/III as the most important APL release ever. Part of the reason for this monumental hubris may be the advent of control structures which are talked about elsewhere by Adrian Smith, but at least part of their pride will be in the new native Windows session and, most importantly, the APLGUI which has been changed from a monolithic set of APL functions (which reduced the available namespace by a 26th and the available workspace by considerably more) to a few system functions and variables working through an external DLL. The result is faster and cleaner, but they have also changed the interface in some ways that significantly improve its suitability for large system development.
What I intend to do over the next few pages is to examine whether the improvements in the APGUI justify this claim and to compare it to its main rival, Dyalog APL/W v6.3. I will not go into how to code applications under +3 as this will doubtless be covered elsewhere. What you will get will be my impressions and my opinions but I will try to take you beneath the veneer of those smooth demonstrations that show you what will impress, and more importantly what will work.
I have spent most of the last eighteen months with Dyalog 6.3 developing, with Adrian Smith, the development environment Causeway [Smith, Vector 10.4, pp64-77]. I therefore have a pretty clear idea of what is important to me in a workable GUI interface. Since the arrival in the UK about a month ago of version 1.1 of +3, I have been working in my own time on the development of Causeway for +3 and have marked what has pleased me and what has annoyed me about it. What I have been doing with it is quite specific, in that it uses the APLGUI in a way that its developers never imagined. However my main concern is always to be able to produce fast, feature rich, reliable systems in the shortest amount of time possible and I imagine that the majority of you will share my aim.
The APLGUI that comes with +3 is a development from that in +2 but it has overcome most of the faults that so crippled +2. Firstly it is fast. My impression is that there is no noticeable difference in speed between it and Dyalog whereas the +2 APLGUI was at least ten times slower. The functions Win and W_Call which drove the +2 APLGUI and the variables Wself, Warg and Wres have been replaced by system functions and variables respectively. Whether you would agree with them that they have provided a clean upgrade path from the APLGUI in APL*PLUS/II is debatable. For the majority of UK readers this shouldn’t be a problem though, as you could probably count the number of serious +2 APLGUI developers in the UK on the fingers of one hand.
The method of attaching callback code to events has changed and the means of identifying APLGUI objects has changed from system-generated numbers to developer-generated names. The most impressive change however is the way in which, with the interpreter and session being native Windows programs, the handling of any APLGUI objects created is concurrent with work in the session. This was ably demonstrated by James Wheeler in his demonstration when he had a ball bouncing in a form while he worked in the session changing the variable which determined the ball’s size, and velocity. This may seem a bit of a gimmick but over the last couple of weeks it has made my life quite a lot easier as I have been able to get under the covers of my code as it is working.
The way in which a form interacts with others and in particular the form that was active when it was created is very flexible and gets over the problem that we have in Dyalog of having a choice of allowing user-input on only one form or on them all.
There has also been a new object, the Timer which generates special events at regular intervals. This is what kept the ball bouncing in the demo but it could also be of use in real-time applications and I have used it myself in Causeway to defer execution of some code.
Free Standing Menus
The Menu class appears only to provide menus that hang from menu bars. Although pop-up menus (menus that appear at the cursor position) were not initially fashionable they are nevertheless remarkably useful to have, and are becoming increasingly popular. In order to provide a usable form designer for Causeway I regard them as essential. In order that you don’t spend your time waltzing from a new control to the property dialogue box, to the toolbar and back to the control I allow you to click the mouse button on the form and pop a menu asking what kind of object you want. You click on an object and up comes another menu asking how you want to change it. So useful are they that I have been forced to develop a routine to create, using ⎕wcall, a pop-up menu and return the user’s choice from it. It worked but it involved placing a ‘filter’ between the APLGUI form on which I placed the menu, and Windows, to catch the WM_COMMAND message that Windows sent to report which menu item had been selected. This is like hooking DOS interrupts and cleaning out drains, messy and to be avoided at all costs.
The documentation, while well organised, is in some places quite sparse and in many places just not rigorous enough. For example, in the documentation for the Click event we have:
When a mouse click occurs for the object. This event can occur either by user action or by invoking the Click method using ⎕wi.
It fails to mention that it can occur as the result of the user pressing the spacebar while a Check control has the focus. Nor does it mention here that it can occur as a result of the program setting the value of the check box (whether it is checked or not) – more about this later.
In contrast I found the documentation on the use of ⎕wcall very useful. In fact had it been any less good I doubt that I would have been able to get my pop-up menu facility to work in the couple of hours it took. Filters and window classes are not easy to get across in a few paragraphs, but with a couple of well chosen examples they introduced it well.
It is a shame that they have re-imposed the same restrictions as have Dyalog on what can be a child of what. When James Wheeler demonstrated the product in December he showed a bitmap as a child of a bitmap and a form as the child of a form. In release 1.1 'q.q'⎕wi'New' 'Form' produces the rather bizarre ’PARENTAGE ERROR’. I thought it very useful that a master form could have other forms as its children and when it was deleted all its children would also disappear. In Causeway we have a hierarchical form system with forms being conceptually children of other forms. We have to manage this with a table in the workspace (or under Dyalog, in the data of the root) and we have to be very careful that on deletion of forms the table is properly updated. It would have been much easier handled by the interpreter but obviously Manugistics found some very good reason why it was impossible.
The development of the callback methodology is interesting. This is about what to do when Windows informs APL that the user has done something on one of its controls, e.g. clicked on a button. The way that they chose to implement this in +2 was crippling. If the user clicked a button BB on a form FF then the system would execute the function BB_FF_Click_handler, no more and no less. This meant that to handle five events each on twenty controls on the thirty forms that might comprise a medium sized system you would need 3000 distinct functions, probably most of them the same.
In +3 each event valid for a control has an associated property that can be set to a text vector that will be executed on the occurrence of the event. This is very flexible, and an improvement on the methodology of Dyalog that only allows functions. In Dyalog you can use the same function for different events/control combinations, but many of these functions will be very simple and in +3 would not be needed at all. It is a pity that when looking at Dyalog the developers at Manugistics did not take note of the ability not only to associate a function with an event, but also an arbitrary APL array that would be passed as the left argument of the function. This is useful for exactly the same reason. If the callback code needs access to some data that is specific to that event on that object, then the workspace need not be cluttered with odd named variables to achieve that effect. It is possible to hold the data in the data property of the control, indexed by event name, and this works but is less clean.
As mentioned earlier there is an interesting feature of callbacks. When, under program control, I set the value of a Check box to change it, say, from being selected to not being selected, a Click event is generated on the box. I, the program, am being told that I have just changed the value. I can hear you say that if I had a more object-oriented mindset I would realise that it is the box that is being informed that it has just changed and might want to do something about it. So, what if it was a callback on the box that did the changing in the first place. Consider that I might have set, in some way, the box to ‘watch’ an APL variable. We do this all the time in Causeway. The variable has changed so I update the box. Then I get a Click on the box to say that it just changed, so I change the variable to match it. And then ... Actually there is a feature called recursions that will trap this kind of thing and (by default) if it happens more than 50 times it will stop. This used to be called STACK FULL but the neat thing is that you can, for debugging purposes, set the limit to be quite low, perhaps five or ten. This means that you catch the little bug(ger)s early.
Deferred Method or Callback Execution
When I execute a Method on a control or form using ⎕wi, then any callbacks on that control that would be triggered as a result of the method, are executed during the call to ⎕wi and before it returns to the part of the program that called it. A similar behaviour is possible in Dyalog using 1 ⎕nq object message. This is not however necessarily desirable. If for instance, the code executed in the callback refers to a global variable, and there is a local of the same name in the function that executes the method, then the callback will use the value in the local rather than the global. In order to avoid name clashes of that sort a strict naming convention must be adhered to with perhaps different prefixes for locals, globals, labels and functions. This is fine until you start to use code provided by someone else who may not share your convention. This is bad for me who is writing a system that, as a result of callbacks, executes arbitrary code written by application developers who want to know nothing of the naming conventions in the ‘system’ code.
In Dyalog this problem does not arise. You ⎕nq object message, the message is put on the Windows queue, and it is not processed until you have left the function to go back to the message loop (⎕dq in Dyalog). I have emulated this behaviour in +3 by having my own message queue and by using a callback on a Timer to fire a function to empty and process the queue. It is not ideal and some sort of deferred execution would be preferable.
Methods vs. Events
This problem illustrates a difference in approach between Dyalog and +3. In +3 if you want to do something to an object, for instance make it visible, you are encouraged to use a method, in this case Show. There is a parallel between methods properties and functions and variables. The methods are, as it were, an object’s functions, and the properties are its variables. As indicated above the two are sometimes closely intertwined. The setting of the value property of a Button to -1 seems exactly equivalent to invoking its Click method. In Dyalog you may change an object property in the same way, but the only other way of changing the object is to queue a message to it that, had it come from Windows, would have had the desired effect.
A combination of the +3 approach and a hangover from the days of the +2 APLGUI provide a useful bit of functionality. First some background.
The main APLGUI function ⎕wi takes as its left argument the name of an APLGUI object. If this is omitted then the value of the system variable ⎕wself is used instead. In execution of a callback on an object ⎕wself is automatically set to the name of the object. This means that monadic calls of ⎕wi act on the object.
The methods and properties of the forms and controls are part of the name hierarchy. Regardless of the left argument to ⎕wi I can refer to a property of an object by prefixing to it the name of the object. There are certain shortcuts. If for instance a property, method or object name is preceded by a colon ‘:’ then it is taken to be a property, method or object of the form. Thus if I am executing a callback on a button B1 on a form and wish to know the text property of an edit, E1, on the same form I need only use ⎕wi ':E1.text' not even knowing the name of the form.
Close and Destroy
In the methods Close and Delete and the events Close and Destroy, Manugistics have provided a good clean way to implement the behaviour, seen in so many multiple form applications, of allowing a child form to notice the intention to close the application and to take appropriate action, perhaps rejecting the close if, after consultation with the user, it is deemed inappropriate. This can be a minefield and is similar to the cascading delete in a relational database. In either case the wind-up requires two passes, one to check that everyone agrees and one to implement the deletion. The freeing of associated resource and the cleaning up of registration tables in the case of Causeway must be implemented from the Destroy event leaving the Close as a simple answer to a question.
The main difference between graphics under +3 and under Dyalog is that under Dyalog the graphics are objects that can be moved, that report events and that retain their essence after being covered by other windows. Under +3 there is a Draw method. It is an operation to change temporarily the appearance of an object. There appear to be all the standard facilities there such as circles, lines, polygons and boxes. One thing that Windows doesn’t provide in its Graphics Device Interface (GDI) and that likewise is not given here, is a Bezier curve. This is very simple and fast to implement in machine code or C and is a powerful drawing tool. It is what makes scalable TrueType fonts possible. Neither do they provide a simple way in APL to define bitmaps and icons. The manipulation and definition of bitmaps and icons, which are after all only matrices of numbers, is so suited to APL that it seems odd that Manugistics expect us to use inferior tools such as Paintbrush to produce them. With APL, for instance it is possible to take a black and white bitmap of some text and with a few rotations and comparisons produce a grey embossed version of the same.
Still I must emphasise that the most important feature that the +3 graphics are missing is persistence. If I were the type of person who could put up with having to write code to redraw a graph on a piece of window every time it was accidentally obscured, then I would probably put up with writing in C, or perhaps even COBOL.
The scale property provides a means of specifying a different internal co-ordinate system for an object than the default. On the whole it is well implemented and achieves its purpose well. If, for instance,you want to draw a graph in a frame and you use a PostScript-like co-ordinate system with the origin in the bottom left corner then set the scale property to 0 100 0 -100 100 (proportional, top, left, height & width). Then 0 0 will be the bottom left hand corner and 100 100 will be the top right. It has other units such as pixels, twips and points, however the default unit for position and size (unless set by scale) is the character unit. On a VGA screen this is 16 pixels deep by 8 across, on a SuperVGA with LargeFonts it will be larger.
There are two reasons that I believe this to be an unfortunate choice. Firstly, in a graphical environment there should be no need to be counting in different units on the two axes. In order to put a border of a uniform width around a control I should not have to make it so many character units deep and double that number wide. Secondly, if the average character size of the system is different in the target environment from that in the development environment then all the forms and their controls will change size to match the new character size. Typically this would mean that they would grow and take up more of the valuable screen real estate that the user just spent a couple of thousand pounds to get. While for simple dialogue boxes it is a good idea for the size to increase, there are many applications for which it is not, e.g. spreadsheets & word processors.
So, you don’t like the default, then change it I hear you say. Two problems – it is impossible to change the default for the positioning of forms. The system object ’#’ does not have a scale property (it is always characters) and so the position of forms must always be specified in character units. Furthermore if I change the scale of a form to pixels and create a frame in it, the position (the where property) of the frame is in pixels but the ‘size’ is in character units as the frame did not inherit the scale of the parent but took instead the global default. This is in contrast to Dyalog where by default all objects inherit the coord of their parents, and where all you have to do is to set the coord property of ’.’, the root object, to pixels and everything subsequently created is in pixels.
Here we have something that is symptomatic in some respects of Manugistics’ attitude to its users, i.e. us. The DblClick event is only reported by the items on a List or a Combo control. These are the obvious things where you might think that a user should usefully double-click the mouse, both to select an item and to indicate acceptance of his selection in one fell swoop. However there are more situations where it might be useful. Take for example the Windows Control Panel. It appears to be a form in which are drawn a number of icons on which a double click causes a specific program to load. One might try this in +3. One might create the form and draw in it a number of icons using the Draw method. Then one would be stymied. The Form does not report a double click.
Why not? I can only assume that the paternal Manugistics designers did not think that we would want to know about it. They have made assumptions about the type of applications that we might develop in the same way that they have assumed that we might be shipping applications as complete runtime systems with resources such as bitmaps and icons bound into the interpreter. They are C developers and programmers and so that is how they think.
There are a few things that Dyalog provides that are useful and difficult to emulate. The first of these, the free standing menu has already been mentioned, another is the LOCATOR. This is a means by which we can use the mouse pointer to select an area of the screen by drawing out a rectangle whose size (and potentially position) are updated automatically by the system. This facility is used in ]WED the screen editor but is not generally available.
Portability vs. Control
There are two definite advantages in +3 for the developer who is committed to Windows in one or more of its flavours and who therefore does not regard UNIX portability as necessary.
The facilities offered by the objects in the APLGUI are considerably richer than those offered in the corresponding controls under Dyalog. The Menu object can have associated an accelerator key that automatically selects the menu item whenever it is pressed (to achieve this behaviour in Dyalog it would be necessary to trap the keystroke event in all objects in which it were valid and compare the pressed key with a table stored by the developer on the form). The Edit object has a number of styles that make life so much easier for the programmer. One in particular, the ‘password’ style is quite painful to emulate. The messages also have more detailed information. There are messages for key down and key up as well as for key press and they indicate, among other things, the current state of the Capslock key.
The second advantage is the way in which, if the developer needs to add functionality to a control, or to keep a closer eye on what is happening to it, he has access to the control’s window handle, the unique identifier by which Windows identifies the control. This he can use in a call to a Windows DLL function which will then act upon the control. This is dangerous. It is getting in between the APLGUI and its objects, but in skilled hands it could be a powerful tool. Without it my pop-up menu would have involved a great deal more work than it did.
Undoubtedly one of the main reasons for the lack of most of the above functionality in Dyalog has been the insistence that it must be possible to implement the interface under UNIX. In Toronto Dyadic demonstrated some APL/W code running unchanged on a UNIX box under the development version of their Motif product. Because the +3 APLGUI is very much more closely bound in with Windows, this kind of portability would just not be possible.
If the overall impression I give is of dissatisfaction it is perhaps because I have gone into detail about the things with which I have had problems and glossed over some of the really useful features of the product. There is no doubt that it is a workmanlike product and immeasurably better than APL*PLUS/II. It provides a similar capability to Dyalog v6.3 and while it is richer in some areas it is poorer in others. It gives finer control over many objects but it has only primitive graphics. There are areas of design that I found frustrating, such as the odd callback behaviour, and areas which I found a blessed relief, such as the flexibility on Wait and the Close & Destroy events. On balance I would still choose Dyalog v6.3 because of the greater simplicity and predictability of the callback structure and because of the graphics. By now it may be an academic choice as Dyalog v7 is promised for July 4th. It would be impossible to assess it from the brochures, but namespaces could be equally as important a development as control structures and the extra features that they promise to pack into the GUI should knock APL*PLUS/III 1.1 into a cocked hat. The humble application developer can only benefit.
(webpage generated: 10 October 2007, 01:43)