Differences in Second Generation APLs
Vector 8:3, page 52
Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 52
This paper covers differences that I am aware of between a number of second generation APLs. It is not necessarily an exhaustive list, and my knowledge and available sources are far from complete. All Sharp implementations are different again, and in general are not covered.
Note the differences between APLs from the same supplier - IBM and STSC are both guilty of this. As you can see, the list is rather long, and I have not considered any System Functions at all.
In the case of code written for a given second generation APL, the probability of a function working without modification in a different implementation is only slightly higher than the probability of it working under VS APL.
Valid object names¶
Underbar and overbar _ and ¯ are allowed in APL2 and APL.68000 identifiers, but not as initial character. APL*PLUS/MF allows neither, APL*PLUS/PC allows _ but not as the first character. Dyalog only allows _, but this can be the initial character.
Dyalog allows uppercase, underscored, and lowercase alphas in identifiers. APL*PLUS/MF does not permit lowercase. APL2 permits uppercase and underscored with lowercase being an alternative for underscored. APL.68000 allows lowercase, although some (dumb terminal) versions will still use underscored instead.
Function headers Z←A FOO B;C;D;E;F¶
Dyalog APL insists on elidable left arguments being enclosed in braces { } and allows "shy" results (also denoted by being enclosed in braces). This is also true of DEC VAX APL, I believe. (DEC also allow an axis specification.) Braces are not accepted by APL*PLUS/MF, APL2, APL.68000, or any first generation APL.
APL2 allows either space or ; as separator in the locals list. This is not true of APL.68000, Dyalog, APL*PLUS/MF, nor any first generation APL. Dyalog and APL*PLUS allow A←A FOO B and B←A FOO B, as does APL2 and APL.68000.
Defined operators¶
The programmer may define operators with header syntax Z← A(F OP G) B in APL2, APL.68000 and Dyalog but not any flavour of APL*PLUS or any first generation APL. See also above remarks on braces in Dyalog.
Strand notation¶
Strand (or vector) notation Z←A B C (A B C all variables) is allowed in APL2, APL.68000, Dyalog, APL*PLUS/MF, but not in any Sharp or first generation implementation. Strand notation involving quoted strings can differ in APL*PLUS/MF, depending on the setting of the system variable ⎕CLEVEL.
Strand notation assignment¶
is allowed in each of Dyalog, APL2, APL.68000 and APL*PLUS/MF. APL2 and APL.68000 syntax seems to differ from the others in that the variables being assigned to must be enclosed in parentheses.
The latter causes a SYNTAX ERROR in other APLs. APL2/PC differs from APL2/MF, but reportedly in the curious way that it produces a different result rather than an error.
is illegal (rightly so in my opinion) in all but APL2 and APL.68000.
Diamond¶
Is supported in all APLs except APL2/MF and would be used in preference to constructs such as →0 Z←EXPR by any APLer to whom it was available.
Primitive Functions, Operators etc.¶
Enlist/Type ∊A. Monadic ∊ means enlist in APL2, type in Dyalog and APL*PLUS/MF. It generates a SYNTAX ERROR in APL*PLUS PC.
R←ENLIST R;⎕TRAP
⍝∇ REDUCE ARBITRARY APL VARIABLE R TO SIMPLE VECTOR
⍝ ENLIST (MONADIC ∊) IN APL2
⎕TRAP←∆PASSBACKERRORS
→(0≠⍴R←,R)/S
L:→(1=|≡R)/0 ⋄ R←0⍴⊃R ⋄ →L
S:→(1=|≡R)/0 ⋄ →(0=⍴R)/L
R←⊃,/,¨R ⋄ →S
⍝:⍺ MHJ 31MAY90 FROM MAINFRAME
A←TYPE A
⍝∇ ATTEMPT TO DEFINE DYALOG, APL*PLUS ∊ IN APL2/MF, APL.68000
A←↑0⍴⊂A
Selective specification (F Z)←EXPR. is allowed in APL2/MF, APL.68000 and Dyalog, but not in APL*PLUS or APL2/PC. The domain with respect to function F may differ.
Enclose ⊂A. Same in all APL2-like second generation APLs; the basic difference is between these and Sharp implementations.
Enclose with axis ⊂[1]A. Specific to APL2, APL.68000. Dyalog and APL*PLUS use split ↓A or ↓[1]A.
Partitioned enclose or partition A⊂B. In Dyalog and APL*PLUS/MF A must be boolean. In APL2 and APL.68000 A is integer. The Dyalog A⊂B is reproduced by (+\A)⊂B) in APL2 and APL.68000. APL2 and APL.68000 allows values from B to be removed from the result, Dyalog and APL*PLUS do not, apart from the case where there are leading zeros in A. In Dyalog and APL*PLUS, for vector B,
Pick A⊃B. is the same in Dyalog, APL*PLUS, APL2 and APL.68000.
Disclose ⊃B (APL2 APL.68000). Is mix ↑B in Dyalog and APL*PLUS. APL*PLUS II will give a LENGTH ERROR on ↑'FRED' 'JOE'.
First ↑B (APL2, APL.68000). Is ⊃B in Dyalog and APL*PLUS.
Depth ≡B. APL*PLUS/MF has two definitions, controlled by a system variable ⎕CLEVEL. The APL2 and APL.68000 definition can be represented by:
If B is a simple scalar,
≡Bis 0.
Otherwise≡Bis defined recursively as1+⌈/≡¨,B
This is the same for APL*PLUS/MF with ⎕CLEVEL≠0. Dyalog |≡B is defined similarly, but ×≡B is ¯1 if depth of nesting at any level is different. APL*PLUS/MF with ⎕CLEVEL=0 is similar to Dyalog, but has magnitude 0⌈¯1+|≡B.
Axis operator. Axis operator with primitive scalar functions A F[I] B does not exist in APL*PLUS or Dyalog. In Dyalog it can be simulated with a defined operator. Ravel with axis (,[I]B), take with axis (↑,[I]B) and drop with axis (A↓[I]B) are present in APL2 and APL.68000 but not Dyalog or APL*PLUS/MF.
Squid ⌷ (indexing function). Is in APL2 and APL.68000 but does not exist in Dyalog or APL*PLUS.
Bracket indexing A[B]. Has been extended in Dyalog and APL*PLUS, but not APL2 or APL.68000, to allow nested B (scatter-point indexing). Dyalog and APL*PLUS/MF differ on the range of nested arguments allowed for this.
Find ⍷. Does not exist in Dyalog or APL*PLUS before Release 9. For text vector arguments, it can be simulated easily in APL*PLUS using ⎕SS. The Dyalog AP SS can be used to simulate most instances.
Each operator F¨. When applied to empty data F¨E, APL*PLUS gives a NONCE ERROR; Dyalog tries to return (⍴E)⍴⊂F∊⊃E; APL2 and APL.68000 return the fill function applied to the prototype of E.
Composition operator F∘G. Exists in Dyalog but not APL2, APL.68000 or APL*PLUS.
Commute operator F⍨. Exists in Dyalog but not APL2, APL.68000 or APL*PLUS.
Catenate-first-axis A⍪B. Exists in Dyalog, APL.68000 and APL*PLUS/PC but not APL2 or APL*PLUS/MF.
Function assignment F←+/. Exists in Dyalog but not APL*PLUS, APL2 or APL.68000.
Assignment as a pseudo-operator A F←B and A[I] F←B. Exists in Dyalog but not APL*PLUS, APL2 or APL.68000.
Set functions A∩B A∪B A~B. Exist in Dyalog. ~ (without) is in APL*PLUS PC and APL*PLUS II but not APL*PLUS m/f. Only A~B in APL2 and APL.68000.
Unique ∪A. Exists in Dyalog, but not APL*PLUS, APL2 or APL.68000.
Index generator ⍳N. Has been extended in Dyalog to accept a non-singleton argument, producing a nested array result. This extension does not apply to APL2, APL.68000 or APL*PLUS.
Replicate and expand. Have been extended in Dyalog to take generalised left arguments. This extension does not apply to APL2, APL.68000 or APL*PLUS. In Dyalog and APL*PLUS/MF, they continue to be classed as functions rather than as operators. Thus:
will work. It does not work on APL*PLUS II, APL2 or APL.68000.
N-wise reduce N F/B. Is in APL2 and APL.68000 but is not present in Dyalog or APL*PLUS.
Reduction and inner-product. With non-scalar functions work differently between (Dyalog and APL*PLUS/MF) and (APL2, APL.68000 and APL*PLUS II). Non-scalar reductions on empty arguments may be different where they does not produce an error.
High level formatting. The implementations of ⎕FMT (Dyalog, APL.68000 and APL*PLUS) and A⍕B (APL2 with text A) all are different. APL*PLUS and APL*PLUS II insert a column of blank spaces on the left of numbers - others do not (⍕9 1 ⍴⍳9).
Default display. Differs.
The atomic vector ⎕AV. Is specific to each implementation.
Shared variables. Are specific to each implementation, and may not be present.
Error handling. The system function to signal an error is different in each implementation. APL.68000 implements APL2’s ⎕EA ⎕EC ⎕ET as well as its own ⎕ERX. Facilities to take alternative action on errors exist in all second generation APLs. Apart from APL2, it is possible to design utilities which take the same action in other implementations.
Complex numbers. Are available in APL2/MF but not APL2/PC, Dyalog, APL.68000 or APL*PLUS.
Roll ?A. For some arguments e.g. ?¯1+2*31, roll gives different results on different systems for the same value of ⎕RL. ?¯2+2*31 seems to give the same result, at least between Dyalog and APL*PLUS/MF. The domain of roll differs between Dyalog and others. In Dyalog, it must be stored as a positive integer (up to ¯1+2*31); in others it can be a "near integer" requiring floating point storage (up to ⌊/⍳0) As the roll algorithm can generate at most ¯2+2*31 distinct values, it seems logical to use this value.
Note: Alan Sykes has tested ?¯2+2*31 on a number of interpreters, and reports that they all gave the same results with the exception of APL*PLUS/PC. It seems that although APL*PLUS/PC uses the (implicit) standard ⎕RL←(¯1+2*31)|(7*5)×⎕RL algorithm for updating ⎕RL, it switches to an algorithm which uses 8 successive values of ⎕RL to generate 1 random number when the argument to ? exceeds ¯1+2*15.
Placement of parentheses. Different interpreters allow parentheses to be included in expressions at different points. This is true of APL*PLUS/MF versus APL*PLUS II. Usually these parentheses are only needed to deal with some nastiness in a second generation language feature.
Complex indexing. There are differences in such expressions as A B C[3]. I strongly recommend steering clear of these. Also, I recall problems with a benchmark involving A[I][J][K].
Differences in arithmetic precision. Alan Sykes remarked on differences in A⌹B in his APL87 paper. There may be others.
Internal Storage. The number of bytes needed to store an object can vary widely between implementations. For example APL*PLUS/PC does not have boolean storage. Dyalog does not have arithmetic progression vectors. PC-based APLs have short integers. These differences can mean the difference between a successful run and an afternoon of WS FULLs.