ASWI Programming Standards
Vector 8:2, page 111
Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 111
Introduction¶
This paper describes a set of standards proposed by the committee of the "APL-Share-Ware-Initiative", ASWI for short. These standards are an integration of the various standards applied by BSO/Management Support (Utrecht, Netherlands), Philips/PASS-PC’S (Eindhoven, Netherlands), and the Institute for Theoretical Biology (Leiden, Netherlands).
The objective of this standard is two-fold. The first objective is to define a set of rules according to which APL programming should be carried out, in order to improve program maintainability. It is recognized that in a professional APL programming environment, where different people work for different clients, a need exists for a concise and standardized use of APL.
The second objective is to smooth the introduction to new programs for potential users. To fulfil this objective a set of standard names is proposed which should be available in every workspace and which act and inform according to preconceived, generally accepted notions. This ensures that a novice will always know how to move around in the on-line documentation of a foreign workspace.
We ask all programmers participating in ASWI to adhere to these standards for the following reasons. First of all, standards are a boon for not-too-experienced programmers because - hopefully - standards reflect the accumulated wisdom of experts. Secondly, standards are useful because the writers can fall back to automatisms and can focus their thinking on the real hard nuts in the program. And finally, readers can access the information faster when they don’t need to puzzle things out but can rely on standards instead. This holds for good standards, but it holds for mediocre standards too.
So, even non-superb standards are often better than very clever incidentally used constructions. For this reason, we urge programmers to deviate from this standard in exceptional cases only and then to document these deviations carefully in order to ensure program maintainability.
The remaining text will cover the following topics:
- naming conventions
- branching conventions
- documentation conventions
- comments
- messages
- miscellaneous
Naming Conventions¶
This paragraph outlines the various standards for naming of systems, workspaces, functions, variables and labels.
Systems. An APL system is a collection of one (or more) APL workspaces and files which conceptually form a whole. Together they perform the functions described in the functional specification of the system. The system is identified by a 3 character identifier (no more, no less). Each of the characters should be alphabetic capitals. Valid identifiers are in the range of ‘AAA’ to ‘ZZZ’. We will refer to the system identifier as "SID" hereafter.
Examples:
DLG - Dialogue system
PLT - Plotting system
RNA - RNA analysis
SCR - Screen utilities
TED - Text editing system
WHL - Whaling population growth simulation
Workspaces. The workspace is identified by a name of 3 or more characters of which the first three are the SID. All characters should be capitals and digits may be used (not in the SID). It is advisable not to use names with more than eight characters.
Preferably a system is contained in 1 workspace. If this is not feasible (for example for reasons of memory requirements) the system should be divided into functionally cohesive subsystems distributed over different workspaces. The names of those workspaces all start with the same SID.
Example:
WHLDATA - file which contains all data of whale simulation.
WHLSIM - workspace which performs population simulation.
WHLANAL - workspace which statistically analyses results.
Functions. We distinguish between user functions, sub-functions and imported functions.
-
USER FUNCTIONS
By user functions we mean:
- driver or main functions (the ones that start up the system).
- functions to be activated by the end-user directly.User functions can be recognized by:
- an easy-to-remember name.
- error-proof and with error messages in the language of the end-user.
- sometimes no parameters.
- sometimes no explicit result.A user function has a name of at least 5 characters of which the first three are the SID and the next two are alphabetic capitals. The remaining characters may be alphanumeric capitals.
Examples:
PLTHISTGRAM,PLTPIE&PLTGRAPHWHLSETPARMS,WHLSIMULATE,WHLGRAPH
-
SUB-FUNCTIONS
Sub-functions are functions that are not used by the end-user directly. In general this type of function is called from other APL functions. A sub-function has a name of at least 6 characters of which the first three are the SID, followed by "_". The rest of the characters may be alphanumeric capitals.
Try to recognize functionally related sub-functions, and characterize them with common characters in position 5 and 6 of their names. (For systems with many functions, you can apply this principle recursively for remaining characters.)
Example:
SIM_…all simulation programs of system with SID=SIM. SIM_DS…all discrete sub-functions. SIM_CN…all continuous sub-functions. SIM_CNAS…all continuous sub-functions for "assignment". SIM_CNTR…all continuous sub-functions for "transfer". SIM_CNSP…all continuous sub-functions for "splitting". -
IMPORTED SUB-FUNCTIONS
Sub-functions which are copied from other workspaces are "imported sub-functions". They retain their original name. Because their names don’t start with the proper SID, their foreign origin remains obvious.
If you introduce any change in the code of that function, the name should be changed in accordance to the new workspace in which it resides. (If necessary, you can explain the origin in the comment.)
Standard Names. The following niladic functions should always be present in the workspace whenever applicable.
-
SIDLXin⎕LX←'SIDLX'
Niladic programSIDLXwill either start the main programSIDBEGINor present the most general information which is provided by∆SIDABSTRACT(see paragraph DOCUMENTATION).
For example in workspace WHLSIM:and in workspace DLGUTILS:
-
SIDBEGIN
If a workspace has one user function only, then this function is invoked by functionSIDBEGIN.
In workspaces with more than one user function or with sub-functions (utilities) only, functionSIDBEGINonly presents those alternative functions.
For example in workspace WHLSIM: -
SIDRECOVER
Any system which might be corrupted by unexpected errors or crashes should provide a functionSIDRECOVERto repair the damage as well as possible. If automatic recovery is awkward or impossible,SIDRECOVERshould direct the user to the proper information, or describe the best procedure to do so.
For example in workspace WHLSIM:
Variables. This paragraph will outline the conventions for shared variables, global, sub-global and local variables.
Global Variables. A global variable is a variable which is not local to a function, or a variable which is stored in an APL file. So a global variable is always available for reference by every APL function in the workspace.
The name of a global variable is at least 5 characters long. The first three characters are the SID. The next characters are lowercase alphanumerics.
The use of global variables must be restricted as much as possible! Examples:
SCRappl,SCRfrs,SCRsubglbls,SCRmiss.RNAenergyrules,RNAsequence,RNAstructure,RNAparams.
Sub-global Variables. A sub-global variable is a variable, which is not a global variable but is accessed by more than one function. The name of a sub-global variable is at least 6 characters long. The first three are the SID, followed by "_". The remaining characters are all lowercase character. Examples:
WHL_menu,WHL_params,WHL_select.RNA_options,RNA_choice.
The use of sub-global variables must be restricted as much as possible!
Local Variables. A local variable is a variable which is local to that function. The name of a local variable may be A-E or H-K or M-Q, S-Y. Or alternatively formulated, all capitals except F, G, L, R, or Z. For clarity longer, mnemonic names could be used up to 4 characters in order to improve the readability of the programs.
The name of the arguments and the explicit result of a function are L, Z and R or short mnemonic names which start with L, Z or R.
Z: the variable name Z is reserved for the explicit result.
L: the variable name L is reserved for the left argument of a function.
R: the variable name R is reserved for the right argument of a function.
F: the function name F is reserved for the left argument of an operator.
G: the function name G is reserved for the right argument of an operator.
I,J,K: it is advisable to reserve I, J and K for counters and important indices.
T: We suggest using T for temporary line-locals (a line-local is a variable which gets its value somewhere else in the same line).The variables F, G, L and R should not be assigned a value in any function.
When mnemonic names are used for the arguments or for the explicit result, the following rules must be obeyed:
- the names may be up to 4 characters long (longer names might conflict with names of user functions).
- the names must be alphanumeric capitals.
- F, G, L, Z and R may never be used.
- the first character should be L, R, Z if that variable is the left argument, right argument, or explicit result.
- the standard names for labels should not be used for variables.
- comment lines explaining the meaning of the arguments and the explicit result, must still be in the function and conform to the current standard.
Shared Variables. The names of shared variables are still under discussion. We welcome any suggestions.
Labels. The only permissible label names are B#, E# (with # a number), BE, XX and EXIT. See next paragraph.
Branching¶
There are numerous ways in APL to branch to function lines. But it is also true that this excessive number of possibilities has given APL a bad name. Imagine an APL function in which different ways of branching are used (for example: →L×⍳C, →(C)⍴L, →C↑L, →C↓L, →(C)/L). It is clear that in reading such a function, a substantial amount of time is needed to solve the flow in that function.
For reasons of structured programming one should not think in branches but in conceptual blocks of code which are executed once, multiple times or not at all. Each block is marked by a label B# at its first statement and by a label E# at its last statement, with # a unique number for each block.
So, we suggest new programs adopt the following 4 types of construction:
-
Condition:
-
For-loop & Repeat while:
-
Repeat until:
-
If/else & Case:
Remember that the numbers identify different blocks in one function (not different types of construction).
Short conditions or repetitions can be coded as:
BE:→(...)/1+1↑⎕LC ⋄ short conditional expression
BE:→(...)/1+1↑⎕LC ⋄ short repeating expression ⋄ →⎕LC
BE: short repeating expression ⋄ →(...)/1↑⎕LC
BE:→(...)/1↑⎕LC ⍙ short repeating expression
Here "⍙" stands for "lev" or for "⎕FX 'Z←L ⍙ R' 'Z←L'".
Never branch to results of a calculation or to absolute line numbers!
To exit a function prematurely, do not use "→0". Use label "EXIT" instead which is at the end of a function. So apply the following type of construction:
Documentation¶
This paragraph outlines the proposed on-line documentation for programmers and for end-users. We suggest implementing the following documentation in functions which yield the text as their resulting vector, with each line separated by a return-character. Use uppercase and lowercase characters as in normal text (not uppercase only).
Our convention is simple and straightforward: document anything you like by using an APL function which yields a character vector, and give this function the same name as the item you are documenting, prefixed with "∆". For example, if you document the global variable "WHLxyz" the documentation is generated by function "∆WHLxyz".
Programmers’ Documentation. By on-line programmers’ documentation we mean a description of all components of an APL system in the workspace or on file so that it can be used rapidly at all times by a programmer. This documentation is intended for system maintenance and development.
The following items should be documented and on-line available:
- SYSTEM. If any general information exists which should be available for the programmer, then it is documented in variable
∆SIDSYSTEM. Example: if important information exists for system WHL, it is documented in∆WHLSYSTEM. - GLOBAL VARIABLES. Global variables must be described briefly (1 line per variable) by function
∆SIDGLOBALS. If more extensive information is useful, then that particular variable is also described separately. Example: global variablesRNAenergyrules,RNAsequencecould be described extensively in∆RNAenergyrulesand∆RNAsequence. - SHARED VARIABLES. Shared variables must be described briefly (1 line per variable) by
∆SIDSHARED. Similar to the global variables, more extensive information can be presented separately. Example: shared variableCTLcan also be described in∆CTL. - VERSION-CONTROL. If you don’t have a proper version-control system we suggest you apply the variable
∆SIDHISTORYto document any changes. Example:
⎕←∆RNAHISTORY
Problem |Date |Author |Change
----------------------+------+--------+-----------------
-File selector without|031089|V.Batenb|RNA_FIL[5 7.1 11]
folders | | |RNA_BOX new
| | |RNA_curfile new
-Absolete energyvalues|211189|JJ.Riet |RNArule new values
A component file is documented in its 0th component.
User Documentation. On-line user documentation is useful for experienced users who have forgotten some particular details and want to refresh their memory. This requires that the information is short and compact and can be found easily by following standard procedures.
On-line user documentation is also useful for the novice, but here it has two different purposes. First the user wants to learn if the workspace will attend to his needs (investigation process) and second how to use it or where to find more elaborate information (application process). The first purpose -investigation - also requires short compact information; only the second purpose needs more elaborate information.
Both types of user are properly served with standard names to find their information. For this the following names serves:
-
∆SIDABSTRACT
∆SIDABSTRACTreturns 1 (or at most 2) lines which describe the system very briefly (compare this with the more extensive descriptions in∆SIDDESCRIBEand∆SIDHOW). If functionSIDLXdoes not start functionSIDBEGIN, then it activates∆SIDABSTRACT. For example: -
∆SID
∆SIDgenerates 6 lines with the following basic information:
1.SID.
2. complete name of the workspace.
3. version number, release and/or last modification date; anything which uniquely distinguishes this workspace from earlier or newer versions.
4. copyright holder.
5. name, address or telephone number of person or company to be contacted for information.
6. manuals, books and other documentation of the system. -
∆SIDDESCRIBE
Program∆SIDDESCRIBEdescribes what the Workspace will do: the purpose of the Workspace. Program∆SIDDESCRIBEshould inform the reader in a nutshell if the workspace is appropriate for his problem. It does not teach the reader how to work with the workspace (that is the function of∆SIDHOW), but only tells what the workspace does. This extensive information is summarised in∆SIDABSTRACT. -
∆SIDHOW
Program∆SIDHOWdescribes how to work with the workspace. It describes the various options of the user-functions and the required syntax. If the Workspace contains several user functions which can be activated by the user independently, than∆SIDHOWat least summarises each user function. -
∆SID-
If∆SIDHOWis insufficiently brief, then for each function a describing "∆SID-" could be added which explains the particulars of that function. So the syntax of each user functionsSIDxyz(which should at least briefly be described in "∆SIDHOW") can be described more elaborately in∆SIDxyz.This documentation is the only elaborate one, because it is primarily intended for the novice to learn how to operate the various functions. Example: function
WHLSIMULATEhas its syntax described in∆WHLSIMULATE, functionRNAFOLDin∆RNAFOLD.
⎕←∆CPXPOLARHOW
Purpose: convert polar to cartesian coordinates
Syntax: PL ← CPXPOLAR CRT
CPXPOLAR converts cartesian coordinates to polar coordinates.
Its inverse program is CPXCART.
The right argument CRT specifies the cartesian coordinates. It
can be a vector of pairs, or a 2-column table with X-Y values.
The result PL are the polar equivalents. The rank and size of
PL are identical to those of CRT. Each pair is the modulus and
the angle in radians.
Example 1 0 <--> CPXPOLAR 1 0
1 0.78 0.71 0.71
1 1.57 0 1
Comments¶
Use comments to describe what is done and why, but not how it is done (that’s what APL is for). Any APL function should at least contain the following comments
[1] ⍝⍝ description what the function does
[2] ⍝ R: description of the right argument
[3] ⍝ L: description of the left argument
[4] ⍝ Z: description of the result
[5] ⍝ G: names of used globals and subglobals, if any
[6] ⍝ P: name of programmer, dates of changes
Example:
[0] Z ← L VBL_DOCMENT R;A;L∘IO
[1] ⍝⍝ Document system and print to various devices.
[2] ⍝ R[i;]: Character names of output devices i.
[3] ⍝ L[]: Title to be printed.
[4] ⍝ Z: '' if OK, else error message.
[5] ⍝ G: VBLprint; VBLerr; VBLglobal <=== bad design, many
[6] ⍝ P: EvBatenburg; 6/83,3/84,8/84,2/85. (sub-)globals
Furthermore we suggest 2 types: section comment and line comment.
- Section comments explain several lines of code. This type of comment uses a whole line in the function.
- Line comments illuminate the code of a line. This type of comment trails at the right of that particular line. Example:
Messages¶
Messages are still under discussion. We welcome anybody who has suggestions.
React immediately where the error is discovered. If a test discovers an error, this is the place where the first action should be taken. Avoid printing of error messages in sub-functions, but express the occurrence of an error in the explicit result. (For example: ’’(empty vector) instead of computed array, 0 (zero) instead of computed array, error message instead of computed array)
Also avoid letting a sub-function halt the system by "→". The reason for both suggestions is that a sub-function may very well be unhappy with an exceptional condition, but its caller might better be suited to react to such a condition.
Miscellaneous¶
In this section a few remarks are made on APL programming practice. The size of an APL function should be within working conditions and preferably less. This means that if one is working with a screen that displays 20 lines of 80 characters each, the size of APL functions should preferably be less than, or equal to 20 lines of 80 characters.
Good APL functions…
- are readable.
- perform one conceptual task only.
- can be used as building blocks.
- are like APL primitive functions; so they will give a defined result for all parameter values.
- work for missing left argument (default) and don’t crash for empty arrays.
- receive data in the right argument and control in the left argument.
Good APL functions are not necessarily (CPU) efficient. What is (CPU) efficient today may very well be (CPU) inefficient tomorrow (and vice versa).
Re-think again about your design if an APL function…
- is bigger than your screen.
- uses branches.
- uses (sub-)global variables.
ASWI Standards Committee¶
FHDv.Batenburg, Institute for Theoretical Biology, Kaiserstraat 63, 2311GP Leiden, the Netherlands.
TRC.Bonnema, University Twente, Postbus 217, 7500AE Enschede, the Netherlands.
Lv.Geldrop, I.P.Sharp-Reuter, Raiffeisenstraat 11, 5611CH Eindhoven, the Netherlands.
Hv.Loon, ORIGIN/Nederland, Gebouw HKB-6, Kastanjelaan 1, 5616LH Eindhoven, the Netherlands.
B.Smoor, Adfee, Dorpstraat 50, 4128BZ Lexmond, the Netherlands.