Criticism of the APL programming language

From Wikipedia, the free encyclopedia

The APL programming language has been used since the mid 1960s on mainframe computers and has itself evolved in step with computers and the computing market. APL is not widely used, but minimalistic and high-level by design, at several points in its history it could have captured a more significant market share, but never did. APL first appeared on large mainframe computers and, like C and Pascal, did find its way to CP/M and MS-DOS based microcomputers. Unlike C and Pascal, APL did not flourish in the microcomputer arena until hardware of sufficient computing horsepower became commonly available. Perhaps accounting for its lack of mainstream appeal, APL's characteristics have always led to much criticism of the language. As always, such complaints may arise from misconceptions, have origins in distant APL history and be no longer be relevant today, or they may have some degree of validity. This article is concerned only with the latter two categories.

Despite the recurring claims that programming talent is still a high priced commodity, the market has been loathe or simply unwilling to even try the potential benefits APL has to offer. Acceptance or rejection of APL is sometimes a highly emotionally charged issue, often with individuals on both sides of the discussion having incomplete or incorrect information.

Many beginning programmers have difficulty learning APL's syntax and peculiarities (although this is not unique to APL), and even many expert programmers find APL programs difficult to maintain and debug, unless exceptional care was taken in their production.

Contents

[edit] APL Character Set

The APL language features a very compact notation which centers around a special character set visually depicting the operations to be performed. These symbols are an extension of traditional arithmetic and algebraic notation and are partly the reason it is possible to formulate extremely terse and compact problem solutions in APL. These characters have all been incorporated into Unicode.

  • The additional characters can give APL a special elegance and concision not possible in other languages, using symbols visually mnemonic of the functions they represent. Many choices for the various glyphs made were quite remarkable, providing an intuitive graphical depiction of the operation.
  • On the other hand, especially for a newcomer, the extended character set can lead to a stong degree of complexity and unreadability, typically when the symbols are strung together into a single mass without any comments. The glyph choices are not always optimal : monadic and dyadic functions of a glyph are for example sometimes unrelated.

When APL was introduced, in 1969, the Selectric typewriter used interchangeable printing element. However, while considered "fast" (15 characters per second) and "quiet" compared to an ASR33 terminal, it was still slow for heavy output, the Diablo (daisywheel) terminal being hardly better with its 30 cps. 300 baud was on the higher end in these years.

The compact nature of APL worked well with the slow hardware. Video terminals, unless equipped with the requisite APL character generator either in ROM or in their control unit (3270-3274), could not faithfully display APL code. The ability to display and print the APL character set was a hardware requirement which often was not met[1]. That did not help the growth of APL in the early years.

Today, the problem of APL font display has largely been solved by bitmapped font technology which is now generalized. Beginning programmers accustomed to languages like C++ or Java may be discouraged by the combination of terse APL notation and the presence of extended symbols :

' ( ) + , - . /  :  ; < = >  ? [ ]
\ _ ¨ ¯ × ÷

Even with unicode, it may still be a struggle to get the APL characters to appear correctly. Depending on your browser settings, many of the characters in the above table may or may not appear as APL symbols. Many of these symbols are not even used by, nor valid in current versions of APL.

Various transliteration schemes have been developed, for both the transmission of APL programs through a non-APL medium, or for display purposes, such as to display the text of an APL function in an e-mail message. One would not normally want to program in this manner. Today, Openoffice Writer easily manages the mixing of APL characters with normal text using the font Arial Unicode, Documentation becomes easier with simple cut-and-paste. Provided they are configured correctly, present Internet browsers display a mix of APL characters with any supported human language(s) as well, this page being an example.

In the recent past, use of handheld computers such as the BlackBerry, Palm Pilot, and processors built into cellular telephones, suggests that the market for a compact language could be developing. At this time, only one vendor, Dyalog, has such an implementation. The J language, which features further advances in array programming and thinking, but without the special symbols, has yet to be found on a BlackBerry device.

[edit] The One-Liner

One often cited complaint about the APL language is the ability to write an entire program in one line of code, with the (perhaps intended) effect that the resulting code is neither readable nor maintainable, even by the original author.

In reality, such one liners were often several program statements glued together with some artificial construct or multiple assignment.

In APL circles, the one-liner sometimes provides a form of recreation and amusement. However, the one-liner is understood to be a form or recreation and little else, and in no way represents good programming practice.

In very early APL implementations such as for the IBM 1130, execution of program lines required disk activity to retrieve the next line. With this older hardware, disk activity was quite slow, and programs could be made to run faster by containing fewer lines. Later, with more modern computers and significantly more memory, this practice may have stuck, compounded by the relative difficulty in which APL program lines were entered and edited.

Today, a one-liner would typically be less efficient than thoughtfully authored code. There is comparatively little per-line CPU time consumed, plus more attention is given to the algorithm chosen. In a one-liner, thought would be given to attaching program fragments together without regards to overall aesthetics or efficiency.

The diamond symbol, the statement separator, was introduced early on and was rapidly adopted by nearly all APL vendors. IBM was late to adopt this feature, which appeared in later versions of the APL2 product in the 1980s. This partially solved any legitimate need to write such lines as now one line of code could contain multiple statements. Usage of the diamond symbol was largely a matter of style, the alternative being not to use them at all, leading to "long and skinny" programs.

As a practical matter, lack of the diamond symbol in some IBM versions, notably APL.SV and VSAPL, was not optimal with respect to usability. As the response time of many systems was far from sparkling (often having to do to the machine being overloaded rather than poor code) scrolling through functions could be slow. Today, with workstation technology, this no longer happens.

[edit] APL Idioms

Like many other languages, APL programs contain idioms, or in this context, expressions when taken as a whole to accomplish a certain thing. Today, these may be called code snippets.

One authoritative list of APL idioms was called the FinnAPL Idiom List or FinnAPL Idiom Library and was widely circulated among APL programmers. Documented idioms were typically things like "determine whether any of the bits in a given boolean vector were on" or "right-justify a ragged character matrix" or "sort a numeric matrix". These were often not very long, and part of the experience of being an APL programmer is to identify uses of these idioms while reading code.

To a lesser extent, an idiom list was a poor substitute for an APL program library, which never truly existed. Often systems were delivered with one or more workspaces containing useful functions, however this was never standard throughout APL users as were standard libraries for C or C++.

On the language implementation level, several systems used a form of idiomatic recognition, where a sequence of characters is recognised as a distinct primitive function and treated as such. Some speedup to statement execution can be expected with this approach.

[edit] APL Keyboard

In nearly all modern APL implementations, APL characters are entered by means of keyboard mappings or Input Method Editors. Today, the growth of APL is often hampered by the unwillingness of newcomers to learn the language on account of difficulty posed by the currently available hardware.

Although no longer relevant today, it is interesting to take the early APL user's hardware into consideration. Prior to the widespread usage of full screen terminals, APL was executed with a printing terminal, such as the IBM Selectric 2741, or various Xerox and Anderson-Jacobsen products. APL usage from printing terminals was especially miserable, however no alternative existed at the time. The IBM 3270 and various personal computer implementations brought with them a full screen editor which represented a dramatic increase in the quality of APL usage. Previously, some APL glyphs needed to be overstruck, that is a character, backspace, and another, thus requiring a special procedure to actually delete characters. This complicated line editing considerably and made program entry and editing awkward and tedious.

¨
1
¯
2
<
3

4
=
5

6
>
7

8

9

0
-
+
÷
×
 ?
Q

W
ɛ
E

R

T

Y

U
̾
I

O
*
P


A

S

D
_
F

G

H

J
'
K

L
(
[
)
]

Z

X

C

V

B

N
|
M
 ;
,
 :
.
\
/

Compared to today, it was unreasonably difficult and time consuming to enter then later edit APL statements. Looking at APL literature dating back to the 1960s and 1970s, when printing terminals were the norm, one sees a coding style influenced by the fact that APL code was difficult to edit. It was easier to insert characters into a line than to break it up, or just to add something to end of an existing line. Quality of early APL code could have been far better, had editing it been easier.

Newer keyboard layouts such as the overstrike-free Union and Unified keyboard arrangement, influenced by the IBM 3270 keyboard, have made life far easier for APL programmers accustomed to earlier conditions. It has not, however, shown itself to be convincing viewed from the perspective of an APL beginner. The following keyboard layout, a Finnish variant of the IBM 3270 APL keyboard, more correctly resembles current vendor offerings. Note the underscored alphabetics - these have been eliminated or deprecated in some APL implementations.

IBM:n APL2-päätteen näppäimistökartta.

Today, the problem of requiring a special keyboard of input method editor has not been solved to the satisfaction of an APL newcomer. However, the notion of a "language bar", a place in the development environment where APL function symbols are enumerated and can be clicked instead of entered on a keyboard, looks very promising.

[edit] Order of Execution

APL features a rich set of primitive functions which range from arithmetic and logical operations to matrix inversion. Most functions relating to arithmetic and numeric processing are separate symbols, while functions relating to the APL system, external services, and introspection, are implemented as keyword functions preceded by the "quad" character. Further, APL features infix notation throughout the language for both user-defined and primitive functions.

From the outset, rather than develop complicated rules for operator precedence, it was clear that a simpler approach was necessary on account of the sheer number of symbols. The APL rule is that a statement is executed from right to left with all functions having equal precedence. This is not to say that 3-1 equals -2, the ordering of the arguments themselves to functions is not reversed.

FORTRAN, as the first widely-used high level language, popularized rules of precedence thought to concur with ordinary arithmetic. That is, statements are evaluated from left to right while the following operations, unless otherwise indicated by explicit parenthesis, are executed in the following order: function calls, exponentiation, multiplication and division, and addition and subtraction. Later versions of Fortran included a logical if statement and it followed that relational operations and logical operations followed behind addition and subtraction.

Many later languages followed this or similar strategies. The C programming language provided for 15 levels of precedence,[2] however these in reality did not differ significantly from those of Fortran.

Other languages with notable exceptions to the "usual" order of precedence include the following:

  • ALGOL, which, in some early versions, allowed programmers to configure the operator precedence at compile time
  • Smalltalk, similar to APL, implemented no operator precedence but unlike APL, evaluated statements in a strict left-to-right manner
  • POP-2, exactly opposite to APL, implemented operator precedence in a left to right manner, complete with assignment, indicated with a right-pointing arrow, at the end of the line.

In retrospect, as the APL language design required a large number of symbols, the choice of a strict right-to-left execution seems eminently reasonable. Further, unlike most other languages, calls to user-written APL functions appear as an infix notation which is fully consistent with the precedence scheme of APL.

[edit] Name Scoping

Since its inception, APL has had two classes of name scope, namely global and local names. Global names were defined at the workspace level, while local names were declared local to a function but visible to functions lower in the calling tree. Usually, this applied to variables, though it was later not uncommon to have local functions. Although a name was local to a procedure, it was not strictly local, that is, the name was visible in functions further in the calling tree. Similarly, a name could be shadowed by declaring it local in a function; the global definition would be not be visible to functions at the level it was localised or below.

At least two APL dialects included some form of namespaces where global definitions inside the namespaces would not collide with names outside. Also, at least two APL dialects included a form of direct definition, an alternative way to represent functions, where only names assigned in the procedure were localised.

The consequence of APL scoping rules are that a variable assigned in a function will overwrite a more global definition unless the name is localised.

[edit] Line Labels, Branching, and Control Structures

Early versions of APL included only the Branch Arrow and the Line Label to effect flow control. Arguably, what was initially delivered was already quite powerful, in that the building blocks existed to build conditional and computed GOTOs were present in the language from the outset. Line labels, unlike other languages, were immutable local variables present in a function and assumed the value of whatever line numbers on which they were present. APL allowed a form of "precomputed branching" where branch targets of conventional loops were calculated in advance.

The famous comment from Dijkstra, that the APL language is a mistake carried to perfection, probably originated from the fact that at the time this comment was made, no proper language punctuation relating to flow control other than the branch arrow and line label were present in the language.

Early versions of APL allowed only a branch operation which had a target of an existing line in an APL function, zero, which caused a function return, or an empty vector, which caused flow control to continue. Conditional branches were often coded in the following manner: branch(X = 1)/6 This line would be read "if X equals 1, then branch to 6". As APL execution is from right to left, this would work in a counterintuitive way: (X=1) would evaluate to zero or one, then would be the left argument to the compression function. 0/6 would evaluate to an empty vector, and in this case the function would keep going without taking the branch. 1/6 would evaluate to 6, or more precisely, a one-element vector of 6 as its first and only element, and thus APL would branch to line 6. If line 6 did not exist, it would be the same as branching to zero, i.e. return. Many variations on this theme were possible.

Not long afterwards, APL language included the notion of a line label. A line label was simply an identifier followed by a colon at the immediate left of a line of APL code, and would evaluate to a numeric scalar corresponding to the line on which it was found. Unlike C and other languages, a line label was a normal identifier with a scalar numeric value which could appear in any expression and was subject to the usual APL scoping rules.

A line label was treated like any local variable, except the assignment was implicitly done by by virtue of the label appearing on a line. Like ordinary local variables, their scope was not strictly local, and a sub-function could see the values of line labels of the calling function. This was a source for error, while accessing a label from another function returned a legitimate value which could cause an intended branch to an unintended wrong location.

With the advent of the Execute function, which first appeared in IBM APL.SV in 1970, users were able to code a crude if-then statement. This was considered by many to be incredibly poor style, however excusable, considering the few alternatives. The Execute function was from the outset very versatile, allowing functions to dynamically create and execute APL code snippets - quite a long way off from providing program flow control.

Elements of the APL language made flow control unnecessary for much of the time. In the example +/(X>100)/X, which (for a one-dimensional array X) gives the sum of the elements of X which exceed 100, there is no need for a loop to process elements of X one at a time, nor an If statement to decide whether to include each element in the total. It was not uncommon to find APL programs with no usage of branching whatsoever.

In the mid 1980s, a new featured appeared in STSC's new line of interpreters, control structures, which allowed a programmer to code loops and if-then-else constructs in a manner consistent with many other languages, such as Pascal and C. This feature was later adopted and included by other vendors of the language. Interestingly, control structures were never available in any of the later or current versions of IBM APL2, however programs did exist which could bootstrap the feature into APL implementations which did not support it.

[edit] Function Valence

One common early complaint was the inability to pass more than two formal arguments to a defined function. Although this problem has not been entirely solved in the course of APL evolution, effective workarounds have been available since the introduction of nested arrays in the early 1980s (or, in the case of I.P.Sharp's APL implementation, the introduction of the package data type around 1976).

In most versions of APL, functions:

  • May or may not return a result; and,
  • Have no arguments; or,
  • Have only a right argument; or,
  • Have both left and right arguments.

This yields six types of functions, with zero or one result, and zero, one, or two formal arguments.

One problem with this scheme is that a function which lacks arguments but returns a result is syntactically indistinguishable from an ordinary variable. It would follow that functions which do not return arguments do not follow the INFIX rule.

Visible in the release of newer interpreters starting in the 1970s, function calling rules had been relaxed such that functions which require both a left and right argument could be called with the left argument elided. This requires that the presence of the left variable be tested to determine the correct calling context. One vendor, Dyalog, requires that optional left arguments be declared in the function header as optional with the use of curly braces. Arguably, this reduces any ambiguity at the time the function is called.

The introduction of nested arrays in the language resulted in a practical way to, albeit not formally, pass additional arguments to functions. Here, Dyalog has also changed the function header syntax such that a list of arguments can be passed to and returned from a function. This feature eliminates the explicit bundling and unbundling of the arguments by the programmer and convincingly implements passing more than two arguments.

I. P. Sharp Associates introduced the "Package" data type around 1976. First called "Piles", packages enabled a programmer to package a collection of disparate objects into a variable. Unlike nested arrays, APL functions could also be put into packages, thus enabling the passing of functions as arguments, albeit in a roundabout manner. Although they required explicit packing and unpacking and were sometimes syntactically inconvenient, packages solved the problem of passing a large number of arguments to a function.

Although Dyalog's recent extended header syntax goes a long way to making multiple arguments and results usable, it does not completely solve the problem that multiple arguments are truly formally passed to a function. Consider the following function header:

R := myfunction (ARG1 ARG2 ARG3);A;B;C

What is formally accepted by myfunction is a single array of three items which is unbundled automatically by the interpreter and placed in the names ARG1, ARG2, and ARG3. This is not the same as three separate formal arguments.

The A+ language, considered by some to be a dialect of APL, which contains many aggressive extensions and changes to more standard APL language, solves the problem of passing formal arguments with an extended function header syntax. Currently, A+ functions are limited to a maximum of nine formal arguments.

[edit] Syntax Anomalies

With a minimum of punctuation, strict adherence to an INFIX notation, and right-to-left statement evaluation, the syntax of APL does not leave much wiggle room for anomaly. Nonetheless, some syntactic anomalies or errors had been introduced in the language, many of them having been removed in the course of APL's evolution.

One early anomaly in APL\360 and other early IBM APL interpreters was the use of the semicolon as an output separator. The programmer could list a series of values or expressions, typically scalar or vector quantities, and the interpreter would attempt display them on a single line. Usage of the semicolon implied or looked like catenation, however as the semicolon was not a function, the result of the expression could not be assigned to a value. One APL implementation went as far as to treat the semicolon in this context as form of catenation. With the addition of comprehensive formatting functions in the next few years, this feature was dropped from most APL interpreters by 1980.

First introduced by STSC and I. P. Sharp Associates in the early 1970s, the []FMT function helped APL enter the realm of business programming by providing comprehensive formatting akin to picture formatting in COBOL and numeric formatting in FORTRAN. However, []FMT normally required a list of values which would be formatted in accordance to the format phrases supplied in the left argument. Note that this was an early complaint of APL functions, the ability to pass more than two arguments to a function. The temporary syntax for the []FMT function's right argument was a list of expressions separated by semicolons - in reality, in this context, []FMT was supplied a degenerate nested array. This syntax gradually disappeared as nested arrays became more fully implemented and available in the 1980s.

The one distinctive anomalous function remaining today in APL is the indexing function, denoted by use of the square brackets. As with the output separator and []FMT function, the semicolon is used to separate the dimensions being selected. Consider the following expression:

(index expression)[index1;index2;index3;...;indexn]

The size, shape, and rank of the result are, in essence, a sum or concatenation of the individual indexes. An alternate form of indexing, called squad indexing from the fact that the symbol chosen is a narrower, or squished, quad, allows the indexing argument to be phrased in terms of a nested array. This newer function was introduced by IBM APL2 in the early 1980s at the time when nested array features were introduced into the language.

Despite its anomalous implementation, legacy APL indexing is thought to be easily grasped and used by a newcomer to the language.

[edit] Economy of Expression

One occasional criticism of C is that it can be concise to the point of being cryptic. A classic example that appears in K&R[3] is the following function to copy the contents of string t to string s:

void strcpy(char *s, char *t)
{
    while (*s++ = *t++);
}

Of course, one would not normally expect APL programmers to complain about a language being so terse as to be cryptic.[4]

But APL programmers might wonder about these complaints when they can copy a string (or any other variable) with the simple statement:

     s ← t  

which does exactly what it says, once you've understood the assignment symbol.

The normal complaint about APL was that it was much too cryptic, far worse than any imaginable C language example.

From the outset, APL was designed to be truly compact, as for the core language, symbols were chosen instead of keywords. Over time, the APL coding style has expanded slightly, that is, taken on some white space, possibly due to the following:

  • Blank lines are now allowed in functions
  • APL comments are allowed following APL code
  • The Diamond statement separator is introduced
  • Better full screen editing introduced in APL implementations
  • Presence of Control Structures

Although the APL language from the beginning has been designed to be compact and expressive, the language is slowly evolving to be slightly less compact.

[edit] Internal Consistency

In principle, APL supports two datatypes - numeric and character. Historically, on IBM 360 architectures, numeric quantities were usually implemented as a 1-bit boolean, a 4-byte integer, and an 8-byte double precision floating point number. APL implementations for other hardware, such as the CDC 6600, modified these definitions accordingly to fit on the hardware at hand. In the recent past, with personal computer implementations of APL, there had been a tendency to omit the boolean data type and use a two-byte integer, however recent APL implementations have reverted fully to the original historical definitions. One vendor, Dyalog, currently supports three integer widths, namely one, two, and four byte integers. The introduction of 64-bit integer quantities in newer computers will likely introduce a wider integer into the palette of supported datatypes. At this time, no APL implementation supports a short floating point number.

The APL language was originally so designed as to allow the user the freedom of not having to worry about such low-level details such as datatype, with data conversion done by the interpreter as needed. In reality, particularly recently with the introduction of new interfaces such as COM and .Net, and also in the course of sensible workspace management, the programmer needs to have some control over the datatypes the system assigns. Most arithmetic primitive functions are well-behaved regarding the promotion of data types:

  • Arithmetic (typically in addition and multiplication) overflow will promote a datatype
  • Division will yield a floating result when appropriate
  • The floor and ceiling functions will demote a datatype from double to integer provided the number itself is small enough
  • Relational functions (such as =, >, and <) always return a boolean value

Type demotion is yet another matter. A floating point operation may yield a result which is representable in an integer datatype, however the result of every operation would need to be preemptively checked. This could be an expensive operation which could cost execution time penalty

[edit] Connectivity

Early versions of APL, such as APL\360, had no connectivity with the outside world. For a normal user, there was no facility to get data into the system other than to type it in, and no other way to get data out but to print it. Some batch utilities existed to move workspaces. Later, some intelligent terminals allowed the output to be recorded and input to proceed from on-board storage devices.

In the mid 1960s, STSC and I. P. Sharp Associates jointly developed a file system where a user could store data outside the workspace but not outside the APL system. Batch utilities existed to import and export record data to component files.

In 1971, IBM released APL.SV, a continuation of APL\360, which featured Shared Variables as a means to access data outside the APL system. Later, VS APL and APL2, which ran under the mainframe's TSO or CMS system, facilitated rather comprehensive connectivity to mainframe features, such as the ability to run host commands, scripts, use other facilities such as GDDM and DB2. A common criticism of APL at the time was that it was too insular - VSAPL rectified all connectivity isses while APL2 upheld the tradition of providing support for new technologies, such as the then-new [DB2] relational database and later the TCP/IP communications protocol.

With the advent of personal computers and Unix workstations, APL products developed for these system usually featured comprehensive connectivity to operating system facilities. Today, most APLs support connectivity with Microsoft .Net, Java, COM, ODBC, operating system files, APIs, programs written in other (compiled) languages, and the Internet.

[edit] Efficiency

From the early days, the APL implementations were always criticized for being poor performers. The context of this complaint was that back in the mainframe days, APL performance in a timesharing environment was being compared to FORTRAN or COBOL or even PL/I in a batch environment. Although this comparison may have been fair comparing production applications, the business reason for using APL was more often to realise the benefits some of the users of APL would enjoy, such as the rapid application development or prototyping aspects of the language. There was seldom any question whether performance would be comparatively poor — it was.

Early PC implementations were rather demanding on the hardware, often leaving an APL application which was much slower than its mainframe version. However, as CPU time was essentially free, letting a personal computer run for several hours or overnight was not an unacceptable means to achieve cost savings over traditional (and expensive) mainframe service providers.

Later PC implementations performed very favourably compared to their mainframe counterparts, on account of both the CPU speed and the availability of inexpensive ROM memory. The introduction of the 32-bit Intel 80386 class of processor and corresponding new APL implementations which leveraged the new hardware and memory enabled the unrestricted movement of APL applications off of the mainframe. At this time, performance ceased to be an issue, particularly when newer languages such as Java ran 20 times slower than C,[5] often with little complaint. If an application runs fast enough to satisfy the user's needs, then no additional optimisation work may be necessary. Also, often the addition of more memory or the upgrade of a CPU may be sufficient, rather than reworking software.

Irrespective of the general lowering of performance expectations everywhere, the nature of certain applications requires higher performance than current interpreted APL implementations could ever deliver. Real-time computer graphics is only one field where APL would be especially suitable but where poor performance is an unacceptable obstacle.

[edit] Standardization

APL is unique in that it enjoyed a balanced following on both mainframe and personal computers. Other languages, such as COBOL, could be considered an almost exclusively mainframe language, while languages such as C could be considered almost exclusively a language for a small machine. COBOL compilers for personal computers and C compilers for mainframes did indeed exist, however they never captured a dominant market share nor caused a wave of application migration.

The earliest APL implementation offered little more than a computational engine. Input and output, other than terminal and keyboard, did not exist. There were no built-in facilities to read files or to handle screen I/O. These began to emerge in 1971 with IBM's APL.SV product and reflected the current IBM methodology and thinking at the time, namely shared variables to specialised processors which handled file IO, such as TSIO. Screen I/O for IBM Workstations was based on the IBM 3270, protocol, and controller, and was also supported by shared variables. Around the same time, non-IBM ASCII terminals appeared on the market which performed specialised printing functions, graphics, and even tape storage. Depending on the APL system at hand, these were handled by the []ARBOUT and []ARBIN system commands which allowed the programmer to communicate with such ASCII devices. IBM support of non-IBM terminal devices was often minimal at best; []ARBOUT and []ARBIN functions were found on the time sharing services. In effect, IBM APL systems supported IBM terminal devices, support for exotic non-IBM devices was often achieved by non-standard means.

Among the large timesharing companies which deployed highly customised and advanced versions of IBM/360, there was a large amount of standardisation with IBM. However, in the 1980s, when APL development spread to personal computers, vendors would add proprietary features, both to enhance the language, and to capture very limited market share. Further, in the PC arena, the market leader arguably was no longer IBM, rather STSC.

From a programmer's perspective, standardisation can be achieved by using cover functions to implement vendor-specific solutions. The core language of APL itself is highly portable and can be easily moved from one vendor's implementation to another. Most new APL development has been in the area of interfaces to the host (i.e. Windows API) and component models (COM, .Net). Relatively little development happens to the core APL language itself, but when it does, vendors typically add features to make their systems more IBM APL2 compliant.

With the advent of Linux and Windows, it would not be reasonable to expect support of legacy features, such as screen IO (versus Windows handling) and file I/O. Thus one should reasonably expect standardisation in the area of new operating system support.

But from a vendor's perspective, as APL is not a high-growth area, vendors cling to their customers by means of proprietary features built into their respective versions of the language. Perhaps the main problem is that standardisation is not in the vendors' interests, and the vendors are the ones today chiefly responsible for the growth of the APL market and the design given to language extension.

[edit] Maintenance

On the one hand, the brevity of APL programs is often at the very least confusing to the newcomer. On the other hand, APL brevity has the very positive side effect of reducing the sheer volume of code needed to formulate solutions to complex problems. Code explosion of 10 to 1 or more is not uncommon when rewriting APL applications in more traditional languages such as Visual Basic or C++. For an experienced APL developer, the amount of time for immersion in a new application can be a small fraction of the time it would take the VB or Java counterpart.

Clearly, for a newcomer to immerse him or herself in any new application, irrespective of language, can take a considerable amount of time.

Further, as APL is interpretive and interactive, the environment makes it possible for the user to do exploratory programming: to execute program fragments in isolation, to stop and restart program execution, and to manually alter variables. This was available decades before the widespread use of IDEs such as Eclipse and Visual Studio.

As APL programs are usually short and syntax is comparatively simple to parse and well-behaved, plus the fact that APL code is not subject to C-style preprocessing, it is not difficult to write APL programs which analyze or change other APL programs. It is and was possible to do advanced code analysis directly in the APL environment which one today might find in advanced IDEs.

[edit] Wall Street Use

In a 2007 book, A Demon of Our Own Design, financial risk management expert Richard Bookstaber argues that APL became a cult in certain brokerage firms and investment banks in the 1980s, and that its inability to elegantly deal with loops contributed to some of the financial crises of the 1980s and 1990s.[6]

Bookstaber specifically mentions a situation at Morgan Stanley which took place where an incorrectly coded (but performant) model was used and subsequently contributed to trading losses. A correctly coded model would have required an iterative solution which presumably would have performed unacceptably slowly given the requirement to stay in APL.

Bookstaber also suggests that the model could have been rewritten in a faster language. If Morgan Stanley used mainframe APL at the time, the practical choices would have been to rewrite the model in Fortran or PL/I. If A+ was being used, then iterative portions of the model could have been written in languages like C and linked with APL.

By this time, most versions of APL, irrespective of the platform, supported mixed-language programming. The non-performant parts of an application could be coded in an appropriate scalar language, then used in APL. This represented real leverage in some difficult performance situations.

Morgan Stanley and other Wall Street firms relied very heavily on APL to facilitate the rapid development of solutions by experts in their domain. These experts were more likely traders than professional programmers. Further, as the time-to-market of a solution is very critical and short, often days or minutes, the ability to produce a solution quickly equates to true competitive advantage. Requiring a professional programmer to work along side a trader in such a situation may have introduced unacceptable delays in producing results.

As a testament to the importance of high-productivity array languages in their organisation, Morgan Stanley went on to produce its own proprietary APL-like language, A+, for use within the organization. Amongst other things, this accomplished the migration of computation from the mainframe (which required frequent replacement to the next higher performing model) to high-performance workstations.

[edit] Entrepreneur Code

APL was and still is a fertile means where an entrepreneur, specifically an individual or group with a business idea but without the backing of a programming staff, is able to build an application and sell the service or product to a wider audience. In a sense, this is much like more conventional prototyping, except the programmer and user are much less disconnected if not the same person, but the programmer may not begin with the requisite knowledge or skill to author programs properly. Over time, a system may grow, however unless care was taken in its production, it could likely be difficult to maintain.

On the one hand, APL offered two valuable features to the entrepreneur - firstly, it was possible to build and grow an application rapidly mostly with domain knowledge while insulating the programmer from some tedious details of programming. Secondly, it was probably done without a large programming staff and without the expenses of maintaining it. However, without professional assistance from the beginning, correcting authored code to comply with best programming practices may be difficult or expensive, thus contributing to the reputation of APL being suitable for write-only code.

[edit] Conclusion

For all practical purposes, APL is inseparable from the special character set it was designed around. Although printing and display technology has evolved to the point where the output of extended glyphs (not to mention every glyph currently in Unicode) can safely be taken for granted, the same cannot be said for the entry of such characters. Although input method editors and extended keyboards exist for authoring APL code, the entry of these extended characters is still largely the barrier in recruiting and keeping new APL talent. Without doubt, the APL character set has been the chief obstacle in wider acceptance and growth of the language.[7]

At least three vendors introduced the notion of a "Language Bar", an area in the development environment window where some or all APL function glyphs were enumerated. An alternative to finding the character on the keyboard would be to click the glyph on the language bar and have the character appear as if it were typed on the keyboard.

From a different perspective, APL was designed to be extremely terse. One of the means in which APL achieves this objective is by the use of the extended character set. New APL-like languages, notably J and K, which uphold the tradition of brevity but dispose of the myriad of problems inherent in using a special character set, do so with digraphs and function symbol overloading.

The market has shown a preference for the familiar. Arguably, one reason for the popularity of Java and C# languages, other than the immense marketing campaign launched by the mega corporations, is that these languages strongly resemble predecessor languages such as C++, C, and Pascal. Which in turn resembled PL/1. Which in turn resembled Fortran, Algol, and maybe Cobol.

APL never had the benefit of being modeled after a familiar language, instead it had the development efforts of IBM (which sold high-priced mainframes) and several time sharing companies (which sold high-priced services) and grew with its own merit. This ended abruptly with the rise of the personal computer and a business model where entry level pricing to newer (but arguably inferior) technologies was practically free.

[edit] Notes

  1. ^ That was an advantage for IBM,indeed, because the 3270 terminal and the 6670/3800/3820 and 3816 could display and print these characters
  2. ^ Brian W. Kernighan and Dennis M. Ritchie: The C Programming Language, 1st ed., Prentice Hall, 1978, p. 49.
  3. ^ Brian W. Kernighan and Dennis M. Ritchie: The C Programming Language, p. 101.
  4. ^ Timothy Budd: An APL Compiler, Springer-Verlag, 1978, p. 43.
  5. ^ David Flanagan: Java in a Nutshell, 1st ed., O'Reilly and Associates, 1996, p. 8.
  6. ^ Richard Bookstaber:A Demon of Our Own Design, John Wiley & Sons, 2007, pp. 43-50
  7. ^ Robert Bernecky: QuadAV Considered Harmful - Still, Snake Island Research, 1990, p.1.

[edit] See also