A Component File Class for Dyalog APL

Dick Bowman

July 2006

There's probably been more twaddle written and said over the past ten years about object-oriented programming than any other programming topic.

With Version 11 of APL/W, Dyalog has allowed APL programmers a direct entry into this world, whether it's another example of APL coming late to a party that everyone else is leaving (think Expert Systems, for example) remains to be seen.  But, new ways of writing code are available to us, and there are some benefits.  But there are traps to fall into and lessons to learn (and we learn by doing).

One area where there are benefits is file-handling (a companion paper - currently being written - describes similar adventures in the GUI).  Let's open up by reviewing and updating the ways we write code to handle component files.

Appreciate that APL/W 11 contains a ComponentFile class, and that this is quite functional.  But that it's "there" makes light of one of the OOP mythconceptions - objects are easy to use (and - more generally - APL/W 11 breaks another of the OOP guiding principles, that classes are black boxes which don't reveal their insides.  If you can't see the inside, and there isn't any documentation, what use would an object be?).  I write this, and create my own DogComponentFile class, so that I can document the specification, the process of creating a (simple) class, how to use the class, the benefits of adopting the new(er) paradigm, idiosyncracies in the Dyalog implementation of OOP, and pitfalls waiting to trap the unwary.  But I promise that you won't read anything here along the lines of "OOP solves all the problems of code development".

The code shown here is not certified bug-free - you may feel that you would rather create your own variant to suit your environment and purposes rather than use DogComponentFile as you see it here.  Feel free, that's what I decided to do after I'd looked at Dyalog's ComponentFile.

Review of Component Files

Reviewing the "traditional" component file functions:

Quad-function Purpose Comments New Equivalent
FAPPEND Append components to a file Append
FAVAIL Check that file system is available Is it ever not, in a current APL environment? (none)
FCREATE Create a new component file ⎕NEW
FDROP Drop components from start or end of a file Drop
FERASE Erase a file Arguably archaic and superseded by direct OS calls (none)
FHOLD Holds a file Hold
FLIB Return list of files in a folder Arguably archaic and superseded by direct OS calls (none)
FNAMES Names of tied files (none)
FNUMS Tie numbers (none)
FRDAC Read the file access matrix ReadAccess
FRDCI Read component information ReadComponentInfo
FREAD Read a component Read
FRENAME Rename a file Arguably archaic and superseded by direct OS calls (none)
FREPLACE Replace a file component Replace
FRESIZE Resize a file Resize
FSIZE Size of a file Size
FSTAC Set the file access matrix SetAccess
FSTIE Shared tie ⎕NEW
FTIE Exclusive tie ⎕NEW
FUNTIE Untie ⎕EX

Which all has its roots in early days of APL, some of the functions are themselves archaic (but useful in the sense that they abstract APL application code from OS-specifics), some of the function syntax is archaic (tie numbers being the most obvious).

DogComponentFile Class Specification

The meta-goal of the DogComponentFile class is to replace all of these quadFcalls with something which is less archaic, with the goal of producing more literate application code (although the APL programmer can easily comprehend the traditional function usage).  Having got this DogComponentFile class in place, it might then be relatively straightforward to base specialised variants of component files on it in a way that is more natural than has historically been the case with bare quadFxyz - but note that this will not be attempted within the context of this paper.

There will be (as nearly as possible) a one-to-one correspondence between traditional quadFxyz functions and the methods of the DogComponentFile calls (making for simple transitions between old and new paradigms), but note that it will be shown that alternative coding methods will be revealed which would not be possible without the OOP model.

One difference between DogComponentFile and the Dyalog ComponentFile class is that DogComponentFile allows both shared and exclusive ties.

Tasks such as erasing and renaming files are left to the operating system - treating component files as "just another file type".

Creating and Destroying Instances

Two rather different things can be done with files, traditional code has kept them more separate than the OOP model.  quadFSTIE and quadFTIE have traditionally been used to make a file available to APL for reading and/or writing - the file has to exist, and an error occurs if code tries to tie nonexistent files.  DogComponentFile borrows conceptually from Dyalog's supplied ComponentFile class and combines two actions when a component file object is "created"

Both creation and destruction are implicit - they're invoked by using APL primitives which indirectly call the required APL (class) code.  This arms-length environment is one area where OOP is at variance with the more direct cause-and-effect paradigm that APL has traditionally had (or the APL programmers ought to have aspired to).

Creation

Create a new DogComponentFile object (instance) like this

cfile←⎕NEW DogComponentFile ('c:\dick\temp\abc' 'shared')

Behind the scenes APL finds and executes this code from the DogComponentClass definition

 ∇ Open w;filename;mode
      ⍝ Open file, either shared or exclusive
      :Implements Constructor
      :Access Public Instance
      filename mode←w
      :Select mode
      :Case 'shared'
          :Trap 0
              tie←filename ⎕FSTIE 0
          :Else
              ⎕FUNTIE filename ⎕FCREATE 0
              tie←filename ⎕FSTIE 0
          :EndTrap
      :Else
          :Trap 0
              tie←filename ⎕FTIE 0
          :Else
              :Trap 22
                  filename ⎕FCREATE 0
              :Else
                  ⎕SIGNAL 22
              :EndTrap
          :EndTrap
      :EndSelect
      ⎕DF'Dogon Research Component File <',filename,'>'
    ∇

There are a couple of things we can do within APL

          cfile
Dogon Research Component File <c:\dick\temp\abc>
      ⎕nl 9.1
cfile

Notice that it's quite wrong, and APL/W will produce error messages if you try, to call Open directly.

Destruction

Having got a DogComponentFile instance (object) we need to be able to rid ourselves of it, and quadEX does the necessary - not only ridding ourselve of cfile in the workspace, but also doing whatever housekeeping we want done by going and finding the Destructor code in the DogComponentFile class definition (it "just knows" which class created an object).  So

⎕ex 'cfile'

which has executed this

 ∇ Close
      ⍝ Close file
      :Implements Destructor
      :Trap 0
          ⎕FUNTIE tie
      :EndTrap
    ∇

Again, you can't use Close directly.

Foibles of Dyalog - Beware

Although classes are "new" and one of the much-vaunted benefits of OOP is that what happens inside class code stays within class code the actual implementation is less tidy.  Specifically, that tie numbers continue to exist and are visible to all of your APL code, which in turn means that you can carry on using quadFREAD and its chums inside your application should you so desire,  It's rather reminiscent of what happened when the :Trap control keyword came along - it was implemented using the underlying quadTRAP/quadSIGNAL stuff, which was as visible as ever.

Maybe one day Dyalog is going to find a way of hiding all of this old stuff,

In the meantime, the only advice is "don't mix your metaphors - either use the new stuff or the old stuff - if the new stuff won't do it for you, write some new bits yourself to achieve what you need".  Otherwise, there will be tears.

The Remaining Functions/Methods

Most of the functions are direct equivalents of the traditional quadFxyz, exceptions being

The functions are (essentially) simple covers for the quadFxyz functions, for example...

∇ {z}←Append w
      ⍝ Append a component
      :Access Public Instance
      z←w ⎕FAPPEND tie
    ∇

Using the DogComponentFile Class

Obvious Benefits

Comparing code on a one-for-one basis...
Traditional APL Using the DogComponentFile Class
tie←'c:\dick\temp\oldfile' ⎕fcreate 0 cfile←⎕new DogComponentFile ('c:\dick\temp\oops' 'shared')
'abcdefghij' ⎕fappend¨tie cfile.Append¨'abcdefghij'  
⎕fread¨tie,¨3 4 cfile.Read 3 4
⎕funtie tie ⎕ex 'cfile'    

Although the established APL programmer has no difficulty reading the traditional form, the "new-style" code self-documents a little better, and is purged of the archaic housekeeping of a tie number. Writing covers for quadNEW and quadEX (with appropriately meaningful names) would also step further in this more literary style of code.

Not-so-obvious Benefits

Dyalog have introduced some new(er than new) syntax, which is used in this class property definition

:Property Numbered Default Components
    :Access Public Instance
        ∇ r←Shape args
          r←⍬⍴¯1+1↑1↓⎕FSIZE tie
        ∇
        ∇ r←Get arg
          r←⎕FREAD tie,arg.Indexers
        ∇
        ∇ Set arg
          arg.NewValue ⎕FREPLACE tie,arg.Indexers
        ∇
    :EndProperty

It's all described in the Version 11 Release Notes, but here are few further thoughts...

Which seems a bit special-purpose, and restrictive - further experience is going to show what else this sort of thing can be useful for, but it does take us back to indexed assignment rather than the more general selective specification.  But it does mean that we can write expressions like

(⊂2 3 4)⌷cfile to read components 2 3 and 4, and
((⊂2 3 4)⌷cfile)←'xyz' to replace components 2 3 and 4

And, for those who use index-origin zero it means that we can think of component files as able to operate in a compatible way (so long as you've set index origin in the class definition)...

    ⎕io
0
    0⌷cfile
a
    ⎕io←1
    1⌷cfile
a

But you'll need to keep your head screwed on the right way round if you start dropping components from the start of the file.

And Finally...

The complete class definition (part-plagiarised from the ComponentFile class supplied as part of the APL/W product) is here.


Watch this space for further explorations of APL/W OOP extensions.

Page updated 2 August 2006

Copyright © Dogon Research, 2006.  Material from the Dogon Research Music and APL Pages may be freely redistributed, but copyright is retained and attribution to Dogon Research is requested.