Recently, the people at APLX announced their intention to retire and let APLX loose, sans support.

Users who are willing to live with it will have to rely on other APLX users for help. Those who want to migrate to another vendor have the choice of going to APL2, APL2000, Dyalog APL, Nars2000 or one of the newer APLs on the block.

Transferring work

Moving code across will be a problem in most cases. The usual way to do this is to write the CR of programs, in ravel order, in native files and read them back, with proper translation, in the target APL. With a minimum of header changes the code will fix in the workspace but it is unlikely to work the first time; unless the code is trivial there are too many differences between each vendor to succeed immediately. For example any GUI code WON’T work. Code WILL have to be modified.

And moving data across, specially enclosed arrays, will present difficulties.

Fortunately, some of these problems have already been dealt with.

Method 1

Most vendors have implemented the ATF (APL Transfer Format) protocol which takes care of doing the write out/read in of code and data. All you have to do is eyeball the result and make amendments.

APLX has the )OUT system to write out an entire workspace using this method. Simply doing

	)OUT  \tmp\xfr1.atf

Should serialize the current workspace and produce file \tmp\xfr1.atf which can be used by other APLs to reproduce the code.

For example, if you wish to import this file into APL2000 or Dyalog, you should type (in APL2000 or Dyalog)

	]in  \tmp\xfr1.atf

Expect problems. Some programs will probably fail to be defined.

Method 2

The second method is similar: you transform your code and data using some piece of software and you read it back using another program that does the reverse. The program to write out the code/data serializes everything, the program to read it in translates the stream and can apply some transformation BEFORE fixing the code in the workspace thereby improving the odds of success and reducing effort.

The way to do this is )LOAD your code, )COPY the transfer code and call the proper routine to do the work. This should produce a transfer file which can be used to bring back the code in the new APL.

Pros and cons

The benefit of method 1 is it’s available in most APLs. The drawback is its limitations: no automatic translation of code.

The benefit of method 2 is you can apply transformations and customize the code being translated. The drawback is you have to write or get the code which is NOT supplied by any vendor.

Fortunately, the code to do this is out there in the public domain. It works with the major vendors and it’s free.

Getting the free stuff

Some code for method 2 is available at http://www.milinta.com/apl.html. There are sections there for each major vendor and the transfer code is available for each one of them. It’s old code but should still work. The workspace to do the work is called xfrpc in all cases (the extension is different for each vendor).

For example, if you wish to move to APL2000 you can get the xfrpc.aws workspace from the APLX section to move the code out and the xfrpc.w3 from the APL2000 section to bring the code in there.

Going from APLX you can )LOAD your ws, )COPY the xfrpc.aws workspace and use the ∆xfrto program to transfer your code out to file (given as argument) without any extension. So, e.g.

	∆xfrto '\tmp\mycode'

will produce file \tmp\myfile.xpw on your disk.

In APL2000 you can )load the xfrpc.w3 workspace and use the ∆xfrfrom program to bring back the code. The argument to ∆xfrfrom is the same name given to ∆xfrto in APLX with the extension .xpw. If you want the code to be translated and some code added (and you should want to) you should add the switch /trans=2. The final statement should look like this:

	∆xfrfrom '\tmp\mycode.xpw   /trans=2'

The web site explains the whole process in details. You can customize the translation list if you wish. See http://www.milinta.com/xfrpc.htm and the disclaimer.

Dyalog

APLX being no longer available from MicroAPL Ltd, in agreement with MicroAPL, Dyalog has accepted to host free downloads of the final (version 5.0) APLX installation packages and documentation and to host the APLX forums. Dyalog also made an effort to produce code that will ease the transfer of APLX to Dyalog for those interested in moving to Dyalog APL (V15 is now free for personal use).

One thing which is simpler with Dyalog is that their user command ]IN already integrates the xfrpc.dws workspace (it is called xfrcode there). There is no need to download it from Milinta.com.

You still have to get xfrpc.aws workspace to create the transfer file but you don’t need to get the receiving workspace.

Things to consider when moving from APLX to Dyalog

Here is a list of differences going from APLX to Dyalog. Some are easy to emulate, some are not.

There are many other differences (for example in the language itself) but only the ones that are relevant to the migration of APLX code to Dyalog are presented here.

Most entries are listed preceded with a difficulty code:

  • (1) is easy to translate or emulate in Dyalog
  • (2) is harder and
  • (3) is very difficult or impossible.

It is assuming V5 in APLX and V15 in Dyalog.

Basics

(2) APLX variable names can contain a high minus (¯), Dyalog cannot

(2) Brackets ([ ]) bind to the NAME to the left . A[2]B[1] is a two element vector in APLX, a scalar in Dyalog.

(3) Assignments without parentheses do NOT propagate to all names to the left. A B←1 2 only assigns to B, in Dyalog it assigns to both if A is not a visible program. This should not present problems for existing code but the introduction of namespaces later on may do so.

(2) Operand binding is different with /. 1 0 1/¨⍳3 is (1 1)(2 2)(3 3) in APLX, not (,1)⍬(,3) as in Dyalog

(1) Monadic is enlist (same as Dyalog in ⎕ML>0)

(1) Monadic is first (same as in Dyalog with ⎕ML<2)

(3) accepts system commands (X←⍎')SYMBOLS') in APLX

(1) Depth () works a la APL2, Dyalog needs ⎕ML=3 for that.

(1) Monadic Lex () returns a shy result of 0 0⍴0, Dyalog returns the right argument.

(1) Dyadic Left shoe, partition enclose (), works a la APL2, Dyalog need ⎕ML=3 for that.

(1) Monadic Right shoe is Disclose (), it works a la APL2

(3) In APLX is used as some form of formatting, akin to dyadic

(3) Format by specification (using ⎕FC) or format by example (with a character left argument) is not supported in Dyalog

(3) input and output is different. In APLX the prompt (if any) is replaced by blanks which can be changed using ⎕PR.

(3) APLX uses 64b integers (in their 64b version). Any conversion to Dyalog of integers >2*53 will lose some precision.

(3) System variables can be assigned values in APLX (⎕WA←3), which is not allowed in Dyalog.

(3) Some functions accept ‘;’ to delimit their arguments (e.g. ⎕SS (a1;a2;a3))

(1) APLX accepts double quotes to denote string (e.g. "this is a string")

GUI

There are many system functions for GUI (⎕WE, ⎕WARG, ⎕EVA, ⎕EVN, ⎕EVT, etc.) None is implementable easily in Dyalog or any other APL for that matter.

Multi-Tasking

APLX can spawn many APL tasks. Dyalog can multi-thread and has isolates.

Error related System functions in APLX

(2) ⎕EC returns a 3 integer error code

(2) ⎕LER is similar to ⎕EN but with (2) different values

(1) ⎕ERS is similar to ⎕SIGNAL in Dyalog

(2) ⎕ERX has no equivalent in Dyalog

(1) ⎕ES is similar ⎕SIGNAL in Dyalog

(2) ⎕ET returns a 2 integer error code

(3) ⎕EV has no equivalent in Dyalog

(2) ⎕LE is somewhat similar to Dyalog ⎕DMX

File operations

(2) APLX uses special file primitives (e.g. ) to manipulate files. Some use special chars (e.g. UCS 9031) and are combined with the Axis Bracket operator which is not possible in Dyalog.

It also uses ⎕Ffns similar to Dyalog’s. Some names are different and some functions return different results. The user number (⎕AI[1]) is used for file operation, checking against the access matrix in both APLs, 0 denoting root or super user with no restriction. Under Unix this user number is always defined. Under Windows, for Dyalog, the user number is 0, effectively rendering the access matrix ineffective. Dyalog has a File Server (called DFS) which provides security instead.

The access codes for each file function are not all the same.

APLX has the concept of local (client) and remote (server) and allows some file functions to access either by prefixing the argument with a (client) or (server) before. No can do in Dyalog. This goes for other related functions like ⎕HOST.

(2) APLX also uses library numbers, associating a positive integer to a folder using ⎕MOUNT. There is no equivalent in Dyalog.

(2) When creating a file under Windows, Dyalog adds the extension DCF if none exists. It also ignores any (library) number before the name and assumes it IS part of the name.

(2) ⎕FDUP is ⎕FCOPY in Dyalog. The access code is different (16384 vs 4096).

(2) ⎕FLIB also accepts a library number (integer) as argument. This represents a row in the MOUNT table. Only files which end in the AQF extension will appear in the list.

(2) ⎕FRDCI reports the time when the component was written in seconds since 2000/1/1. Dyalog reports it in 1/60th of a second since 1970/1/1.

(2) ⎕FRDFI similarly reports timestamps. In APLX it is a 4×2 matrix of WHO, WHEN of creation/reserved/reserved/update . Dyalog reports creation/reserved/access matrix/reserved/update.

(2) ⎕FCSIZE Dyalog does not have the equivalent of this function which reports the size of an object on file and in the workspace.

(2) ⎕FRENAME accepts a filename as right argument under APLX, Dyalog doesn’t.

(2) ⎕FSIZE reports five elements in APLX while Dyalog reports four. The fourth element may be 0 in APLX meaning "no limit". Not so in Dyalog. The fifth element is the unused space in the file.

(2) APLX has two file functions not defined in Dyalog: ⎕FWRITE and ⎕FDELETE which allow you to insert and delete specific components.

Native files

(2) ⎕LIB is pretty much the same as ⎕NINFO⍠1 in Dyalog, you need to supply the folder name only, not the * after.

(2) ⎕NCREATE does not support a 2nd element in the right argument and tie numbers must be negative in Dyalog

(3) ⎕NERROR has no exact equivalent in Dyalog. However ⎕DMX can provide some info.

(2) ⎕NLOCK is similar to Dyalog, not quite the same though.

(3) ⎕NTYPE has no equivalent in Dyalog

(2) ⎕NWRITE is very much like ⎕NREPLACE

APLX Control structures

(2) :repeat accepts a number while Dyalog does not

(1) :try is :trap in Dyalog

(2) :try and :endtry cannot appear on the same line

(1) :catchall is :else

(2) :catchif takes a Boolean argument. There is no catching on a specific error (number). Typically a programmer will use :CatchIf 11=↑⎕LER

(2) :leave may take a label as argument

Classes

Classes (OO) are very different in Dyalog. Any implementation will not work as is.

Dyalog only supports APL and .Net classes (no Ruby or Java)

There is no NULL object in Dyalog although there is a ⎕NULL.

Close to Dyalog:

(2) ⎕GETCLASS : for APL and .Net only you can use execute ()

(2) ⎕CLASSNAME : format () will display a string of the class name.

Not supported:

(3) ⎕DS, ⎕IC, ⎕MIXIN, ⎕UNMIX and most other OO related functions.

Other System functions possibly presenting problems

Function Comment
(1) ⎕a lowercase Alphabet, Dyalog only has ⎕A
(1) ⎕AI has seven elements, Dyalog cannot supply meaningful values for the last three ones. [1] is 1000 by default whereas it is zero on Dyalog
(2) ⎕CALL only .Net can be supported
(2) ⎕C this is akin to ⎕ARBIN/ARBOUT in Dyalog
(2) ⎕CHART this might be replaced by ⎕SE.UCMD ‘chart …’
(1) ⎕CL can be replaced by (⍬⍴⎕LC)
(2) ⎕CLASS has two nested vectors in Dyalog
(3) ⎕CONF has no equivalent in Dyalog
(3) ⎕C has no equivalent in Dyalog but is used for old APL.68000 workspaces so is unlikely to cause problems
(1) ⎕CT is 1E¯13 by default in APLX instead of 1e¯14 in Dyalog
(1) ⎕EDIT is ⎕ED in Dyalog but APLX allows you to specify the type using a left argument
(2) ⎕EVAL Dyalog can only talk to R and is very different
(1) ⎕EX APLX reports if the name has been erased, Dyalog reports if the name is available AFTER attempting erasure, not a big deal
(3) ⎕FC is used in APLX when format () is used dyadically. No equivalent in Dyalog.
(1) ⎕FI ⎕VI is like ⎕VFI in Dyalog
(3) ⎕HC Hard Copy, no such equivalent in Dyalog
(1) ⎕HOST there is no way to use the timeout (left argument) feature of APLX in Dyalog
(3) ⎕ID System ID number, no such thing in Dyalog
(2) ⎕IMPORT ⎕EXPORT are missing in Dyalog. All but ‘slk’ can be emulated fairly easily
(1) ⎕M ⎕W are character matrices of Months and Weekdays unavailable in Dyalog
(2) ⎕MC is Missing Character for ⎕UCS and has no equivalent in Dyalog which has full Unicode
(1) ⎕N is UCS 1 in APLX. Dyalog has its own ⎕NULL. APLX does have a ⎕NULL but it is related to the Null Object (OO)
(1) ⎕NA is very similar to Dyalog
(1) ⎕OV is like a namespace in Dyalog without its dynamic nature, a static namespace if you will
(2) ⎕PROFILE is similar to Dyalog
(1) ⎕RL there is only one Random Number Generator in APLX but it accepts arguments up to 2*1024
(2) ⎕SETUP is used to set or query various parameters for the interface with external architectures such as .Net (e.g. Using)
(1) ⎕SI is a simple vector in APLX
(2) ⎕SQL has no equivalent in Dyalog. Ws SQAPL is the closest thing Dyalog has
(2) ⎕SS is a function akin to ⎕S/⎕R in Dyalog
(1) ⎕STOP ⎕TRACE accepts 0 as left argument to REMOVE control, not set a stop on line 0 as in Dyalog
(1) ⎕SYMB Dyalog has no limit on the symbol table so doesn’t have this concept
(1) ⎕TC also ⎕I , ⎕TCBEL, ⎕TCBS, ⎕TCDEL, ⎕TCESC, ⎕HT (⎕T), ⎕FF, ⎕LF (⎕L), ⎕NL (⎕R) and ⎕NUL. Those are individual characters that may have a special effect in APLX
(2) ⎕TF produces a simple string of the representation of a function or variable in APLX
(1) ⎕TIME reports the time in APLX
(2) ⎕TR translates text between APLX and the rest of the world
(2) ⎕TT is Terminal Type in APLX
(3) ⎕UL is the number of APLX tasks running
(1) ⎕WSSIZE is ws TOTAL size in APLX

Many of these are easy to mimic in Dyalog but it may be sometimes preferable to alter the APLX code in order to avoid having to produce mimicking code in Dyalog.

Dyalog supplies some code to cover the most common cases like ⎕SS and ⎕IMPORT but not ⎕TR for example.

Post production

Once the code is defined it is a good idea to run some checks to see if anything needs attention.

For example, to test if constructions like A[2]B[3] are used you can use the ]locate user command to find out crude cases:

	]locate "(⍺\[[ ;0-9]+\]){2,}" -pattern -exclude=c

Which will try to locate more than one ({2,}) name () followed by a ‘[‘, followed by one or more space, semi-colon, or digit, ([ ;0-9]+) then followed by ‘]‘. It will do so outside of comments (-exclude=c)

Comments

It doesn’t matter how you look at it, transferring non trivial code from one APL to another will not be done easily.

But with these restrictions in mind and the tools available out there it should not be too difficult to get something going fairly rapidly. And by adapting the code on both sides you can reach an acceptable version.

The trick is to run the 2 in parallel until you can let go of the APLX version.

Happy translation 🙂