Dyalog APL 17.0 Help

Welcome to Dyalog APL's online Help and Documentation for Version 17.0.

Documentation is available in two formats: Help systems and PDF files.

Help Systems:

  • Pressing <F1> when the cursor is positioned after a primitive function or operator symbol, the name of a system function, etc. will open the appropriate page in the help system (offline under Microsoft Windows, online with the RIDE).
  • Note: The help system only includes a subset of the complete documentation set; the full set is available as PDF files.
  • There is also online help at http://help.dyalog.com/17.0/.

PDF Files:

  • All of the documentation supplied with a release of Dyalog APL resides in the help subdirectory of the Dyalog installation and in the Documentation Centre.
  • If you want to print any of the manuals that form part of the Help system, then PDFs suitable for printing are available at https://www.dyalog.com/documentation_170.htm; the offline PDFs supplied with the release are intended for on-screen browsing.

If you are using Dyalog under Microsoft Windows, then the Documentation Centre (offline) can be accessed under the Help menu in the Session.

If you are using the RIDE, then the Documentation Centre (online) can be accessed under the Help menu in the Session.

The documentation is updated throughout the life of each version of Dyalog; the latest versions of the files and the online help for all supported versions are available at http://docs.dyalog.com and http://help.dyalog.com

If you report an issue with the documentation, could you please include the following information: Version 17.0, revision 2987 dated 20230217.

Please note that unless otherwise stated, all the examples in the documentation assume ⎕IO is 1, and ⎕ML is 1.


Version 17.0 Key Features

Key Features

Dyalog APL Version 17.0 provides the following new features, enhancements and changes:

Performance Improvements

As part of the ongoing Performance Quality Assurance project, Version 17.0 includes a considerable amount of research and development work designed to substantially improve speed of execution.

The performance of 128-bit Decimal floating-point calculations on all platforms which do not have hardware support for such numbers has been significantly improved by changing the internal format for such numbers. See 128-Bit Decimal Numbers.

  • Editing scripts is significantly faster. The improvement is especially noticeable on large scripts.
  • ⎕NINFO is faster when the Wildcard option is enabled and the name does not contain any wildcard characters.

New Idioms

The following new idioms provide the fastest way to sort arrays of any rank:

Expression | Description
{(⊂⍋⍵)⌷⍵}XA | XA sorted into ascending order
{(⊂⍒⍵)⌷⍵}XA | XA sorted into descending order

Language Enhancements

New Language Features

  • Monadic Grade Up (⍋), Grade Down (⍒) and Interval Index (⍸) have been extended to apply to all arrays. See Total Array Ordering.
  • New system function ⎕NCOPY. See Native File Copy .
  • New system function ⎕NMOVE. See Native File Move .
  • The localisation of names in the header of a defined function and operator has been augmented by Locals Lines which may appear between line [0] and the first executable statement. See Locals Lines.

Enhancements

A number of the native file functions have been extended to handle multiple files. Instead of accepting just a single file name, they now accept zero, one, or multiple file names. Where appropriate these functions also accept wildcards in names.

  • The Unique primitive function (monadic ∪) has been extended to work with all arrays, not just vectors. See Unique.
  • ⎕CSV provides a new column type (numeric/empty) and 3 new variant options to handle metacharacters. The Overwrite variant option is replaced by IfExists. See Comma Separated Values.
  • ⎕MKDIR accepts multiple file names. See Make Directory.
  • ⎕NDELETE accepts multiple file names, wildcards, and has an option to delete non-empty directories. See Native File Delete.
  • ⎕NEXISTS accepts multiple file names and wildcards. See Native File Exists.
  • ⎕NINFO accepts multiple file names, reports additional properties and has a Recurse variant option. See Native File Information.
  • ⎕NPARTS accepts multiple file names. See File Name Parts.
  • ⎕NPUT now supports an option to append data to a file. See Write Text File.
  • ⎕NCREATE is extended to allow semi-automatic naming of files and to allow existing files to be overwritten. See Native File Create .
  • System functions ⎕CSV, ⎕NGET, ⎕NPUT, ⎕R, ⎕S which accept an encoding name (e.g. 'Windows-1252') have been extended to support any user-definable 1-byte character set. See Comma Separated Values, Read Text File, and Write Text File.
  • To facilitate the use of all system functions in dfns, those that previously did not return a result now return a shy result. See Shy Results for System Functions.

  • Global Triggers have been enhanced to identify indexed assignment. See Global Triggers.

New I-beam Features

  • A new I-beam function provides the list of syntax colour tokens. See Syntax Colour Tokens
  • A new I-beam function obtains the name of a system temporary directory. See Temporary Directory.
  • Two new I-beam functions have been provided to better manage the information pertaining to objects associated with files. See Loaded File Object Info and Examples:. The information reported has been supplemented by the file checksum and modification date.

New Command-Line Options

  • New -apl and -cef options are provided to control how Command-Line parameters are processed. See Command-Line Options.

IDE Enhancements

  • The Find Objects Tool provides a simpler, cleaner user-interface and is no longer a tabbed dialog. See Find Objects Tool.
  • The Backtick keyboard provided by the RIDE may now be used natively. See Backtick Keyboard.

GUI Enhancements

  • The CellMove event message contains 2 new elements to resolve a validation anomaly that occurred when CellMove and CellChange events activated callbacks on the same Grid. See CellMove.


Locals Lines

Locals Lines are lines in a defined function or operator that serve only to define local names.

A Locals Line may appear anywhere between line [0] and the first executable statement in the function or operator. Locals lines may be interspersed with blank lines and comments. A Locals Line is identified by starting with a semicolon, prefixed optionally by whitespace. It may contain a comment at the end.

A Locals Line must be of the form ;name;name;name where name is any valid APL name or localisable system variable. The names are localised on entry to the function exactly as if they were specified as locals on line [0].

Example

      ∇ r←foo y;a;b       ⍝ some locals
               ;c;d       ⍝ some more locals
        (a b c d)←y
        r←a+b-c×d
      ∇

The function foo shown above localises names a, b, c and d (the indentation on line [1] in this example is entirely optional)

Syntactical errors on Locals Lines are detected when the user attempts to fix the function using the Editor or ⎕FX and will causes the operation to fail.


Global Triggers

A global Trigger is a function that triggers on any assignment to a global variable in the same namespace.

This is implemented by the function declaration statement:

    :Implements Trigger *

The argument to the trigger function is an instance of the internal class TriggerArguments which contains the following members:

Member | Description
Name | The name of the global variable that is about to be changed.
Indexers | If the assignment is some form of indexed assignment, Indexers is an array with the same shape as the sub-array that was assigned and contains the ravel-order, ⎕IO-sensitive, indices of the changed elements. Otherwise, Indexers is undefined.

Example:

     ∇ foo args
[1]    :Implements Trigger *
[2]    args.Name'has changed'
[3]    :If 2=args.⎕NC'Indexers'
[4]        '⍴Indexers'(⍴args.Indexers)
[5]        'Indexers'(,args.Indexers)
[6]    :EndIf
     ∇

      vec←⍳5
 vec  has changed

      a b←10 'Pete'
 a  has changed
 b  has changed

      vec[2 4]←99
 vec  has changed
 ⍴Indexers  2
 Indexers  2 4

      array←2 3 4⍴⍳12
 array  has changed

      (2 1 3↑array)←42
 array  has changed
 ⍴Indexers  2 1 3
 Indexers  1 2 3 13 14 15

Notes:
  • like other Triggers, only the most recently fixed global trigger function will apply and be called on assignment to a global variable.
  • global triggers do not apply to local names nor to semi-globals (names which are localised further up the stack).
  • an assignment to a global variable will fire both its specific trigger (if defined) and the global trigger. However, the order of execution is undefined.
  • do not use an argument name for your trigger function that may conflict with a global variable name in the namespace.

Further Example

A potential use for a global trigger is to detect the unintended creation of global variables due to localisation omissions. Note however that the timing of the activation of the Trigger is unpredictable. In this example, the trigger for the assignment to b activates after function hoo has exited. When Threads are involved, timing becomes even less predictable.

     ∇ CatchGlobals arg
[1]    ⍝ Displays a warning when a global is assigned
[2]    :Implements Trigger *
[3]    '*** assignment to global variable: ',
        arg.Name,' from ',1↓⎕SI
     ∇
     ∇ foo
[1]    goo
     ∇
     ∇ goo
[1]    hoo
     ∇
     ∇ hoo
[1]    a←10
[2]    b←a
     ∇
      foo
*** assignment to global variable: a from  hoo  goo  foo
*** assignment to global variable: b from  goo  foo


DECF Change

128-Bit Decimal Numbers

On all platforms except IBM's AIX on POWER 128-bit decimal numbers are now represented using Binary Integer Decimal (BID) encoding format. Previous versions of Dyalog use Densely Packed Decimal (DPD) format.

This change has been made to speed up 128-bit floating-point calculations under all non-AIX/POWER platforms when ⎕FR is 1287. AIX/POWER continues to use DPD since DPD is supported by the hardware; there is no performance degradation on AIX as a result of the change on all other platforms.

In 17.0 128-bit decimal numbers are automatically converted from BID to DPD format and vice versa when necessary; workspaces and component files can be shared between AIX and non-AIX versions of Dyalog APL.

Arrays containing 128-bit decimal values written to component files by 17.0 interpreters on non-AIX platforms cannot be read by earlier interpreters on any platform; the error DOMAIN ERROR: Array is from a later version of APL will be signalled. Arrays containing 128-bit decimal values written to component files by 17.0 interpreters on AIX/POWER can be read by earlier interpreters on all platforms (subject to other limitations which are detailed in the interoperability section of these release notes). The same is true of TCPSockets, Conga communications and arrays that are serialised and unserialised using 219⌶ and 220⌶.

The ⎕NA type code D will continue to mean DECF DPD on AIX/POWER and will mean BID on all other platforms.


Version 17.0 System Requirements

System Requirements

Microsoft Windows

Dyalog APL Version 17.0 is supported on versions of Microsoft Windows from Windows 7 up to and including Windows 10 and Windows Server 2016.

Microsoft .NET Interface

Dyalog APL Version 17.0 .NET Interface requires Version 4.0 or greater of the Microsoft .NET Framework. It does not operate with earlier versions of .NET.

For full Data Binding support (including support for the INotifyCollectionChanged interfaceThis interface is used by Dyalog to notify a data consumer when the contents of a variable, that is data bound as a list of items, changes. 1), and Syncfusion, Version 17.0 requires .NET Version 4.5.

The examples provided in the sub-directory Samples/asp.net require that IIS is installed. If IIS and ASP.NET are not present, the asp.net sub-directory will not be installed during the Dyalog installation.

AIX

For AIX, Version 17.0 requires AIX 7.2 or higher, and a POWER7 chip or higher.

Raspberry Pi

On the Raspberry Pi, Dyalog 32-bit Unicode supports Raspbian Jessie or later.

Non-Pi Linux

For non-Pi Linux, Version 17.0 only exists as 64-bit interpreters - there are no 32-bit versions. It is built on Debian 7, and QAed on RedHat 6; it runs on all recent distributions, including Ubuntu 14.04 and openSUSE Leap 42.3. Contact Dyalog for information about other distributions.

macOS/Mac OS X

Version 17.0 requires Mac OS X Yosemite or El Capitan or macOS Sierra or later. The target Mac must have been introduced in 2010 or later.


Version 17.0 Interoperability and Compatibility

Interoperability

Introduction

Workspaces and component files are stored on disk in a binary format (illegible to text editors). This format differs between machine architectures and among versions of Dyalog. For example, a file component written by a PC may well have an internal format that is different from one written by a UNIX machine. Similarly, a workspace saved from Dyalog Version 17.0 will differ internally from one saved by a previous version of Dyalog APL.

It is convenient for versions of Dyalog APL running on different platforms to be able to interoperate by sharing workspaces and component files. From Version 11.0, component files and workspaces can generally be shared between Dyalog interpreters running on different platforms. However, this is not always possible and the following sections describe limitations in interoperability:

Code and ⎕ORs

Code that is saved in workspaces, or embedded within ⎕ORs stored in component files, can only be read by the Dyalog version which saved them and later versions of the interpreter. In the case of workspaces, a load (or copy) into an older version would fail with the message:

this WS requires a later version of the interpreter.

Every time a ⎕OR object is read by a version later than that which created it, time may be spent in converting the internal representation into the latest form. Dyalog recommends that ⎕ORs should not be used as a mechanism for sharing code or objects between different versions of APL.

"Ordinary" Arrays

With the exception of the Unicode restrictions described in the following paragraphs, Dyalog APL provides interoperability for arrays that only contain (nested) character and numeric data. Such arrays can be stored in component files - or transmitted using TCPSocket objects and Conga connections, and shared between all versions and across all platforms.

Full cross-platform interoperability of component files is only available for large-span component files.

Null Items (⎕NULL) and Compressed Components

⎕NULLs and components from compressed component files, which were created in Version 17.0, can be brought into Versions 14.1, 15.0 and 16.0 provided that the interpreters have been patched to revision 33394 or higher. Attempts to bring ⎕NULLor compressed component into earlier versions of Dyalog APL or lower revisions of the aforementioned versions will fail with:

DOMAIN ERROR: Array is from a later version of APL.

Object Representations (⎕OR)

An attempt to ⎕FREAD a component containing a ⎕OR that was created by a later version of Dyalog APL will generate DOMAIN ERROR: Array is from a later version of APL. This also applies to APL objects passed via Conga or TCPSockets, or objects that have been serialised using 220⌶ .

32 vs. 64-bit Component Files

It is no longer possible to create or write to small-span (32-bit) files; however it is still currently possible to read from small span files. Setting the second item of the right argument of ⎕FCREATE to anything other than 64 will generate a DOMAIN ERROR.

Note that small-span (32-bit-addressing) component files cannot contain Unicode data. Unicode editions of Dyalog APL can only write character data which would be readable by a Classic edition (consisting of elements of ⎕AV).

External Variables

External variables are subject to the same restrictions as small-span component files regarding Unicode data. External variables are unlikely to be developed further; Dyalog recommends that applications which use them should switch to using mapped files or traditional component files. Please contact Dyalog if you need further advice on this topic.

32 vs. 64-bit Interpreters

There is complete interoperability between 32- and 64-bit interpreters, except that 32-bit interpreters are unable to work with arrays or workspaces greater than 2GB in size.

Note however that under Windows a 32-bit version of Dyalog APL may only access 32-bit DLLs, and a 64-bit version of Dyalog APL may only access 64-bit DLLs. This is a Windows restriction.

Unicode vs. Classic Editions

Two editions are available on some platforms. Unicode editions work with the entire Unicode character set. Classic editions (a term which includes versions prior to 12.0) are limited to the 256 characters defined in the atomic vector, ⎕AV).

Component files have a Unicode property. When this is enabled, all characters will be written as Unicode data to the file. The Unicode property is always off for small-span (32-bit addressing) files, as these cannot contain Unicode data. For large-span (64-bit addressing) component files, the Unicode property is set on by Unicode Editions and off by Classic Editions, by default. The Unicode property can subsequently be toggled on and off using ⎕FPROPS.

When a Unicode edition writes to a component file that cannot contain Unicode data, character data is mapped using ⎕AVU; it can therefore be read without problems by Classic editions.

A TRANSLATION ERROR will occur if a Unicode edition writes to a non-Unicode component file (that is either a 32-bit file, or a 64-bit file when the Unicode property is currently off) if the data being written contains characters that are not in ⎕AVU.

Likewise, a Classic edition will issue a TRANSLATION ERROR if it attempts to read a component containing Unicode data that is not in ⎕AVU from a component file.

A TRANSLATION ERROR will also be issued when a Classic edition attempts to )LOAD or )COPY a workspace containing Unicode data that cannot be mapped to ⎕AV using the ⎕AVU in the recipient workspace.

TCPSocket objects have an APL property that corresponds to the Unicode property of a file, if this is set to Classic (the default) the data in the socket will be restricted to ⎕AV, if Unicode it will contain Unicode character data. As a result, TRANSLATION ERRORs can occur on transmission or reception in the same way as when updating or reading a file component.

The symbols ⊆, ⍸, ⍤, ⍠, ⌸ and ⌺ used for the Nest (Interval Index) and Where (Partition) functions, the Rank, Variant, Key and Stencil operators respectively are available only in the Unicode edition. In the Classic edition, these symbols are replaced by ⎕U2286, ⎕U2378, ⎕U2364, ⎕U2360, ⎕U2338 and ⎕U233A respectively. In both Unicode and Classic editions Variant may be represented by ⎕OPT.

Very large array components

An attempt to read a component greater than 2GB in 32-bit interpreters will result in a WS FULL.

TCPSockets and Conga

TCPSockets and Conga can be used to communicate between differing versions of Dyalog APL and are subject to similar limitations to those described above for component files.

Auxiliary Processors

A Dyalog APL process is restricted to starting an AP of exactly the same architecture from the same operating system. In other words, the AP must share the same word-width and byte-ordering as its interpreter process.

Session Files

Session (.dse) files can only be used on the platform on which they were created and saved. Under Microsoft Windows, Session files may only be used by the architecture (32-bit-or 64-bit) of the Version of Dyalog that saved them.


Announcements

Tools and Interfaces

In addition to the software provided as part of the Dyalog installation package, there are a growing number of tools and interfaces available for download from GitHub. For details, see https://www.dyalog.com/tools/tools-and-code-libraries.htm.

Withdrawal of Support for Version 14.1

The supported Versions of Dyalog APL are now Version 17.0, 16.0 and 15.0. Version 14.1 and earlier versions are no longer supported.

Planned Operating System Requirements for the next version

Dyalog Ltd expects that the next version of Dyalog will require the following minimum platform requirements:

Operating System | Version
Microsoft Windows | Windows 7 or Server 2008 R2
AIX | 7.2 on POWER 7
Linux | RedHat/Centos 7 or equivalent
OS X | OS X Yosemite 10.10.x
Raspberry Pi | Raspbian Jessie or above

Further updates to this information will appear on the Forums as and when available.

Planned Hardware Requirements for next version

The same as Dyalog Version 17.0.

Deprecation of small-span component files

As announced in the Version 16.0 Release Notes, the facility to write to small-span component files has been removed. You may continue to tie and read small-span component files.

However, if an attempt is made to execute any system function that would write to or amend the file in any way, the operation will fail as follows:

FILE ACCESS ERROR: Small-span files are read-only; ⎕FCOPY can create a writable large-span copy

The system functions that are affected are: ⎕FAPPEND, ⎕FREPLACE, ⎕FDROP, dyadic ⎕FPROPS, ⎕FRENAME, ⎕FRESIZE, ⎕FSTAC. In addition, ⎕FCHK cannot write to small-span files, so cannot perform Repair or Rebuild operations.


Bug Fixes

A number of bug fixes implemented in Version 17.0 may change the way that existing code operates and are therefore documented in this section.

Incorrect Identity Element (9849)

When ⎕FR is 645, the expressions ⌈/2⍴1E400 and ⌈/2⍴1E400 now correctly generate DOMAIN ERROR. Previously these expressions returned a (wrong) result.

Correction to System Function ⎕R

In earlier versions in Line mode (the default) ⎕R applied to an argument which ends with multiple empty lines would return one fewer element than it was passed. In Version 17.0 all the empty elements are preserved.

Examples

      ≢('a' ⎕r'bb') 'Andy' '' 'Pete'
3

      ≢('a' ⎕r'bb') 'Andy' '' 'Pete' ''
4

      ≢('a' ⎕r'bb') 'Andy' '' 'Pete'  '' ''
5

In previous versions, the results were 3, 3, 4 respectively.

APL_COMPLEX_AS_V12 parameter

If APL_COMPLEX_AS_V12 is set to 1, objects containing complex numbers cannot be transferred to or from component files, TCP/IP (CONGA), or auxiliary processors and may not be used as an argument to Serialise/Deserialise Array (220⌶). Instead, a DOMAIN ERROR will be issued.


Command-Line Options

The command-line to run the Dyalog program or a bound Dyalog executable may now contain options which control how parameters are handled by the Dyalog component.

-apl Option

The -apl option is designed to be used for bound executables. It causes the following parameter to be passed to the Dyalog engine for processing. If multiple parameters need to be passed to the Dyalog engine each must be preceded with -apl. In versions prior to Version 17.0 all command-line parameters were ignored by the Dyalog DLL.

-cef Option

The -cef option is designed to be used with the Development EXE and the Run-Time EXE (see Files). It causes the following parameter to be ignored by the Dyalog executable. In versions prior to Version 17.0 all command-line parameters are passed to the Dyalog executable, whether or not they are relevant to it.

This option is intended to isolate parameters intended for the built-in Chromium Embedded Framework (CEF) which provides the HTMLRenderer object. See HTML Renderer Documentation.

.


IDE Enhancements


Backtick Keyboard

The Backtick keyboard provided by the RIDE may now be used natively. For information on using this keyboard interface, see http://docs.dyalog.com/17.0/RIDE User Guide.pdf Section 7.4.

By default, the Backtick keyboard is disabled . To enable it, select Options/Configure from the Session menu, click the Unicode Input tab, then click Configure Layout ....

Now check the option button labelled Enable Backtick Keyboard introducer. You may replace the backtick character (`) with an alternative character to act as the introducer for APL glyphs, but take care to choose a character that is otherwise unused.

Finally, click OK. Despite the general warning message that appears, this change will take effect and you may use the Backtick keyboard layout immediately.


Find Objects Tool

The Find Objects tool is a modeless dialog box that may be toggled on and off by the system action [WSSearch]. In a default Session, this action is attached to a MenuItem in the Tools menu and a Button on the session toolbar.

The Find Objects tool allows you to search the active workspace for objects that satisfy various criteria.

Name

The Named field is used to search for objects with a particular name and is case-insensitive.

Containing Text

The Containing Text field is used to search for objects that contain a particular text string. The string search is controlled by the fields Match Case, Use Regular Expressions, Match Whole Word and As Symbol Reference.

Match Case specifies whether or not the string search (for name and/or contents) is case sensitive.

Use Regular Expressions specifies whether or not regular expressions are applicable. For example, if you enter FOO* into the field labelled Containing Text and check this box, the system will find objects that contain any text string starting with the 3 characters FOO.

If this box is not checked, the system will find objects that contain the 4 characters FOO*.

Text searches are performed using PCRE. If the Use Regular Expressions box is checked, the full range of regular expressions provided by PCRE are available for use. See PCRE Regular Expression Syntax Summary.

Match Whole Word specifies whether or not the search is restricted to entire words.

As Symbol Reference specifies whether or not the search is restricted to APL symbols. If so, matching text in comments and other strings is ignored.

Object Criteria

Four check boxes are provided for you to specify the types of objects you wish to locate. For example, if you clear Variables, Operators and Namespaces, the system will only search for functions.

To make the search dependent upon modification, you must check the Modified Objects check box.

To locate objects modified by a particular user, enter the user name in the field labelled Modified by. Otherwise leave this blank.

To find objects which have been modified at a certain time or within a specified period of time, check the appropriate radio button and enter the appropriate dates or time spans.

If you wish to restrict the search to find only objects whose size is within a given range, check the box labelled Size is between and enter values into the fields provided.

Location Criteria

You can restrict the search to a particular namespace by typing its name into the field labelled Look in. You can further restrict the search by clearing the Include sub-namespaces and Include Session namespace check boxes. Clearing the former restricts the search to the root namespace or to the namespace that you have specified in Look in, and does not search within any sub-namespaces contained therein. Clearing the latter causes the system to ignore ⎕SE in its search.

When you press the Find Now button, the system searches for objects that satisfy all of the criteria that you have specified on all 3 pages of the dialog box and displays them in a ListView. The example below illustrates the result of searching the workspace for all objects containing references to the symbol Speak.

You may change the way in which the objects are displayed in the ListView using the View menu or the tool buttons, in the same manner as for objects displayed in the Workspace Explorer. You may also edit, delete and rename objects in the same way. Furthermore, objects can be copied or moved by dragging from the ListView in the Search tool to the TreeView in the Explorer.

If you wish to specify a completely new set of criteria, press the New Search button. This will reset all of the various controls of the dialog box to their default values.


New Buttons for Editor Toolbar

New Tool Buttons

Editor Toolbar

Two new buttons have been added to the Editor toolbar.

Button | Description
Toggle tree view | Toggles the treeview on/off.
Previous Location | Certain operations (such as selecting an item in the treeview) reposition the caret in the Editor window. This button moves the caret back to its previous location.

Session Tools

A new button has been added to the Session toolbar.

Boxing On/Off 		Executes the user command ]boxing to toggle boxing on/off.


Other Changes

  • The left argument to ⎕CY may now be a vector of character vectors.
  • 2000⌶ accepts a new argument 19 which reports the number of calls to ⎕WA and 2002⌶.
  • For a VALUE ERROR, the error message and ⎕DMX now report the undefined name.
  • For a LIMIT ERROR caused by an insufficiency of GUI resources, ⎕DMX now identifies the cause.
  • ⎕FX has been extended to allow ∇s around functions.
  • If a file contains a single function surrounded by ∇s the Editor treats it as a single function. Previously this was not the case.
  • Version 17.0 supports late binding of Base Classes and included namespaces. This means that the Editor will fix a Class even though its Base Class is not present in the workspace. The Base Class is only required to be present when the Class is instantiated. The same is true for included namespaces (namespaces declared using the :Include statement).
  • If the system cannot infer the type of a file from its content, it treats it as a function.
  • ⎕STACK has changed so that when there is an inner dfn on the stack, instead of reporting the ⎕OR of that inner dfn (which might be anonymous) it reports the ⎕OR of the capsule (which is always named). A capsule is defined as the outermost dfn in a set of nested dfns. This makes it more consistent with ⎕LC and ⎕XSI and other stack-related functions, which always work with capsules and capsule-relative line numbers.
  • The left argument to ⎕ED is now a character scalar that specifies the type for all the names in the right argument Y, or a character vector whose elements specify the types of each of the corresponding names in Y.
  • In earlier versions of Dyalog attempting to ⎕FIX a malformed scripted object would result in the generic message:
    DOMAIN ERROR: There were errors processing the script. In Version 17.0 the error reported is the same as the first error which appears in the status window; for example:
    DOMAIN ERROR: invalid base class or interface declaration.
    A side effect of this is that ⎕DMX.ENX will be different, and the text and error numbers that appear in the status window may differ compared with earlier versions.
  • The native-file related functions now include the file or directory name in the error message.
  • The position of the caret in an error report is more informative than in previous versions and now identifies more precisely the operation that failed.


Language Enhancements

Language Changes

The following table summarises the main changes to language features in Version 17.0.

Function | Description | Change
⎕CSV | Comma Separated Values | Supports user-defined character set, a new column type (numeric/empty) and 3 new variant options to handle metacharacters.
⎕MKDIR | Make Directory | Supports multiple files
⎕NCOPY | Native File Copy | New system function
⎕NDELETE | Native File Delete | Supports multiple files, wildcards and recursion
⎕NEXISTS | Native File Exists | Supports multiple files and wildcards
⎕NGET | Read Text File | Supports user-defined character set
⎕NINFO | Native File Information | Supports multiple files, recursion and additional file properties
⎕NPARTS | Native File Parts | Supports multiple files
⎕NMOVE | Native File Move | New system function
⎕NPUT | Write Text File | Supports user-defined character set and append operation
⎕R and ⎕S | Search/Replace | Supports user-defined character set


Shy Results for System Functions

To facilitate the use of system functions in dfns, it has been decided to extend those that (in previous versions) do not return a result, to return a shy result. This decision affects the following system functions which now return shy results.

System Function | Shy result
{X} ⎕ARBOUT Y | ⍬
X ⎕CMD Y | Process ID of created process
{X} ⎕CY Y | 0⍴⊂''
{X} ⎕LOCK Y | New lock level of Y
X ⎕SH Y | Process ID of created process
⎕SHADOW Y | Boolean vector

Due to the minor nature of the effect on the Version 17.0 documentation, the full descriptions of these system functions are not included in these Release Notes.


Grade Down Monadic

Grade Down (Monadic) R←⍒Y

Y may be any array of rank greater than 0 but may not contain namespaces. R is an integer vector being the permutation of ⍳1↑⍴Y that places the sub-arrays along the first axis in descending order. For the rules for comparing items of Y with one another, see Grade Up (Monadic).

⎕IO is an implicit argument of Grade Down.

Examples

      ⍒22.5 1 15 3 ¯4
1 3 4 2 5

      M
2 3 5
1 4 7

2 3 4
5 2 4

2 3 5
1 2 6
      ⍒M
1 3 2

Note that character arrays sort differently in the Unicode and Classic Editions.

      M
Goldilocks
porridge
Porridge
3 bears
Unicode Edition Classic Edition
      ⍒M
2 3 1 4

      ⍒M
3 1 4 2

      M[⍒M;]
porridge
Porridge
Goldilocks
3 bears

      M[⍒M;]
Porridge
Goldilocks
3 bears
porridge

      ⍴pb
6 3
      pb
┌────────┬─────┬───┐
│Rivers  │Jason│554│
├────────┼─────┼───┤
│Daintree│John │532│
├────────┼─────┼───┤
│Rivers  │Jason│543│
├────────┼─────┼───┤
│Foad    │Jay  │558│
├────────┼─────┼───┤
│Scholes │John │547│
├────────┼─────┼───┤
│Scholes │John │535│
└────────┴─────┴───┘
      ⍒pb
5 6 1 3 4 2


Grade Up Monadic

Grade Up (Monadic) R←⍋Y

Y may be any array of rank greater than 0 but may not contain namespaces. R is an integer vector being the permutation of ⍳1↑⍴Y that places the sub-arrays along the first axis in ascending order. The rules for comparing items of Y with one another are as follows:

Rules for comparing simple scalars

  • Numeric comparisons are exact, as if ⎕CT←⎕DCT←0 and ⎕FR←1287
  • Two real numbers are compared numerically, thus 1.2 precedes 3.
  • In the Unicode Edition two characters are compared numerically according to their position in the Unicode table. Thus 'a' (⎕UCS 97) precedes
    'b' (⎕UCS 98). In the Classic Edition characters are compared according to their index in ⎕AV.
  • Complex numbers are ordered by first comparing their real parts. If these are equal, the order is determined by comparing their imaginary parts.
    Thus 1J¯2 precedes 1 which precedes 1J2.
  • ⎕NULL (which represents a null item obtained from an external source) precedes all numbers, and all numbers precede all characters.
    Thus ⎕NULL precedes 100, and 100 precedes 'A'.

Rules for comparing non-scalar arrays

  • Arrays are compared item by item in ravel order.
  • For arrays of equal shape, the order is determined by the first pair of items which differ, thus (1949 4 29) precedes (1949 4 30). Similarly ('April' 29) precedes ('April' 30).
  • Arrays with the same rank but different shape are ordered as if the shorter array were padded with items that precede all other types of item (negative infinity) including ⎕NULL. Thus 'car' precedes 'carpet'
    and (1949 4) precedes (1949 4 30). An alternative model is to say that shorter arrays precede longer ones that begin the same way. For character vectors this is described as Lexicographical ordering, which is the order that words appear in a dictionary.
  • Arrays with differing rank are ordered by first extending the shape of the lower-ranked array with 1s at the beginning, and then comparing the resultant equal-rank arrays as described above. So, to compare a vector (rank 1) with a matrix (rank 2), the vector is reshaped into a 1-row matrix.
  • Empty arrays are compared first by type alone, so an empty numeric array precedes an empty character array, regardless of rank or shape.
    Thus ((0 3 2)⍴0) precedes ''. If the empty arrays are of the same type, they are sorted in order of their shape vector, working right to left.
    So ((0 5 2)⍴99) precedes ((0 3 4)⍴0) and
    ((0 3 4)⍴'') precedes ((1 0 5 4)⍴'').

⎕IO is an implicit argument of Grade Up

Examples

      ⍋22.5 1 15 3 ¯4
5 2 4 3 1

      M
2 3 5
1 4 7

2 3 4
5 2 4

2 3 5
1 2 6
      ⍋M
2 3 1

Note that character arrays sort differently in the Unicode and Classic Editions.

      M
Goldilocks
porridge
Porridge
3 bears

Unicode Edition Classic Edition
      ⍋M
4 1 3 2

      ⍋M
2 4 1 3

      M[⍋M;]
3 bears
Goldilocks
Porridge
porridge
      M[⍋M;]
porridge
3 bears
Goldilocks
Porridge

      ⍴pb
6 3
      pb
┌────────┬─────┬───┐
│Rivers  │Jason│554│
├────────┼─────┼───┤
│Daintree│John │532│
├────────┼─────┼───┤
│Rivers  │Jason│543│
├────────┼─────┼───┤
│Foad    │Jay  │558│
├────────┼─────┼───┤
│Scholes │John │547│
├────────┼─────┼───┤
│Scholes │John │535│
└────────┴─────┴───┘
      ⍋pb
2 4 3 1 6 5


Unique

Unique R←∪Y

Y may be any array. R is a vector of the unique major cells of Y (the unique items of a vector, the unique rows of a matrix and so forth), in the order in which they first appear in Y. For further information, see Major Cells.

⎕CT and ⎕DCT are implicit arguments of Unique.

Examples

      ∪ 22 10 22 22 21 10 5 10
22 10 21 5

      ∪ v←'CAT' 'DOG' 'CAT' 'DUCK' 'DOG' 'DUCK'
┌───┬───┬────┐
│CAT│DOG│DUCK│
└───┴───┴────┘
      ⊢mat←↑v
CAT
DOG
CAT
DUCK
DOG
DUCK
      ∪mat
CAT
DOG
DUCK

      a←3 4 5⍴⍳20
      a
 1  2  3  4  5
 6  7  8  9 10
11 12 13 14 15
16 17 18 19 20

 1  2  3  4  5
 6  7  8  9 10
11 12 13 14 15
16 17 18 19 20

 1  2  3  4  5
 6  7  8  9 10
11 12 13 14 15
16 17 18 19 20
      ∪a
 1  2  3  4  5
 6  7  8  9 10
11 12 13 14 15
16 17 18 19 20


Comma Separated Values

Comma Separated Values {R}←{X} ⎕CSV Y

This function imports and exports Comma Separated Value (CSV) data.

Monadic ⎕CSV imports data from a CSV file or converts data from CSV format to an internal format. Dyadic ⎕CSV exports data to a CSV file or converts data from internal format to a CSV format.

Internal Format

Arrays that result from importing CSV data or arrays that are suitable for exporting as CSV data are represented by 3 possible structures:

  • A table (a matrix whose elements are character vectors or scalars, or numbers).
  • A vector, each of whose items contain field (column) values. Character field values are character matrices; numeric field values are numeric vectors.
  • A vector, each of whose items contain field (column) values. Character field values are vectors of character vectors; numeric field values are numeric vectors.

Note that when importing CSV data, all fields are assumed to be character fields unless otherwise specified (see Column Types below). A field that contains only "numbers" will not be converted to numeric data unless specified as being numeric.

MetaCharacters

Some characters in a CSV file are metacharacters which define the structure of the data; for example, the field separator character between fields. Characters which are not metacharacters are literal characters. The variant options QuoteChar, EscapeChar and DoubleQuote make it possible to interpret metacharacters as literal characters and thus permit fields to contain field separator characters, leading and trailing spaces, and line-endings.

Fixed-width fields do not require these options and they are ignored if fixed-width fields are being processed.

Monadic ⎕CSV

R←⎕CSV Y

Y is an array that specifies just the source of the CSV data (see below) or a 1,2,3 or 4-element vector containing:

[1] | Source of CSV Data
[2] | Description of the CSV data
[3] | Column Types
[4] | Header Row Indicator

Source may be one of:

  • a character vector or scalar containing a file name
  • a native tie number
  • a character vector or scalar containing CSV data with embedded newline characters. To avoid this source being interpreted as a file name, Y[2] must be specified as 'S'.
  • a vector of character vectors and/or scalars containing CSV data with implicit newlines after each character vector or scalar

Description

If Y[1] is a file name or tie number Description may be one of:

  • a character vector specifying the file encoding such as 'UTF-8' (see File Encodings).
  • a 256-element numeric vector that maps each possible byte value (0-255) to a Unicode code point (1st element = Unicode code point corresponding to byte value 0, and so on). ¯1 indicates that the corresponding byte value is not mapped to any character. Apart from ¯1, no value may appear in the table more than once.

If omitted or empty, the file encoding is deduced (see below).

If Y[1] is a character array containing CSV data Description is a character scalar 'S' (simple) or 'N' (nested). The default is 'N'

Column Types

This is a scalar numeric code or vector of numeric codes that specifies the field types from the list below. If Column Types is zilde or omitted, the default is 1 (all fields are character).

0 | The field is ignored.
1 | The field contains character data.
2 | The field is to be interpreted as being numeric. Empty cells and cells which cannot be converted to numeric values are not tolerated and cause an error to be signalled.
3 | The field is to be interpreted as being numeric but invalid numeric vales are tolerated. Empty fields and fields which cannot be converted to numeric values are replaced with the Fill variant option (default 0).
4 | The field is to be interpreted numeric data but invalid numeric data is tolerated. Empty fields and fields which cannot be converted to numeric values are returned instead as character data; this type is disallowed when variant option Invert is set to 1.
5 | The field is to be interpreted as being numeric but empty fields are tolerated and are replaced with the Fill variant option (default 0). Non-empty cells which cannot be converted to numeric values are not tolerated and cause an error to be signalled.

Note that if Column Types is specified by a scalar 4, all numeric data in all fields will be converted to numbers.

Header Row Indicator

This is a Boolean value (default 0) to specify whether or not the first record in a CSV file is a list of column labels. If Header Row Indicator is 1, the first record (the header row) is treated differently from other records. It is assumed to contain character data (labels) regardless of Y[3] and is returned separately in the result.

Variant options

Monadic ⎕CSV may be applied using the Variant operator with the following options. The Principal option is Invert.

Name | Meaning | Default
Invert | 0, 1 or 2 (see below) | 0
Separator | The field separator, any single character. If Widths is other than ⍬, Separator is ignored. | ','
Widths | A vector of numeric values describing the width (in characters) of the corresponding columns in the CSV source, or ⍬ for variable width delimited fields | ⍬
Decimal | The decimal mark in numeric fields - one of '.' or ',' | '.'
Thousands | The thousands separator in numeric fields, which may be specified as an empty character vector (meaning no separator is defined) or a character scalar | ''
Trim | A Boolean specifying whether undelimited/unescaped whitespace is trimmed at the beginning and end of fields | 1
Ragged | A Boolean specifying whether records with varying numbers of fields are allowed; see notes below | 0
Fill | The numeric value substituted for invalid numeric data in columns of type 3 | 0
Records | The maximum number of records to process or 0 for no limit. This applies only to a file specified by a tie number. | 0
QuoteChar | The field quote character (delimiter), which may be specified as an empty character vector (meaning none is defined) or a character scalar | "
EscapeChar | The escape character, which may be specified as an empty character vector (meaning none is defined) or a character scalar | ''
DoubleQuote | A Boolean which indicates whether (1) or not (0) a quote character within a quoted field is represented by two consecutive quote characters | 1

The Separator, QuoteChar and EscapeChar characters, when defined, must be different.

Other options defined for export are also accepted but ignored.

Invert Option

This option specifies how the CSV data should be returned as follows:

0 | A table (a matrix whose elements are character vectors or scalars or numbers).
1 | A vector, each of whose items contain field (column) values. Character field values are character matrices; numeric field values are numeric vectors.
2 | A vector, each of whose items contain field (column) values. Character field values are vectors of character vectors; numeric field values are numeric vectors.

QuoteChar, EscapeChar and DoubleQuote Options

If EscapeChar is set then any character may be prefixed by the escape character. The escape character is typically defined as '\'. The escape character immediately followed by the character c is the literal character c even if c alone would have been a metacharacter.

If QuoteChar is set then fields may be delimited by the specified quote character. Within quoted fields all characters except the quote character, and the escape character if defined, are literal characters.

If DoubleQuote is set to 1 then two consecutive quote characters within a quoted field are interpreted as the single literal quote character.

Result

The result R contains the imported data.

If Y[4] does not specify that the data contains a header then R contains the entire data in the form specified by the Invert variant option.

If Y[4] does specify that the data contains a header then R is a 2-element vector where:

  • R[1] is the imported data excluding the header.
  • R[2] is a vector of character vectors containing the header record.

Examples

      ⊃⎕NGET CSVFile←'c:\Dyalog16.0\sales.csv'
┌→───────────────────────────────────────────────┐
│Product,Sales                                   │
│             Widgets,1912                       │
│                         Gimlets,205            │
│                                    Dingbats,189│
│                                                │
└────────────────────────────────────────────────┘

      ⎕CSV CSVFile
┌→───────────────────┐
↓ ┌→──────┐  ┌→────┐ │
│ │Product│  │Sales│ │
│ └───────┘  └─────┘ │
│ ┌→──────┐  ┌→───┐  │
│ │Widgets│  │1912│  │
│ └───────┘  └────┘  │
│ ┌→──────┐  ┌→──┐   │
│ │Gimlets│  │205│   │
│ └───────┘  └───┘   │
│ ┌→───────┐ ┌→──┐   │
│ │Dingbats│ │189│   │
│ └────────┘ └───┘   │
└∊───────────────────┘

      ⎕CSV CSVFile'' ⍬ 1 ⍝ Header row
┌→────────────────────────────────────────────┐
│ ┌→──────────────────┐ ┌→──────────────────┐ │
│ ↓ ┌→──────┐  ┌→───┐ │ │ ┌→──────┐ ┌→────┐ │ │
│ │ │Widgets│  │1912│ │ │ │Product│ │Sales│ │ │
│ │ └───────┘  └────┘ │ │ └───────┘ └─────┘ │ │
│ │ ┌→──────┐  ┌→──┐  │ └∊──────────────────┘ │
│ │ │Gimlets│  │205│  │                       │
│ │ └───────┘  └───┘  │                       │
│ │ ┌→───────┐ ┌→──┐  │                       │
│ │ │Dingbats│ │189│  │                       │
│ │ └────────┘ └───┘  │                       │
│ └∊──────────────────┘                       │
└∊────────────────────────────────────────────┘

      ⎕CSV CSVFile''(1 2)1 ⍝ Fields are Char, Num
┌→──────────────────────────────────────────┐
│ ┌→────────────────┐ ┌→──────────────────┐ │
│ ↓ ┌→──────┐       │ │ ┌→──────┐ ┌→────┐ │ │
│ │ │Widgets│  1912 │ │ │Product│ │Sales│ │ │
│ │ └───────┘       │ │ └───────┘ └─────┘ │ │
│ │ ┌→──────┐       │ └∊──────────────────┘ │
│ │ │Gimlets│  205  │                       │
│ │ └───────┘       │                       │
│ │ ┌→───────┐      │                       │
│ │ │Dingbats│ 189  │                       │
│ │ └────────┘      │                       │
│ └∊────────────────┘                       │
└∊──────────────────────────────────────────┘

      (⎕CSV⍠'Invert' 1)CSVFile'' (1 2) 1    ⍝ Invert 1
┌→────────────────────────────────────────────────────┐
│ ┌→──────────────────────────┐ ┌→──────────────────┐ │
│ │ ┌→───────┐ ┌→───────────┐ │ │ ┌→──────┐ ┌→────┐ │ │
│ │ ↓Widgets │ │1912 205 189│ │ │ │Product│ │Sales│ │ │
│ │ │Gimlets │ └~───────────┘ │ │ └───────┘ └─────┘ │ │
│ │ │Dingbats│                │ └∊──────────────────┘ │
│ │ └────────┘                │                       │
│ └∊──────────────────────────┘                       │
└∊────────────────────────────────────────────────────┘
      ⊃(⎕CSV⍠'Invert' 2)CSVFile'' (1 2) 1    ⍝ Invert 2
┌→──────────────────────────────────────────────────┐
│ ┌→───────────────────────────────┐ ┌→───────────┐ │
│ │ ┌→──────┐ ┌→──────┐ ┌→───────┐ │ │1912 205 189│ │
│ │ │Widgets│ │Gimlets│ │Dingbats│ │ └~───────────┘ │
│ │ └───────┘ └───────┘ └────────┘ │                │
│ └∊───────────────────────────────┘                │
└∊──────────────────────────────────────────────────┘

Notes

  • When Y specifies just the source of the CSV data, it does not need to be enclosed or ravelled to create a 1-element vector.
  • Y[2], the description of the source, distinguishes an otherwise ambiguous character vector source (which could contain either CSV data or a file name). The other source forms are unambiguous but the description, when given, must still match the given source type.
  • Tab-separated fields may be imported by specifying 'Separator' (⎕UCS 9).
  • Fields containing embedded new lines are supported (they must, of course, appear in quotes or be prefixed by the escape character). On import, line endings are always converted to a single line feed character.
  • If Ragged is not set then all records must have the same number of fields (character delimited format) or same number of characters (fixed width field format).
  • If Ragged is set:
    • The expected number of columns must be specified using the Widths variant option and/or the column types in Y[3].
    • In character delimited format, all processed records are implicitly extended or truncated as required so that they contain the expected number of fields; implicitly added fields will be empty.
    • In fixed width format, all processed records are implicitly extended with spaces or truncated as required so that they contain as many characters as are specified in the Widths option declaration.

File handling

Data may be read from a named file or a tied native file. A tied native file may be read in sections by repeatedly invoking ⎕CSV for a specified maximum number of records (specified by the Records variant) until no more data is read.

In all cases the files must contain text using one of the supported encodings. See File Encodings. The method used to determine the file encoding is as follows:

  • If a Byte Order Mark (BOM) is encountered at the start of the file, it is used regardless of Y[2] (if specified). Note, however, that the BOM can only be encountered if the file is read from the start - specifically, if a native file is read in sections, any BOM present will only be encountered when the first section is read.
  • Otherwise, the file will be read and decoded according to the file encoding in Y[2] if specified.
  • Otherwise:
    • Native files will be decoded as if 'UTF-8' had been specified.
    • Files specified by name will be examined and the likely file encoding will be deduced using the same heuristics performed by ⎕NGET.

Note also:

  • Native files are read from the current file position. On successful completion, the file position will be at the first unprocessed character (end of file if the Records variant option is not specified). If an error is signalled the file position is undefined.
  • The result does not report the file encoding or line ending type as it does with ⎕NGET. If this information is required then it must be obtained by other means.

Dyadic ⎕CSV

{R}←X ⎕CSV Y

The left argument X is either:

  • a matrix or a vector of vectors/matrices containing the data to be converted to CSV format.
  • or a 2-element vector containing a matrix or vector of vectors/matrices containing the data to be converted to CSV format, and a vector of character vectors containing the header record.

Y is a 1 or 2-element vector containing:

[1] | Destination of CSV Data (see below)
[2] | Description of the CSV data (see below)

Destination - may be one of:

  • a character vector or scalar containing a file name
  • a native tie number
  • an empty character vector, indicating that the CSV data is to be returned in the result R

Description

If Y[1] is a file name or tie number, Description may be:

  • a character vector specifying the file encoding such as 'UTF-8' (see File Encodings).
  • a 256-element numeric vector that maps each possible byte value (0-255) to a Unicode code point (1st element = Unicode code point corresponding to byte value 0, and so on). ¯1 indicates that the corresponding byte value is not mapped to any character. Apart from ¯1, no value may appear in the table more than once.

If Y[1] is empty, Description may be a character scalar 'S' (simple) or 'N' (nested). If omitted, the default is 'S'

Variant options

Dyadic ⎕CSV may be applied using the Variant operator with the following options.

Name | Meaning | Default
IfExists | a character vector 'Error' or 'Replace' which specifies, when creating a named file which already exists, whether to overwrite it ('Replace') or signal an error ('Error') | 'Error'
Separator | the field separator, any single character. If Widths is other than ⍬, Separator is ignored. | ','
Widths | a vector of numeric values describing the width (in characters) of the corresponding columns in the CSV source, or ⍬ for variable width delimited fields | ⍬
Decimal | the decimal mark in numeric fields - one of '.' or ',' | '.'
Thousands | the thousands separator in numeric fields, which may be specified as an empty character vector (meaning no separator is defined) or a character scalar | ''
Trim | a Boolean specifying whether whitespace is trimmed at the beginning and end of character fields | 1
LineEnding | the line ending sequence - see Line separators: | (13 10) on Windows; 10 on other platforms
QuoteChar | The field quote character (delimiter), which may be specified as an empty character vector (meaning none is defined) or a character scalar | "
EscapeChar | The escape character, which may be specified as an empty character vector (meaning none is defined) or a character scalar | ''
DoubleQuote | A Boolean which indicates whether (1) or not (0) a quote character within a quoted field is represented by two consecutive quote characters | 1

The Separator, QuoteChar and EscapeChar characters, when defined, must be different. Other options defined for import are also accepted but ignored.

The Overwrite variant option (Boolean) from Version 16.0 remains supported but is deprecated in favour of IfExists.

QuoteChar, EscapeChar and DoubleQuote options

  • The CSV text will be generated such that it can be read back according to the corresponding rules for import.
  • If these options do not permit this (for example, a field contains the quote character and neither DoubleQuote or EscapeChar are set) an error is signalled.
  • Quoting and Escaping is used as conservatively as possible.
  • If both QuoteChar and EscapeChar are set, quoting is favoured.

If Y specifies that the CSV data is written to a file then R is the number of bytes (not characters) written, and is shy.

Otherwise, R is the CSV data in the format specified in Y, and is not shy.

Examples

       CSVFile←'c:\Dyalog16.0\sales.csv'
       ⎕←DATA HDR←⎕CSV CSVFile''(1 2)1
┌→──────────────────────────────────────────┐
│ ┌→────────────────┐ ┌→──────────────────┐ │
│ ↓ ┌→──────┐       │ │ ┌→──────┐ ┌→────┐ │ │
│ │ │Widgets│  1912 │ │ │Product│ │Sales│ │ │
│ │ └───────┘       │ │ └───────┘ └─────┘ │ │
│ │ ┌→──────┐       │ └∊──────────────────┘ │
│ │ │Gimlets│  205  │                       │
│ │ └───────┘       │                       │
│ │ ┌→───────┐      │                       │
│ │ │Dingbats│ 189  │                       │
│ │ └────────┘      │                       │
│ └∊────────────────┘                       │
└∊──────────────────────────────────────────┘

     DATA⍪←'Gizmos' 23
      DATA HDR ⎕CSV''
┌→────────────┐
│Product,Sales│
│             │
│Widgets,1912 │
│             │
│Gimlets,205  │
│             │
│Dingbats,189 │
│             │
│Gizmos,23    │
│             │
│             │
└─────────────┘

       CSVFile1←'c:\Dyalog16.0\sales1.csv'
       ⎕←DATA HDR ⎕CSV CSVFile1

67
       DATA⍪←'Gimbals' 123
       ⎕←DATA HDR ⎕CSV CSVFile1
FILE NAME ERROR: Unable to create file ("The file exists.")
       ⎕←DATA HDR ⎕CSV CSVFile1
      ∧
       ⎕←DATA HDR(⎕CSV⍠'IfExists' 'Replace')CSVFile1

80

Notes

  • When Y contains only the destination of the CSV data (i.e. omits the description in its second element) it does not have to be enclosed to form a single element vector.
  • Native files are written from the current file position. On successful completion, the file position will be at the end of the written data. If an error is signalled the amount of data written is undefined.
  • If the file encoding specifies that a BOM is required and output is to a native file, it will only be written if the file position is initially at 0 - that is, the start of the file is being written.
  • When fixed width fields are written, character data shorter than the specified width is padded with spaces to the right and character data longer than the specified width signals an error. Numeric data is converted to character data as far as possible so that it fits into the specified width. If this is not possible, an error is signalled.
  • Tab-separated fields may be exported by specifying 'Separator' (⎕UCS 9).
  • Fields containing a single embedded new line are supported. On export, line feed characters are mapped back to the defined line ending sequence.


Make Directory

Make Directory {R}←{X}⎕MKDIR Y

This function creates new directories.

Y is a character vector or scalar containing a single directory name, or a vector of character vectors containing zero or more directory names. Names must conform to the naming rules of the host Operating System.

By default, for each file in Y the path must exist and the base name must not exist (see File Name Parts), otherwise an error is signalled. The optional left argument X is the numeric scalar 0, 1, 2 or 3 which amends this behaviour as shown in the following table. If omitted, it is assumed to be 0.

0 | Default behaviour.
1 | No action is taken if a directory specified by Y already exists. The return value may be used to determine whether a new directory was created or not.
2 | Any part of the paths specified in Y which does not already exist will be created in preparation of creating the corresponding directory.
3 | Combination of 1 and 2.

If Y specifies a single name, the shy result R is a scalar 1 if a directory was created or 0 if not. If Y is a vector of character vectors, R is a vector of 1s and 0s with the same length as Y.

Examples

      ⎕NEXISTS '/Users/Pete/Documents/temp'
0
      ⎕←⎕MKDIR '/Users/Pete/Documents/temp'
1
      ⎕←⎕MKDIR '/Users/Pete/Documents/temp'
FILE NAME ERROR: Directory exists
      ⎕←⎕MKDIR'/Users/Pete/Documents/temp'
     ∧

      ⎕←⎕MKDIR'/Users/Pete/Documents/temp/t1/t2'
FILE NAME ERROR: Unable to create directory ("The system cannot find the path specified.")
      ⎕←⎕MKDIR'/Users/Pete/Documents/temp/t1/t2'
     ∧

      ⎕←2 ⎕MKDIR'/Users/Pete/Documents/temp/t1/t2'
1
      ⊢⎕MKDIR'temp1' 'temp2'
1 1

Note

When multiple names are specified they are processed in the order given. If an error occurs at any point whilst creating directories, processing will immediately stop and an error will be signalled. The operation is not atomic; some directories may be created before this happens. In the event of an error there will be no result and therefore no indication of how many directories were created before the error occurred.


Native File Copy

Native File Copy {R}←X ⎕NCOPY Y

This function copies native files and directories from one or more sources specified by Y to a destination specified by X. ⎕NCOPY is similar to ⎕NMOVE (see Native File Move ).

X is a character vector that specifies the name of the destination.

Y is a character vector that specifies the name of the source, or a vector of character vectors containing zero or more sources.

Source and destination path names may be full or relative (to the current working directory) path names which adhere to the operating system conventions.

If X specifies an existent directory then each source in Y is copied into that directory, otherwise X specifies the name of the copy. X must specify an existent directory if the source contains multiple names or if the Wildcard option is set.

The shy result R contains count(s) of top-level items copied. If Y is a single source name, R is a scalar otherwise it is a vector of the same length as Y.

Variant Options

⎕NCOPY may be applied using the Variant operator with the options Wildcard (the Principal option), IfExists and PreserveAttributes.

Wildcard Option (Boolean)

0 | the name or names in Y identifies a specific file name.
1 | the name or names in Y that specify the base name and extension (see File Name Parts), may also contain the wildcard characters "?" and "*". An asterisk is a substitute for any 0 or more characters in a file name or extension; a question-mark is a substitute for any single character.

Note that when Wildcard is 1, element(s) of R can be 0, 1 or >1. If Wildcard is 0, elements of R are always 1.

IfExists Option

The IfExists variant option determines what happens when a source file is to be copied to a target file that already exists. It does not apply to directories, only to the files within them.

Value | Description
'Error' | Existing files will not be overwritten and an error will be signalled. This is the default
'Skip' | Existing files will not be overwritten but the corresponding copy operation will be skipped (ignored).
'Replace' | Existing files will be overwritten.
'ReplaceIfNewer' | Existing files may be overwritten if, and only if, the corresponding source file is newer (more recently modified) than the existing one, otherwise it is skipped.

The following cases cause an error to be signalled regardless of the value of the IfExists variant.

  • If the source specifies a directory and the destination specifies an existing file.
  • If the source specifies a file and the same base name exists as a sub-directory in the destination.

PreserveAttributes Option (Boolean)

The PreserveAttributes variant option determines whether or not file attributes are preserved. It does not apply to directories, only to files.

0 | file attributes are not preserved.
1 | where possible, copied files will be given at least the same modification time as the source. Other file attributes will be preserved as permitted by the operating system and file system.

Note also that when files are copied across file systems, the different file systems may have different timestamp granularity and the timestamps may not be exactly the same.

Examples

There are a number of possibilities which are illustrated below. In all cases, if the source is a file, a copy of the file is created. If the source is a directory, a copy of the directory and all its contents is created.

Examples (single source, Wildcard is 0)

  • The source name must be an existent file or directory.
  • If the destination name does not exist but its path name does exist, the source is copied to the destination name.
  • If the destination name is an existing directory the copy is created within that directory with the base name of the source.
       ⊃1 ⎕NPARTS ''
i:/Documents/Dyalog APL-64 17.0 Unicode Files/

⍝ Make a named back-up of the Session file
      ⊢'session.bak' ⎕NCOPY 'default.dlf'
1
      ⊢ ⎕MKDIR 'backups' ⍝ Make a backups directory
1
 ⍝ Copy the Session file to backups directory
      ⊢'backups'⎕NCOPY'default.dlf'
1
      ↑⊃0 (⎕NINFO⍠1) 'backups\*'
backups/default.dlf

Examples (single source, Wildcard is 1)

  • The source name may include wildcard characters which matches a number of existing files and/or directories. The destination name must be an existing directory.
  • The files and/or directories that match the pattern specified by the source name are copied into the destination directory. If there are no matches, zero copies are made.
       ⊃1 ⎕NPARTS ''
i:/Documents/Dyalog APL-64 17.0 Unicode Files/

      ⊢ ⎕MKDIR 'backups' ⍝ Make a backups directory
1
⍝ Copy all files to backups directory
      ⊢'backups'(⎕NCOPY⍠'Wildcard' 1)'*.*'
3

      ↑⊃0 (⎕NINFO⍠1) 'backups\*'
backups/default.dlf
backups/def_uk.dse
backups/UserCommand20.cache

Examples (multiple sources, Wildcard is 0)

  • Each source name must specify a single file or directory which must exist. The destination name must be an existing directory.
  • Copies of each of the files and/or directories specified by the source base names are made in the destination directory.
       ⊃1 ⎕NPARTS ''
i:/Documents/Dyalog APL-64 17.0 Unicode Files/

      ⊢ ⎕MKDIR 'backups' ⍝ Make a backups directory
1
⍝ Copy 2 files to backups directory
      ⊢'backups'⎕NCOPY'default.dlf' 'def_uk.dse'
1 1
      ↑⊃0 (⎕NINFO⍠1) 'backups\*'
backups/default.dlf
backups/def_uk.dse

Examples (multiple sources, Wildcard is 1)

  • The destination name must be an existing directory.
  • Copies of each of the files and/or directories that match the patterns specified by the source names (if any) are made in the destination directory.
      ⊃1 ⎕NPARTS ''
i:/Documents/Dyalog APL-64 17.0 Unicode Files/

      ⊢ ⎕MKDIR 'backups' ⍝ Make a backups directory
1
⍝ Copy files to backups directory
      ⊢'backups'(⎕NCOPY⍠1)'d*' 'UserCommand20.cache'
2 1
      ↑⊃0 (⎕NINFO⍠1) 'backups\*'
backups/default.dlf
backups/def_uk.dse
backups/UserCommand20.cache

Notes

  • The special directories . and .. can never be copied into an existing directory.
  • If any source name is a symbolic link it is dereferenced; that is, the source or directory it references is copied rather than the link itself.
  • In the result R, a directory together with all its contents is counted once. A directory may be partially copied if the IfExists option is set to 'Replace' or 'ReplaceIfNewer').
  • If an error occurs during the copy process then processing will immediately stop and an error will be signalled. The operation is not atomic; some items may be copied before this happens. In the event of an error there will be no result and therefore no indication of how many names were copied before the error occurred.


Native File Create

Native File Create {R}←X ⎕NCREATE Y

This function creates a new file. Under Windows the file is opened with mode 66 (see Native File Tie). Under non-Windows operating systems the current umask will specify the file permissions. The name of the new file is specified by the left argument X which must be a simple character vector or scalar containing a valid pathname for the file.

Y is 0 or a negative integer value that specifies an (unused) tie number by which the file may subsequently be referred. If Y is 0, the system allocates the first (closest to zero) available tie number which is returned as the result.

The shy result of ⎕NCREATE is the tie number of the new file.

Variant Options

⎕NCREATE may be applied using the Variant operator with the options Unique and IfExists. There is no primary option.

Unique Option (Boolean)

0 | the file named by X will be created
1 | a uniquely named file will be created by extending the base name (see File Name Parts) with random characters. If a unique name cannot be created then an error will be signalled. The actual name of the file can be determined from ⎕NNAMES or ⎕NINFO.

IfExists Option (character vector)

Error | ⎕NCREATE will generate a FILE NAME ERROR if the file already exists
Replace | ⎕NCREATE will replace an existing file with an empty one of the same name.

Examples

      ⊢'myfile' ⎕NCREATE 0
¯1
      ⎕NUNTIE ¯1
      ⊢'myfile' ⎕NCREATE 0
FILE NAME ERROR: myfile: Unable to create file ("The file exists.")
      ⊢'myfile'⎕NCREATE 0
               ∧
      ⊢'myfile' (⎕NCREATE⍠'IfExists' 'Replace') 0
¯1    ⍝ Note that it uses same tie number as before

      ⊢'myfile' (⎕NCREATE⍠('Unique' 1)) 0
¯2
      ⎕NNUMS,⎕NNAMES
¯1 myfile
¯2 myfile52c36z

Notes:

  • Setting IfExists to Replace has no effect when Unique is 1, because the file cannot already exist.
  • The IfExists option does not affect the operation of slippery ties.


Native File Delete

Native File Delete {R}←{X}⎕NDELETE Y

This function deletes files and directories.

Y is a character vector or scalar containing a single file or directory name, or a vector of character vectors containing zero or more file or directory names. Names must conform to the naming rules of the host Operating System.

The optional left argument X is a numeric scalar; valid values are shown in the following table. If omitted, its default value is 0.

0 | Each file or directory with the given name must exist.
1 | If the file or directory with the given name does not exist then no action is taken. The result R may be used to determine whether the file or directory was deleted or not.
2 | If a name identifies a non-empty directory it, and all its contents, are to be deleted.
3 | Combination of 1 and 2.

R is a numeric count of top-level entities deleted when processing the corresponding name in Y. If Y specifies a single name, R is a scalar. If Y is a vector of character vectors R is a vector with the same length as Y.

Variant Options

⎕NDELETE may be applied using the Variant operator with the Wildcard option.

Wildcard Option (Boolean)

0 | the name or names in Y identifies a specific file name.
1 | the name or names in Y that specify the base name and extension (see File Name Parts), may also contain the wildcard characters "?" and "*". An asterisk is a substitute for any 0 or more characters in a file name or extension; a question-mark is a substitute for any single character.

Note that when Wildcard is 1, element(s) of R can be 0 or >1. If Wildcard is 0, elements of R are always 1.

If Y specifies the name of a symbolic link, ⎕NDELETE deletes that symbolic link; the target of the symbolic link is unaffected.

Examples

      ⎕NEXISTS'/Users/Pete/Documents/temp/t1/t2'
1
      ⊢⎕NDELETE'/Users/Pete/Documents/temp/t1/t2'
1
      ⊢⎕NDELETE'/Users/Pete/Documents/temp/t1/t2'
FILE NAME ERROR: Invalid file or directory name ("The system cannot find the file specified.")
      ⊢⎕NDELETE'/Users/Pete/Documents/temp/t1/t2'
     ∧

      ⊢1 ⎕NDELETE'/Users/Pete/Documents/temp/t1/t2'
0
      ⊢⎕NDELETE 'temp1' 'temp2'
1 1
      ⊢⎕MKDIR'temp1' 'temp2'
1 1
       ⊢(⎕NDELETE⍠1)'t*'
2
      ⊢⎕MKDIR'temp1'
1
      ⊢'Hello World' ⎕NPUT 'temp1/hw.txt'
13
      ⊢⎕NDELETE 'temp1'
FILE ACCESS ERROR: temp1: Unable to delete directory ("The directory is not empty.")
      ⊢⎕NDELETE'temp1'
       ∧
      ⊢2 ⎕NDELETE 'temp1'
1

If the file is in use or the current user is not authorised to delete it, ⎕NDELETE will not succeed but will instead generate a FILE ACCESS ERROR.

Note

When multiple names are specified they are processed in the order given. If an error occurs at any point whilst deleting files or directories, processing will immediately stop and an error will be signalled. The operation is not atomic; the directory contents may be partially deleted before this happens. In the event of an error there will be no result and therefore no indication of how many files were deleted before the error occurred.


Native File Exists

Native File Exists R←⎕NEXISTS Y

This function reports whether or not file and directories exist.

Y is a character vector or scalar containing a single directory name, or a vector of character vectors containing zero or more directory names. Names must conform to the naming rules of the host Operating System.

If Y specifies a single name, the result R is a scalar 1 if a file or directory exists or 0 if not. If Y is a vector of character vectors, R is a vector of 1s and 0s with the same length as Y.0

Variant Options

⎕NEXISTS may be applied using the Variant operator with the Wildcard option.

Wildcard Option (Boolean)

0 | the name or names in Y identifies a specific file name.
1 | the name or names in Y that specify the base name and extension (see File Name Parts), may also contain the wildcard characters "?" and "*". An asterisk is a substitute for any 0 or more characters in a file name or extension; a question-mark is a substitute for any single character.

If the Wildcard option is 1, R indicates whether or not one or more matches to the corresponding pattern in Y exist.

Example

      ⎕←⎕MKDIR'/Users/Pete/Documents/temp/t1/t2'
1
      ⎕NEXISTS'/Users/Pete/Documents/temp/t1/t2'
1
      ⎕NEXISTS'/Users/Pete/Documents/temp/t1/t2/pd'
0

      ⊢⎕MKDIR'temp1' 'temp2'
1 1
      ⎕NEXISTS 'temp1' 'temp2' 'temp3'
1 1 0
      (⎕NEXISTS⍠1) 't*'
1

Note

If Y is a symbolic link, ⎕NEXISTS will return 1 whether or not the target of the symbolic link exists.


Read Text File

Read Text File R←{X} ⎕NGET Y

This function reads the contents of the specified text file. See also Write Text File.

Y is either a character vector/scalar containing the name of the file to be read, or a 2-item vector whose first item is the file name and whose second is an integer scalar specifying flags for the operation.

If flags is 0 (the default value if omitted) the content in the result R is a character vector. If flags is 1 the result is a nested array of character vectors corresponding to the lines in the file.

The optional left-argument X is either

  • a character vector that specifies the file-encoding as shown in the table below.
  • a 256-element numeric vector that maps each possible byte value (0-255) to a Unicode code point (1st element = Unicode code point corresponding to byte value 0, and so on). ¯1 indicates that the corresponding byte value is not mapped to any character. Apart from ¯1, no value may appear in the table more than once.

Table 1: File Encodings

Encoding | Description
UTF-8 | The data is encoded as UTF-8 format.
UTF-16LE | The data is encoded as UTF-16 little-endian format.
UTF-16BE | The data is encoded as UTF-16 big-endian format.
UTF-16 | The data is encoded as UTF-16 with the endianness of the host system (currently BE on AIX platforms, LE on all others).
UTF-32LE | The data is encoded as UTF-32 little-endian format.
UTF-32BE | The data is encoded as UTF-32 big-endian format.
UTF-32 | The data is encoded as UTF-32 with the endianness of the host system (currently BE on AIX platforms, LE on all others).
ASCII | The data is encoded as 7-bit ASCII format.
Windows-1252 | The data is encoded as 8-bit Windows-1252 format.
ANSI | ANSI is a synonym of Windows-1252.

The above UTF formats may be qualified with -BOM or -NOBOM (e.g. UTF-8-BOM). See Write Text File.

Whether or not X is specified, if the start of the file contains a recognised Byte Order Mark (BOM), the file is decoded according to the BOM. Otherwise, if X is specified the file is decoded according to the value of X. Otherwise, the file is examined to try to decide its encoding and is decoded accordingly.

The result R is a 3-element vector comprising (content) (encoding) (newline) where:

content | A simple character vector, or a vector of character vectors, according to the value of flags.
encoding | The encoding that was actually used to read the file. If this is a UTF format, it will always include the appropriate endianness (except for UTF-8 to which endianness doesn't apply) and a -BOM or -NOBOM suffix to indicate whether or not a BOM is actually present in the file. For example, UTF-16LE-BOM. If X specified a user-defined encoding as a 256-element numeric vector, encoding will be that same vector.
newline | Determined by the first occurrence in the file of one of the newline characters identified in the line separator table, or ⍬ if no such line separator is found.

If content is simple then all its line separators (listed in the table below) are replaced by (normalised to) ⎕UCS 10, which in the Classic Edition must be in ⎕AVU (else TRANSLATION ERROR).

If content is nested, it is formed by splitting the contents of the file on the occurrence of any of the line separators shown in the table below. These line separators are removed.

The 3rd element of the result newline is a numeric vector from the Value column of the table below corresponding to the first occurrence of any of the newline characters in the file. If none of these characters are present, the value is ⍬.

Table 2: Line separators:

Value | Code | Description
newline characters
13 | CR | Carriage Return (U+000D)
10 | LF | Line Feed (U+000A)
13 10 | CRLF | Carriage Return followed by Line Feed
133 | NEL | New Line (U+0085)
other line separator characters
11 | VT | Vertical Tab (U+000B)
12 | FF | Form Feed (U+000C)
8232 | LS | Line Separator (U+2028)
8233 | PS | Paragraph Separator (U+2029)


Native File Information

Native File Information R←{X}⎕NINFO Y

This function returns information about one or more files or directories.

Y may be:

  • a numeric scalar containing the tie number of a native file
  • a character vector or scalar containing a file or directory name that conforms to the naming rules of the host Operating System.
  • a vector of character vectors and/or tie numbers

Variant Options

⎕NINFO may be applied using the Variant operator with the options Wildcard (the Principal option), Recurse and Follow.

Wildcard Option (Boolean)

0 | the name or names in Y identifies a specific file name.
1 | the name or names in Y that specify the base name and extension (see File Name Parts), may also contain the wildcard characters "?" and "*". An asterisk is a substitute for any 0 or more characters in a file name or extension; a question-mark is a substitute for any single character.

Recurse Option (Boolean)

0 | the name(s) in Y are searched for only in the corresponding specified directory
1 | the name(s) in Y are searched for in the corresponding specified directory as well as all sub-directories. If Wildcard is also 1, the wild card search is performed recursively.

The optional left argument X is a simple numeric array containing values shown in the following table.

Follow Option (Boolean)

0 | the properties reported are those of the symbolic link itself
1 | the properties reported for a symbolic link are those of the target of the symbolic link

The optional left argument X is a simple numeric array containing values shown in the following table.

X | Property | Default
0 | Name of the file or directory, as a character vector. If Y is a tie number then this is the name which the file was tied. |
1 | Type, as a numeric scalar: 0=Not known 1=Directory 2=Regular file 3=Character device 4=Symbolic link (only when Follow is 0) 5=Block device 6=FIFO (not Windows) 7=Socket (not Windows) | 0
2 | Size in bytes, as a numeric scalar | 0
3 | Last modification time, as a timestamp in ⎕TS format | 7⍴0
4 | Owner user id, as a character vector – on Windows a SID, on other platforms a numeric userid converted to character format | ''
5 | Owner name, as a character vector | ''
6 | Whether the file or directory is hidden (1) or not (0), as a numeric scalar. On Windows, file properties include a "hidden" attribute; on non-Windows platforms a file or directory is implicitly considered to be hidden if its name begins with a "." | ¯1
7 | Target of symbolic link (when Type is 4) | ''
8 | Current file position | 0
9 | Last access time in ⎕TS format, when available | 7⍴0
10 | Creation time in ⎕TS format, when available | 7⍴0
11 | Whether the file can (1) or cannot (0) be read (¯1 if unknown) | ¯1
12 | Whether the file can (1) or cannot (0) be written (¯1 if unknown) | ¯1

Note that the current file position identifies where ⎕NREAD will next read from or ⎕NAPPEND will next write to and is only pertinent when the corresponding value in Y is a tie number rather than a name. It will be reported as 0 for named files.

Each value in X identifies a property of the file(s) or directory(ies) identified by Y whose value is to be returned in the result R. If omitted, the default value of X is 0. Values in X may be specified in any order and duplicates are allowed. A value in X which is not defined in the table above will not generate an error but results in a ⍬ (Zilde) in the corresponding element of R.

R is the same shape as X and each element contains value(s) determined by the property specified in the corresponding element in X. The depth of R depends upon whether or not the Wildcard option is enabled. If, for any reason, the function is unable to obtain a property value, (for example, if the file is in use exclusively by another process) the default value shown in the last column is returned instead.

If the Wildcard option is not enabled (the default) then Y specifies exactly one file or directory and must exist. In this case each element in R is a single property value for that file. If the name in Y does not exist, the function signals an error. On non-Windows platforms "*" and "?" are treated as normal characters. On Windows an error will be signalled since neither "*" nor "?" are valid characters for file or directory names.

If the Wildcard option is enabled, zero or more files and/or directories may match the pattern in Y. In this case each element in R is a vector of property values for each of the files. Note that no error will be signalled if no files match the pattern.

When using the Wildcard option, matching of names is done case insensitively on Windows and macOS, and case sensitively on other platforms. The names '.' and '..' are excluded from any matches. The order in which the names match is not defined.

Examples

      (0 1 2) ⎕NINFO 'c:/Users/Pete/Documents'
┌→───────────────────────────────────┐
│ ┌→──────────────────────┐          │
│ │c:/Users/Pete/Documents│ 1 163840 │
│ └───────────────────────┘          │
└∊───────────────────────────────────┘

      ⊃1⎕NPARTS '' ⍝ current working directory
c:/Users/Pete/
      (⎕NINFO⍠1)'D*'
┌─────────────────────────────────────┐
│┌───────┬─────────┬─────────┬───────┐│
││Desktop│Documents│Downloads│Dropbox││
│└───────┴─────────┴─────────┴───────┘│
└─────────────────────────────────────┘

      (⎕NINFO⍠1)'Documents/*.zip'
┌──────────────────────┐
│┌────────────────────┐│
││Documents/dyalog.zip││
│└────────────────────┘│
└──────────────────────┘

      ⍪ (0,⍳6) ⎕NINFO 'Documents/dyalog.zip'
┌──────────────────────────────────────────────┐
│Documents/dyalog.zip                          │
├──────────────────────────────────────────────┤
│2                                             │
├──────────────────────────────────────────────┤
│3429284                                       │
├──────────────────────────────────────────────┤
│2016 1 22 16 43 58 0                          │
├──────────────────────────────────────────────┤
│S-1-5-21-2756282986-1198856910-2233986399-1001│
├──────────────────────────────────────────────┤
│HP/Pete                                       │
├──────────────────────────────────────────────┤
│0                                             │
└──────────────────────────────────────────────┘

      ⊃1⎕NPARTS '' ⍝ current working directory
C:/Users/Pete/Documents/Dyalog APL-64 16.0 Unicode Files/
      (⎕NINFO⍠1)'*.*'
┌──────────────────────────────────────────────────────┐
│┌───────────┬──────────┬─────────┬───────────────────┐│
││default.dlf│def_uk.dse│jsonx.dws│UserCommand20.cache││
│└───────────┴──────────┴─────────┴───────────────────┘│
└──────────────────────────────────────────────────────┘

      ⊢ ⎕MKDIR 'd1' 'd2'
1 1
      'a'∘⎕NPUT¨'find' 'd1/find' 'd1/nofind' 'd2/find'
      (⎕ninfo⍠'Recurse' 1)'find'
┌──────────────────────┐
│┌───────┬───────┬────┐│
││d1/find│d2/find│find││
│└───────┴───────┴────┘│
└──────────────────────┘

The following expression will return all Word document (.docx and .doc) in the current directory, searching recursively through any sub-directories:

     (⎕NINFO⍠('Recurse' 1)('Wildcard' 1))'*.docx' '*.doc'

Note

Of the file timestamps, only the last modification time should be considered reliable and portable. Neither the access time or creation time are well supported across all platforms.


Native File Move

Native File Move {R}←X ⎕NMOVE Y

This function moves native files and directories from one or more sources specified by Y to a destination specified by X. ⎕NMOVE is similar to ⎕NCOPY (see Native File Copy ).

When possible ⎕NMOVE renames files and directories, which effects a fast move when the source and destination are on the same file system. By default (see RenameOnly option below), if ⎕NMOVE is unable to rename files or directories, it instead copies them and deletes the originals.

X is a character vector that specifies the name of the destination.

Y is a character vector that specifies the name of the source, or a vector of character vectors containing zero or more sources.

Sources and destinations may be full or relative (to the current working directory) path names adhering to the operating system convention.

If Y specifies more than one source, X must be a character vector that specifies an existent directory to which each of the sources in Y is to be moved.

The shy result R contains count(s) of top-level items moved. If Y is a single source name, R is a scalar otherwise it is a vector of the same length as Y.

Variant Options

⎕NMOVE may be applied using the Variant operator with the options Wildcard (the Principal option), IfExists and RenameOnly.

Wildcard Option (Boolean)

0 | the name or names in Y identifies a specific file name.
1 | the name or names in Y that specify the base name and extension (see File Name Parts), may also contain the wildcard characters "?" and "*". An asterisk is a substitute for any 0 or more characters in a file name or extension; a question-mark is a substitute for any single character.

Note that when Wildcard is 1, element(s) of R can be 0 or >1. If Wildcard is 0, elements of R are always 1.

IfExists Option

The IfExists variant option determines what happens when a source file is to be copied to a target file that already exists. It does not apply to directories, only to the files within them.

Value | Description
'Error' | Existing files will not be overwritten and an error will be signalled. This is the default
'Skip' | Existing files will not be overwritten but the corresponding copy operation will be skipped (ignored).

The following cases cause an error to be signalled regardless of the value of the IfExists variant.

  • If the source specifies a directory and the destination specifies an existing file.
  • If the source specifies a file and the same base name exists as a sub-directory in the destination.

RenameOnly Option (Boolean)

The RenameOnly option determines what happens when it is not possible to rename the source.

0 | the source will be copied and the original deleted
1 | the move will fail

Examples

A number of possibilities exist, illustrated by the following examples. In all cases, if the source is a file, the file is moved. If the source is a directory, the directory and all of its contents are moved.

Examples (single source, Wildcard is 0)

  • The source name must be an existent file or directory.
  • If the destination name does not exist but its path name does exist, the source is moved to the destination name.
  • If the destination name is an existing directory the source name is moved to that directory.

       ⊃1 ⎕NPARTS ''
i:/Documents/Dyalog APL-64 17.0 Unicode Files/

⍝ Rename the Session file
      ⊢'session.dlf' ⎕NMOVE 'default.dlf'
1
      ⊢ ⎕MKDIR 'backups' ⍝ Make a backups directory
1
 ⍝ Move the Session file to backups directory
      ⊢'backups'⎕NMOVE'default.dlf'
1
      ↑⊃0 (⎕NINFO⍠1) 'backups\*'
backups/default.dlf

Examples (single source, Wildcard is 1)

  • The source name may include wildcard characters which matches a number of existing files and/or directories. The destination name must be an existing directory.
  • The files and/or directories that match the pattern specified by the source name are moved into the destination directory. If there are no matches, zero copies are made.
       ⊃1 ⎕NPARTS ''
i:/Documents/Dyalog APL-64 17.0 Unicode Files/

      ⊢ ⎕MKDIR 'backups' ⍝ Make a backups directory
1
⍝ Move all files to backups directory
      ⊢'backups'(⎕NMOVE⍠'Wildcard' 1)'*.*'
3
      ↑⊃0 (⎕NINFO⍠1) 'backups\*'
backups/default.dlf
backups/def_uk.dse
backups/UserCommand20.cache

Examples (multiple sources, Wildcard is 0)

  • Each source name must specify a single file or directory which must exist. The destination name must be an existing directory.
  • Each of the files and/or directories specified by the source base names are moved to the destination directory.
       ⊃1 ⎕NPARTS ''
i:/Documents/Dyalog APL-64 17.0 Unicode Files/

      ⊢ ⎕MKDIR 'backups' ⍝ Make a backups directory
1

⍝ Move 2 files to backups directory
      ⊢'backups'⎕NMOVE'default.dlf' 'def_uk.dse'
1 1
      ↑⊃0 (⎕NINFO⍠1) 'backups\*'
backups/default.dlf
backups/def_uk.dse

Examples (multiple sources, Wildcard is 1)

  • The destination name must be an existing directory.
  • Each of the files and/or directories that match the patterns specified by the source names (if any) are moved to the destination directory.
      ⊃1 ⎕NPARTS ''
i:/Documents/Dyalog APL-64 17.0 Unicode Files/

      ⊢ ⎕MKDIR 'backups' ⍝ Make a backups directory
1
⍝ Move files to backups directory
      ⊢'backups'(⎕NMOVE⍠1)'d*' 'UserCommand20.cache'
2 1
      ↑⊃0 (⎕NINFO⍠1) 'backups\*'
backups/default.dlf
backups/def_uk.dse
backups/UserCommand20.cache

Note

When ⎕NMOVE copies and deletes files:

  • The operation will take longer to complete.
  • File modification times will be preserved but other attributes such as file ownership may be changed.
  • Read permissions will be needed on all files within a directory which is moved.
  • If the operation fails at any point and an error is signalled it is possible that there may be files and/or directories left duplicated in both the source and destination. It is not possible that a file or directory may be removed from the source without having been copied to the destination.


File Name Parts

File Name Parts R←{X} ⎕NPARTS Y

Splits a file or directory name into its constituent parts.

Y is a character vector or scalar containing a single name, or a vector of character vectors containing zero or more names. Names must conform to the file-naming rules of the host Operating System.

The file(s) need not exist; indeed this system function makes no attempt to identify or locate it/them.

The optional left-argument X specifies whether or not the name or names specified by Y are normalised before being processed. The default value 0 means no normalisation; 1 means normalise as follows:

  • Pathnames are made absolute.
  • On Windows, all "\" directory separators are changed to "/".
  • The resultant name is simplified by removing extraneous directory separators etc. On Windows, this includes resolving occurrences of "." and ".." within the name. On non-Windows platforms single "." are removed. Note that ".." and symbolic links interact differently on Windows to other platforms; on other platforms they cannot be removed without reference to the file system itself and are left in place.

If Y is a scalar or vector, the result R is a 3-element vector of character vectors as follows:

[1] | path
[2] | base name
[3] | extension

The path identifies the directory in which the file exists.

The base name is the name of the file stripped of its path and extension, if any.

The extension is the file extension including the leading ".".

If Y is a vector of character vectors, R is a vector of 3-element character vectors and is the same length as Y.

Examples

      ⎕CMD 'CD'⍝ Current working directory
c:\Users\Pete

      1 ⎕NPARTS 'α'
┌→─────────────────────────┐
│ ┌→─────────────┐ ┌→┐ ┌⊖┐ │
│ │c:/Users/Pete/│ │α│ │ │ │
│ └──────────────┘ └─┘ └─┘ │
└∊─────────────────────────┘
      1 ⎕NPARTS '\Users\Pete\Documents\dyalog.zip'
┌→───────────────────────────────────────────┐
│ ┌→───────────────────────┐ ┌→─────┐ ┌→───┐ │
│ │C:/Users/Pete/Documents/│ │dyalog│ │.zip│ │
│ └────────────────────────┘ └──────┘ └────┘ │
└∊───────────────────────────────────────────┘

      ⊃'.'⎕wg'APLVersion'
AIX-64
      1 ⎕nparts'/home/andys/./..'
┌────────────┬──┬┐
│/home/andys/│..││
└────────────┴──┴┘

      1 ⎕NPARTS '.' '..'
┌────────────────┬───────┐
│┌───┬─────────┬┐│┌───┬┬┐│
││i:/│Documents││││i:/││││
│└───┴─────────┴┘│└───┴┴┘│
└────────────────┴───────┘

Note that ⊃1 ⎕NPARTS '' returns the current working directory.

      ⊃1 ⎕NPARTS ''
┌→─────────────┐
│c:/Users/Pete/│
└──────────────┘


Write Text File

Write Text File {R}←X ⎕NPUT Y

This function writes character data to a text file. See also Read Text File.

Y is either a simple character vector or scalar containing the name of the file to be written, or a 2-item vector whose first item is the file name and whose second is an integer scalar specifying flags for the operation.

If flags is 0 (the default value if omitted) the file will not be overwritten if it already exists and ⎕NPUT will signal an error. If flags is 1 the file will be overwritten. If flags is 2 the file will be appended to; i.e.

flags | file does not exist | file exists
0 | data is written to new file | error signalled, file is unchanged
1 | data is written to new file | file is overwritten
2 | data is written to new file | data is appended to file

The left-argument X is comprised of 1, 2 or 3 items which identify (content) (encoding) (newline) respectively.

content is either a vector of character vectors, each of which represents a line in the file to be written, or a simple character vector.

If specified, encoding is either:

  • a character vector from the first column in the table File Encodings. If encoding specifies a UTF format, it may be qualified with -BOM (e.g. UTF-8-BOM), which causes a Byte Order Mark (BOM) to be written at the beginning of the file or -NOBOM which does not. If the -BOM or -NOBOM suffix is omitted, UTF-8 defaults to UTF-8-NOBOM, while the other UTF formats default to -BOM.
  • a 256-element numeric vector that maps each possible byte value (0-255) to a Unicode code point (1st element = Unicode code point corresponding to byte value 0, and so on). ¯1 indicates that the corresponding byte value is not mapped to any character. Apart from ¯1, no value may appear in the table more than once.

If omitted, encoding defaults to UTF-8-NOBOM.

Note: If a non-empty file is appended to:

  • No BOM will be written, even if encoding specifies it.
  • No check is made that the existing file content is text in the same encoding format.

If specified, newline is numeric and is either ⍬ or a scalar or vector from the column labelled Value in the newline characters section of the table Line separators:. Any other value causes DOMAIN ERROR. If newline is omitted it defaults to (13 10) on Windows and 10 on other platforms.

If content is nested, each element is considered to be to a logical line in the file, and when the file is written, a line separator character corresponding to newline is appended to each and every element, i.e. the data written to the file (excluding the BOM) is:

      ∊content,¨⊂⎕UCS newline

If content is simple each and every LF (⎕UCS 10) character that it contains is first replaced by the character corresponding to newline. If not present, one LF character is added to the end of the array prior to these replacements.

In both cases, any other line separator characters are written as is to the file. This allows the APL programmer to insert other line endings if so desired.

If content contains anything other than a character vector or scalar (or these, nested) then a DOMAIN ERROR is signalled.

The shy result R is the number of bytes written to the file.

Note that when content is a vector of character vectors and encoding is omitted; it is necessary to enclose the left argument.

Example:

      txt←'mene' 'mene' 'tekel' 'upharsin'
      ⎕←(⊂txt) ⎕NPUT 'writing.txt'
25
      ⊢(⊂'adding' '3' 'lines')⎕NPUT'writing.txt' 2
18


Changes to I-Beams

I-beam Changes

I-beam functionality changed from Version 16.0.

A | Description | Change
201 | Syntax Colour Tokens | New function
739 | Temporary Directory | New function
5177 | List Loaded File Objects | Now reports file check sum and last modification time
5178 | Remove Loaded File Object Info | New function
5179 | Loaded File Object Info | New function
7159 | JSON Import | Removed (replaced by ⎕JSON)
7160 | JSON Export | Removed (replaced by ⎕JSON)
7161 | JSON TrueFalse | Removed (replaced by ⎕JSON)


Syntax Colour Tokens

Syntax Colour Tokens R←201⌶Y

This function provides a description of the syntax colour tokens reported by 200⌶. See This function obtains syntax colouring information for a function.

Y is ⍬ (zilde).

R is a 3-column matrix that describes the syntax colouring tokens as follows:

R[;1] | Token type
R[;2] | Token Value
R[;3] | Internal description

Example

      ⍴201⌶⍬
207 3
      3 3↑201⌶⍬
┌────────────┬─┬────────────┐
│Global token│0│MINI_NULL   │
├────────────┼─┼────────────┤
│Global token│1│MINI_COMMENT│
├────────────┼─┼────────────┤
│Global token│2│MINI_UCC    │
└────────────┴─┴────────────┘


Temporary Directory

Temporary Directory R←739⌶Y

Returns the name of a system temporary directory suitable for user files, as a character vector. The name reported does not include a trailing directory separator

Y is 0.

The result R is a character vector.

Example (Windows)

      739⌶0
C:/Users/Pete/AppData/Local/Temp

Example (non-Windows)

      739⌶0
/tmp


Remove Loaded File Object Info

Remove Loaded File Object Info R←5178⌶Y

The editor may be used to edit Dyalog script files (.dyalog files) and general text files and to save the contents in the workspace. Additionally ⎕FIX can be used to fix scripts held in files. This I-Beam removes the information held about an object in the workspace specified by Y that is associated with such a file.

Y is a character vector that specifies the name of a workspace object or a ref to an object.

R is Boolean. 1 means that the information was removed; 0 that it wasn't.

Note that the workspace object itself remains in the workspace; just the information about its associated file is removed.

Examples:

      dyalog←2 ⎕NQ '.' 'GetEnvironment' 'DYALOG'
      aedit←'/SALT/spice/aedit.dyalog'
      ⊢⎕FIX 'file://',dyalog,aedit
#.arrayeditor
      5178⌶'arrayeditor'
1
      5178⌶'xyz' ⍝ unused name
0


Loaded File Object Info

Loaded File Object Info R←5179⌶Y

The editor may be used to edit Dyalog script files (.dyalog files) and general text files and to save the contents in the workspace. Additionally ⎕FIX can be used to fix scripts held in files. This I-Beam returns details about an object in the workspace specified by Y that is associated with such a file.

Y is a character vector that specifies the name of a workspace object or a ref to an object.

R is an 8-element vector containing the following information pertaining to the object and

Element | Contains
1 | Object name or ref (Y)
2 | Parent namespace
3 | Name class (see ⎕NC)
4 | File name
5 | Start line (first line in file, 0 origin, of the object)
6 | Line count (number of lines in file occupied by the object)
7 | File Checksum
8 | File modification time (⎕TS format)

If an object occupies a file in its entirety, both Start line and Line count are 0.

Examples:

      dyalog←2 ⎕NQ '.' 'GetEnvironment' 'DYALOG'
      aedit←'/SALT/spice/aedit.dyalog'
      ⊢⎕FIX 'file://',dyalog,aedit
#.arrayeditor
      1 1 1 0 1 1 1 1/ 5179⌶'arrayeditor'
┌─────────────┬─┬─┬─┬─┬────────┬───────────────────┐
│#.arrayeditor│#│9│0│0│008fe4ed│2018 5 11 8 56 10 0│
└─────────────┴─┴─┴─┴─┴────────┴───────────────────┘
      1 1 1 0 1 1 1 1/ 5179⌶'arrayeditor.List'
┌────┬─────────────┬─┬──┬─┬────────┬───────────────────┐
│List│#.arrayeditor│3│22│5│008fe4ed│2018 5 11 8 56 10 0│
└────┴─────────────┴─┴──┴─┴────────┴───────────────────┘
      5179⌶'xyz' ⍝ unused name
┌┬──────┬─┬┬─┬─┬────────┬────────────────┐
││[Null]│0││0│0│00000000│1970 1 1 0 0 0 0│
└┴──────┴─┴┴─┴─┴────────┴────────────────┘


CellMove Event

CellMove Event 151
Applies To: Grid

Description

If enabled, this event is reported when the user attempts to position the cursor over a cell in a Grid by clicking the left mouse button or by pressing a cursor movement key. The purpose of this event is to allow an application to perform some action prior to the user entering a cell, to inhibit entry to a cell, or to deny exit from the current cell.

The default action is to position the user on the new cell. This action can be prevented by returning a 0 from the callback function attached to the event.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is an 8 element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CellMove' or 151
[3] | New cell row | integer
[4] | New cell column | integer
[5] | Scroll flag | 0 or 1
[6] | Selection flag | 0, 1 or 2
[7] | Mouse flag | 0 or 1
[8] | Changed flag | 0 or 1 (relates to current cell)
[9] | New value | new value of current cell or ⍬

The 5th element of the event message is 1 if switching to the new cell would cause the Grid to scroll.

The 6th element of the event message is 1 if the user is moving to the new cell by extending the selection. It is 2 if the user selects an entire row or column (by clicking on a title), which moves the current cell to the first one in the selection.

The 7th element of the event message is 1 if the mouse is used to switch to a new cell.

The 8th element of the event message is 1 if the user is attempting to move to the new cell from another cell in the Grid having typed in (as if to alter) the current cell.

The 9th element of the event message is the intended new value in the current cell or ⍬ (zilde) if Changed flag is 0.

The CellMove event may be used to validate and refuse changes as the user navigates between cells. See also CellChange.

An application can position the user on a particular cell in a Grid by calling CellMove as a method. If so, the argument need contain only the New cell row and New cell column parameters.


UNIX Specific Release Notes

Summary

This section summarises the changes specific to Dyalog APL Version 17.0 on non-Windows platforms. This list currently consists of:

  • AIX
  • Linux (including the Raspberry Pi)
  • macOS/ Mac OS X

Hardware Requirements

AIX

For AIX, Version 17.0 requires AIX 7.2 or higher, and a POWER7 chip or higher.

Raspberry Pi

On the Raspberry Pi, Dyalog 32-bit Unicode supports Raspbian Jessie or later.

Non-Pi Linux

For non-Pi Linux, Version 17.0 only exists as 64-bit interpreters - there are no 32-bit versions. It is built on Debian 7, and QAed on RedHat 6; it runs on all recent distributions, including Ubuntu 14.04 and openSUSE Leap 42.3. Contact Dyalog for information about other distributions.

macOS/Mac OS X

Version 17.0 requires Mac OS X Yosemite or El Capitan or macOS Sierra or later. The target Mac must have been introduced in 2010 or later.

RIDE and Dyalog APL 17.0

Dyalog Version 17.0 supports RIDE 3 and RIDE 4 only; RIDE 2 is not supported. Dyalog recommends that RIDE 4 is used in preference to RIDE 3. RIDE 4 can be used with Version 15.0 too.

RIDE 4 is supported on Raspberry Pi models 2 and 3 only; models Zero and 1 are not supported (the underlying libraries which RIDE is built on are not available for the Pi Zero and 1). The Dyalog RIDE Reference Guide details how to configure the APL session to support the underscored alphabet; contact support@dyalog.com if you wish to be able to generate key-chords which result in the underscored alphabet being entered into APL.

Note that on Linux and Pi, if RIDE 4 is installed after Dyalog 16.0 an extra icon will be added to the window manager's start menu which will start Dyalog with a RIDE front end.

Location of configuration and log files

In Dyalog 17.0 the location of various configuration and log files has been changed so that they are all put in one directory. See the UNIX Installation and Configuration Guide for more information.

SQAPL on macOS

Dyalog 17.0 for macOS includes support for SQAPL. However, it is necessary to install iODBC and suitable drivers for your database before SQAPL can work. The SQL Interface Guide describes the steps that are typically necessary to get SQAPL connected to a MySQL database.

4000⌶ and 4002⌶

4000⌶ (Fork process) and 4002⌶ (Reap processes) have been withdrawn on all platforms except AIX. This is due to limitations imposed by the HTMLRenderer, and due to problems in the interaction of forking processes and using RIDE.


Documentation

The documentation set for Dyalog is installed in the help sub-directory of the main Dyalog installation directory.

The latter is given by the expression:

      ⎕←2 ⎕NQ'.' 'GetEnvironment' 'DYALOG'
C:\Program Files\Dyalog\Dyalog APL-64 15.0 Unicode

Example:

      dyalog←2⎕nq'.' 'GetEnvironment' 'DYALOG'
      ⎕cmd 'dir "',dyalog,'/help"'
 Volume in drive C is OS
 Volume Serial Number is 3013-866E

 Directory of C:\Program Files\Dyalog\Dyalog APL-64 15.0 Unicode\help

18/01/2016  11:53    <DIR>          .
18/01/2016  11:53    <DIR>          ..
11/01/2016  17:20           182,965 APL Workspace Transfer Guide.pdf
11/01/2016  17:20           467,005 Application Tuning Guide.pdf
11/01/2016  17:20           587,605 Code Libraries Reference Guide.pdf
11/01/2016  17:20           249,461 Compiler User Guide.pdf
11/01/2016  17:20           451,949 Conga User Guide.pdf
...


Files and Directories

Unicode and Classic Editions

Dyalog APL continues to be available in two separate editions; Unicode and Classic.

  • The Unicode edition is intended for users who need to develop Unicode applications now, and are prepared to make the necessary (usually small) changes to existing applications in order to support new Unicode character types.
  • The Classic edition is intended for customers who want to take advantage of other product enhancements, but do not wish to use Unicode at this time.

The two different editions are maintained from the same source code, and every effort will be made to ensure that they are identical except for the handling of character arrays, and the transfer of data into and out of the workspace.

32-Bit and 64-Bit Versions

Two separate versions of Dyalog for Microsoft Windows are available. The 32-bit version will run on both 32-bit and 64-bit Operating Systems; the 64-bit version will only run on a 64-bit Operating System.

Files

The following tables show files that are included in the different versions and editions under Microsoft Windows. These are referred to in the remainder of this document and in other documents by the name shown in the first column of the tables.

With the exception of the following all these files may be distributed as part of end-user applications, under the terms and conditions of a Dyalog APL Run-Time Agreement. Please contact Dyalog or your distributor, or see the Dyalog web page for more information.

Non-Distributable Development Components

  • Development EXE
  • Development DLL
  • Array Editor

Name | File
32-bit Unicode | Dyalog APL 17.0Unicode\
Development EXE | dyalog.exe
Development DLL | dyalog170_32_unicode.dll
Array Editor | dlaedit32.dll
Run-Time EXE | dyalogrt.exe
Run-Time DLL | dyalog170rt_unicode.dll
Bridge DLL | bridge170_unicode.dll
Dyalog DLL | dyalog32.dll
DyaRes DLL | dyares170_32.dll
DyalogProvider DLL | dyalogprovider.dll
DyalogNet DLL | dyalognet.dll
APLScript Compiler | dyalogc_unicode.exe
For Conga and RIDE | conga30ssl32.dll
For Conga and RIDE | conga30_32.dll
 | exestub.dll
 | dllstub.dll
SQAPL INI | sqapl.ini
SQAPL ERR | sqapl.err
SQAPL DLL | cwdya62u32w.dll
APLUNICD INI | aplunicd.ini
 | sharpplot.dll
 | sharpplot.xml
32-bit Classic | Dyalog APL 17.0 Classic\
Development EXE | dyalog.exe
Development DLL | dyalog170_32.dll
Array Editor | dlaedit32.dll
Run-Time EXE | dyalogrt.exe
Run-Time DLL | dyalog170rt.dll
Bridge DLL | bridge170.dll
Dyalog DLL | dyalog32.dll
DyaRes DLL | dyares170_32.dll
DyalogProvider DLL | dyalogprovider.dll
DyalogNet DLL | dyalognet.dll
APLScript Compiler | dyalogc.exe
For Conga and RIDE | conga30ssl32.dll
For Conga and RIDE | conga30_32.dll
 | exestub.dll
 | dllstub.dll
SQAPL INI | sqapl.ini
SQAPL ERR | sqapl.err
SQAPL DLL | cwdya62c32w.dll
APLUNICD INI | aplunicd.ini
 | sharpplot.dll
 | sharpplot.xml
64-bit Unicode | Dyalog APL-64 17.0 Unicode\
Development EXE | dyalog.exe
Development DLL | dyalog170_64_unicode.dll
Array Editor | dlaedit64.dll
Run-Time EXE | dyalogrt.exe
Run-Time DLL | dyalog170_64rt_unicode.dll
Bridge DLL | bridge170-64_unicode.dll
Dyalog DLL | dyalog64.dll
DyaRes DLL | dyares170_64.dll
DyalogProvider DLL | dyalogprovider.dll
DyalogNet DLL | dyalognet.dll
APLScript Compiler | dyalogc64_unicode.exe
For Conga and RIDE | conga30ssl64.dll
For Conga and RIDE | conga30_64.dll
 | exestub.dll
 | dllstub.dll
SQAPL INI | sqapl.ini
SQAPL ERR | sqapl.err
SQAPL DLL | cwdya62u64w.dll
APLUNICD INI | aplunicd.ini
 | sharpplot.dll
 | sharpplot.xml
64-bit Classic | Dyalog APL-64 17.0 Classic\
Development EXE | dyalog.exe
Development DLL | dyalog170_64.dll
Array Editor | dlaedit64.dll
Run-Time EXE | dyalogrt.exe
Run-Time DLL | dyalog170_64rt.dll
Bridge DLL | bridge170-64.dll
Dyalog DLL | dyalog64.dll
DyaRes DLL | dyares170_64.dll
DyalogProvider DLL | dyalogprovider.dll
DyalogNet DLL | dyalognet.dll
APLScript Compiler | dyalogc64.exe
For Conga and RIDE | conga30ssl64.dll
For Conga and RIDE | conga30_64.dll
 | exestub.dll
 | dllstub.dll
SQAPL INI | sqapl.ini
SQAPL ERR | sqapl.err
SQAPL DLL | cwdya62c64w.dll
APLUNICD INI | aplunicd.ini
 | sharpplot.dll
 | sharpplot.xml

File Naming Conventions

The following file naming conventions have been adopted for the various files distributed with and used by Dyalog APL.

Extension | Description
.dws | Dyalog APL Workspace
.dse | Dyalog APL Session
.dcf | Dyalog APL Component File
.DXV | Dyalog APL External Variable
.din | Dyalog APL Input Table
.dot | Dyalog APL Output Table
.dft | Dyalog APL Format File
.DXF | Dyalog APL Transfer File
.dlf | Dyalog APL Session Log File
.dyalog | Dyalog APL SALT file
.dyapp | Dyalog APL SALT application file

Note that some of these extensions, notably .dcf, .dlf, .dot and .DXF, are not unique to Dyalog and conflict with the same extensions used by other software applications. Although all the above file extensions are associated with Dyalog during its installation, these associations may subsequently be changed by the installation of other software or by a Windows System restore.


APL Fonts

Unicode Edition

The default font for the Unicode Edition is APL385 Unicode The Dyalog Std TT, Dyalog Alt TT, and APL385 Unicode fonts are the copyright of Adrian Smith. 1 which is a TrueType font and is installed as part of Dyalog APL. APL385 Unicode is the font used to print APL characters in this manual. In principle, you may use any other Unicode font that includes the APL symbols, such as Arial Unicode MS (available from Microsoft).

Classic Edition

In the Classic Edition, there are two types of APL font provided; bitmap (screen) and TrueType. There are also two different layouts, which are referred to as Std and Alt.

The bitmap fonts are designed for the screen alone and are named Dyalog Std and Dyalog Alt. The TrueType fonts have a traditional 2741-style italic appearance and are named Dyalog Std TT and Dyalog Alt TT1.

The Std layout, which was the standard layout for Versions of Dyalog APL up to Version 10.1 contains the APL underscored alphabet Ⓐ-Ⓩ. The underscored alphabet is a deprecated feature and is only supported in this Version of Dyalog APL for backwards compatibility.

The Alt layout, which replaced the Std layout as the standard layout for Version 12.0 Classic Edition onwards, does not have the underscored alphabet, but contains additional National Language characters in their place. Note that the extra National Language symbols share the same ⎕AV positions with the underscored alphabet. If, for example, you switch from the Std font layout to the alternative one, you will see the symbol Á (A-acute) instead of the symbol Ⓐ (A-underscore).

You may use either a bitmap font or a TrueType font in your APL session (see UI Guide: Session Operations Session Operations for details). You MUST use a TrueType font for printing APL functions.


The APL Command Line

The command line for Dyalog APL is described below; the command line for non-Windows versions of Dyalog APL is very similar and is also documented in Dyalog for UNIX UI Guide: Starting APL.

Usually the command line is specified in the Target: field of the APL shortcut. The full pathname to the Dyalog executable is usually surrounded by double quotes as it contains spaces.

Command Line

dyalog [ options ] [ debug ] [ ws ] [param] [param] [param]...

where:

[dyalog]

Is the location of the Dyalog executable. Usually this is the full pathname, surrounded by double quotes.

[options]

-x | No ⎕LX execution on workspace loads.
-a | Start in USER mode.
-b | Suppress the banner in the Session..
-s | Disable the Session. This option is ignored in Windows versions.
-q | Don't quit APL on error (used when piping input into APL).
-c | Signifies a command-line comment. All characters to the right are ignored.
-cef | Instructs Dyalog to ignore the parameter that immediately follows. This is designed to isolate parameters intended for the Chromium Embedded Framework (CEF)

[debug]

-Dc | Check workspace integrity after every callback function.
-Dw | Check workspace integrity on return to session input.
-DW | Check workspace integrity after every line of APL (application will run slowly as a result)
-DK | Log session keystrokes in (binary) file ./apllog.

[ws]

The name of a Dyalog APL workspace to be loaded. Unless specified, on Windows the file extension .DWS is assumed.

[param]

A parameter name followed by an equals sign (=) and a value. The parameter name may be one of the standard APL parameters (see Configuration Parameters) or a name and value of your own choosing (see GetEnvironment). Note that this differs from Dyalog APL under UNIX, where parameters must be passed as environment variables.

Examples:

"c:\program files\…\dyalog.exe" myapp maxws=64000
"c:\program files\…\dyalog.exe" session_file=special.dse
"c:\program files\…\dyalog.exe -x myapp aplt=mytrans.dot default_io=0 myparam=42"


APL Exit Codes

When APL or a bound .EXE terminates, it returns an exit code to the calling environment. If APL is started from a desktop icon, the return code is ignored. However, if APL is started from a script (UNIX) or a command processor, the exit code is available and may be used to determine whether or not to continue with other processing tasks. The return codes are:

0 | Successful ⎕OFF, )OFF, )CONTINUE, graphical exit from GUI
1 | APL failed to start. This will occur if there was a failure to read a translate file, there is insufficient memory, or a critical parameter is incorrectly specified or missing.
2 | APL was terminated by SIGHUP or SIGTERM (UNIX) or in response to a QUIT WINDOWS request. APL has done a clean exit.
3 | APL issued a syserror.
4 | Runtime violation. This occurs if a runtime application attempts to read input from the Session. Only a development version has a Session.
5 | APL was unable to load the Conga libraries (14.1.25383 onwards). In 16.0 the RIDE libraries have been included in the Conga libraries.
6 | RIDE_INIT or one of its components was ill-defined, or APL was unable to use the port, and/or unable to resolve the hostname (14.1.25383 onwards)
7 | Reserved
8 | Windows rejected APL's request to create a session window (in earlier versions this generated a syserror 126)
9 | Dyalog has encountered a Microsoft Windows-related error when starting and is unable to continue. For example it cannot register clipboard formats.
10 | CEF sub-process crash - something has gone unexpectedly wrong with either the HTMLRenderer or CEF sub-processes and cannot continue
11 | Cannot create c-stack (macOS only)

Notes:

Under UNIX exit codes greater than 127 indicates (127+signal number) of the untrapped signal which caused the process to terminate.

APL applications can generate a custom return code by specifying an integer value to the right of ⎕OFF. Dyalog recommends using values greater than 12 for this purpose.


Configuration Parameters

Introduction

Dyalog APL is customised using a set of configuration parameters which are defined in a registry folder.

In addition, parameters may be specified as environment variables or may be specified on the APL command line.

Furthermore, you are not limited to the set of parameters employed by APL itself as you may add parameters of your own choosing.

Although for clarity parameter names are given here in mixed case, they are case-independent under Windows. Under UNIX and Linux, Dyalog parameters must be specified as environment variables and must be named entirely in upper-case.

Setting Parameter Values

You can change the parameters in 4 ways:

  • Using the Configuration dialog box that is obtained by selecting Configure from the Options menu on the Dyalog APL/W session. See The Configuration Dialog Box for details.
  • By directly editing the Windows Registry using REGEDIT.EXE or REGEDIT32.EXE.
  • By defining the parameters as environment variables.
  • By defining the parameters on the APL command line.

This scheme provides a great deal of flexibility, and a system whereby you can override one setting with another. For example, you can define your normal workspace size (maxws) in the Registry, but override it with a new value specified on the APL command line. The way this is done is described in the following section.

How APL Obtains Parameter Values

When Dyalog APL/W requires the value of a parameter, it uses the following rules.

  1. If the parameter is defined on the APL command line, this value is used.
  2. Otherwise, APL looks for an environment variable of the same name and uses this value.
  3. Otherwise, if the parameter in question is inifile, the default value of Software\Dyalog\Dyalog APL/W 17.0 Unicode (Unicode Edition) or Software\Dyalog\Dyalog APL/W 17.0 Classic (Classic Edition) is assumed.
  4. Otherwise, if the parameter in question is dyalog, the name of the directory from which the Dyalog APL program was loaded is assumed.
  5. The value of any other parameter is obtained from the registry folder defined by the value of inifile.

Note that the value of a parameter obtained by the GetEnvironment method (see GetEnvironment) uses exactly the same set of rules.

The following section details those parameters that are implemented by Registry Values in the top-level folder identified by inifile. Values that are implemented in sub-folders are mainly internal and are not described in detail here. However, any Value that is maintained via a configuration dialog box will be named and described in the documentation for that dialog box in The APL Environment.

Specifying Size-related Parameters

Several of the configuration parameters define sizes.

The value of the parameter must consist of an integer value, optionally followed immediately by a single character which denotes the units to be used. If the value contains no character the units are assumed to be KiB.

Valid values for units are:

K(KiB), M(MiB), G(GiB), T(TiB), P(PiB) and E(EiB).

Specifying an invalid value will prevent Dyalog APL from starting.

AddClassHeaders

This parameter specifies what the Tracer displays when tracing the execution of a function in a script. If set to 1, the Tracer displays just the first line of the script and the function in question. If set to 0, the entire script is shown in the Tracer window.

APL_CODE_E_MAGNITUDE

The introduction of decimal floating point numbers lead to the maximum allowable print precision being increased from 17 to 34, which resulted in a change in the way numbers in the range (10*17) to (10*34) in function bodies are descannedDescanning refers to the internal process used to convert the internal representation of APL code into a character array. For numbers in function statements, this process uses the maximum value of Print Precision. 1. For example, the number one sextillion (1021) in a function is descanned by Version 12.1 as 1E21 and by Version 13.0 as 1000000000000000000000.

Whilst this change has no other deleterious effect, it means that code that contains such numbers is harder to read, and the result of ⎕CR (and other character representations) of the same function may have changed between Version 12.1 and later versions of Dyalog causing undesired affects in code management systems.

The APL_CODE_E_MAGNITUDE parameter allows the user to choose between the behaviour seen in Version 12.1 and earlier and in more recent behaviour. It also allows the user to specify the size of numbers above which those numbers are display in exponential format.

If the APL_CODE_E_MAGNITUDE parameter is undefined or set to 0 (the default), numbers are descanned and displayed as normal.

If APL_CODE_E_MAGNITUDE has the value -1, numbers greater than or equal to 1017 will be displayed using exponential format, as in Version 12.1.

If APL_CODE_E_MAGNITUDE has a value between 2 and 34, numbers greater than or equal to 10value will be displayed using exponential format.

The effect of setting this parameter to any other value is undefined.

APL_COMPLEX_AS_V12

Support for Complex Numbers means that some functions produce different results from older Versions of Dyalog APL. If APL_COMPLEX_AS_V12 is set to 1 the behaviour of code developed using Version 12.1 or earlier will be unchanged; in particular:

  • Power (*) and logarithm (⍟) do not produce Complex Numbers as results from non-complex arguments.
  • ⎕VFI will not honour "J" or "j" as part of a number.
  • ¯4○Y will be evaluated as (¯1+Y*2)*0.5, which is positive for negative real arguments.

If APL_COMPLEX_AS_V12 is set to any other value or is not set at all then code developed using version 12.1 or earlier may now generate Complex Numbers.

In addition, if APL_COMPLEX_AS_V12 is set to 1, objects containing complex numbers cannot be transferred to or from component files, TCP/IP (CONGA), or auxiliary processors and may not be used as an argument to Serialise/Deserialise Array (220⌶). Instead, a DOMAIN ERROR will be issued.

Note that this feature is provided to simplify the transition of older code to currently supported Versions of Dyalog APL. It does not prevent the generation and use of Complex Numbers using newer features (such as explicitly specifying a Complex Number literal), and the intention is that it will be removed in a future release of Dyalog APL.

APL_FCREATE_PROPS_C

This parameter specifies the default checksum level for newly-created component files. If unspecified, the default checksum level is 1.

APL_FCREATE_PROPS_J

This parameter specifies the default journaling level for newly-created component files. If unspecified, the default journaling level is 1.

APL_FAST_FCHK

This parameter specifies whether Dyalog APL should optimise ⎕FCHK by allowing it to reliably determine whether a component file had been properly untied and therefore does not need to be checked (this is overridable using the ⎕FCHK option 'force').

Optimising ⎕FCHK in this way has a performance impact on ⎕FUNTIE and it is recommended this optimisation is switched off if your application frequently ties and unties files.

Note: this only affects component files with journaling enabled.

The values of the parameter are:

0 | Do not optimise ⎕FCHK (optimise ⎕FUNTIE instead)
1 | Optimise ⎕FCHK

The default value of the parameter is 0 on all platforms. On Windows, setting the value 1 has no effect.

APL_MAX_THREADS

Specifies the maximum number of system threads that are to be used for parallel execution. The default is the number of virtual processors that the computer is configured to have and the maximum value is 64.

AplCoreName

This parameter specifies the directory and name of the file in which aplcore should be saved. The optional wild-card character (*) is replaced by a number when the file is written. If there is more than one "*" in AplCoreName, the string is used as is; no substitution is made. See MaxAplCores

Note that APL terminates with an exit code of 3 when an aplcore file is generated.

aplk (Classic Edition Only)

This parameter specifies the name of your Input Translate Table, which defines your keyboard layout. The keyboard combo in the Configure dialog box displays all the files with the .DIN extension in the APLKEYS sub-directory. You may choose any one of the supplied tables, and you may add your own to the directory. Note that the FILE.DIN table is intended for input from file, and should not normally be chosen as a keyboard table.

aplkeys (Classic Edition Only)

This parameter specifies a search path for the Input Translate Table and is useful for configuring a run-time application. The directory paths are specified using Operating System specific conventions and separated by ";" (Windows) or ":" (UNIX). Its default value is the aplkeys sub-directory of the directory in which Dyalog APL/W is installed (defined by dyalog).

aplnid

Under Windows, this parameter specifies the user number that is used by the component file system to control file sharing and security. If you wish to share component files and/or external variables in a network it is essential that each user has a unique aplnid parameter. It may be any integer in the range 0 to 65535. Note that an aplnid value of 0 causes the user to bypass APL's access control matrix mechanism.

Under UNIX, the user number is obtained from the Operating System (UID) and aplnid is not used. If the user is "root", APL's access control mechanism is ignored.

When a user creates a component file, his user number is recorded in the file to identify him as its owner.

aplt

This parameter specifies the name of the Output Translate Table. On Windows the default is WIN.DOT and there is rarely a need to alter it.

apltrans

This parameter specifies a search path for the Output Translate Table and is useful for configuring a run-time application. The directory paths are specified using Operating System specific conventions and separated by ";" (Windows) or ":" (UNIX). Its default value is the sub-directory apltrans in the directory in which Dyalog APL/W is installed.

auto_pw

This parameter specifies whether or not the value of ⎕PW is derived automatically from the current width of the Session Window. If auto_pw is 1, the value of ⎕PW changes whenever the Session Window is resized and reflects the number of characters that can be displayed on a single line. If auto_pw is 0 (the default) ⎕PW is independent of the Session Window size.

AutoDPI

This parameter determines whether or not the Dyalog program registers the application as DPI-Aware when it initialises. If 1, (the default), Dyalog performs the auto-scaling; if 0, scaling is the responsibility of the programmer or operating system.

AutoFormat

This parameter specifies whether or not you want automatic formatting of Control Structures in functions. The default value is 1 which means that formatting is done automatically for you when a function is opened for editing or converted to text by ⎕CR, ⎕NR and ⎕VR. Automatic formatting first discards all leading spaces in the function body. It then prefixes all lines with a single space except those beginning with a label or a comment symbol (this has the effect of making labels and comments stand out). The third step is to indent Control Structures. The size of the indent depends upon the TabStops parameter. To turn off automatic formatting, set AutoFormat to 0.

AutoIndent

This parameter specifies whether or not you want semi-automatic indenting during editing. The default value is 1. This means that when you enter a new line in a function, it is automatically indented by the same amount as the previous line. This option simplifies the entry of indented Control Structures.

CFEXT

This parameter specifies component file filename extensions.

CFEXT is a string that specifies a colon-separated list of one or more extensions, including any period (".") which separates the extension from its basename.

If undefined, CFEXT defaults to .dcf: on Windows and OS X, and .dcf:.DCF: on all other platforms.

In the Windows case, this means that 'myfile'⎕FTIE 0 will search first for a file named myfile.dcf, and then for a file named myfile (with no extension). As file names are not case-sensitive under Windows, this will find myfile.DCF or MyFile.Dcf and so forth. If none are found with this extension, it will load myfile, MyFile, MYFILE etc.

In the second (non-Windows) case note that 'myfile'⎕FTIE 0 will search first for a file named myfile, then myfile.dcf, then myfile.DCF.

ClassicMode

This parameter specifies whether or not the Session operates in Dyalog Classic mode. The default is 0. If this parameter is set to 1, the Editor and Tracer behave in a manner that is consistent with earlier versions of Dyalog APL.

ClassicModeSavePosition

This parameter specifies whether or not the current size and location of the first of the editor and tracer windows are remembered for next time. It applies only when Classic Mode is enabled.

The size and location of the windows are saved in the registry in the subfolder WindowRects/EditWindow and TraceWindow.

CMD_PREFIX and CMD_POSTFIX

These parameters defines strings within which operating system commands specified as the arguments to ⎕CMD and ⎕SH, and )CMD and )SH, are wrapped. Its purpose is to run the command arguments under a non-standard command shell. This applies to Windows only.

See Windows Command for implementation details.

confirm_abort

This parameter specifies whether or not you will be prompted for confirmation when you attempt to abort an edit session after making changes to the object being edited. Its value is either 1 (confirmation is required) or 0. The default is 0.

confirm_close

This parameter specifies whether or not you will be prompted for confirmation when you close an edit window after making changes to the object being edited. Its value is either 1 (confirmation is required) or 0. The default is 0.

confirm_fix

This parameter specifies whether or not you will be prompted for confirmation when you attempt to fix an object in the workspace after making changes in the editor. Its value is either 1 (confirmation is required) or 0. The default is 0.

confirm_session_delete

This parameter specifies whether or not you will be prompted for confirmation when you attempt to delete lines from the Session Log. Its value is either 1 (confirmation is required) or 0. The default is 1.

default_div

This parameter specifies the value of ⎕DIV in a clear workspace. Its default value is 0.

default_io

This parameter specifies the value of ⎕IO in a clear workspace. Its default value is 1.

default_ml

This parameter specifies the value of ⎕ML in a clear workspace. Its default value is 1.

default_pp

This parameter specifies the value of ⎕PP in a clear workspace. Its default value is 10.

default_pw

This parameter specifies the value of ⎕PW in a clear workspace. Note that ⎕PW is a property of the Session and the value of default_pw is overridden when a Session file is loaded.

default_rtl

This parameter specifies the value of ⎕RTL in a clear workspace. Its default value is 0.

default_wx

This parameter specifies the value of ⎕WX in a clear workspace. This in turn determines whether or not the names of properties, methods and events of GUI objects are exposed. If set (⎕WX is 1), you may query/set properties and invoke methods directly as if they were variables and functions respectively. As a consequence, these names may not be used for global variables in GUI objects.

DMXOUTPUTONERROR

This parameter specifies in which windows DMX error messages are displayed. It is an integer whose value is the sum of the specified windows where 1 = Status Window and 2 = Session Window.

DockableEditWindows

This parameter specifies whether or not individual edit windows can be undocked from (and docked back into) the (MDI) Editor window. Its default value is 0. This parameter does not apply if ClassicMode is set to 1.

DoubleClickEdit

This parameter specifies whether or not double-clicking over a name invokes the editor. Its default is 1. If DoubleClickEdit is set to 0, double-clicking selects a word and triple-clicking selects the entire line.

dyalog

This parameter specifies the name of the directory in which Dyalog APL is installed.

DyalogEmailAddress

This parameter specifies the contact email address for Dyalog Limited.

DYALOG_EVENTLOGGINGLEVEL

This parameter applies under Windows only, and specifies whether a log entry is written to the Windows Event Log or not when Dyalog APL would pop up a message box due to an unexpected termination of Dyalog APL. See Handling Unexpected Application Errors in Windows for more information.

DYALOG_EVENTLOGNAME

This parameter applies under Windows only, and is either the name of the event log to which an event message will be written, or the source of the event message (depending on the registry entries which may or may not have been defined) when Dyalog APL would pop up a message box due to an unexpected termination of Dyalog APL. See Handling Unexpected Application Errors in Windows for more information.

DyalogHelpDir

This parameter specifies the full pathname of the directory that contains the Dyalog APL help file (dyalog.chm).

DyalogInstallDir

This parameter specifies the full pathname of the directory in which Dyalog APL is installed.

DYALOG_NOPOPUPS

This parameter specifies whether a MsgBox will appear (0, the default) or will not (1) when Dyalog APL terminates unexpectedly. This applies to APL on Windows only. See Handling Unexpected Application Errors in Windows for more information.

DYALOG_PIXEL_TYPE

When the Coord property is set to 'Pixel', this parameter specifies how it is interpreted. If the value of DYALOG_PIXEL_TYPE is RealPixel or if DYALOG_PIXEL_TYPE is undefined, the object behaves as if Coord was 'RealPixel'. If the value of DYALOG_PIXEL_TYPE is ScaledPixel, the object behaves as if Coord were 'ScaledPixel'.See Coord.

DyalogWebSite

This parameter specifies the URL for the Dyalog web site.

edit_cols, edit_rows

These parameters specify the initial size of an edit window in character units.

edit_first_x, edit_first_y

These parameters specify the initial position on the screen of the first edit window in character units. Subsequent edit windows will be staggered. These parameters only apply if ClassicMode is 1.

edit_offset_x, edit_offset_y

These parameters specify the amount by which an edit window is staggered from the previous one.

ErrorOnExternalException

This parameter specifies the behaviour when a System Exception occurs in an external DLL. If this parameter is set to 1, and an exception occurs in a call on an external DLL. APL generates an EXTERNAL DLL EXCEPTION error (91), instead of terminating with a System Error. This error may be trapped.

EditorState

This is an internal parameter that remembers the state of the last edit window (normal or maximised). This is used to create the next edit window in the appropriate state.

ExternalHelpURL

If UseExternalHelpURL is 1, Dyalog attempts to use the Microsoft Document Explorer and online help, for example from Visual Studio (if installed), to display help for external objects, such as .Net Types. This parameter specifies the URL to be used. In most cases the default setting of "ms-help://ms.mscc.v80" will be sufficient. On some configurations it may be necessary to change this. See UseExternalHelpURL

greet_bitmap

This parameter specifies the filename of a bitmap to be displayed during initialisation of the Dyalog APL application. It is used typically to display a product logo from a runtime application. The bitmap will remain until either an error occurs, or it is removed using the GreetBitmap method of the Root object.

greet_bitmap=c:\myapp\logo.bmp
history_size

This parameter specifies the size of the buffer used to store previously entered (input) lines in the Session. See Specifying Size-related Parameters for further details about defining a valid value for this parameter. The maximum value is 2Gb.

inifile

This parameter specifies the name of the Windows Registry folder that contains the configuration parameters described in this section. For example,

INIFILE=Software\Dyalog\mysettings
InitialKeyboardLayout (Unicode Edition Only)

This parameter specifies the name of the keyboard to be selected on startup. When you start an APL session, this layout will automatically be selected as the current keyboard layout if the value of InitialKeyboardLayoutInUse is 1.

InitialKeyboardLayoutInUse (Unicode Edition Only)

This Boolean parameter specifies whether or not the keyboard specified by InitialKeyboardLayout is selected as the current keyboard layout when you start an APL session.

InitialKeyboardLayoutShowAll (Unicode Edition Only)

This Boolean parameter specifies whether or not all installed keyboards are listed in the choice of keyboards in the Configuration dialog box (Unicode Input tab).

input_size

This parameter specifies the size of the buffer used to store marked lines (lines awaiting execution) in the Session. See Specifying Size-related Parameters for further details about defining a valid value for this parameter.

KeyboardInputDelay

This parameter specifies the delay (in milliseconds) before the system reacts to a user keystroke by:

  • updating the name of the Current Object in the Session statusbar. See The Current Object.
  • offering a list of names for auto-completion. See Auto Complete Tab
lines_on_functions

This parameter specifies whether or not line numbers are displayed in edit and trace windows. It is either 0 (the default) or 1.

Note that this parameter determines your overall preference for line numbering, and this setting persists between APL sessions. You can however still toggle line numbering on and off dynamically as required by clicking Line Numbers in the Options menu on the Session Window. These temporary settings are not saved between APL sessions

localdyalogdir

This parameter specifies the name of the directory in which Dyalog APL/W is installed on the client, in a client/server installation

log_file

This parameter specifies the pathname to the Session log file; it can be absolute or relative to the working directory.

log_file_inuse

This parameter specifies whether or not the Session log is saved in a session log file.

log_size

This parameter specifies the size of the Session log buffer. See Specifying Size-related Parameters for further details about defining a valid value for this parameter. The maximum value is 2Gb.

mapchars (Classic Edition Only)

In previous versions of Dyalog APL, certain pairs of characters in ⎕AV were mapped to a single font glyph through the output translate table. For example, the ASCII pipe ¦ and the APL style | were both mapped to the APL style |. From Version 7.0 onwards, it has been a requirement that the mapping between ⎕AV and the font is strictly one-to-one (this is a consequence of the new native file system). Originally, the mapping of the ASCII pipe and the APL style, the APL and ASCII quotes, and the ASCII ^ and the APL ^ were hard-coded. The mapping is defined by the mapchars parameter.

mapchars is a string containing pairs of hexadecimal values which refer to 0-origin indices in ⎕AV. The first character in each pair is mapped to the second on output. The default value of mapchars is DB0DEBA7EEC00BE0 which defines the following mappings.

From |  |  | To
Hex | Decimal | Symbol | Hex | Decimal | Symbol
DB | 219 | ‘ | 0D | 13 | '
EB | 235 | ^ | A7 | 167 | ^
EE | 238 | ⌷ | C0 | 192 | |
0B | 11 | . | E0 | 224 | .

To clear all mappings, set MAPCHARS=0000.

MaxAplCores

This parameter is used in conjunction with the AplCoreName parameter to control the maximum number of aplcore files that are saved. It applies when the string specified by AplCoreName ends with an asterisk (*). If so, when saving an aplcore file, Dyalog performs the following steps:

  1. Identifies the highest number ending of those files that match the directory/name pattern specified by AplCoreName. If none, assume 0.
  2. Increments that number, then saves the aplcore in a new file ending with the new number.
  3. If necessary, deletes lower-numbered files to retain only the maximum number of files specified by MaxAplCores.

See also: AplCoreName.

maxws

This parameter determines your workspace size and is the amount of memory allocated to the workspace at APL start-up. MAXWS. See Specifying Size-related Parameters for further details about defining a valid value for this parameter.

The default value is 256M (256MiB), with the exception of the Raspberry Pi where the default is 64M. Values less than 4M are ignored, and the maximum value is 15E.

For example, to get a 4GiB workspace, set:

        MAXWS=4G

Dyalog APL places no implicit restriction on workspace size, and the virtual memory capability of the underlying operating system allows you to access more memory than you have physically installed. However if you use a workspace that greatly exceeds your physical memory you will encounter excessive paging and your APL programs will run slowly. You may also cause the system to crash.

Note that the memory used for the workspace must be contiguous.

32-bit versions of Dyalog APL are typically limited to between 1.3GiB to 1.9GiB under Windows, and 1.9GiB under UNIX. These are operating system limitations imposed on 32-bit processes rather than ones imposed by Dyalog APL, and are affected by the number and size of DLLs/shared libraries that are loaded into the process space.

64-bit versions of Dyalog APL have no such limitations; Dyalog has used workspaces of 96GiB on various platforms.

OverstrikesPopup (Unicode Edition Only)

This is a Boolean parameter that specifies whether or not the Overstrikes popup is enabled.

PassExceptionsToOpSys

This is a Boolean parameter that specifies the default state of the Pass Exception check box in the System Error dialog box. See Handling Unexpected Application Errors in Windows for more information.

pfkey_size

This parameter specifies the size of the buffer that is used to store programmable function key definitions. See Examples. See Specifying Size-related Parameters for further details about defining a valid value for this parameter.

ProgramFolder

This parameter specifies the name of the folder in which the Dyalog APL program icons are installed.

PropertyExposeRoot

Each workspace contains a flag that specifies whether or not the names of Properties, Methods and Events of the Root object are exposed. If set, you may query/set the Properties of Root and invoke the Root Methods directly as if they were variables and functions respectively. As a consequence, these names may not be used for global variables in your workspace. This parameter determines the default value of the flag in a CLEAR WS.

PropertyExposeSE

Each workspace contains a flag that specifies whether or the names of Properties, Methods and Events of the Session object are exposed. If set, you may query/set the Properties of ⎕SE and invoke ⎕SE Methods directly as if they were variables and functions respectively. As a consequence, these names may not be used for global variables in the ⎕SE namespace. This parameter determines the default value of the flag in a CLEAR WS.

qcmd_timeout

This parameter specifies the length of time in milliseconds that APL will wait for the execution of a Windows command to start. Its default value is 5000 milliseconds.

ResolveOverstrikes (Unicode Edition Only)

Specifies whether or not the user may enter an APL composite symbol using overstrikes.

RIDE_INIT

This parameter determines how the interpreter should behave with respect to the RIDE protocol. Setting this configuration parameter on the machine that hosts the interpreter enables the interpreter-RIDE connection.

The format of the value is:

 <setting> : <address> : <port>

setting is the action the interpreter should take. Valid values are:

  • serve – listen for incoming connections
  • connect – connect to the specified RIDE and end the session if this fails
  • poll – try to connect to the specified RIDE at regular intervals and reconnect if the connection is lost

address is the machine on which to listen for a connection (if setting is serve) or connect to (if setting is connect/poll). Valid values are:

  • the name of the machine
  • the IPv4 address of the machine
  • the IPv6 of the machine
  • empty – if setting is serve then the interpreter listens to everything on every network interface, if setting is connect/poll then the interpreter only listens for local connections (127.0.0.1).

port is the TCP port to listen on

The RIDE_INIT configuration parameter is set automatically when launching a new Dyalog Session from the RIDE.

RIDE_SPAWNED

If non-zero, this parameter disables ⎕SR and )SH which instead generate DOMAIN ERROR. This parameter is used to prevent certain user-interfaces from being executed from a RIDE session which does not support them, and which would otherwise cause the RIDE session to become unresponsive. See RIDE Reference Guide.

RunAsService

When RunAsService is set to 1 (the default is 0) Dyalog APL will not prompt for confirmation when the user logs off, and the interpreter will continue to run across the logoff logon process

SaveContinueOnExit

Specifies whether or not your current workspace is saved as CONTINUE.DWS before APL terminates.

SaveLogOnExit

Specifies whether or not your Session log is saved before APL terminates.

SaveSessionOnExit

Specifies whether or not your current Session is saved in your Session file before APL terminates.

Serial

Specifies your Dyalog APL/W Serial Number.

session_file

This parameter specifies the name of the file from which the APL session (⎕SE) is to be loaded when APL starts. If not specified, a .dse extension is assumed. This session file contains the ⎕SE object that was last saved in it. This object defines the appearance and behaviour of the Session menu bar, tool bar(s) and status bar, together with any functions and variables stored in the ⎕SE namespace.

SessionOnTop

Specifies whether or not the Session may appear on top of Edit and Trace Windows in Classic Dyalog mode. See ClassicMode.

ShowStatusOnError

Specifies whether or not the Status window is automatically displayed (if required) when APL attempts to write output to it.

SingleTrace

Specifies whether there is a single Trace window, or one Trace window per function. This applies only if ClassicMode is 1.

SkipBlankLines

This parameter causes the Tracer to automatically skip lines that contain no executable statement (i.e. blank lines and comment lines), with the exception of the first line in the function, and in the case of a traditional function (not a dfn), the last line if it is a comment. If SkipBlankLines is 1, the Tracer skips blank lines. If SkipBlankLines is 2, the Tracer skips comment lines. If SkipBlankLines is 3, the Tracer skips both blank lines and comment lines.

StatusOnEdit

Specifies whether or not a status bar is displayed at the bottom of an Edit window.

sm_cols, sm_rows

These parameters specify the size of the window used to display ⎕SM when it is used stand-alone. They are not used if the window is specified using the SM object.

TabStops

This parameter specifies the number of spaces inserted by pressing the Tab key in the editor. Its default value is 4.

trace_cols, trace_rows

These parameters specify the initial size of a trace window in character units.

trace_first_x, trace_first_y

These parameters specify the initial position on the screen of the first trace window in character units. Subsequent trace windows will be staggered. This applies only if ClassicMode is 1.

trace_offset_x, trace_offset_y

These parameters specify the amount by which a trace window is staggered from the previous one. These apply only if ClassicMode is 1 and SingleTrace is 0.

Trace_level_warn

This parameter specifies the maximum number of Trace windows that will be displayed when an error occurs and Trace_on_error is set to 1. If there are a large number of functions in the state indicator, the display of their Trace windows may take several seconds. This parameter allows you to restrict the potential delay to a reasonable value and its default is 16. If the number of Trace windows would exceed this number, the system instead displays a warning message box. This parameter is ignored if you invoke the Tracer explicitly. This parameter applies only if ClassicMode is 1 and SingleTrace is 0.

Trace_on_error

This parameter is either 0 (the default) or 1. If set to 1, Trace_on_error specifies that the Tracer is automatically deployed when execution of a defined function halts with an error. A stack of Trace windows is immediately displayed, with the top Trace window receiving the input focus.

TraceStopMonitor

This parameter specifies which of the ⎕TRACE (1), ⎕STOP (2) and ⎕MONITOR (4) columns are displayed in Trace and Edit windows. Its value is the sum of the corresponding values.

UnicodeToClipboard (Classic Edition only)

This parameter specifies whether or not text that is transferred to and from the Windows clipboard is treated as Unicode text. If UnicodeToClipboard is 0 (the default), the symbols in ⎕AV are mapped to ASCII text (0-255). In particular, the APL symbols are mapped to ASCII symbols according to their positions in the Dyalog APL font. If UnicodeToClipboard is 1, the symbols in ⎕AV are mapped to Unicode text and the APL symbols are mapped to their genuine Unicode equivalent values.

UseExternalHelpURL

This parameter specifies whether or not Dyalog attempts to use the Microsoft Document Explorer and online help to display help for external objects, such as .Net Types. See ExternalHelpURL.

WantsSpecialKeys (Unicode Edition Only)

This parameter specifies a list of applications (e.g. putty.exe) that use the command strings in the Input Translate Tables.

WrapSearch

This parameter specifies whether or not Search/Replace in the Editor stops at the bottom or top of the text (depending upon the direction of the search), or continues the search from the start or end as appropriate.

WSEXT

This parameter specifies workspace filename extensions. It complements the WSPATH parameter in that together they determine the file search order to satisfy )LOAD or )COPY; it also specifies the filename extension to add on )SAVE or )CONTINUE if none is explicitly provided.

WSEXT is a string that specifies a colon-separated list of one or more extensions, including any period (".") which separates the extension from its basename.

If undefined, WSEXT defaults to .dws: on Windows and OS X, and :.dws:.DWS on all other platforms.

In the Windows case, this means that )LOAD myws will search first for a file named myws.dws, and then for a file named myws (with no extension). As file names are not case-sensitive under Windows, this will find myws.DWS or MyWs.Dws and so forth. If none are found with this extension, it will load myws, MyWs, MYWS etc.

In the second (non-Windows) case note that )LOAD myws will search first for a file named myws, then myws.dws, then myws.DWS.

WSPATH

This parameter defines the workspace path. This is a list of directories that are searched in the order specified when you )LOAD or )COPY a workspace and when you start an Auxiliary Processor. The directory paths are specified using Operating System specific conventions and separated by ";" (Windows) or ":" (UNIX).

The following Windows example causes )COPY, )LOAD and )LIB to look first in the current directory, then in D:\MYWS, and then in the (normal) installation workspace directory.

WSPATH=.;D:\MYWS;C:\Program Files\Dyalog\Dyalog APL 14.1 Unicode\ws
XPLookAndFeel

This Boolean parameter specifies whether or not Native Look and Feel is used. This affects the appearance of user-interface controls such as Buttons. The default is 1. See The Configuration Dialog Box.

yy_window

This parameter defines how Dyalog APL is to interpret a 2-digit year number. If yy_window is not set (the default) then under Windows, Version 13.2 onwards will adhere to the rules specified in the Windows Region and Language 2-digit year settings.

Dyalog allows a choice of input date formats for ⎕SM and GUI edit fields. If you have chosen a 2-digit year format such as MM/DD/YY, then an input of 02/01/00 will by default be interpreted as 1st February 1900 - not 1st February 2000.

If your application uses a 4-digit year format such as YYYY-MM-DD, the problem will not arise.

You can use the yy_window parameter to cause your application to interpret 2-digit dates in as required without changing any APL code.

Sliding versus Fixed Window

Two schemes are in common use within the industry: Sliding or Fixed date windows.

Use a Fixed window if there is a specific year, for example 1970, before which, dates are meaningless to your application. Note that with a fixed window, this date (say 1970) will still be the limit if your application is running in a hundred years' time.

Use a Sliding window if there is a time period, for example 30 years, before which dates are considered too old for your application. With a sliding window, you will always be able to enter dates up to (say) 30 years old, but after a while, specific years in the past (for example 1970) will become inaccessible.

Setting a Fixed Window

To make a fixed window, set parameter yy_window to the 4-DIGIT year which is the earliest acceptable date. For example:

YY_WINDOW=1970

This will cause the interpreter to convert any 2-digit input date into a year in the range 1970, 1971 ... 2069

Setting a Sliding Window

To make a sliding window, set parameter yy_window to the 1- or 2-DIGIT year which determines the oldest acceptable date. This will typically be negative.

YY_WINDOW=-30

Conversion of dates now depends on the current year:

If the current year is 1999, the earliest accepted date is 1999-30 = 1969.

This will cause the interpreter to convert any 2-digit input date into a year in the range 1969, 1970 ... 2068.

However if your application is still running in the year 2010, the earliest accepted date then will be 2010-30 = 1980. So in the year 2010, a 2-digit year will be interpreted in the range 1980, 1981 ... 2079.

Advanced Settings

You can further restrict date windows by setting an upper as well as lower year limit.

YY_WINDOW=1970,1999

This causes 2-digit years to be converted only into the range 1970, 1971 ... 1999. Any 2-digit year (for example, 54) not convertible to a year in this range will cause a DOMAIN ERROR.

The sliding window equivalent is:

YY_WINDOW=-10,10

This would establish a valid date window, ten years either side of the current year. For example, if the current year is 1998, the valid range would be (1998-10) – (1998+10), in other words: 1988, 1989, → 2008.

One way of looking at the yy_window variable is that it specifies a 2-element vector. If you supply only the first element, the second one defaults to the first element + 99.

Note that the system uses only the number of digits in the year specification to determine whether it refers to a fixed (4-digits) or sliding (1-, or 2-digits) window. In fact you can have a fixed lower limit and a sliding upper limit, or vice versa.

YY_WINDOW=1990,10

Allows dates as early as 1990, but not more than 10 years hence.

YY_WINDOW=0,1999

Allows dates from the current year to the end of the century.

If the second date is before, or more than 99 years after the first date, then any date conversion will result in a DOMAIN ERROR. This might be useful in an application where the end-user has control over the input date format and you want to disallow any 2-digit date input.

YY_WINDOW=1,0


Registry Sub-Folders

A large amount of configuration information is maintained in the Windows Registry in sub-folders of the main folder identified by inifile.

Many of these values are dynamic, for example the position of the various Session windows, is maintained in a Registry sub-folder so that their appearance is maintained from one invocation of APL to the next. These types of Registry values are considered to be internal and are therefore not described herein.

However, and Registry Value that is maintained via a configuration dialog box will be named and described in the documentation for that dialog box in Chapter 2.

AutoComplete

This contains registry entries that describe your personal AutoComplete options. See Auto Complete Tab.

Captions

This contains registry entries to customise the Captions used in the various windows of the Dyalog APL IDE. See Window Captions.

Colours

This contains entries that describe the colour schemes you have and your personal preferences. See Colour Selection Dialog.

Editor

This contains certain entries for the Editor.

Event Viewer

This contains entries that describe your settings for the Event Viewer. See UI Guide: The Event Viewer.

Explorer

This contains entries that describe your settings for the Workspace Explorer. See UI Guide: The Workspace Explorer Tool.

files

This contains the size of your recently used file list (see General Tab) and the list of your most recently loaded workspaces.

KeyboardShortcuts/keys

This contains the definitions of your Keyboard Shortcuts (Unicode Edition only). See Keyboard Shortcuts Tab.

KeyboardShortcuts/chars

This contains the Registry Keyboard mappings between keystrokes and APL characters (Unicode Edition only). See UI Guide: Registry Keyboard Unicode Edition and the Registry Keyboard.

LanguageBar

This contains the definitions of the symbols, tips, and help for the symbols in the LanguageBar.

Printing

This contains the entries for your Printer Setup options. See Print Configuration Dialog Box.

SALT

This contains entries for SALT. See SALT.

Search

This contains dynamic entries for the Find Objects Tool. See UI Guide: Find Objects Tool.

Threads

This contains entries to remember your preferences for Threads. See UI Guide: The Threads Menu.

UnicodeIME

This contains entries for the Dyalog Unicode IME.

ValueTips

This contains entries for your Value Tips preferences. See UI Guide: Value Tips.

WindowRects

This contains entries to maintain the position of various Session tool windows so that they remain consistent between successive invocations of APL.

Array Editor

The Array Editor stores its settings in the following registry sub-folder:

HKEY_CURRENT_USER\Software\DavidLiebtag.com\Array Editor\1.1\Options


Window Captions

The captions of the various windows that comprise the Dyalog Integrated Development Environment (IDE) are user-configurable and defined by entries in the Windows registry in the Captions subkey of the main Dyalog key.

Note that this only applies when the windows are floating (un-docked). When a window is docked Dyalog displays a fixed non-configurable caption.

Note also that the Captions subkey is not created by the interpreter; the user must create the subkey and the values.

Each entry is a string value whose name identifies the window as follows:

Window Name | Description
Session | The main Dyalog APL session window
Editor | The Editor window
SysTray | The hint on Dyalog icons in the System Tray
MessageBox | The notification Message Box that is displayed in various circumstances; for example, when an object cannot be fixed by the Editor
Explorer | The Workspace Explorer tool
Rebuild Errors | The dialog box that is displayed if one or more objects cannot be re-instantiated when a workspace is loaded
Status | The Status window
Event Viewer | The Event Viewer
FindReplace | The Find/Replace dialog box
ExitDialog | The Exit dialog box that is displayed when the user closes the Session window
WSSearch | The Find Objects tool
Syserror | The Syserror Message Box

Each string value should contain a mixture of your own text and keywords which are enclosed in braces, e.g. {TITLE}. Keywords act like variables and are replaced at display time by corresponding values as described in the table below.

Keyword | Value
{TITLE} | The window name shown in the first column of the previous table
{WSID} | Workspace ID (⎕WSID)
{NSID} | Current Namespace
{SNSID} | Current Namespace (short version)
{PRODUCT} | The name of the Dyalog product, e.g. "Dyalog APL/W - 64"
{VER_A} | The main version number, e.g. "14"
{VER_B} | The secondary version number, e.g. "0"
{VER_C} | The tertiary version number (currently the internal revision number)
{PID} | The process ID
{CHARS} | "Classic" or "Unicode"
{BITS} | "32" or "64"
{XLOC} | The namespace currently being explored (Explorer only)

For example, if the Registry contains .\Captions\Session whose value is:

    My APL ({WSID}) Version {VER_A}.{VER_B}[{VER_C}]  - {PID}

then the caption displayed in a new Dyalog APL Session window might be:

    My APL (CLEAR WS) Version 14.0[20105] - 4616


Workspace Management

Workspace Size and Compaction

The maximum amount of memory allocated to a Dyalog APL workspace is defined by the maxws parameter (on non-Windows platforms this is defined by the environment variable MAXWS).

Upon )LOAD and )CLEAR, APL allocates an amount of memory corresponding to the size of the workspace being loaded (which is zero for a clear ws) plus the workspace delta.

The workspace delta is 1/16th of maxws, except if there is less than 1/16th of maxws in use, delta is 1/64th of maxws. This may also be expressed as follows:

      delta←maxws{⌈⍺÷⊃(⍵>⍺÷16)⌽64 16}ws

where maxws is the value of the maxws parameter and ws is the currently allocated amount of workspace. If maxws is 16384KB, the workspace delta is either 256KB or 1024 KB, and when you start with a clear ws the workspace occupies 256KB.

When you erase objects or release symbols, areas of memory become free. APL manages these free areas, and tries to reuse them for new objects. If an operation requires a contiguous amount of workspace larger than any of the available free areas, APL reorganises the workspace and amalgamates all the free areas into one contiguous block as follows:

  1. Any un-referenced memory is discarded. This process, known as garbage collection, is required because whole cycles of refs can become un-referenced.
  2. Numeric arrays are demoted to their tightest form. For example, a simple numeric array that happens to contain only values 0 or 1, is demoted or squeezed to have a ⎕DR type of 11 (Boolean).
  3. All remaining used memory blocks are copied to the low-address end of the workspace, leaving a single free block at the high-address end. This process is known as compaction.
  4. In addition to any extra memory required to satisfy the original request, an additional amount of memory, equal to the workspace delta, is allocated. This will always cause the process size to increase (up to the maxws limit) but means that an application will typically achieve its working process size with at most 4+15 memory reorganisations.
  5. However, if after compaction, the amount of used workspace is less than 1/16 of the Maximum workspace size (maxws), the amount reserved for working memory is reduced to 1/64th maxws. This means that workspaces that are operating within 1/16th of maxws will be more frugal with memory

Note that if you try to create an object which is larger than free space, APL reports WS FULL.

The following system function and commands force a workspace reorganisation as described above:

        ⎕WA, )RESET, )SAVE, )LOAD, )CLEAR

However, in contrast to the above, any spare workspace above the workspace delta is returned to the Operating System. On a Windows system, you can see the process size changing by using Task Manager.

The system function ⎕WA may therefore be used judiciously (workspace reorganisation takes time) to reduce the process size after a particularly memory-hungry operation.

Note that in Dyalog APL, the SYMBOL TABLE is entirely dynamic and grows and shrinks in size automatically. There is no SYMBOL TABLE FULL condition.

Additional functions for managing the memory used by the workspace are described in Memory Manager Statistics and Specify Workspace Available.


Interface with Windows

Windows Command Processor commands may be executed directly from APL using the system command )CMD or the system function ⎕CMD. This system function is also used to start other Windows programs. For further details, see the appropriate sections in Language Reference.


Auxiliary Processors

Introduction

Auxiliary Processors (APs) are non-APL programs which provide Dyalog APL users with additional facilities. They run under the control of Dyalog APL.

Typically, APs are used where speed of execution is critical, for utility libraries, or as interfaces to other products. APs may be written in any compiled language, although C is preferred and is directly supported.

Dyalog would recommend that rather than creating APs, customers should now create DLLs (Dynamic Shared Libraries)/shared libraries. If very high performance is required, customers should consider DWA (Direct Workspace Access); contact support@dyalog.com for more information about DWA, including pre-requisite training courses.

Starting an AP

An Auxiliary Processor is invoked using the dyadic form of ⎕CMD. The left argument to ⎕CMD is the name of the program to be executed; the value of the WSPATH parameter is used to find the named file. In Dyalog APL/W, the right argument to ⎕CMD is ignored.

        'xutils' ⎕CMD ''

On locating the specified program, Dyalog APL starts the AP and initialises a memory segment for communication between the workspace and the AP. This communication segment allows data to be passed from the workspace to the other process, and for results to be passed back. The AP then sends APL some information about its external functions (names, code numbers and calling syntax), which APL enters in the symbol table. APL then continues processing while the AP waits for instructions.

Using the AP

Once established, an AP is used by making a reference to one of its external functions. An external function behaves as if it was a locked defined function, but it is in effect an entry point to the AP. When an external function is referenced, APL transmits a code number to the AP, followed by any arguments. The AP then takes over and performs the desired processing before posting the result back.

Terminating the AP

An AP is terminated when all the last of its external functions is expunged from the active workspace. This could occur with the use of )CLEAR, )LOAD, )ERASE, ⎕EX, )OFF, )CONTINUE or ⎕OFF.

Example:

Start an Auxiliary Processor called EXAMPLE. This fixes two external functions called DATE_TO_IDN and IDN_TO_DATE which deal with the conversion of International Day Numbers to Julian Dates.

.------------------------.
|      APL PROCESS       |
|------------------------|
|     )CLEAR             |
|clear ws                |
|                        |   start AP  .--------------.
|    'EXAMPLE' ⎕CMD ''   |------------>|  AP EXAMPLE  |
|                        |             |--------------|
|                        | info about  |Send info on  |
|                        |<------------|external fns  |
|                        |  functions  |              |
|    )FNS                |             |  wait ...    |
|DATE_TO_IDN IDN_TO_DATE |             |              |
|                        |function code|              |
|    IDN_TO_DATE 19407   |------------>|call relevant |
|                        |    19407    | subroutine   |
|    wait ...            |             |              |
|                        |<-18 Feb 53--| send result  |
|18 Feb 53               |             |              |
|                        | terminate   |              |
|     )CLEAR             |------------>|     EXIT     |
|clear ws                |  and stop   .--------------.
|                        |
.------------------------.


Access Control for External Variables

External variables may be EXCLUSIVE or SHARED. An exclusive variable can only be accessed by the owner of the file. If you are on a Local Area Network (LAN) a shared external variable may be accessed (concurrently) by other users. The exclusive or shared status of an external variable is set by the XVAR function in the UTIL workspace.

Access to an external variable is faster if it has exclusive status than if it is shared. This is because if several users are accessing the file data must always be read and written directly to disk. If it has exclusive status, the system uses buffering and avoids disk accesses where possible.


Creating Executables

Creating Executables and COM Servers

Dyalog APL provides the facility to package an APL workspace as a Windows executable (EXE), an OLE Server (in-process or out-of-process), an ActiveX Control or a .NET Assembly. This may be done by selecting Export … from the File menu of the APL Session window which brings up the Create bound file dialog box as illustrated later in this section.

The Create bound file dialog box offers selective options according to the type of file you are making. The system detects which of these types is most appropriate from the objects in your workspace. For example, if your workspace contains an ActiveXControl namespace, it will automatically select the ActiveX Control option.

If you are creating an executable (EXE) the system provides the following options:

  • You may bind your EXE as a Dyalog APL run-time application, or as a Dyalog APL developer application. The second option will allow you to debug the application should it encounter an APL error.
  • You may bind your EXE as a console-mode application. A console application does not have a graphical user interface, but runs as a background task using files or TCP/IP to perform input and output.
  • You may specify whether or not your .EXE will honour Native Look and Feel.

You can package the workspace as a stand-alone executable or as a .EXE file that must be accompanied by the Dyalog APL Dynamic Link Library (dyalog150.dll or dyalog150rt.dll), in which case the DLL should be installed in the same directory (as the EXE) or in the Windows System directory.

Various Dyalog-supplied files are required (such as the runtime DLL for creating a bound runtime executable); all such files are assumed to reside in the Dyalog directory, as specified by default in the registry. The location of this directory is most easily reported by calling

      +2⎕nq '.' 'GetEnvironment' 'Dyalog'

The creation of both in-process and out-of-process COM servers produces a .TLB (Type Library) file. This file is created in the same directory as the workspace - so write access must be allowed to this directory. In the case of an in-process server, the content of this file is then embedded into the DLL, and the file is deleted. For an out-of-process server the file persists and may be needed at runtime. This requirement means that even if you do not )Save the workspace, you should set the workspace name so that )SAVE would work - that is the directory where the workspace would be saved has write access.

In addition, a temporary copy of your workspace is created, the location of which is determined by the Windows function GetTempPath().

All registration information is written to HKEY_LOCAL_MACHINE in the registry which will require enhanced permissions (aka "run as administrator") for the Dyalog interpreter. Later versions of the interpreter may provide an option to write to HKEY_CURRENT_USER.

The Create bound file dialog box contains the following fields. These will only be present if applicable to the type of bound file you are making.

Item | Description
File name | Allows you to choose the name for your bound file. The name defaults to the name of your workspace with the appropriate extension.
Save as type | Allows you to choose the type of file you wish to create
Runtime application | If this is checked, your application file will be bound with the Run-Time DLL. If not, it will be bound with the Development DLL. The latter should normally only be used to permit debugging.
Console application | Check this box if you want your executable to run as a console application. This is appropriate only if the application has no graphical user interface.
Enable Native Look and Feel | If checked, Native Look and Feel will be enabled for your bound file; otherwise it will be disabled.
Icon file | Allows you to associate an icon with your executable. Type in the pathname, or use the Browse button to navigate to an icon file.
Command line | For an out-of-process COM Server, this allows you to specify the command line for the process. For a bound executable, this allows you to specify command-line parameters for the corresponding Dyalog APL DLL.

The following example illustrates how you can package the supplied workspace calc.dws as an executable. Before making the executable, it is essential to set up the latent expression to run the program using ⎕LX as shown. Notice that in this case it is not necessary to execute ⎕OFF; the calc.exe program will terminate normally when the user closes the calculator window and the system returns to Session input.

In this example, the supplied workspace calc.dws is first saved to a directory to which the user has write access and, just to make certain, the Dyalog program is run as Administrator.

Then, when you select Export… from the File menu, the following dialog box is displayed.

The Save as Type option has been set to Standalone Executable (includes interpreter exe) which means that a single .exe will be created containing the Dyalog APL executable and the CALC workspace.

The Runtime application checkbox is checked, indicating that calc.exe is to incorporate the runtime version of Dyalog APL.

As this is a GUI application, the Console application checkbox is left unset.

Note that if you enter the name of a file containing an icon (use the Browse button to browse for it) that icon will be bound with your executable and be used instead of the standard Dyalog APL icon.

The Command Line box allows you to enter parameters and values that are to be passed to your executable when it is invoked.

Version Information

You may embed version information into your .exe by clicking the Version button and then completing the Version Information dialog box that is illustrated below.

On clicking Save, the following message box is displayed to confirm success.


Run-Time Applications and Components

Using Dyalog APL you may create different types of run-time applications and components. Note that the distribution of run-time applications and components requires a Dyalog APL Run-Time Agreement. Please contact Dyalog or your distributor, or see the Dyalog web page for more information.

For a list of the distributable components and their corresponding file names, for the different versions of Dyalog, see Files .

These components are referred to in hereafter by the name shown in the first column of the table. It is essential that you distribute the components that are appropriate for the Edition you are using.

Universal C Runtime DLLs

Under Windows, many of the Dyalog APL run-time components (.EXE and .DLL) are linked dynamically with the Microsoft Universal C Runtime library (the UCRT) which is supplied and installed as part of the normal Dyalog development installation.

At execution time it is important that the Dyalog runtime components bind with a version of the UCRT that is compatible with (i.e. the same as or newer than) the one with which they were built.

Windows 10

If the end-user of the Dyalog application is known to be running Windows 10, the Dyalog application will pick up the system-wide UCRT which is part of Windows 10. There is therefore no need to include the UCRT with a Dyalog run-time application.

Other Versions of Windows

The UCRT is not supplied with versions of Windows prior to Windows 10. On these platforms, it is therefore necessary to install the UCRT as part of the installation of the Dyalog run-time application. There are two ways to achieve this which are referred to herein as the VCRedist installation and App-local installation. Dyalog recommends the former.

VCRedist Installation (Recommended)

The VCRedist package, which includes the UCRT, is supplied with the Dyalog development package.

Simply copy the vc_redistx86.exe (32-bit version) or vc_redistx64.exe (64-bit version) program from the Dyalog development package into your own installation package and execute it as part of the installation of your Dyalog run-time application. This installs the UCRT into a shared Windows location; in effect the UCRT becomes part of the Windows system. The installation therefore requires Administrator privileges.

App-local Installation

An alternative is to install the UCRT components into the same directory as your Dyalog run-time application. There are two ways to obtain these files.

Either:

Install the Dyalog development package (ideally onto a separate system just for this purpose) without administrator rights. This will perform an App-local installation of Dyalog itself. Then copy the UCRT files into your installation package. These files are:

  • those beginning with api-ms*
  • ucrtbase.dll
  • vcruntime140.dll

Or:

Download and install the Windows 10 SDK from:
https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk, and follow the instructions in the link below.https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt

Finally, modify your installer to add these files to the same folder as your Dyalog run-time application.

Stand-alone run-time

This is the simplest type of run-time to install. Using the File/Export menu item on the Session window, you can create a standard Windows executable program file (EXE) which contains your workspace and the Run-Time version of the Dyalog APL interpreter. To distribute your application, you need to supply and install:

  1. your bound executable (EXE)
  2. whatever additional files that may be required by your application

Start-up parameters may be specified on the application command line and are obtained by calling the GetCommandLine or GetCommandLineArgs methods. All command-line parameters will be ignored by the Dyalog engine unless they are preceded by the -apl option. Start-up parameters for the Dyalog engine may also be specified and bound with the EXE when you make it.

If your application uses any component of the Microsoft .NET Framework, you must distribute the Bridge DLL and DyalogNet DLLs. These DLLs must be placed in the same directory as your EXE.

Bound run-time

This option requires the separate installation of the Run-Time DLL, but compared with the stand-alone executable option, may save disk space and memory if your customer installs and runs several different Dyalog applications. Using the File/Export menu item on the Session window, you can create a standard Windows executable program file (EXE) which contains your workspace bound to the Run-Time DLL. To distribute your application, you need to supply and install:

  1. your bound executable (EXE)
  2. The Run-Time DLL

whatever additional files that may be required by your application

Start-up parameters may be specified on the application command line and are obtained by calling the GetCommandLine or GetCommandLineArgs methods. All command-line parameters will be ignored by the Dyalog engine unless they are preceded by the -apl option. Start-up parameters for the Dyalog engine may also be specified and bound with the EXE when you make it.

If your application uses any component of the Microsoft .NET Framework, you must distribute the Bridge DLL and DyalogNet DLLs. These DLLs must be placed in the same directory as your EXE.

Workspace based run-time

A workspace based run-time application consists of the Dyalog APL Run-Time Program (Run-Time EXE) and a separate workspace. To distribute your application, you need to supply and install:

  1. your workspace
  2. the Run-Time EXE
  3. whatever additional files that may be required by your application

The command-line for your application invokes the Run-Time EXE, passing it start-up parameters required for the Run-Time EXE itself (such as MAXWS) and any start-up parameters that may be required by your application. You will need to associate your own icon with your application during its installation.

If your application uses any component of the Microsoft .NET Framework, you must distribute the Bridge DLL and DyalogNet DLLs. These DLLs must be placed in the same directory as your EXE.

Out-of-process COM Server

To make an out-of-process COM Server, you must:

  1. establish one or more OLEServer namespaces in your workspace, populated with functions and variables that you wish to export as methods, properties and events.
  2. use the File/Export … menu item on the Session window to register the COM Server on your computer so that it is ready for use.

The command-line for your COM Server invokes the Run-Time EXE, passing it the start-up parameters required for the Run-Time EXE itself (such as MAXWS) and any start-up parameters that may be required by your application.

To distribute an out-of-process COM Server, you need to supply and install the following files:

  1. your workspace
  2. the associated Type Library (.tlb) file (created by File/Export)
  3. the Run-Time EXE
  4. whatever additional files that may be required by your application

To install an out-of-process COM Server you must set up the appropriate Windows registry entries. See Interface Guide for details.

In-process COM Server

To make an in-process COM Server, you must:

  1. establish one or more OLEServer namespaces in your workspace, populated with functions and variables that you wish to export as methods, properties and events.
  2. use the File/Export … menu item on the Session window to create an in-process COM Server (DLL) which contains your workspace bound to the Run-Time DLL. This operation also registers the COM Server on your computer so that it is ready for use.

To distribute your component, you need to supply and install

Your COM Server file (DLL)

  1. the Run-Time DLL
  2. whatever additional files that may be required by your COM Server.

Note that you must register your COM Server on the target computer using the regsvr32.exe utility.

ActiveX Control

To make an ActiveX Control, you must:

  1. establish an ActiveXControl namespace in your workspace, populated with functions and variables that you wish to export as methods, properties and events.
  2. use the File/Export … menu item on the Session window to create an ActiveX Control file (OCX) which contains your workspace bound to the Run-Time DLL. This operation also registers the ActiveX Control on your computer so that it is ready for use.

To distribute your component, you need to supply and install

Your ActiveX Control file (OCX)

  1. the Run-Time DLL
  2. whatever additional files that may be required by your ActiveX Control.

Note that you must register your ActiveX Control on the target computer using the regsvr32.exe utility.

Microsoft .NET Assembly

A Microsoft .NET Assembly contains one or more .NET Classes. To make a Microsoft .NET Assembly, you must:

  1. establish one or more NetType namespaces in your workspace, populated with functions and variables that you wish to export as methods, properties and events.
  2. use the File/Export … menu item on the Session window to create a Microsoft .NET Assembly (DLL) which contains your workspace bound to the Run-Time DLL.

To distribute your .NET Classes, you need to supply and install

  1. your Assembly file (DLL)
  2. the Run-Time DLL
  3. the Bridge DLL
  4. the DyalogNet DLL
  5. whatever additional files that may be required by your .NET Assembly.

All the DLLs and subsidiary files must be installed in the same directory as the .NET Assembly.

Additional Files for Syncfusion

Under a licensing agreement with Syncfusion, Dyalog includes the Syncfusion library of WPF controls. These may be used by Dyalog APL users to develop applications, and may be distributed with Dyalog APL run-time applications.

The Syncfusion libraries comprise a set of .NET assemblies which are supplied in the Syncfusion/4.5 sub-directory of the main Dyalog APL installation directory (for example: c:\Program Files\Dyalog\Dyalog APL-64 14.0 Unicode\Syncfusion\4.5.

If you use any of the Syncfusion controls in your runtime application, you must include the Syncfusion library.

Accessing your Application Using RIDE

If you wish to access your run-time application remotely using the RIDE, you must put a copy of the appropriate Conga DLLs (see Files) in the same directory as your .EXE or workspace. This is different from previous versions of Dyalog which had separate RIDE DLLs.

Additional Files for SQAPL

If your application uses the SQAPL/EL ODBC interface, you must distribute and install four additional components.

  • SQAPL INI
  • SQAPL ERR
  • SQAPL DLL
  • APLUNICD INI

For the names of the files corresponding to these components, see Files.

The SQAPL DLL must be installed in the user's Windows directory or be on the user's path.

Miscellaneous Other Files

DyaRes DLL

If your run-time application uses any of the bitmaps or other GUI resources that are built into the Dyalog Session, you must include the DyaRes DLL with your application.

AUXILIARY PROCESSORS

If you use any of the Auxiliary Processors (APs) included in the sub-directory xutils, you must include these with your application. Note that, like workspaces, Dyalog APL searches for APs using the WSPATH parameter. If your application uses APs, you must ensure that you specify WSPATH or that the default WSPATH is adequate for your application..

DYALOG32 and/or DYALOG64

This DLL is used by some of the functions provided in the QUADNA.DWS workspace. If you include any of these in your application this DLL must be installed in the user's Windows directory or be on the user's path.

Registry Entries for Run-Time Applications

The Run-Time DLL does not obtain any parameter values from the Windows registry. If you need to specify any Dyalog APL parameter values, they must be defined in the command line when you create an EXE.

The Run-Time EXE does obtain parameter values for the Windows registry, but does not require them to be present. If the default values of certain parameters are inappropriate, you may specify their values on the command line. There is normally no requirement to install registry entries for a run-time application that uses the Run-Time EXE.

For example, your application may require a greater or lesser maxws parameter (workspace size) than the default value. This may be done by adding the phrase MAXWS=nnnn (where nnnn is the required workspace size) after the name of your application workspace on the command line, for example:

      dyalogrt.exe MYAPP.DWS MAXWS=200M

Note that the default value of the DYALOG parameter (which specifies where it looks for various other files and sub-directories) is the directory from which the application (dyalogrt.exe) is loaded.

Nevertheless, registry entries will be required in the following circumstances.

  1. If your Classic Edition run-time application requires that the user inputs APL characters, you will need to specify input/output tables (parameters APLK, APLT, APLKEYS and APLTRANS).

Installing Registry Entries

To specify parameters using the Registry, you must install a suitable registry folder for each user of your application. By default, Version 17.0 will use registry folders similar to:

HKEY_CURRENT_USER\Software\Dyalog\Dyalog APL/W 17.0 Unicode

or

HKEY_LOCAL_MACHINE\SOFTWARE\Dyalog\Dyalog APL/W-64 17.0

You may choose a different name for your registry folder if you wish. If so, you must tell Dyalog APL the name of this folder by specifying the INIFILE parameter on the command line. For example:

dyalogrt.exe myapp.dws INIFILE=Software\MyCo\MyApplication

You may install entries into the registry folder in one of two ways:

  1. Using a proprietary installation program such as InstallShield
  2. Using the REGEDIT utility. This utility program installs registry entries defined in a text file that is specified as the argument to the program. For example, if your file is called APLAPP.REG, you would install it on your user's system by executing the command:
REGEDIT APLAPP.REG

An example 5-line file that specifies the APLNID and MAXWS parameters might be as follows:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Dyalog\Dyalog APL/W 17.0]
"aplnid"="42"
"maxws"="8096"


COM Objects and the Dyalog APL DLL

Introduction

Each different implementation of Dyalog contains two versions of the Dyalog APL Dynamic Link Library, a development version (Development DLL) and a run-time version (Run-Time DLL). For further details, see Files.

In the remainder of this section, the term Dyalog APL DLL is used to refer to any one of these DLLs. The term COM object is used to refer to a Dyalog APL in-process OLE Server (OLEServer object) or a Dyalog APL ActiveX Control (ActiveXControl object).

The Dyalog APL DLL is used to host COM objects and .NET objects written in Dyalog APL. Although this section describes how it operates with COM objects, much of this also applies when it hosts .NET objects. Further information is provided in the .NET Interface Guide.

Classes, Instances and Namespace Cloning

A COM object, whether written in Dyalog APL or not, represents a class. When a host application loads a COM object, it actually creates an instance of that class.

When a host application creates an instance of a Dyalog APL COM object, the corresponding OLEServer or ActiveXControl namespace is cloned. If the host creates a second instance, the original namespace is cloned a second time.

Cloned OLEServer and ActiveXControl namespaces are created in almost exactly the same way as those that you can make yourself using ⎕OR and ⎕WC except that they do not have separate names. In fact, each clone believes itself to be the one and only original OLEServer or ActiveXControl namespace, with the same name, and is completely unaware of the existence of other clones.

Notice that cloning does not initially replicate all the objects within the OLEServer or ActiveXControl namespace. Instead, the objects inside the cloned namespaces are actually represented by pointers to the original objects in the original namespace. Only when an object is changed does any information get replicated. Typically, the only objects likely to differ from one instance to another are variables, so only one copy of the functions will exist in the workspace. This design enables many instances of a Dyalog APL COM object to exist without overloading the workspace.

Workspace Management

By default, the Dyalog APL DLL does not use a fixed maximum workspace size, but automatically increases the size of its active workspace as required. If you write a run-away COM object, or if there is insufficient computer memory available to load a new control, it is left to the host application or to Windows itself to deal with the situation.

Nevertheless, it is possible to specify a value for maxws for the application in which the Dyalog APL DLL is embedded. This is achieved by defining a Registry key named:

HKLM\Software\Dyalog\Embedded\<appname>

or on 64-bit Windows:

HKLM\Software\Wow6432Node\Dyalog\Embedded\<appname>

where <appname> is the name of the application, containing a String Value named maxws set to the desired size. If you were running an APL in-process server from Microsoft Excel, the application name would be excel.exe.

When an application loads its first Dyalog APL COM object, it starts the Dyalog APL DLL which initialises a CLEAR WS. It then copies the namespace tree for the appropriate OLEServer or ActiveXControl object into its active workspace.

This namespace tree comprises the OLEServer or ActiveXControl namespace itself, together with all its parent namespaces with the exception of the root workspace itself. Note that for an ActiveXControl, there is at least one parent namespace that represents a Form.

For example, if an ActiveXControl namespace is called #.F.Dual, the Dyalog APL DLL will copy the contents of #.F into its active workspace when the first instance of the control is loaded by the host application.

If the same host application creates a second instance of the same OLEServer or ActiveXControl, the original namespace is cloned as described above and there is no further impact on the workspace

If the same host application creates an instance of a different Dyalog APL COM object, the namespace tree for this second object is copied from its DLL or OCX file into the active workspace. For example, if the second control was named X.Y.MyControl, the entire namespace X would be copied.

This design raises a number of points:

  1. Unless you are in total control of the user environment, you should design a Dyalog APL COM object so that it can operate in the same workspace as another Dyalog APL COM object supplied by another author. You cannot make any assumptions about file ties or other resources that are properties of the workspace itself.
  2. If you write an ActiveXControl whose ultimate parent namespace is called F, a host application could not use your control at the same time as another ActiveXControl (perhaps supplied by a different author) whose ultimate parent namespace is also called F.
  3. Dyalog APL COM objects must not rely on variables or utility functions that were present in the root workspace when they were saved. These functions and variables will not be there when the object is run by the Dyalog APL DLL.
  4. A Dyalog APL COM object may create and subsequently use functions and variables in the root workspace, but if two different COM objects were to adopt the same policy, there is a danger that they would interfere with one another. The same is true for ⎕SE.

Multiple COM Objects in a Single Workspace

If your workspace contains several OLEServer or ActiveXControl objects which have the same ultimate parent namespace, the Dyalog APL DLL will copy them all into the active workspace at the time when the first one is instanced. If the host application requests a second COM object that is already in the workspace, the namespace tree is not copied again.

If the workspace contains several OLEServer or ActiveXControl objects which have different ultimate parents, their namespace trees will be copied in separately.

Parameters

With the exception of maxws (see above) the Dyalog APL DLL does not read parameters from the registry, command-line or environment variables. This means that all such parameters will have their default values.


APL Application as a Service

Introduction

Dyalog APL provides a mechanism for users to register and manage an application workspace as a Windows service. The application workspace must implement an interface to handle messages from the Windows Service Control Manager (SCM) in addition to the code required to drive the application.

Windows Services run as background tasks controlled by the SCM. When the computer is started, Windows Services are run before a user logs on to the system and do not normally interact with the desktop. A Dyalog service is run under the auspices of Local System.

Installing and Uninstalling a Dyalog Service

To install a Dyalog service it is necessary to run dyalog.exe from the command line with administrator privileges, specifying the application workspace and the following parameters, where service_name is a name of your choice.

  • APL_ServiceInstall=service_name

The command must specify the full pathname to dyalog.exe and to the application workspace. A slightly modified version of this command line will be stored by the SCM and re-executed whenever the service is started.

Dyalog installs the service with a Startup Type of Automatic. This means that it will be started automatically whenever the computer is restarted. However, it is necessary to start it manually (using the SCM) the first time after it is installed.

The same command must be used to uninstall the service, but with:

  • APL_ServiceUninstall=service_name

The following table summarises the parameters that can be specified by the user. Other parameters will appear on the command line in the SCM, but should not be specified by the user.

Parameter | Description
APL_ServiceInstall | Causes Dyalog to register the named service, using the current command line, but with APL_ServiceRun replacing APL_ServiceInstall in the SCM.
APL_ServiceUninstall | Causes Dyalog to uninstall the named service.

The Application Workspace

The application workspace must be designed to handle and respond (in a timely manner) to notification messages from the SCM as well as to provide the application logic. SCM notifications include instructions to start, stop, pause and resume.

SCM notification messages generate a ServiceNotification event on the Root object. To handle these messages, it is necessary to attach a callback function to this event, and to invoke the Wait method or ⎕DQ'.' to process them. This must be executed in thread 0.

If the application is designed to be driven from events such as Timer or TCPSocket or user-defined events, it too may be implemented via callbacks in thread 0 under the control of the same Wait method or ⎕DQ'.'. If the application uses Conga it is recommended that it runs in a separate thread.

The workspace ws\aplservice.dws is included in the APL release. Its start-up function is as follows:

     ⎕lX←'Start'

     ∇ Start;ServiceState;ServiceControl
[1]    :If 'W'≠3⊃#.⎕WG'APLVersion'
[2]        ⎕←'This workspace only works using Dyalog APL for
              Windows version 14.0 or later'
[3]        :Return
[4]    :EndIf
[5]    :If 0∊⍴2 ⎕NQ'.' 'GetEnvironment' 'RunAsService'
[6]        Describe
[7]        :Return
[8]    :EndIf
[9]    ⍝ Define SCM constants
[10]   HashDefine
[11]   ⍝ Set up callback to handle SCM notifications
[12]   '.'⎕WS'Event' 'ServiceNotification' 'ServiceHandler'
[13]   ⍝ Global variable defines current state of the service
[14]   ServiceState←SERVICE_RUNNING
[15]   ⍝ Global variable defines last SCM notification to the
         service
[16]   ServiceControl←0
[17]   ⍝ Application code runs in a separate thread
[18]   Main&0
[19]   ⎕DQ'.'
[20]   ⎕OFF
     ∇

Handling ServiceNotification Events

To give the workspace (which may be busy) time to respond to SCM notifications, Dyalog responds immediately to confirm that the service has entered the appropriate pending state. For example, if the notification is SERVICE_CONTROL_STOP, Dyalog informs the SCM that the service state is SERVICE_STOP_PENDING. It is then up to the callback function to confirm that the state has reached SERVICE_STOPPED.

The following sample function is provided in aplservice.dws.

ServiceHandler Callback Function

     ∇ r←ServiceHandler(obj event action state);sink
[1]   ⍝ Callback to handle notifications from the SCM
[2]
[3]   ⍝ Note that the interpreter has already responded
[4]   ⍝ automatically to the SCM with the corresponding
[5]   ⍝ "_PENDING" message prior to this callback being reached
[6]
[7]   ⍝ This callback uses the SetServiceState Method to confirm
[8]   ⍝ to the SCM that the requested state has been reached
[9]
[10]   r←0  ⍝  so returns a 0 result (the event has been handled,
[11]        ⍝ no further action required)
[12]
[13]  ⍝ It stores the desired state in global ServiceState to
[14]  ⍝ notify the application code which must take appropriate
[15]  ⍝ action. In particular, it must respond to a "STOP or
[16]  ⍝ "SHUTDOWN" by terminating the APL session
[17]
[18]   :Select ServiceControl←action
[19]   :CaseList SERVICE_CONTROL_STOP SERVICE_CONTROL_SHUTDOWN
[20]       ServiceState←SERVICE_STOPPED
[21]       state[4 5 6 7]←0
[22]
[23]   :Case SERVICE_CONTROL_PAUSE
[24]       ServiceState←SERVICE_PAUSED
[25]
[26]   :Case SERVICE_CONTROL_CONTINUE
[27]       ServiceState←SERVICE_RUNNING
[28]   :Else
[29]       :If state[2]=SERVICE_START_PENDING
[30]           ServiceState←SERVICE_RUNNING
[31]       :EndIf
[32]   :EndSelect
[33]   state[2]←ServiceState
[34]   sink←2 ⎕NQ'.' 'SetServiceState'state
     ∇

The Application Code

The following function illustrates how the application code for the service might be structured. It is merely an illustration, but however it is done, it is important that the code handles the instructions to pause, continue and stop in an appropriate manner. In this example, the function Main creates a log file and writes to it when the state of the service changes.

     ∇ Main arg;nid;log;LogFile
[1]    ⎕NUNTIE ⎕NNUMS
[2]    log←{((⍕⎕TS),' ',⍵,⎕UCS 13 10)⎕NAPPEND ⍺}
[3]    LogFile←'c:\ProgramData\TEMP\APLServiceLog.txt'
[4]    :Trap 22
[5]        nid←LogFile ⎕NCREATE 0
[6]    :Else
[7]        :Trap 22
[8]            nid←LogFile ⎕NTIE 0
[9]            0 ⎕NRESIZE nid
[10]       :Else
[11]           ⎕←'Unable to tie or create logfile'
[12]       :EndTrap
[13]   :EndTrap
[14]   nid log'Starting'
[15]   :While ServiceState≠SERVICE_STOPPED
[16]       :If ServiceControl≠0 ⋄
               nid log'ServiceControl=',⍕ServiceControl ⋄ :EndIf
[17]       :If ServiceState=SERVICE_RUNNING
[18]           nid log'Running'
[19]       :ElseIf ServiceState=SERVICE_PAUSED
[20]           ⍝  Pause application
[21]       :EndIf
[22]       ServiceControl←0 ⍝ Reset (we only want to log changes)
[23]       ⎕DL 10 ⍝ Just to prevent busy loop
[24]   :EndWhile
[25]   ⎕NUNTIE nid
[26]   ⎕OFF 0
     ∇

Debugging Dyalog Services

Services are run in the background under the auspices of Local System, and not associated with an interactive user. Neither the APL Session nor any GUI components that it creates will be visible on the desktop. This prevents the normal editing and debugging tools from being available.

However, the Dyalog APL Remote Integrated Development environment (RIDE) may be connected to any APL session, including one running as a Windows Service, and provide a debugging environment. For more information, see the RIDE User Guide. Note however that the Conga DLLs/shared libraries must be available - usually they should reside in the same directory as the interpreter. In previous versions of Dyalog separate RIDE DLLs/shared libraries were supplied; these have been subsumed into the Conga libraries in 16.0.

Event Logging

When a service is installed or removed, Dyalog APL records events in the Dyalog APL section of the Applications and Services Logs which can be viewed using the Windows system Event Viewer.


APLService Logging Events

The aplservice workspace contains the class SysLog which can be used to log events to the Windows Event Log. These events can be accessed programmatically or viewed using the Windows Event Viewer found in the Windows Administrative Tools.

Windows Event Log Concepts

Every message logged in the Windows Event Log has a named source. Frequently this source will be the name of the application which generates the message. Windows has multiple event log files. By default, messages will be logged in the Application log file found in the Windows Logs section of the Windows Event Viewer. Alternatively, you can create a custom log located in the Applications and Services Logs section in the Windows Event Viewer as shown by the "mylog" entry in the screenshot below. Multiple applications can use the same source and multiple sources can write to the same log file, but a given source may only write to a single log file.

Using SysLog in Your Application

Before deploying your Dyalog APL application as a service, you should:

  1. Consider what events or messages the application should log and their severity level. SysLog allows you to specify severity levels of Error, Warning, and Informational.
  2. Create the log source and optionally its custom log using SysLog.CreateEventSource. This must be done when running Dyalog as an administrator and prior to running your Dyalog service. Once the event source is created, it is not necessary to run your application as an administrator in order to write to the Windows Event Log.
  3. Within your application, you have two options for writing to the Windows Event Log:
    1. You may use the SysLog.WriteLog method. SysLog.WriteLog will verify that the log source exists and then write your message. This has the advantage of being standalone and can be called whenever you desire
    2. You may create an instance of the SysLog class and use the Write method. This has the advantage of not incurring the overhead of verifying the existence of the log source each time a log message is written

SysLog Usage

SysLog implements an interface to a subset of the functionality of Microsoft's System.Diagnostics.EventLog class. Some of SysLog's methods, namely CreateEventSource, DeleteEventSource and DeleteLog, require you to run Dyalog as an administrator to be fully functional.

All of the methods in SysLog with the exception of Write are shared methods meaning you do not have to create an instance of SysLog in order to execute them.

SysLog.CreateEventSource sourcename {logname}

Purpose:

Creates a new Windows Event Log source and optionally specifies or creates a Windows Event Log for the source.

Argument | Description
sourcename | character vector source name that does not already exist
{logname} | optional character vector log name with which to associate the source name. If not supplied, the source will be associated with the Windows Logs/Application log. If there is no log named logname, it will be created.
{level} SysLog.WriteLog sourcename message

Purpose:

Writes a message to the Windows Event Log associated with sourcename, optionally specifying a severity level.

Argument | Description
sourcename | character vector source name of an existing source
message | character vector message to write to the log
{level}

optional singleton indicating the severity level of the message; defaults to informational if level is not specified:

1,'E' or 'e' | may be used for error messages
2,'W' or 'w' | may be used for warning messages
3,'I' or 'i' | may be used for informational messages
{level} instance.Write message

Purpose:

Writes a message to the Windows Event Log associated with source name specified for the SysLog instance, optionally specifying a severity level.

Argument | Description
sourcename | character vector source name of an existing source
message | character vector message to write to the log
{level}

optional singleton indicating the severity level of the message; defaults to informational if level is not specified:

1,'E' or 'e' | may be used for error messages
2,'W' or 'w' | may be used for warning messages
3,'I' or 'i' | may be used for informational messages

Example:

      logger←⎕NEW SysLog 'mysource'
      1 logger.Write 'The sky is falling!'
Boolean←SysLog.LogExists logname

Purpose:

Returns 1 if a Windows Event Log named logname exists, 0 otherwise.

Argument | Description
logname | character vector Windows Event Log log name
Boolean←SysLog.EventSourceExists sourcename

Purpose:

Returns 1 if a Windows Event Log source named sourcename exists, 0 otherwise.

Argument | Description
sourcename | character vector Windows Event Log source name
logname←LogNameFromSourceName sourcename

Purpose:

Returns the Windows Event Log log name associated with the source named sourcename.

Argument | Description
sourcename | character vector Windows Event Log source name
logname | character vector Windows Event Log log name
DeleteEventSource sourcename

Purpose:

Deletes the Windows Event Log source named sourcename.

Argument | Description
sourcename | character vector Windows Event Log source name
DeleteLog logname

Purpose:

Deletes the Windows Event Log log named logname.

Argument | Description
logname | character vector Windows Event Log log name


Workspaces

APL expressions are evaluated within a workspace. The workspace may contain objects, namely classes, namespaces, operators, functions and variables defined by the user. APL expressions may include references to primitive operators, functions and variables provided by APL. These objects do not reside in the workspace, but space is required for the actual process of evaluation to accommodate temporary data. During execution, APL records the state of execution through the STATE INDICATOR which is dynamically maintained until the process is complete. Space is also required to identify objects in the workspace in the SYMBOL TABLE. Maintenance of the symbol table is entirely dynamic. It grows and contracts according to the current workspace contents.

Workspaces may be explicitly saved with an identifying name. The workspace may subsequently be loaded, or objects may be selectively copied from a saved workspace into the current workspace.

Under UNIX, workspace names must be valid file names, but are otherwise unrestricted. See your UNIX documentation for details.

Under Windows, Dyalog APL workspaces are stored in files with the suffix ".DWS". However, they are referred to from within APL by only the first part of the file name which must conform to Windows file naming rules.

If the name of the file in which the workspace is saved contains spaces, the ws argument for the system functions )SAVE, )COPY, )PCOPY, )LOAD, )XLOAD and )DROP should be surrounded by two double-quote (") characters. To include a " character in the file name, you must specify two adjoining double-quotes (i.e. """"). Note however that Windows does not allow double-quotes in file names, so this effectively applies only to non-Windows systems.

Examples

      )SAVE Pete's work
unacceptable char

The above statement fails because the presence of the space in the file name requires that it be surrounded by "s.

      )SAVE "Pete's work"
Pete's work.dws saved Sun Jan 17 16:23:17 2016

      )COPY "Pete's work" A B C
.\Pete's work.dws saved Sun Jan 17 16:23:17 2016

      )DROP "Pete's work"
Sun Jan 17 16:24:16 2016


Arrays

A Dyalog APL data structure is called an array. An array is a rectangular arrangement of items, each of which may be a single number, a single character, a namespace reference (ref), another array, or the ⎕OR of an object. An array which is part of another array is also known as a subarray.

An array has two properties; structure and data type. Structure is identified by rank, shape, and depth.

Rank

An array may have 0 or more axes or dimensions. The number of axes of an array is known as its rank. Dyalog APL supports arrays with a maximum of 15 axes.

  • An array with 0 axes (rank 0) is called a scalar.
  • An array with 1 axis (rank 1) is called a vector.
  • An array with 2 axes (rank 2) is called a matrix.
  • An array with more than 2 axes is called a multi-dimensional array.

Shape

Each axis of an array may contain zero or more items. The number of items along each axis of an array is called its shape. The shape of an array is itself a vector. Its first item is the length of the first axis, its second item the length of the second axis, and so on. An array, whose length along one or more axes is zero, is called an empty array.

Depth

An array whose items are all simple scalars (i.e. single numbers, characters or refs) is called a simple array. If one or more items of an array is not a simple scalar (i.e. is another array, or a ⎕OR), the array is called a nested array. A nested array may contain items which are themselves nested arrays. The degree of nesting of an array is called its depth. A simple scalar has a depth of 0. A simple vector, matrix, or multi-dimensional array has depth 1. An array whose items are all depth 1 subarrays has depth 2; one whose items are all depth 2 subarrays has depth 3, and so forth.

Type

An array, whose elements are all numeric, is called a numeric array; its TYPE is numeric. A character array is one in which all items are characters. An array whose items contain both numeric and character elements is of MIXED type.


Numbers

Dyalog APL supports both real numbers and complex numbers.

Real Numbers

Numbers are entered or displayed using conventional decimal notation (e.g. 299792.458) or using a scaled form (e.g. 2.999792458E5).

On entry, a decimal point is optional if there is no fractional part. On output, a number with no fractional part (an integer) is displayed without a decimal point.

The scaled form consists of:

  1. an integer or decimal number called the mantissa,
  2. the letter E or e,
  3. an integer called the scale, or exponent.

The scale specifies the power of 10 by which the mantissa is to be multiplied.

Example

      12 23.24 23.0 2.145E2
12 23.24 23 214.5

Negative numbers are preceded by the high minus (¯) symbol, not to be confused with the minus (-) function. In scaled form, both the mantissa and the scale may be negative.

Example

      ¯22 2.145E¯2 ¯10.25
¯22 0.02145 ¯10.25

Complex Numbers

Complex numbers use the J notation introduced in IBM APL2 and are written as aJb or ajb (without spaces) where the real and imaginary parts a and b are written as described above. The capital J is always used to display a value.

Examples

      2+¯1*.5
2J1
      .3j.5
0.3J0.5
    1.2E5J¯4E¯4
120000J¯0.0004

The empty vector (⍳0) may be represented by the numeric constant ⍬ called ZILDE.


Characters

Characters are entered within a pair of APL quotes. The surrounding APL quotes are not displayed on output. The APL quote character itself must be entered as a pair of APL quotes.

Examples

      'DYALOG APL'
DYALOG APL
      'I DON''T KNOW'
I DON'T KNOW
      '*'
*


Enclosed Elements

An array may be enclosed to form a scalar element through any of the following means:

  • by the enclose function (⊂)
  • by inclusion in vector notation
  • as the result of certain functions when applied to arrays

Examples

      (⊂1 2 3),⊂'ABC'
1 2 3  ABC

    (1 2 3) 'ABC'
1 2 3  ABC

      ⍳2 3
1 1  1 2  1 3
2 1  2 2  2 3


Legal Names

APL objects may be given names. A name may be any sequence of characters, starting with a non-numeric character, selected from the following:

ABCDEFGHIJKLMNOPQRSTUVWXYZ_
abcdefghijklmnopqrstuvwxyz
ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß
àáâãäåæçèéêëìíîïðñòóôõöøùúûüþ
0123456789
∆⍙
ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ

Note that using a standard Unicode font (rather than APL385 Unicode used in the table above), the last row above would appear as the circled alphabet, Ⓐ to Ⓩ.

Examples

Legal | Illegal
THIS∆IS∆A∆NAME | BAD NAME
X1233 | 3+21
SALES | S!H|PRICE
pjb_1 | 1_pjb


Specification of Variables

A variable is a named array. An undefined name or an existing variable may be assigned an array by specification with the left arrow (←).

Examples

      A←'CHIPS WITH EVERYTHING'
      A
CHIPS WITH EVERYTHING

      X Y←'ONE' 'TWO'
      X
ONE
      Y
TWO


Vector Notation

A series of two or more adjacent expressions results in a vector whose elements are the enclosed arrays resulting from each expression. This is known as vector (or strand) notation. Each expression in the series may consist of one of the following:

  1. a single numeric value
  2. single character, within a pair of quotes
  3. more than one character, within a pair of quotes
  4. the name of a variable
  5. the evaluated input symbol ⎕
  6. the quote-quad symbol ⍞
  7. the name of a niladic, defined function yielding a result
  8. any other APL expression which yields a result, within parentheses

Examples

      ⍴A←2 4 10
3
      ⍴TEXT←'ONE' 'TWO'
2

Numbers and characters may be mixed:

      ⍴X←'THE ANSWER IS ' 10
2
      X[1]
 THE ANSWER IS
      X[2] + 32
42

Blanks, quotes or parentheses must separate adjacent items in vector notation. Redundant blanks and parentheses are permitted. In this manual, the symbol pair '←→' indicates the phrase 'is equivalent to'.

      1  2  ←→ (1)(2) ←→ 1  (2)  ←→ (1)  2
      2'X'3 ←→ 2 'X' 3 ←→ (2) ('X') (3)
      1  (2+2) ←→ (1) ((2+2)) ←→ ((1))  (2+2)

Vector notation may be used to define an item in vector notation:

       ⍴X ← 1 (2 3 4) ('THIS' 'AND' 'THAT')
3
      X[2]
 2 3 4
      X[3]
  THIS  AND  THAT

Expressions within parentheses are evaluated to produce an item in the vector:

      Y ← (2+2) 'IS' 4
      Y
4  IS  4

The following identity holds:

      A  B  C  ←→ (⊂A), (⊂B), ⊂C


Structuring of Arrays

A class of primitive functions re-structures arrays in some way. Arrays may be input only in scalar or vector form. Structural functions may produce arrays with a higher rank. The Structural functions are reshape (⍴), ravel, laminate and catenate (,), reverse and rotate (⌽), transpose (⍉), mix and take (↑), split and drop (↓), enlist (∊), and enclose (⊂).

Examples

      2 2⍴1 2 3 4
1 2
3 4

      2 2 4⍴'ABCDEFGHIJKLMNOP'
ABCD
EFGH

IJKL
MNOP
         ↓2 4⍴'COWSHENS'
 COWS  HENS


Display of Arrays

Simple scalars and vectors are displayed in a single line beginning at the left margin. A number is separated from the next adjacent element by a single space. The number of significant digits to be printed is determined by the system variable ⎕PP whose default value is 10. The fractional part of the number will be rounded in the last digit if it cannot be represented within the print precision. Trailing zeros after a decimal point and leading zeros will not be printed. An integer number will display without a decimal point.

Examples

      0.1 1.0 1.12
0.1 1 1.12

      'A' 2 'B' 'C'
A 2 BC

      ÷3 2 6
0.3333333333 0.5 0.1666666667

If a number cannot be fully represented in ⎕PP significant digits, or if the number requires more than five leading zeros after the decimal point, the number is represented in scaled form. The mantissa will display up to ⎕PP significant digits, but trailing zeros will not be displayed.

Examples

      ⎕PP←3

      123 1234 12345 0.12345 0.00012345 0.00000012345
123 1.23E3 1.23E4 0.123 0.000123 1.23E¯7

Simple matrices are displayed in rectangular form, with one line per matrix row. All elements in a given column are displayed in the same format, but the format and width for each column is determined independently of other columns. A column is treated as numeric if it contains any numeric elements. The width of a numeric column is determined such that the decimal points (if any) are aligned; that the E characters for scaled formats are aligned, with trailing zeros added to the mantissae if necessary, and that integer forms are right-adjusted one place to the left of the decimal point column (if any). Numeric columns are right-justified; a column which contains no numeric elements is left-justified. Numeric columns are separated from their neighbours by a single column of blanks.

Examples

      2 4⍴'HANDFIST'
HAND
FIST

      1 2 3 ∘.× 6 2 5
 6 2  5
12 4 10
18 6 15

      2 3⍴2 4 6.1 8 10.24 12
2  4     6.1
8 10.24 12

      2 4⍴4 'A' 'B' 5 ¯0.000000003 'C' 'D' 123.56
 4E0  AB   5
¯3E¯9 CD 123.56

In the display of non-simple arrays, each element is displayed within a rectangle such that the rows and columns of the array are aligned. Simple items within the array are displayed as above. For non-simple items, this rule is applied recursively, with one space added on each side of the enclosed element for each level of nesting.

Examples

      ⍳3
1 2 3

      ⊂⍳3
 1 2 3

      ⊂⊂⍳3
  1 2 3

      ('ONE' 1) ('TWO' 2) ('THREE' 3) ('FOUR' 4)
  ONE  1   TWO  2   THREE  3   FOUR  4

      2 4⍴'ONE' 1 'TWO' 2 'THREE' 3 'FOUR' 4
 ONE    1  TWO   2
 THREE  3  FOUR  4

Multi-dimensional arrays are displayed in rectangular planes. Planes are separated by one blank line, and hyper-planes of higher dimensions are separated by increasing numbers of blank lines. In all other respects, multi-dimensional arrays are displayed in the same manner as matrices.

Examples

      2 3 4⍴⍳24
 1  2  3  4
 5  6  7  8
 9 10 11 12

13 14 15 16
17 18 19 20
21 22 23 24

      3 1 1 3⍴'THEREDFOX'
THE

RED

FOX

The power of this form of display is made apparent when formatting informal reports.

Examples

      +AREAS←'West' 'Central' 'East'
 West  Central  East

      +PRODUCTS←'Biscuits' 'Cakes' 'Buns' 'Rolls'
 Biscuits  Cakes  Buns  Rolls

      SALES←50 5.25 75 250 20.15 900 500
      SALES,←80.98 650 1000 90.03 1200
      +SALES←4 3⍴SALES
  50  5.25   75
 250 20.15  900
 500 80.98  650
1000 90.03 1200

      ' ' PRODUCTS ⍪., AREAS SALES
            West  Central  East
 Biscuits     50     5.25    75
 Cakes       250    20.15   900
 Buns        500    80.98   650
 Rolls      1000    90.03  1200

If the display of an array is wider than the page width, as set by the system variable ⎕PW, it will be folded at or before ⎕PW and the folded portions indented six spaces. The display of a simple numeric or mixed array may be folded at a width less than ⎕PW so that individual numbers are not split across a page boundary.

Example

      ⎕PW←40

      ?3 20⍴100
54 22  5 68 68 94 39 52 84  4  6 53 68
85 53 10 66 42 71 92 77 27  5 74 33 64
66  8 64 89 28 44 77 48 24 28 36 17 49
       1  39  7 42 69 49 94
      76 100 37 25 99 73 76
      90  91  7 91 51 52 32

The ]display User Command

The user command ]display illustrates the structure of an array.

Examples

      ]display 'ABC' (1 4⍴1 2 3 4)
┌→────────────────┐
│ ┌→──┐ ┌→──────┐ │
│ │ABC│ ↓1 2 3 4│ │
│ └───┘ └~──────┘ │
└∊────────────────┘

      ]display ' 'PRODUCTS⍪.,AREAS SALES ⍝ see above
┌────────────────────────────────────────┐
│ ┌→───────────────────────────────────┐ │
│ ↓            ┌→───┐ ┌→──────┐ ┌→───┐ │ │
│ │            │West│ │Central│ │East│ │ │
│ │ -          └────┘ └───────┘ └────┘ │ │
│ │ ┌→───────┐                         │ │
│ │ │Biscuits│ 50     5.25      75     │ │
│ │ └────────┘                         │ │
│ │ ┌→────┐                            │ │
│ │ │Cakes│    250    20.15     900    │ │
│ │ └─────┘                            │ │
│ │ ┌→───┐                             │ │
│ │ │Buns│     500    80.98     650    │ │
│ │ └────┘                             │ │
│ │ ┌→────┐                            │ │
│ │ │Rolls│    1000   90.03     1200   │ │
│ │ └─────┘                            │ │
│ └∊───────────────────────────────────┘ │
└∊───────────────────────────────────────┘

An explanation of the symbols that appear in the borders can be seen by running ]display -?

The ]boxing User Command

The user command ]boxing changes the way in which nested arrays are the displayed in the Session. The following examples show different settings.

Examples

      ]boxing on -style=min
Was OFF -style=min

      'ABC' (1 4⍴1 2 3 4)
┌───┬───────┐
│ABC│1 2 3 4│
└───┴───────┘

      ]boxing on -style=mid
Was ON -style=min

      'ABC' (1 4⍴1 2 3 4)
┌→──┬───────┐
│ABC│1 2 3 4↓
└──→┴~─────→┘

      ]boxing on -style=max
┌→────────────────┐
│Was ON -style=mid│
└─────────────────┘

      'ABC' (1 4⍴1 2 3 4)
┌→────────────────┐
│ ┌→──┐ ┌→──────┐ │
│ │ABC│ ↓1 2 3 4│ │
│ └───┘ └~──────┘ │
└∊────────────────┘

      ]boxing on -style=min
Was ON -style=max
      ]boxing off
Was ON

      'ABC' (1 4⍴1 2 3 4)
 ABC  1 2 3 4

Shy Results

Functions may return shy results.

A shy or suppressed result is a result that is not automatically displayed in the Session, but is suppressed. A shy result of an expression may be displayed by using it as an argument to a function that returns its argument unchanged, by enclosing the expression in parentheses or by assigning it to ⎕.

Examples

      A←10 ⍝ Result of assignment is shy
      (A←10)
10
      ⎕DL 2 ⍝ Result of delay is shy
      ⎕←⎕DL
1.994
      foo&88  ⍝ Result of Spawn (thread number) is shy
      ⊣foo&88
6

See also:

  • Model Syntax
  • Shy Result
  • Execute Expression.


Prototypes and Fill Items

Every array has an associated prototype which is derived from the array's first item.

If the first item is a number, the prototype is 0. Otherwise, if the first item is a character, the prototype is ' '(space). Otherwise, if the first item is a (ref to) an instance of a Class, the prototype is a ref to that Class.

Otherwise (in the nested case, when the first item is other than a simple scalar), the prototype is defined recursively as the prototype of each of the array's first item.

Examples:

Array | Prototype
1 2 3.4 | 0
2 3 5⍴'hello' | ' '
99 'b' 66 | 0
(1 2)(3 4 5) | 0 0
((1 2)3)(4 5 6) | (0 0)0
'hello' 'world' | ' '
⎕NEW MyClass | MyClass
(88(⎕NEW MyClass)'X')7 | 0 MyClass ' '

Fill Items

Fill items for an overtake operation, are derived from the argument's prototype. For each 0 or ' ' in the prototype, there is a corresponding 0 or ' ' in the fill item and for each class reference in the prototype, there is a ref to a (newly constructed and distinct) instance of that class that is initialised by the niladic (default) constructor for that class, if defined.

Examples:

      4↑1 2
1 2 0 0
      4↑'ab'
ab
      4↑(1 2)(3 4 5)
 1 2  3 4 5  0 0  0 0
      2↑⎕NEW MyClass
 #.[Instance of MyClass]  #.[Instance of MyClass]

In the last example, two distinct instances are constructed (the first by ⎕NEW and the second by the overtake).

Fill items are used in a number of operations including:

  • First (⊃ or ↑) of an empty array
  • Fill-elements for overtake
  • For use with the Each operator on an empty array


Cells and Sub-arrays

Certain functions and operators operate on particular cells or sub-arrays of an array, which are identified and described as follows.

K-Cells

A rank-k cell or k-cell of an array are terms used to describe a sub-array on the last k axes of the array. Negative k is interpreted as r+k where r is the rank of the array, and is used to describe a sub-array on the leading |k axes of an array.

If X is a 3-dimensional array of shape 2 3 4, the 1-cells are its 6 rows each of 4 elements; and its 2-cells are its 2 matrices each of shape 3 4. Its 3-cells is the array in its entirety. Its 0-cells are its individual elements.

Major Cells

The major cells of an array X is a term used to describe the sub-arrays on the leading dimension of the array X with shape 1↓⍴X. Using the k-cell terminology, the major cells are its ¯1-cells.

The major cells of a vector are its elements (0-cells). The major cells of a matrix are its rows (1-cells), and the major cells of a 3-dimensional array are its matrices along the first dimension (2-cells).

Examples

In the following, the major cells of A are 1979, 1990, 1997, 2007, and 2010; those of B are 'Thatcher', 'Major', 'Blair', 'Brown', and 'Cameron'; and those of C are the four 2-by-3 matrices.

      A
1979 1990 1997 2007 2010

      B
Thatcher
Major
Blair
Brown
Cameron

   ⍴B
5 8

    ⎕←C←4 2 3⍴⍳24
 0  1  2
 3  4  5

 6  7  8
 9 10 11

12 13 14
15 16 17

18 19 20
21 22 23

Using the k-cell terminology, if r is the rank of the array, its major cells are its r-1-cells.

Note that if the right operand k of the Rank Operator ⍤ is negative, it is interpreted as 0⌈r+k. Therefore the value ¯1 selects the major cells of the array.


Expressions

An expression is a sequence of one or more syntactic tokens which may be symbols or constants or names representing arrays (variables) or functions. An expression which produces an array is called an ARRAY EXPRESSION. An expression which produces a function is called a FUNCTION EXPRESSION. Some expressions do not produce a result.

An expression may be enclosed within parentheses.

Evaluation of an expression proceeds from right to left, unless modified by parentheses. If an entire expression results in an array that is not assigned to a name, then that array value is displayed. (Some system functions and defined functions return an array result only if the result is assigned to a name or if the result is the argument of a function or operator.)

Examples

      X←2×3-1

      2×3-1
4
      (2×3)-1
5

Either blanks or parentheses are required to separate constants, the names of variables, and the names of defined functions which are adjacent. Excessive blanks or sets of parentheses are redundant, but permitted. If F is a function, then:

      F 2←→ F(2) ←→ (F)2 ←→ (F) (2) ←→ F  (2) ←→ F ((2))

Blanks or parentheses are not needed to separate primitive functions from names or constants, but they are permitted:

      -2 ←→ (-)(2) ←→ (-) 2

Blanks or parentheses are not needed to separate operators from primitive functions, names or constants. They are permitted with the single exception that a dyadic operator must have its right argument available when encountered. The following syntactical forms are accepted:

      (+.×) ←→ (+).× ←→ +.(×)

The use of parentheses in the following examples is not accepted:

      +(.)×  or     (+.)×


Functions

A function is an operation which is performed on zero, one or two array arguments and may produce an array result. Three forms are permitted:

  • NILADIC defined for no arguments
  • MONADIC defined for a right but not a left argument
  • DYADIC defined for a left and a right argument

The number of arguments is referred to as its VALENCE.

The name of a non-niladic function is AMBIVALENT; that is, it potentially represents both a monadic and a dyadic function, though it might not be defined for both. The usage in an expression is determined by syntactical context. If the usage is not defined an error results.

Functions have long SCOPE on the right; that is, the right argument of the function is the result of the entire expression to its right which must be an array. A dyadic function has short scope on the left; that is, the left argument of the function is the array immediately to its left. Left scope may be extended by enclosing an expression in parentheses whence the result must be an array.

For some functions, the explicit result is suppressed if it would otherwise be displayed on completion of evaluation of the expression. This applies on assignment to a variable name. It applies for certain system functions, and may also apply for defined functions.

Examples

      10×5-2×4
¯30
      2×4
8
      5-8
¯3
      10×¯3
¯30
      (10×5)-2×4
42

Defined Functions

Functions may be defined with the system function ⎕FX, or with the function editor. A function consists of a HEADER which identifies the syntax of the function, and a BODY in which one or more APL statements are specified.

The header syntax identifies the function name, its (optional) result and its (optional) arguments. If a function is ambivalent, it is defined with two arguments but with the left argument within braces ({}). If an ambivalent function is called monadically, the left argument has no value inside the function. If the explicit result is to be suppressed for display purposes, the result is shown within braces. A function need not produce an explicit result. Refer to Chapter 2 for further details.

Example

     ∇ R←{A} FOO B
[1]    R←⊃'MONADIC' 'DYADIC'[⎕IO+0≠⎕NC'A']
[2]  ∇

      FOO 1
MONADIC

      'X' FOO 'Y'
DYADIC

Functions may also be created by using assignment (←).

Function Assignment & Display

The result of a function-expression may be given a name. This is known as FUNCTION ASSIGNMENT (see also Dfns & Dops). If the result of a function-expression is not given a name, its value is displayed. This is termed FUNCTION DISPLAY.

Examples

      PLUS←+
      PLUS
+
      SUM←+/
      SUM
+/

Function expressions may include defined functions and operators. These are displayed as a ∇ followed by their name.

Example

      ∇ R←MEAN X    ⍝ Arithmetic mean
[1]     R←(+/X)÷⍴X
      ∇

      MEAN
 ∇MEAN

      AVERAGE←MEAN
      AVERAGE
 ∇MEAN

      AVG←MEAN∘,
      AVG
 ∇MEAN ∘,


Operators

An operator is an operation on one or two operands which produces a function called a DERIVED FUNCTION. An operand may be a function or an array. Operators are not ambivalent. They require either one or two operands as applicable to the particular operator. However, the derived function may be ambivalent. The derived function need not return a result. Operators have higher precedence than functions. Operators have long scope on the left. That is, the left operand is the longest function or array expression on its left. The left operand may be terminated by:

  1. the end of the expression
  2. the right-most of two consecutive functions
  3. a function with an array to its left
  4. an array with a function to its left

an array or function to the right of a monadic operator.

A dyadic operator has short scope on the right. That is, the right operand of an operator is the single function or array on its right. Right scope may be extended by enclosing an expression in parentheses.

Examples

      ⍴¨X←'WILLIAM' 'MARY' 'BELLE'
 7  4  5

      ⍴∘⍴¨X
 1  1  1

      (⍴∘⍴)¨X
 1  1  1

      ⎕∘←∘⎕VR¨'PLUS' 'MINUS'
     ∇ R←A PLUS B
[1]    R←A+B
     ∇
     ∇ R←A MINUS B
[1]    R←A-B
     ∇

      PLUS/1 2 3 4
10

Defined Operators

Operators may be defined with the system function ⎕FX, or with the function editor. A defined operator consists of a HEADER which identifies the syntax of the operator, and a BODY in which one or more APL statements are specified.

A defined operator may have one or two operands; and its derived function may have one or two arguments, and may or may not produce a result. The header syntax defines the operator name, its operand(s), the argument(s) to its derived function, and the result (if any) of its derived function. The names of the operator and its operand(s) are separated from the name(s) of the argument(s) to its derived function by parentheses.

Example

      ∇ R←A(F AND G)B
[1]     R←(A F B)(A G B)
      ∇

The above example shows a dyadic operator called AND with two operands (F and G). The operator produces a derived function which takes two arguments (A and B), and produces a result (R).

      12 +AND÷ 4
16 3

Operands passed to an operator may be either functions or arrays.

      12 (3 AND 5) 4
12 3 4  12 5 4

      12 (× AND 5) 4
48  12 5 4


Binding Strength

For two entities X and Y that are adjacent in an expression (that is, X Y), the binding strength between them and the result of the bind is shown in this table:

Y
A F H MOP DOP DOT IDX
X A
6 A
3 AF
3 AF
4 F
7 REF
4 A
F
2 A
1 F
4 F
4 F
4 F
H
1 F
4 F
4 F
4 H
AF
2 A
1 F
MOP
4 ERR
DOP
5 MOP
5 MOP
5 MOP
JOT
5 MOP
5 MOP
5 MOP
4 F
DOT
6 ERR
5 MOP
5 MOP
6 ERR
REF
7 A
7 F
7 H
7 MOP
7 DOP
IDX
3 ERR
3 ERR
3 ERR
A | : *Array, for example, 0 1 2 'hello' ⍺ ⍵
F | : *Function (primitive/defined/derived/system), for example, + - +.× myfn ⎕CR {⍺ ⍵}
H | : *Hybrid function/operator, that is, / ⌿ \ ⍀
AF | : Bound left argument, for example, 2+
MOP | : *Monadic operator, for example, ¨ ⍨ &
DOP | : Dyadic operator, for example, ⍣ ⍠ ⍤ ⌸
JOT | : Jot, that is, compose/null operand ∘
DOT | : Dot, that is, reference/product .
IDX | : square-bracketed expression, for example, [⍺+⍳⍵]
ERR | : Error

* indicates a "first-class" entity, which can be parenthesised or named

In this table:

  • the higher the number, the stronger the binding
  • an empty field indicates no binding for this combination; an error.

For example, in the expression a b.c[d], where a, b, c and d are arrays, the binding proceeds:

      a b . c [d]
       6 7 6 4      ⍝ binding strengths between entities
→     a (b.) c [d]
       0    7 4
→     a (b.c) [d]
       6     4
→     (a(b.c))[d]


Function Trains

Introduction

A Train is a derived function constructed from a sequence of 2 or 3 functions, or from an array followed by two functions, which bind together to form a function.

Forks and Atops

The following trains are currently supported where f, g and h are functions and A is an array:

      f g h
      A g h
        g h

The 3-item trains (f g h) and (A g h) are termed forks while the 2-item train (g h) is termed an atop. To distinguish the two styles of fork, we can use the terms fgh-fork or Agh-fork.

Trains as Functions

A train is syntactically equivalent to a function and so, in common with any other function, may be:

  • named using assignment
  • applied to or between arguments
  • consumed by operators as an operand
  • and so forth.

In particular, trains may be applied to a single array (monadic use) or between 2 arrays (dyadic use), providing six new constructs.

    ⍺(f g h)⍵ ←→ (⍺ f ⍵) g (⍺ h ⍵)   ⍝ dyadic (fgh) fork
    ⍺(A g h)⍵ ←→    A    g (⍺ h ⍵)   ⍝ dyadic (Agh) fork
    ⍺(  g h)⍵ ←→         g (⍺ h ⍵)   ⍝ dyadic       atop

     (f g h)⍵ ←→ (  f ⍵) g (  h ⍵)   ⍝ monadic (fgh) fork
     (A g h)⍵ ←→    A    g (  h ⍵)   ⍝ monadic (Agh) fork
     (  g h)⍵ ←→         g (  h ⍵)   ⍝ monadic       atop

Identifying a Train

For a sequence to be interpreted as a train it must be separated from the argument to which it is applied. This can be done using parentheses or by naming the derived function.

Example - fork: negation of catenated with reciprocal

      (-,÷)5
¯5 0.2

Example - named fork

      negrec←-,÷
      negrec 5
 ¯5 0.2

Whereas, without these means to identify the sequence as a train, the expression:

      -,÷ 5
¯0.2

means the negation of the ravel of the reciprocal of 5.

Idiom Recognition

Function trains lend themselves to idiom recognition, a technique used to optimise the performance of certain expressions.

Example

An expression to find the first position in a random integer vector X of a number greater than 999000 is:

      X←?1e6⍴1e6
      (X≥999000)⍳1
1704

A function train is not only more concise, it is faster too.

      X (⍳∘1 ≥) 999000
1704

Trains of Trains

As a train resolves to a function, a sequences of more than 3 functions represents a train of trains. Function sequences longer than 3 are bound in threes, starting from the right:

... fu fv fw fx fy fz → ... fu (fv fw (fx fy fz))

This means that, in the absence of parentheses, a sequence of an odd number of functions resolves to a 3-train (fork) and an even-numbered sequence resolves to a 2-train (atop):

e f g h i j k → e f(g h(i j k))     ⍝ fork(fork(fork))
f g h i j k →   f(g h(i j k))       ⍝ atop(fork(fork))

Examples

      6( +,-,×,÷)2     ⍝ fork:(6+2),((6-2),((6×2),(6÷2)))
8 4 12 3

      6(⌽+,-,×,÷)2     ⍝ atop: ⌽ (6+2), ...
3 12 4 8

      ]boxing on
Was OFF
      +,-,×,÷          ⍝ boxed display of fork
┌─┬─┬─────────────┐
│+│,│┌─┬─┬───────┐│
│ │ ││-│,│┌─┬─┬─┐││
│ │ ││ │ ││×│,│÷│││
│ │ ││ │ │└─┴─┴─┘││
│ │ │└─┴─┴───────┘│
└─┴─┴─────────────┘
      ⌽+,-,×,÷         ⍝ boxed display of atop
┌─┬───────────────────┐
│⌽│┌─┬─┬─────────────┐│
│ ││+│,│┌─┬─┬───────┐││
│ ││ │ ││-│,│┌─┬─┬─┐│││
│ ││ │ ││ │ ││×│,│÷││││
│ ││ │ ││ │ │└─┴─┴─┘│││
│ ││ │ │└─┴─┴───────┘││
│ │└─┴─┴─────────────┘│
└─┴───────────────────┘
      ]boxing -trains=tree
Was -trains=box
      +,-,×,÷          ⍝ boxed (tree) display of fork
┌─┼───┐
+ , ┌─┼───┐
    - , ┌─┼─┐
        × , ÷

Binding Strengths

The binding strength between the items of a train is less than that of operand-operator binding. In other words, operators bind first with their function (or array) operands to form derived functions, which may then participate as items in a train.

Example:

      +⌿ ÷ ≢            ⍝ fork for mean value
┌─────┬─┬─┐
│┌─┬─┐│÷│≢│
││+│⌿││ │ │
│└─┴─┘│ │ │
└─────┴─┴─┘

      ⌊/,⌈/             ⍝ fork for min_max
┌─────┬─┬─────┐
│┌─┬─┐│,│┌─┬─┐│
││⌊│/││ ││⌈│/││
│└─┴─┘│ │└─┴─┘│
└─────┴─┴─────┘

This means that any of the four hybrid tokens / ⌿ \ ⍀ will not be interpreted as a function if there's a function to its left in the train. In order to fix one of these tokens as a replicate or expand function, it must be isolated from the function to its left:

      (⍳/⍳)3        ⍝ → ⍳/ atop ⍳3 → RANK ERROR
RANK ERROR

      (⍳{⍺/⍵}⍳)3    ⍝ → (⍳3){⍺/⍵}(⍳3) → (⍳3)/(⍳3)
1 2 2 3 3 3

      (⍳(/∘⊢)⍳)3    ⍝ → (⍳3)/⊢(⍳3)
1 2 2 3 3 3

      (2/⍳)3        ⍝ Agh-fork is OK
1 1 2 2 3 3


Parallel Execution

If your computer has more than one CPU or is a multi-core processor, then the scalar dyadic functions ÷, ≥, =, ≤, ⍟, |, !, ○, ∨ and ∧ will, when applied to arrays with a sufficiently large number of elements, execute in parallel in separate system threads.

For example, if you have a computer with 4 cores (either real or virtual) and execute an expression such as (A÷B) where A and/or B contain more than 32,768 elements, then Dyalog will start 4 separate threads, each performing the division on ¼ of the elements of the array(s) and simultaneously creating the corresponding ¼ of the result array. The threads are only started once, and are reused for subsequent multi-threaded operations.

The maximum number of threads to use can be controlled using 1111⌶, and the parallel execution threshold is changed using 1112⌶. These "tuning" I-beams should be considered experimental, and may be changed or replaced in a future release. (See Number of Threads and Parallel Execution Threshold).

Note that these scalar dyadic functions are not multi-threaded when applied to arrays of Boolean or integer values, they are also not multi-threaded for +, - or × when applied to arrays of 64 bits floating (type 645). Tests show that the overhead of preparing such arrays for multi-threaded operations outweigh the performance benefits.


Complex Numbers

A complex number is a number consisting of a real and an imaginary part which is usually written in the form a+ bi, where a and b are real numbers, and i is the standard imaginary unit with the property i2= −1.

Dyalog APL adopts the J notation introduced in IBM APL2 to represent the value of a complex number which is written as aJb or ajb (without spaces). The former representation (with a capital J) is always used to display a value.

Notation

      2+¯1*.5
2J1

      .3j.5
0.3J0.5

      1.2E5J¯4E¯4
120000J¯0.0004

Arithmetic

The arithmetic primitive functions handle complex numbers in the appropriate way.

      2j3+.3j.5 ⍝ (a+bi)+(c+di) = (a+c)+(b+d)i
2.3J3.5

      2j3-.3j5  ⍝ (a+bi)-(c+di) = (a-c)+(b-d)i
1.7J¯2

      2j3×.3j.5 ⍝ (a+bi)(c+di)= ac+bci+adi+bdi2
                ⍝             = (ac-bd)+(bc+ad)i
¯0.9J1.9

The absolute value, or magnitude of a complex number is naturally obtained using the Magnitude function

      |3j4
5

Monadic + of a complex number (a+bi) returns its conjugate (a-bi) ...

      +3j4
3J¯4

... which when multiplied by the complex number itself, produces the square of its magnitude.

       3j4×3j¯4
25

Furthermore, adding a complex number and its conjugate produces a real number:

       3j4+3j¯4
6

The famous Euler's Identity Euler's Identity may be expressed as follows:

      1+*○0j1 ⍝ Euler Identity
0

Different Result for Power

From Version 13.0 onwards, the implementation of X*Y (Power) gives a different answer for negative real X than in all previous Versions of Dyalog APL. This change is however in accordance with the ISO/EEC 13751 Standard for Extended APL.

In Version 13.0 onwards, the result is the principal value; whereas in previous Versions the result is a negative or positive real number or DOMAIN ERROR. The following examples illustrate this point:

      ¯8 * 1 2 ÷ 3          ⍝ Version 12.1
¯2 4
      ¯8 * 1 2 ÷ 3          ⍝ Version 13.0
1J1.732050808 ¯2J3.464101615

      * (1 2 ÷ 3) × ⍟ ¯8    ⍝ Version 13.0
1J1.732050808 ¯2J3.464101615

Circular functions

The basic set of circular functions X○Y cater for complex values in Y, while the following extended functions provide specific features for complex arguments. Note that a and b are the real and imaginary parts of Y respectively and θ is the phase of Y..

(-X) ○ Y | X | X ○ Y
-8○Y | 8 | (-1+Y*2)*0.5
Y | 9 | a
+Y | 10 | |Y
Y×0J1 | 11 | b
*Y×0J1 | 12 | θ

Note that 9○Y and 11○Y return the real and imaginary parts of Y respectively:

      9 11○3.5J¯1.2
3.5 ¯1.2

      9 11∘.○3.5J¯1.2 2J3 3J4
 3.5 2 3
¯1.2 3 4

Comparison

In comparing two complex numbers X and Y, X=Y is 1 if the magnitude of X-Y does not exceed ⎕CT times the larger of the magnitudes of X and Y; geometrically, X=Y if the number smaller in magnitude lies on or within a circle centred on the one with larger magnitude, having radius ⎕CT times the larger magnitude.

As with real values, complex values sufficiently close to Boolean or integral values are accepted by functions which require Boolean or integral values. For example:

      2j1e¯14 ⍴ 12
12 12
      0 ⍱ 1j1e¯15
0

Note that Dyalog APL always stores complex numbers as a pair of 64-bit binary floating-point numbers, regardless of the setting of ⎕FR. Comparisons between complex numbers and decimal floating-point numbers will require conversion of the decimal number to binary to allow the comparison. When ⎕FR=1287, comparisons are always subject to ⎕DCT, not ⎕CT - regardless of the data type used to represent a number.

This only really comes into play when determining whether the imaginary part of a complex number is so small that it can be considered to be on the real line. However, Dyalog recommends that you do not mix the use of complex and decimal numbers in the same component of an application.


128 Bit Decimal Floating-Point Support

Introduction

The original IEE-754 64-bit binary floating point (FP) data type (also known as type number 645), that is used internally by Dyalog APL to represent floating-point values, does not have sufficient precision for certain financial computations – typically involving large currency amounts. The binary representation also causes errors to accumulate even when all values involved in a calculation are "exact" (rounded) decimal numbers, since many decimal numbers cannot be accurately represented regardless of the precision used to hold them. To reduce this problem, Dyalog APL includes support for the 128-bit decimal data type described by IEEE-754-2008 as an alternative representation for floating-point values.

System Variable: ⎕FR

Computations using 128-bit decimal numbers require twice as much space for storage, and run more than an order of magnitude more slowly on platforms which do not provide hardware support for the type. At this time, hardware support is only available from IBM (POWER 6 chips onwards, and recent System z mainframes). Even with hardware support, a slowdown of a factor of 4 can be expected. For this reason, Dyalog allows users to decide whether they need the higher-precision decimal representation, or prefer to stay with the faster and smaller binary representation.

The system variable ⎕FR (for Floating-point Representation) can be set to the value 645 (the installed default) to indicate 64-bit binary FP, or 1287 for 128-bit decimal FP. The default value of ⎕FR is configurable.

Simply put, the value of ⎕FR decides the type of the result of any floating-point calculation that APL performs. In other words, when entered into the session:

     ⎕FR = ⎕DR 1.234 ⍝ Type of a floating-point constant
     ⎕FR = ⎕DR 3÷4   ⍝ Type of any floating-point result

⎕FR has workspace scope, and may be localised. If so, like most other system variables, it inherits its initial value from the global environment.

However: Although ⎕FR can vary, the system is not designed to allow "seamless" modification during the running of an application and the dynamic alteration of ⎕FR is not recommended. Strange effects may occur. For example, the type of a constant contained in a line of code (in a function or class), will depend on the value of ⎕FR when the function is fixed. Similarly, a constant typed into a line in the Session is evaluated using the value of ⎕FR that pertained before the line is executed. Thus, it would be possible for the first line of code above to return 0, if it is in the body of a function. If the function was edited and while suspended and execution is resumed, the result would become 1. Also note:

      ⎕FR←1287
      x←1÷3

      ⎕FR←645
      x=1÷3
1

The decimal number has 17 more 3s. Using the tolerance which applies to binary floats (type 645), the numbers are equal. However, the "reverse" experiment yields 0, as tolerance is much narrower in the 128-bit universe:

      ⎕FR←645
      x←1÷3

      ⎕FR←1287
      x=1÷3
0

Since ⎕FR can vary, it will be possible for a single workspace to contain floating-point values of both types (existing variables are not converted when ⎕FR is changed). For example, an array that has just been brought into the workspace from external storage may have a different type from ⎕FR in the current namespace. Conversion (if necessary) will only take place when a new floating-point array is generated as the result of "a calculation". The result of a computation returning a floating-point result will not depend on the type of the arrays involved in the expression: ⎕FR at the time when a computation is performed decides the result type, alone.

Structural functions generally do NOT change the type, for example:

      ⎕FR←1287
      x←1.1 2.2 3.3

      ⎕FR←645
      ⎕dr x
1287
      ⎕dr 2↑x
1287

128-bit decimal numbers not only have greater precision (roughly 34 decimal digits); they also have significantly larger range- from ¯1E6145 to 1E6145. Loss of precision is accepted on conversion from 645 to 1287, but the magnitude of a number may make the conversion impossible, in which case a DOMAIN ERROR is issued:

      ⎕FR←1287
      x←1E1000

      ⎕FR←645
      x+0
DOMAIN ERROR

WARNING: The use of COMPLEX numbers when ⎕FR is 1287 is not recommended, because:

  • any 128-bit decimal array into which a complex number is inserted or appended will be forced in its entirety into complex representation, potentially losing precision
  • all comparisons are done using ⎕DCT when ⎕FR is 1287, and this is equivalent to 0 for complex numbers.

Conversion between Decimal and Binary

Conversion of data from Binary to Decimal is logically equivalent to formatting, and the reverse conversion is equivalent to evaluating input. These operations are performed according to the same rules that are used when formatting (and evaluating) numbers with ⎕PP set to 17 (guaranteeing that the decimal value can be converted back to the same binary bit pattern). Because the precision of decimal floating-point numbers is much higher, there will always be a large number of potential decimal values which map to the same binary number: As with formatting, the rule is that the SHORTEST decimal number which maps to a particular binary value will be used as its decimal representation.

Data in component files will be stored without conversion, and only converted when a computation happens. It should be stored in decimal form if it will repeatedly be used by application code in which ⎕FR has the value 1287. Even in applications which use decimal floating point everywhere, reading old component files containing arrays of type 645, or receiving data via ⎕NA, the .NET interface or other external sources, will allow binary floating-point values to enter the system and require conversion.

⎕DCT - Decimal Comparison Tolerance

When ⎕FR has the value 1287, the system variable ⎕DCT will be used to specify comparison tolerance. The default value of ⎕DCT is 1E¯28, and the maximum value is 2.3283064365386962890625E¯10 (the value is chosen to avoid fuzzy comparison of 32-bit integers).

Passing floating-point values using ⎕NA

⎕NA supports the data type "D" to represent the Densely Packed Decimal (DPD) form of 128-bit decimal numbers, as specified by the IEEE-754 2008 standard. Dyalog has decided to use DPD, which is the format used by IBM for hardware support, on ALL platforms, although "Binary Integer Decimal" (BID) is the format that Intel libraries use to implement software libraries to do decimal arithmetic. Experiments have shown that the performance of 128-bit DPD and BID libraries are very similar on Intel platforms. In order to avoid the added complication of having two internal representations, Dyalog has elected to go with the hardware format, which is expected to be adopted by future hardware implementations.

The support libraries for writing APs and DLLs include new functions to extract the contents of a value of type D as a string or double-precision binary "float" – and convert data to D format.

Decimal Floats and Microsoft.NET

The Microsoft.NET framework contains a type named System.Decimal, which implements decimal floating-point numbers. However, it uses a different internal format from that defined by IEEE-754 2008.

Dyalog APL includes a Microsoft.NET class (called Dyalog.Dec128), which will perform arithmetic on data represented using the "Binary Integer Decimal" format. All computations performed by the Dyalog.Dec128 class will produce exactly the same results as if the computation was performed in APL. A "DCT" property allows setting the comparison tolerance to be used in comparisons, Ceiling/Floor, etc.).

The Dyalog class is modelled closely after the existing System.Decimal type, providing the same methods (Add, Ceiling, Compare, CompareTo, Divide, Equals, Finalize, Floor, FromOACurrency, GetBits, GetHashCode, GetType, GetTypeCode, MemberwiseClone, Multiply, Negate, Parse, Remainder, Round, Subtract, To*, Truncate, TryParse) and operators (Addition, Decrement, Division, Equality, Explicit, GreaterThan, GreaterThanOrEqual, Implicit, Increment, Inequality, LessThan, LessThanOrEqual, Modulus, Multiply, Subtraction, UnaryNegation, UnaryPlus).

The "bridge" between Dyalog and .NET is able to cast floating-point numbers to or from System.Double, System.Decimal and Dyalog.Dec128 (and perform all other reasonable casts to integer types etc.). Casting a Dyalog.Dec128 to or from strings will perform a "lossless" conversion.

Incoming .NET data types VT_DECIMAL (96-bit integer) and VT_CY (currency value represented by a 64-bit two's complement integer, scaled by 10,000) are converted to 126-bit decimal numbers (DECFs). This conversion is performed independently of the value of ⎕FR.

If you want to perform arithmetic on values imported in this way, then you should set ⎕FR to 1287, at least for the duration of the calculations.

Note that the .NET interface converts System.Decimal to DECFs but does not convert System.Int64 to DECFs.


Namespaces

Namespace is a (class 9) object in Dyalog APL. Namespaces are analogous to nested workspaces.

'Flat' APL Workspace      Workspace with Namespaces
.OLD-------------------.   .NEW-------------------.
|                      |   | FOO MAT VEC          |
| DISPLAY              |   | .Util----------.     |
|                      |   | |DISPLAY       |     |
|   FOO MAT VEC        |   | |...           |     |
|                      |   | '--------------'     |
|   WsDoc_Init         |   | .WsDoc-------------. |
|   WsDoc_Xref         |   | |Init .prt-..fmt--.| |
|   WsDoc_Tree         |   | |     |Init||line || |
|   WsDoc_prt_init     |   | |Tree |    ||     || |
|   WsDoc_current_page |   | |Xref |page||     || |
|   ...                |   | |     '----''-----'| |
|                      |   | '------------------' |
'----------------------'   '----------------------'

They provide the same sort of facility for workspaces as directories do for filesystems. The analogy, based on DOS, might prove helpful:

Operation | Windows | Namespace
Create | mkdir | )NS or ⎕NS
Change | cd | )CS or ⎕CS
Relative name | dir1\dir\file | NS1.NS2.OBJ
Absolute name | \file\file | #.NS.OBJ
Name separator | \ | .
Top (root) object | \ | #
Parent object | .. | ##

Namespaces bring a number of major benefits:

They provide lexical (as opposed to dynamic) local names. This means that a defined function can use local variables and functions which persist when it exits and which are available next time it is called.

Just as with the provision of directories in a filing system, namespaces allow us to organise the workspace in a tidy fashion. This helps to promote an object oriented programming style.

APL's traditional name-clash problem is ameliorated in several ways:

  • Workspaces can be arranged so that there are many fewer names at each namespace level. This means that when copying objects from saved workspaces there is a much reduced chance of a clash with existing names.
  • Utility functions in a saved workspace may be coded as a single namespace and therefore on being copied into the active workspace consume only a single name. This avoids the complexity and expense of a solution which is sometimes used in 'flat' workspaces, where such utilities dynamically fix local functions on each call.
  • In flat APL, workspace administration functions such as WSDOC must share names with their subject namespace. This leads to techniques for trying to avoid name clashes such as using obscure name prefixes like '⍙⍙L1' This problem is now virtually eliminated because such a utility can operate exclusively in its own namespace.

The programming of GUI objects is considerably simplified.

  • An object's callback functions may be localised in the namespace of the object itself.
  • Static variables used by callback functions to maintain information between calls may be localised within the object.

This means that the object need use only a single name in its namespace.


Namespace Syntax

Names within namespaces may be referenced explicitly or implicitly. An explicit reference requires that you identify the object by its full or relative pathname using a '.' syntax; for example:

      X.NUMB ← 88

sets the variable NUMB in namespace X to 88.

      88 UTIL.FOO 99

calls dyadic function FOO in namespace UTIL with left and right arguments of 88 and 99 respectively. The interpreter can distinguish between this use of '.' and its use as the inner product operator, because the leftmost name: UTIL is a (class 9) namespace, rather than a (class 3) function.

The general namespace reference syntax is:

  SPACE . SPACE . (...) EXPR

Where SPACE is an expression which resolves to a namespace reference, and EXPR is any APL expression to be resolved in the resulting namespace.

There are two special space names:

# is the top level or 'Root' namespace.

## is the parent or space containing the current namespace.

⎕SE is a system namespace which is preserved across workspace load and clear.

Examples

      WSDOC.PAGE.NO +← 1     ⍝ Increment WSDOC page count

      #.⎕NL 2                   ⍝ Variables in root space

      UTIL.⎕FX 'Z←DUP A' 'Z←A A'    ⍝ Fix remote function

      ##.⎕ED'FOO'         ⍝ Edit function in parent space

      ⎕SE.RECORD ← PERS.RECORD    ⍝ Copy from PERS to ⎕SE

      UTIL.(⎕EX ⎕NL 2)        ⍝ Expunge variables in UTIL

      (⊃⎕SE #).(⍎⊃↓⎕NL 9).(⎕NL 2)     ⍝ Vars in first ⎕SE
                                      ⍝ namespace.

      UTIL.⍎STRING         ⍝ Execute STRING in UTIL space

You may also reference a function or operator in a namespace implicitly using the mechanism provided by ⎕EXPORT (See ⎕EXPORT is used to set or query the export type of a defined function (or operator) referenced by the ⎕PATH mechanism.) and ⎕PATH. If you reference a name that is undefined in the current space, the system searches for it in the list of exported names defined for the namespaces specified by ⎕PATH. See Example for further details.

Notice that the expression to the right of a dot may be arbitrarily complex and will be executed within the namespace or ref to the left of the dot.

      X.(C←A×B)
      X.C
10 12 14
16 18 20
      NS1.C
10 12 14
16 18 20

Summary

Apart from its use as a decimal separator (3.14), '.' is interpreted by looking at the type or class of the expression to its left:

Template | Interpretation | Example
∘. | Outer product | 2 3 ∘.× 4 5
function. | Inner product | 2 3 +.× 4 5
ref. | Namespace reference | 2 3 x.foo 4 5
array. | Reference array expansion | (x y).⎕nc⊂'foo'


Namespace Reference Evaluation

When the interpreter encounters a namespace reference, it:

  1. Switches to the namespace.
  2. Evaluates the name.
  3. Switches back to the original namespace.

If for example, in the following, the current namespace is #.W, the interpreter evaluates the line:

      A ← X.Y.DUP MAT

in the following way:

  1. Evaluate array MAT in current namespace W to produce argument for function.
  2. Switch to namespace X.Y within W.
  3. Evaluate function DUP in namespace W.X.Y with argument.
  4. Switch back to namespace W.
  5. Assign variable A in namespace W.


Namespaces and Localisation

The rules for name resolution have been generalised for namespaces.

In flat APL, the interpreter searches the state indicator to resolve names referenced by a defined function or operator. If the name does not appear in the state indicator, then the workspace-global name is assumed.

With namespaces, a defined function or operator is evaluated in its 'home' namespace. When a name is referenced, the interpreter searches only those lines of the state indicator which belong to the home namespace. If the name does not appear in any of these lines, the home namespace-global value is assumed.

For example, if #.FN1 calls XX.FN2 calls #.FN3 calls XX.FN4, then:

FN1:
is evaluated in #
can see its own dynamic local names
can see global names in #
FN2:
is evaluated in XX
can see its own dynamic local names
can see global names in XX
FN3:
is evaluated in #
can see its own dynamic local names
can see dynamic local names in FN1
can see global names in #
FN4:
is evaluated in XX
can see its own dynamic local names
can see dynamic local names in FN2
can see global names in XX

The following picture illustrates how APL looks down the stack to find names:

    │           │           │
    │    a+b+c  │           │ [8] h references a, b and c
    │    │ │ │  │           │
    │ ∇h;a │ │  │           │ [7] h localises a
    │      │ │  │           │
    │      │ │  │           │ [6] g calls X.h
    │      │ │  │           │
    │      │ │  │    a+b+c  │ [5] g references a, b and c
    │      │ │  │    │ │ │  │
    │      │ │  │ ∇g;a;│ c  │ [4] g localises a and c
    │      │ │  │      │    │
    │      │ │  │      │    │ [3] f calls Y.g
  ↑ │      │ │  │      │    │
  s │    a+b+c  │      │    │ [2] f references a, b and c
  t │    │ │ │  │      │    │
  a │ ∇f;a;b │  │      │    │ [1] f localises a and b
  c │        │  │      │    │
  k │    a b c  │    a b c  │ [0] global names a, b and c
    └X──────────┴Y──────────┘     in namspaces X and Y

The above diagram represents the SI stack, growing upwards from two namespaces X and Y, which each have three global names a, b and c.

  1. Function f in X localises names a and b.
  2. Function f references names a, b and c.
           ∇ f;a;b
       [1]   a+b+c
       [2]   Y.g
  • The interpreter looks down the stack and finds local names a and b in f's header and c in namespace X.
  3. Function f calls function g in namespace Y.
  4. Function g in Y localises names a and c.
  5. Function g references names a, b and c.
           ∇ g;a;c
       [1]   a+b+c
       [2]   X.h
  • The interpreter looks down the stack and finds local names a and c in g's header and b in namespaces Y.
  6. Function g calls function h in namespace X.
  7. Function h in X localises name a.
  8. Function h references names a, b and c.
           ∇ h;a
       [1]   a+b+c
  • The interpreter looks down the stack and finds local name a in h's header; b in f's header; and c in namespace X.


Namespace References

A namespace reference, or ref for short, is a unique data type that is distinct from and in addition to number and character.

Any expression may result in a ref, but the simplest one is the namespace itself:

      )NS NS1          ⍝ Make a namespace called NS1
      NS1.A←1          ⍝ and populate it with variables A
      NS1.B←2 3⍴⍳6     ⍝ and B

      NS1              ⍝ expression results in a ref
#.NS1

You may assign a ref; for example:

      X←NS1
      X
#.NS1

In this case, the display of X informs you that X refers to the named namespace #.NS1.

You may also supply a ref as an argument to a defined function or a dfn:

     ∇ FOO ARG
[1]    ARG
     ∇
      FOO NS1
#.NS1

The name class of a ref is 9.

      ⎕NC 'X'
9

You may use a ref to a namespace anywhere that you would use the namespace itself. For example:

      X.A
1
      X.B
1 2 3
4 5 6

Notice that refs are references to namespaces, so that if you make a copy, it is the reference that is copied, not the namespace itself. This is sometimes referred to as a shallow as opposed to a deep copy. It means that if you change a ref, you actually change the namespace that it refers to.

      X.A+←1
      X.A
2
      NS1.A
2

Similarly, a ref passed to a defined function is call-by-reference, so that modifications to the content or properties of the argument namespace using the passed reference persist after the function exits. For example:

     ∇ FOO nsref
[1]    nsref.B+←nsref.A
     ∇

      FOO NS1
      NS1.B
3 4 5
6 7 8
      FOO X
      NS1.B
5 6  7
8 9 10

Notice that the expression to the right of a dot may be arbitrarily complex and will be executed within the namespace or ref to the left of the dot.

      X.(C←A×B)
      X.C
10 12 14
16 18 20
      NS1.C
10 12 14
16 18 20


Unnamed Namespaces

The monadic form of ⎕NS makes a new (and unique) unnamed namespace and returns a ref to it.

One use of unnamed namespaces is to represent hierarchical data structures; for example, a simple employee database:

The first record is represented by JOHN which is a ref to an unnamed namespace:

      JOHN←⎕NS ''
      JOHN
#.[Namespace]

      JOHN.FirstName←'John'
      JOHN.FirstName
John

      JOHN.LastName←'Smith'
      JOHN.Age←50

Data variables for the second record, PAUL, can be established using strand, or vector, assignment:

      PAUL←⎕NS ''
      PAUL.(FirstName LastName Age←'Paul' 'Brown' 44)

The function SHOW can be used to display the data in each record (the function is split into 2 lines only to fit on the printed page). Notice that its argument is a ref.

     ∇ R←SHOW PERSON
[1]    R←PERSON.FirstName,' ',PERSON.LastName
[2]    R, ←' is ',⍕PERSON.Age
     ∇

      SHOW JOHN
John Smith is 50

      SHOW PAUL
Paul Brown is 44

An alternative version of the function illustrates the use of the :With :EndWith control structure to execute an expression, or block of expressions, within a namespace:

     ∇ R←SHOW1 PERSON
[1]    :With PERSON
[2]        R←FirstName,' ',LastName,' is ',(⍕Age)
[3]    :EndWith
     ∇

      SHOW1 JOHN
John Smith is 50

In this case, as only a single expression is involved, it can be expressed more simply using parentheses.

     ∇ R←SHOW2 PERSON
[1]    R←PERSON.(FirstName,' ',LastName,' is ',(⍕Age))
     ∇
      SHOW2 PAUL
Paul Brown is 44

Dfns also accept refs as arguments:

      SHOW3←{
        ⍵.(FirstName,' ',LastName,' is ',⍕Age)
      }

      SHOW3 JOHN
John Smith is 50


Arrays of Namespace References

You may construct arrays of refs using strand notation, catenate (,) and reshape (⍴).

      EMP←JOHN PAUL
      ⍴EMP

2

      EMP
 #.[Namespace]  #.[Namespace]

Like any other array, an array of refs has name class 2:

      ⎕NC 'EMP'
2

Expressions such as indexing and pick return refs that may in turn be used as follows:

      EMP[1].FirstName
John
      (2⊃EMP).Age
44

The each (¨) operator may be used to apply a function to an array of refs:

      SHOW¨EMP
 John Smith is 50  Paul Brown is 44

An array of namespace references (refs) to the left of a '.' is expanded according to the following rule, where x and y are refs, and exp is an arbitrary expression:

      (x y).exp → (x.exp)(y.exp)

If exp evaluates to a function, the items of its argument array(s) are distributed to each referenced function. In the dyadic case, there is a 3-way distribution among: left argument, referenced functions and right argument.

Monadic function f:

      (x y).f d e → (x.f d)(y.f e)

Dyadic function g:

      a b (x y).g  d e → (a x.g d)(b y.g e)

An array of refs to the left of an assignment arrow is expanded thus:

      (x y).a←c d   →  (x.a←c)(y.a←d)

Note that the array of refs can be of any rank. In the limiting case of a simple scalar array, the array construct: refs.exp is identical to the scalar construct: ref.exp.

Note that the expression to the right of the '.' pervades a nested array of refs to its left:

      ((u v)(x y)).exp → ((u.exp)(v.exp))((x.exp)(y.exp))

Note also that with successive expansions (u v).(x y z). ..., the final number of "leaf" terms is the product of the number of refs at each level.

Examples:

      JOHN.Children←⎕NS¨'' ''
      ⍴JOHN.Children
2
      JOHN.Children[1].FirstName←'Andy'
      JOHN.Children[1].Age←23

      JOHN.Children[2].FirstName←'Katherine'
      JOHN.Children[2].Age←19

      PAUL.Children←⎕NS¨'' ''
      PAUL.Children[1].(FirstName Age←'Tom' 25)
      PAUL.Children[2].(FirstName Age←'Jamie' 22)

      ⍴EMP
2
      (⊃EMP).Children.(FirstName Age)
  Andy  23   Katherine  19

      ]display (2⊃EMP).Children.(FirstName Age)
.→----------------------------.
| .→---------. .→-----------. |
| | .→--.    | | .→----.    | |
| | |Tom| 25 | | |Jamie| 22 | |
| | '---'    | | '-----'    | |
| '∊---------' '∊-----------' |
'∊----------------------------'

      EMP.Children ⍝ Is an array of refs
  #.[Namespace]  #.[Namespace]    #.[Namespace]  ...

      EMP.Children.(FirstName Age)
   Andy  23   Katherine  19     Tom  25   Jamie  22


Distributed Assignment

Assignment pervades nested strands of names to the left of the arrow. The conformability rules are the same as for scalar (pervasive) dyadic primitive functions such as '+'. The mechanism can be viewed as a way of naming the parts of a structure.

Examples:

      EMP.(FirstName Age)
  JOHN  43   PAUL  44

      EMP.(FirstName Age)←('Jonathan' 21)('Pauline' 22)

      EMP.(FirstName Age)
  Johnathan  21   Pauline  22

⍝ Distributed assignment is pervasive
      JOHN.Children.(FirstName Age)
  Andy  23   Katherine  19

      JOHN.Children.(FirstName Age)←('Andrew' 21)('Kate' 9)

      JOHN.Children.(FirstName Age)
  Andrew  21   Kate  9

More Examples:

      ((a b)(c d))←(1 2)(3 4)   ⍝ a←1 ⋄ b←2 ⋄ c←3 ⋄ d←4

      ((⎕io ⎕ml)vec)←0 ⎕av      ⍝ ⎕io←0 ⋄ ⎕ml←0 ⋄ vec←⎕av

      (i (j k))+←1 2            ⍝ i+←1 ⋄ j+←2 ⋄ k+←2

⍝ Naming of parts:

      ((first last) sex (street city state))←n⊃pvec

⍝ Distributed assignment in :For loop:

      :For (i j)(k l) :In array

⍝ Ref array expansion:

      (x y).(first last)←('John' 'Doe')('Joe' 'Blow')
      (f1 f2).(b1 b2).Caption←⊂'OK' 'Cancel'

⍝ Structure rearrangement:
      rotate1←{       ⍝ Simple binary tree rotation.
           (a b c)d e←⍵
           a b(c d e)
      }
      rotate3←{       ⍝ Compound binary tree rotation.
           (a b(c d e))f g←⍵
           (a b c)d(e f g)
      }


Namespaces and Operators

A function passed as operand to a primitive or defined operator, carries its namespace context with it. This means that if subsequently, the function operand is applied to an argument, it executes in its home namespace, irrespective of the namespace from which the operator was invoked or defined.

Examples

      VAR←99                     ⍝ #.VAR

      )NS X
#.X
      X.VAR←77                   ⍝ X.VAR
      X.⎕FX'Z←FN R' 'Z←R,VAR'

      )NS Y
#.Y
      Y.VAR←88                   ⍝ Y.VAR
      Y.⎕FX'Z←(F OP)R' 'Z←F R'

      X.FN¨⍳3
 1 77  2 77  3 77

      X.FN 'VAR:'
 VAR: 77

      X.FN Y.OP 'VAR:'
 VAR: 77
      ⍎ Y.OP'VAR'
99


External Variables

An external variable is a variable whose contents (value) reside not in the workspace, but in a file. An external variable is associated with a file by the system function ⎕XT. If at the time of association the file exists, the external variable assumes its value from the contents of the file. If the file does not exist, the external variable is defined but a VALUE ERROR occurs if it is referenced before assignment. Assignment of an array to the external variable or to an indexed element of the external variable has the effect of updating the file. The value of the external variable or the value of indexed elements of the external variable is made available in the workspace when the external variable occurs in an expression. No special restrictions are placed on the usage of external variables.

Normally, the files associated with external variables remain permanent in that they survive the APL session or the erasing of the external variable from the workspace. External variables may be accessed concurrently by several users, or by different nodes on a network, provided that the appropriate file access controls are established. Multi-user access to an external variable may be controlled with the system function ⎕FHOLD between co-operating tasks.

Refer to the sections describing the system functions ⎕XT and ⎕FHOLD in Chapter 6 for further details.

Examples

      'ARRAY' ⎕XT 'V'

      V←⍳10
      V[2] + 5
7

      ⎕EX'V'

      'ARRAY' ⎕XT 'F'
      F
1 2 3 4 5 6 7 8 9 10


Component Files

A component file is a data file maintained by Dyalog APL. It contains a series of APL arrays known as components which are accessed by reference to their relative positions or component number within the file. A set of system functions is provided to perform a range of file operations. (See Component Files.) These provide facilities to create or delete files, and to read and write components. Facilities are also provided for multi-user access including the capability to determine who may do what, and file locking for concurrent updates. (See the Dyalog Programming Reference Guide).


Auxiliary Processors

Auxiliary Processors (APs) are non-APL programs which provide Dyalog APL users with additional facilities. They run as separate tasks, and communicate with the Dyalog APL interpreter through pipes (UNIX) or via an area of memory (Windows). Typically, APs are used where speed of execution is critical, such as in screen management software, or for utility libraries. Auxiliary Processors may be written in any compiled language, although 'C' is preferred and is directly supported.

When an Auxiliary Processor is invoked from Dyalog APL, one or more external functions are fixed in the active workspace. Each external function behaves as if it was a locked defined function, but is in effect an entry point into the Auxiliary Processor. An external function occupies only a negligible amount of workspace.

Although Auxiliary Processors are still supported, Dyalog recommends that DLLs/shared libraries, called via the ⎕NA interface should be used on all platforms in future, and that existing APs are converted to DLLs/shared libraries.


Canonical Representation

Operations may be defined with the system function ⎕FX (Fix) or by using the editor within definition mode. Applying ⎕CR to the character array representing the name of an already established operation will produce its canonical representation. A defined operation is composed of lines. The first line (line 0) is called the operation HEADER. Remaining lines are APL statements, called the BODY.

The operation header consists of the following parts:

  1. its model syntactical form,
  2. an optional list of local names, each preceded by a semi-colon (;) character,
  3. an optional comment, preceded by the symbol ⍝.

Only the model is required. If local names and comments are included, they must appear in the prescribed order.


Model Syntax

The model for the defined operation identifies the name of the operation, its valence, and whether or not an explicit result may be returned. Valence is the number of explicit arguments or operands, either 0, 1 or 2; whence the operation is termed NILADIC, MONADIC or DYADIC respectively. Only a defined function may be niladic. There is no relationship between the valence of a defined operator, and the valence of the derived function which it produces. Defined functions and derived functions produced by defined operators may be ambivalent, i.e. may be executed monadically with one argument, or dyadically with two. An ambivalent operation is identified in its model by enclosing the left argument in braces.

The value of a result-returning function or derived function may be suppressed in execution if not explicitly used or assigned by enclosing the result in its model within braces. Such a suppressed result is termed SHY.

The tables below show all possible models for defined functions and operators respectively.

Defined Functions

Result | Niladic | Monadic | Dyadic | Ambivalent
None | f | f Y | X f Y | {X} f Y
Explicit | R←f | R←f Y | R←X f Y | R←{X} f Y
Suppressed | {R}←f | {R}←f Y | {R}←X f Y | {R}←{X} f Y

Note: the right argument Y and/or the result R may be represented by a single name, or as a blank-delimited list of names surrounded by parentheses. For further details, see Namelists.

Derived Functions produced by Monadic Operator

Result | Monadic | Dyadic | Ambivalent
None | (A op)Y | X(A op)Y | {X}(A op)Y
Explicit | R←(A op)Y | R←X(A op)Y | R←{X}(A op)Y
Suppressed | {R}←(A op)Y | {R}←X(A op)Y | {R}←{X}(A op)Y

Derived Functions produced by Dyadic Operator

Result | Monadic | Dyadic | Ambivalent
None | (A op B)Y | X(A op B)Y | {X}(A op B)Y
Explicit | R←(A op B)Y | R←X(A op B)Y | R←{X}(A op B)Y
Suppressed | {R}←(A op B)Y | {R}←X(A op B)Y | {R}←{X}(A op B)Y


Statements

A statement is a line of characters understood by APL. It may be composed of:

  1. a LABEL (which must be followed by a colon :), or a CONTROL STATEMENT (which is preceded by a colon), or both,
  2. an EXPRESSION (see Expressions),
  3. a SEPARATOR (consisting of the diamond character ⋄ which must separate adjacent expressions),
  4. a COMMENT (which must start with the character ⍝).

Each of the four parts is optional, but if present they must occur in the given order except that successive expressions must be separated by ⋄. Any characters occurring to the right of the first comment symbol (⍝) that is not within quotes is a comment.

Comments are not executed by APL. Expressions in a line separated by ⋄ are taken in left-to-right order as they occur in the line. For output display purposes, each separated expression is treated as a separate statement.

Examples

      5×10
50

      MULT: 5×10
50

      MULT: 5×10 ⋄ 2×4
50
8

      MULT: 5×10 ⋄ 2×4  ⍝ MULTIPLICATION
50
8


Global & Local Names

The following names, if present, are local to the defined operation:

  1. the result,
  2. the argument(s) and operand(s),
  3. additional names in the header line following the model, each name preceded by a semi-colon character,
  4. labels,
  5. the argument list of the system function ⎕SHADOW when executed,
  6. a name assigned within a dfn.

All names in a defined operation must be valid APL names. The same name may be repeated in the header line, including the operation name (whence the name is localised). Normally, the operation name is not a local name.

The same name may not be given to both arguments or operands of a dyadic operation. The name of a label may be the same as a name in the header line. More than one label may have the same name. When the operation is executed, local names in the header line after the model are initially undefined; labels are assigned the values of line numbers on which they occur, taken in order from the last line to the first; the result (if any) is initially undefined.

In the case of a defined function, the left argument (if any) takes the value of the array to the left of the function when called; and the right argument (if any) takes the value of the array to the right of the function when called. In the case of a defined operator, the left operand takes the value of the function or array to the left of the operator when called; and the right operand (if any) takes the value of the function or array to the right of the operator when called.

During execution, a local name temporarily excludes from use an object of the same name with an active definition. This is known as LOCALISATION or SHADOWING. A value or meaning given to a local name will persist only for the duration of execution of the defined operation (including any time whilst the operation is halted). A name which is not local to the operation is said to be GLOBAL. A global name could itself be local to a pendent operation. A global name can be made local to a defined operation during execution by use of the system function ⎕SHADOW. An object is said to be VISIBLE if there is a definition associated with its name in the active environment.

Examples

      A←1

     ∇ F
[1]    A←10
[2]  ∇

      F ⍝ <A> NOT LOCALISED IN <F>, GLOBAL VALUE REPLACED
      A
10
      A←1
      )ERASE F

     ∇ F;A
[1]    A←10
[2]  ∇

      F  ⍝ <A> LOCALISED IN <F>, GLOBAL VALUE RETAINED
      A
1

Any statement line in the body of a defined operation may begin with a LABEL. A label is followed by a colon (:). A label is a constant whose value is the number of the line in the operation defined by system function ⎕FX or on closing definition mode.

The value of a label is available on entering an operation when executed, and it may be used but not altered in any expression.

Example

      ⎕VR'PLUS'
    ∇ R←{A} PLUS B
[1]   →DYADIC ⍴⍨2=⎕NC'A' ⋄ R←B ⋄ →END
[2]  DYADIC: R←A+B
[3]  END:
    ∇

      1 ⎕STOP'PLUS'

      2 PLUS 2

PLUS[1]
      DYADIC
2

      END
3


Namelists

The right argument and the result of a function may be specified in the function header by a single name or by a Namelist. In this context, a Namelist is a blank-delimited list of names surrounded by a single set of parentheses.

Names specified in a Namelist are automatically local to the function; there is no need to localise them explicitly using semi-colons.

If the right argument of a function is declared as a Namelist, the function will only accept a right argument that is a vector whose length is the same as the number of names in the Namelist. Calling the function with any other argument will result in a LENGTH ERROR in the calling statement. Otherwise, the elements of the argument are assigned to the names in the Namelist in the specified order.

Example:

     ∇ IDN←Date2IDN(Year Month Day)
[1]    'Year is ',⍕Year
[2]    'Month is ',⍕Month
[3]    'Day is ',⍕Day
[4] ...
     ∇

      Date2IDN 2004 4 30
Year is 2004
Month is 4
Day is 30

      Date2IDN 2004 4
LENGTH ERROR
      Date2IDN 2004 4
     ^

Note that if you specify a single name in the Namelist, the function may be called only with a 1-element vector right argument. If the result of a function is declared as a Namelist, the values of the names will automatically be stranded together in the specified order and returned as the result of the function when the function terminates.

Example:

     ∇ (Year Month Day)←Birthday age
[1]    Year←1949+age
[2]    Month←4
[3]    Day←30
     ∇
      Birthday 50
1999 4 30


Function Declaration Statements

Function Declaration statements are used to identify the characteristics of a function in some way.

The following declarative statements are provided.

  • :Access
  • :Attribute
  • :Implements
  • :Signature

With one exception, these statements are not executable statements and may theoretically appear anywhere in the body of the function. However, it is recommended that you place them at the beginning before any executable statements. The exception is:

:Implements Constructor <[:Base expr]>

In addition to being declarative (declaring the function to be a Constructor) this statement also executes the Constructor in the Base Class whether or not it includes :Base expr. Its position in the code is therefore significant.


Access Statement :Access
:Access <Private|Public><Instance|Shared>
:Access <WebMethod>

The :Access statement is used to specify characteristics for functions that represent Methods in classes (see Methods). It is also applicable to Classes and Properties.

Element | Description
Private|Public | Specifies whether or not the method is accessible from outside the Class or an Instance of the Class. The default is Private.
Instance|Shared | Specifies whether the method runs in the Class or Instance. The default is Instance.
WebMethod | Specifies that the method is exported as a web method. This applies only to a Class that implements a Web Service.
Overridable | Applies only to an Instance Method and specifies that the Method may be overridden by a Method in a higher Class. See below.
Override | Applies only to an Instance Method and specifies that the Method overrides the corresponding Overridable Method defined in the Base Class. See below

Overridable/Override

Normally, a Method defined in a higher Class replaces a Method of the same name that is defined in its Base Class, but only for calls made from above or within the higher Class itself (or an Instance of the higher Class). The base method remains available in the Base Class and is invoked by a reference to it from within the Base Class.

However, a Method declared as being Overridable is replaced in-situ (i.e. within its own Class) by a Method of the same name in a higher Class if that Method is itself declared with the Override keyword. For further information, see Superseding Base Class Methods.

WebMethod

Note that :Access WebMethod is equivalent to:

:Access Public
:Attribute System.Web.Services.WebMethodAttribute


Attribute Statement :Attribute
:Attribute <Name> [ConstructorArgs]

The :Attribute statement is used to attach .NET Attributes to a Method (or Class).

Attributes are descriptive tags that provide additional information about programming elements. Attributes are not used by Dyalog APL but other applications can refer to the extra information in attributes to determine how these items can be used. Attributes are saved with the metadata of Dyalog APL .NET assemblies.

Element | Description
Name | The name of a .NET attribute
ConstructorArgs | Optional arguments for the Attribute constructor

Examples

      :Attribute ObsoleteAttribute
      :Attribute ObsoleteAttribute 'Don''t use' 1


Implements Statement :Implements

The :Implements statement identifies the function to be one of the following types.

:Implements Constructor <[:Base expr]>
:Implements Destructor
:Implements Method <InterfaceName.MethodName>
:Implements Trigger <name1><,name2,name3,...>
:Implements Trigger *
Element | Description
Constructor | Specifies that the function is a Class Constructor.
:Base expr | Specifies that the Base Constructor be called with the result of the expression expr as its argument.
Destructor | Specifies that the function is a Class Destructor.
Method | Specifies that the function implements the Method MethodName whose syntax is specified by Interface InterfaceName.
Trigger | Identifies the function as a Trigger Function which is activated by changes to variable name1, name2, and so forth. Trigger * specifies a Global Trigger that is activated by the assignment of any global variable in the same namespace.


Signature Statement :Signature
:Signature <rslttype←><name><arg1type arg1name>,...

This statement identifies the name and signature by which a function is exported as a method to be called from outside Dyalog APL. Several :Signature statements may be specified to allow the method to be called with different arguments and/or to specify a different result type.

Element | Description
rslttype | Specifies the data type for the result of the method
name | Specifies the name of the exported method.
argntype | Specifies the data type of the nth parameter
argnname | Specifies the name of the nth parameter

Argument and result data types are identified by the names of .NET Types which are defined in the .NET Assemblies specified by ⎕USING or by a :USING statement.

Examples

In the following examples, it is assumed that the .NET Search Path (defined by :Using or ⎕USING includes 'System'.

The following statement specifies that the function is exported as a method named Format which takes a single parameter of type System.Object named Array. The data type of the result of the method is an array (vector) of type System.String.

      :Signature String[]←Format Object Array

The next statement specifies that the function is exported as a method named Catenate whose result is of type System.Object and which takes 3 parameters. The first parameter is of type System.Double and is named Dimension. The second is of type System.Object and is named Arg1. The third is of type System.Object and is named Arg2.

      :Signature Object←Catenate Double Dimension,...
                              ...Object Arg1, Object Arg2

The next statement specifies that the function is exported as a method named IndexGen whose result is an array of type System.Int32 and which takes 2 parameters. The first parameter is of type System.Int32 and is named N. The second is of type System.Int32 and is named Origin.

      :Signature Int32[]←IndexGen Int32 N, Int32 Origin

The next block of statements specifies that the function is exported as a method named Mix. The method has 4 different signatures; i.e. it may be called with 4 different parameter/result combinations.

      :Signature Int32[,]←Mix Double Dimension, ...
            ...Int32[] Vec1, Int32[] Vec2
      :Signature Int32[,]←Mix Double Dimension,...
            ... Int32[] Vec1, Int32[] Vec2, Int32 Vec3
      :Signature Double[,]←Mix Double Dimension, ...
            ... Double[] Vec1, Double[] Vec2
      :Signature Double[,]←Mix Double Dimension, ...
            ... Double[] Vec1, Double[] Vec2, Double[] Vec3


Control Structures

Control structures provide a means to control the flow of execution in your APL programs.

Traditionally, lines of APL code are executed one by one from top to bottom and the only way to alter the flow of execution is using the branch arrow. So how do you handle logical operations of the form “If this, do that; otherwise do the other”?

In APL this is often not a problem because many logical operations are easily performed using the standard array handling facilities that are absent in other languages. For example, the expression:

      STATUS←(1+AGE<16)⊃'Adult' 'Minor'

sets STATUS to 'Adult' if AGE is 16 or more; otherwise sets STATUS to 'Minor'.

Things become trickier if, depending upon some condition, you wish to execute one set of code instead of another, especially when the code fragments cannot conveniently be packaged as functions. Nevertheless, careful use of array logic, defined operators, the execute primitive function and the branch arrow can produce high quality maintainable and comprehensible APL systems.

Control structures provide an additional mechanism for handling logical operations and decisions. Apart from providing greater affinity with more traditional languages, Control structures may enhance comprehension and reduce programming errors, especially when the logic is complex. Control structures are not, however, a replacement for the standard logical array operations that are so much a part of the APL language.


Control Structures

Introduction

Control Structures are blocks of code in which the execution of APL statements follows certain rules and conditions. Control structures are implemented using a set of control words that all start with the colon symbol (:). Control Words are case-insensitive.

There are nine different types of control structures defined by the control words, :If, :While, :Repeat, :For (with the supplementary control words :In and :InEach), :Select, :With, :Trap, :Hold and :Disposable. Each one of these control words may occur only at the beginning of an APL statement and indicates the start of a particular type of control structure.

Within a control structure, certain other control words are used as qualifiers. These are :Else, :ElseIf, :AndIf, :OrIf, :Until, :Case and :CaseList.

A third set of control words is used to identify the end of a particular control structure. These are :EndIf, :EndWhile, :EndRepeat, :EndFor, :EndSelect, :EndWith, :EndTrap, :EndHold and :EndDisposable. Although formally distinct, these control words may all be abbreviated to :End.

Finally, the :GoTo, :Return, :Leave and :Continue control words may be used to conditionally alter the flow of execution within a control structure.

Control words, including qualifiers such as :Else and :ElseIf, may occur only at the beginning of a line or expression in a diamond-separated statement. The only exceptions are :In and :InEach which must appear on the same line within a :For expression.

Key to Notation

The following notation is used to describe Control Structures within this section:

aexp | an expression returning an array,
bexp | an expression returning a single Boolean value (0 or 1),
var | loop variable used by :For control structure,
code | 0 or more lines of APL code, including other (nested) control structures,
andor either one or more :AndIf statements, or one or more :OrIf statements. For further details, see below.
|
.-----------------------.
|                       |
|<--------------.       |<--------------.
|               |       |               |
code            |       code            |
|               |       |               |
|               |       |               |
:AndIf bexp-----'       :OrIf bexp------'
|                       |
|<----------------------'
|

Notes

Code preceding :OrIf and :AndIf

Code that precedes a :OrIf control statement, e.g. code placed between a :If statement and a subsequent :OrIf, will be executed only if the outer condition is false. If instead the outer condition is true, there is no need to execute the :OrIf statement , so it and any preceding lines of code are skipped.

Code that precedes a :AndIf control statement, e.g. code placed between a :If statement and a subsequent :AndIf, will only be executed if the outer condition is true. If instead the outer condition is false, there is no need to execute the :AndIf statement , so it and any preceding lines of code are skipped.

The above behaviour may be examined using the Tracer.

A potential use for code before a :OrIf or :AndIf is to prepare for the conditional test. This preparatory work will only be done if required. For example:

:If x   ⍝ if x is false, skip everything up to the :EndIf
    y←..⍝ set up stuff for the condition on the next line
    :AndIf y
      do stuff
:EndIf

Warning

With the exception of a diamondised statement, a control statement that should not be followed by an expression will generate an error if an expression is supplied.

A line in a function consisting of a control statement followed by a ⋄ and subsequent expression(s) is not currently disallowed but may exhibit unexpected behaviour. In particular, the line will not honour ⎕STOP and will not be metered by ⎕MONITOR. This syntax is not recommended.


Access Statement>

Access Statement :Access

The :Access statement may be used to define the characteristics of a Class, the characteristics of a defined function (Method) in a Class, or the characteristics of other Class members.

:Access Statement in a Function/Method.

:Access Statement in a Class or in other members of a Class.


Attribute Statement :Attribute

The :Attribute statement is used to attach .NET Attributes to a Method or a Class.

:Attribute Statement for a Class.

:Attribute statement for a Method.


LangRef_Flare

If Statement :If bexp

Formal Definition

The simplest :If control structure is a single condition of the form:

[1]   :If AGE<21
[2]       expr 1
[3]       expr 2
[5]   :EndIf

If the test condition (in this case AGE<21) is true, the statements between the :If and the :EndIf will be executed. If the condition is false, none of these statements will be run and execution resumes after the :EndIf. Note that the test condition to the right of :If must return a single element Boolean value 1 (true) or 0 (false).

:If control structures may be considerably more complex. For example, the following code will execute the statements on lines [2-3] if AGE<21 is 1 (true), or alternatively, the statement on line [6] if AGE<21 is 0 (false).

[1]   :If AGE<21
[2]       expr 1
[3]       expr 2
[5]   :Else
[6]       expr 3
[7]   :EndIf

Instead of a single condition, it is possible to have multiple conditions using the :ElseIf control word. For example:

[1]   :If WINEAGE<5
[2]       'Too young to drink'
[5]   :ElseIf WINEAGE<10
[6]       'Just Right'
[7]   :ElseIf WINEAGE<15
[8]       'A bit past its prime'
[9]   :Else
[10]     'Definitely over the hill'
[11]  :EndIf

Notice that APL executes the expression(s) associated with the first condition that is true or those following the :Else if none of the conditions are true.

The :AndIf and :OrIf control words may be used to define a block of conditions and so refine the logic still further. You may qualify an :If or an :ElseIf with one or more :AndIf statements or with one or more :OrIf statements. You may not however mix :AndIf and :OrIf in the same conditional block. For example:

[1]   :If WINE.NAME≡'Chateau Lafitte'
[2]   :AndIf WINE.YEAR∊1962 1967 1970
[3]       'The greatest?'
[4]   :ElseIf WINE.NAME≡'Chateau Latour'
[5]   :Orif WINE.NAME≡'Chateau Margaux'
[6]   :Orif WINE.PRICE>100
[7]       'Almost as good'
[8]   :Else
[9]       'Everyday stuff'
[10]  :EndIf

Please note that in a :If control structure, the conditions associated with each of the condition blocks are executed in order until an entire condition block evaluates to true. At that point, the APL statements following this condition block are executed. None of the conditions associated with any other condition block are executed. Furthermore, if an :AndIf condition yields 0 (false), it means that the entire block must evaluate to false so the system moves immediately on to the next block without executing the other conditions following the failing :AndIf. Likewise, if an :OrIf condition yields 1 (true), the entire block is at that point deemed to yield true and none of the following :OrIf conditions in the same block are executed.


While Statement :While bexp

Formal Definition

The simplest :While loop is :

[1]   I←0
[2]   :While I<100
[3]       expr1
[4]       expr2
[5]       I←I+1
[6]   :EndWhile

Unless expr1 or expr2 alter the value of I, the above code will execute lines [3-4] 100 times. This loop has a single condition; the value of I. The purpose of the :EndWhile statement is solely to mark the end of the iteration. It acts the same as if it were a branch statement, branching back to the :While line.

An alternative way to terminate a :While structure is to use a :Until statement. This allows you to add a second condition. The following example reads a native file sequentially as 80-byte records until it finds one starting with the string 'Widget' or reaches the end of the file.

[1]   I←0
[2]   :While I<⎕NSIZE ¯1
[3]       REC←⎕NREAD ¯1 82 80
[4]       I←I+⍴REC
[5]   :Until 'Widget'≡6⍴REC

Instead of single conditions, the tests at the beginning and end of the loop may be defined by more complex ones using :AndIf and :OrIf. For example:

[1]   :While 100>i
[2]   :AndIf 100>j
[3]       i j←foo i j
[4]   :Until 100<i+j
[5]   :OrIf i<0
[6]   :OrIf j<0

In this example, there are complex conditions at both the start and the end of the iteration. Each time around the loop, the system tests that both i and j are less than or equal to 100. If either test fails, the iteration stops. Then, after i and j have been recalculated by foo, the iteration stops if i+j is equal to or greater than 100, or if either i or j is negative.


Repeat Statement :Repeat

Formal Definition

The simplest type of :Repeat loop is as follows. This example executes lines [3-5] 100 times. Notice that as there is no conditional test at the beginning of a :Repeat structure, its code statements are executed at least once.

[1]   I←0
[2]   :Repeat
[3]       expr1
[4]       expr2
[5]       I←I+1
[6]   :Until I=100

You can have multiple conditional tests at the end of the loop by adding :AndIf or :OrIf expressions. The following example will read data from a native file as 80-character records until it reaches one beginning with the text string 'Widget' or reaches the end of the file.

[1]   :Repeat
[2]       REC←⎕NREAD ¯1 82 80
[3]   :Until 'Widget'≡6⍴REC
[4]   :OrIf 0=⍴REC

A :Repeat structure may be terminated by an :EndRepeat (or :End) statement in place of a conditional expression. If so, your code must explicitly jump out of the loop using a :Leave statement or by branching. For example:

[1]   :Repeat
[2]       REC←⎕NREAD ¯1 82 80
[3]      :If 0=⍴REC
[4]      :OrIf 'Widget'≡6⍴REC
[5]         :Leave
[6]      :EndIf
[7]   :EndRepeat


For Statement :For var :In[Each] aexp

Formal Definition

Single Control Variable

The :For loop is used to execute a block of code for a series of values of a particular control variable. For example, the following would execute lines [2-3] successively for values of I from 3 to 5 inclusive:

[1]   :For I :In 3 4 5
[2]       expr1 I
[3]       expr2 I
[4]   :EndFor

The way a :For loop operates is as follows. On encountering the :For, the expression to the right of :In is evaluated and the result stored. This is the control array. The control variable, named to the right of the :For, is then assigned the first value in the control array, and the code between :For and :EndFor is executed. On encountering the :EndFor, the control variable is assigned the next value of the control array and execution of the code is performed again, starting at the first line after the :For. This process is repeated for each value in the control array.

Note that if the control array is empty, the code in the :For structure is not executed. Note too that the control array may be any rank and shape, but that its elements are assigned to the control variable in ravel order.

The control array may contain any type of data. For example, the following code resizes (and compacts) all your component files

[1]   :For FILE :In (↓⎕FLIB '')~¨' '
[2]       FILE ⎕FTIE 1
[3]       ⎕FRESIZE 1
[4]       ⎕FUNTIE 1
[5]   :EndFor

You may also nest :For loops. For example, the following expression finds the timestamp of the most recently updated component in all your component files.

[1]   TS←0
[2]   :For FILE :In (↓⎕FLIB '')~¨' '
[3]       FILE ⎕FTIE 1
[4]       START END←2⍴⎕FSIZE 1
[5]       :For COMP :In (START-1)↓⍳END-1
[6]           TS⌈←¯1↑⎕FREAD FILE COMP
[7]       :EndFor
[8]       ⎕FUNTIE 1
[9]   :EndFor

Multiple Control Variables

The :For control structure can also take multiple variables. This has the effect of doing a strand assignment each time around the loop.

For example :For a b c :in (1 2 3)(4 5 6), sets a b c←1 2 3, first time around the loop and a b c←4 5 6, the second time.

Another example is :For i j :In ⍳⍴Matrix, which sets i and j to each row and column index of Matrix.

:InEach Control Word

      :For var ... :InEach value ...

In a :For control structure, the keyword :InEach is an alternative to :In.

For a single control variable, the effect of the keywords is identical but for multiple control variables the values vector is inverted.

The distinction is best illustrated by the following equivalent examples:

      :For a b c :In (1 2 3)(3 4 5)(5 6 7)(7 8 9)
          ⎕←a b c
      :EndFor

      :For a b c :InEach (1 3 5 7)(2 4 6 8)(3 5 7 9)
           ⎕←a b c
      :EndFor

In each case, the output from the loop is:

1 2 3
3 4 5
5 6 7
7 8 9

Notice that in the second case, the number of items in the values vector is the same as the number of control variables. A more typical example might be.

      :For a b c :InEach avec bvec cvec
          ...
      :EndFor

Here, each time around the loop, control variable a is set to the next item of avec, b to the next item of bvec and c to the next item of cvec.


Select Statement :Select aexp

Formal Definition

A :Select structure is used to execute alternative blocks of code depending upon the value of an array. For example, the following displays 'I is 1' if the variable I has the value 1, 'I is 2' if it is 2, or 'I is neither 1 nor 2' if it has some other value.

[1]   :Select I
[2]   :Case 1
[3]       'I is 1'
[4]   :Case 2
[5]       'I is 2'
[6]   :Else
[7]       'I is neither 1 nor 2'
[8]   :EndSelect

In this case, the system compares the value of the array expression to the right of the :Select statement with each of the expressions to the right of the :Case statements and executes the block of code following the one that matches. If none match, it executes the code following the :Else (which is optional). Note that comparisons are performed using the ≡ primitive function, so the arrays must match exactly. Note also that not all of the :Case expressions are necessarily evaluated because the process stops as soon as a matching expression is found.

Instead of a :Case statement, you may also use a :CaseList statement. If so, the enclose of the array expression to the right of :Select is tested for membership of the array expression to the right of the :CaseList using the ∊ primitive function.

Note also that any code placed between the :Select and the first :Case or :CaseList statements are unreachable; future versions of Dyalog APL may generate an error when attempting to fix functions which include such code.

Example

[1]   :Select ?6 6
[2]   :Case 6 6
[3]       'Box Cars'
[4]   :Case 1 1
[5]       'Snake Eyes'
[6]   :CaseList 2⍴¨⍳6
[7]       'Pair'
[8]   :CaseList (⍳6),¨⌽⍳6
[9]       'Seven'
[10]  :Else
[11]      'Unlucky'
[12]  :EndSelect


With Statement :With obj

Formal Definition

:With is a control structure that may be used to simplify a series of references to an object or namespace. :With changes into the specified namespace for the duration of the control structure, and is terminated by :End[With]. obj is either the name of or a reference to a namespace. For example, you could update several properties of a Grid object F.G as follows:

       :With F.G
            Values←4 3⍴0
            RowTitles←'North' 'South' 'East' 'West'
            ColTitles←'Cakes' 'Buns' 'Biscuits'
       :EndWith

:With is analogous to ⎕CS in the following senses:

  • The namespace argument to :With is interpreted relative to the current space.
  • With the exception of those with name class 9, local names in the containing defined function continue to be visible in the new space.
  • Global references from within the :With control structure are to names in the new space.
  • Exiting the defined function from within a :With control structure causes the space to revert to the one from which the function was called.

On leaving the :With control structure, execution reverts to the original namespace. Notice however that the interpreter does not detect branches (→) out of the control structure. :With control structures can be nested in the normal fashion:

[1]   :With 'x'           ⍝ Change to #.x
[2]       :With 'y'       ⍝ Change to #.x.y
[3]           :With ⎕SE   ⍝ Change to ⎕SE
[4]               ...     ⍝ ... in ⎕SE
[5]           :EndWith    ⍝ Back to #.x.y
[6]       :EndWith        ⍝ Back to #.x
[7]   :EndWith            ⍝ Back to #


Hold Statement :Hold tkns

Formal Definition

Whenever more than one thread tries to access the same piece of data or shared resource at the same time, you need some type of synchronisation to control access to that data. This is provided by :Hold.

:Hold provides a mechanism to control thread entry into a critical section of code. tkns must be a simple character vector or scalar, or a vector of character vectors. tkns represents a set of "tokens", all of which must be acquired before the thread can continue into the control structure. :Hold is analogous to the component file system ⎕FHOLD which is used to synchronise access between processes. See also File Hold.

Within the whole active workspace, a token with a particular value may be held only once. If the hold succeeds, the current thread acquires the tokens and execution continues with the first phrase in the control structure. On exit from the structure, the tokens are released for use by other threads. If the hold fails, because one or more of the tokens is already in use:

  1. If there is no :Else clause in the control structure, execution of the thread is blocked until the requested tokens become available.
  2. Otherwise, acquisition of the tokens is abandoned and execution resumed immediately at the first phrase in the :Else clause.

tkns can be either a single token:

    'a'
    'Red'
    '#.Util'
    ''
    'Program Files'

… or a number of tokens:

    'red' 'green' 'blue'
    'doe' 'a' 'deer'
    ,¨'abc'
    ↓⎕nl 9

Pre-processing removes trailing blanks from each token before comparison, so that, for example, the following two statements are equivalent:

    :Hold 'Red' 'Green'
    :Hold ↓2 5⍴'Red  Green'

Unlike ⎕FHOLD, a thread does not release all existing tokens before attempting to acquire new ones. This enables the nesting of holds, which can be useful when multiple threads are concurrently updating parts of a complex data structure.

In the following example, a thread updates a critical structure in a child namespace, and then updates a structure in its parent space. The holds will allow all "sibling" namespaces to update concurrently, but will constrain updates to the parent structure to be executed one at a time.

    :Hold ⎕cs''          ⍝ Hold child space
        ...              ⍝ Update child space
        :Hold ##.⎕cs''   ⍝ Hold parent space
            ...          ⍝ Update Parent space
        :EndHold
        ...
    :EndHold

However, with the nesting of holds comes the possibility of a "deadlock". For example, consider the two threads:

Thread 1 Thread 2
:Hold 'red'
    ...
    :Hold 'green'
        ...
    :EndHold
:EndHold

:Hold 'green'
    ...
    :Hold 'red'
        ...
    :EndHold
:EndHold

In this case if both threads succeed in acquiring their first hold, they will both block waiting for the other to release its token.

If this deadlock situation is detected acquisition of the tokens is abandoned. Then:

  1. If there is an :Else clause in the control structure, execution jumps to the :Else clause.
  2. Otherwise, APL issues an error (1008) DEADLOCK.

You can avoid deadlock by ensuring that threads always attempt to acquire tokens in the same chronological order, and that threads never attempt to acquire tokens that they already own.

Note that token acquisition for any particular :Hold is atomic, that is, either all of the tokens or none of them are acquired. The following example cannot deadlock:

Thread 1 Thread 2
:Hold 'red'
    ...
    :Hold 'green'
        ...
    :EndHold
:EndHold

:Hold 'green' 'red'
    ...
    :EndHold

Examples

:Hold could be used for example, during the update of a complex data structure that might take several lines of code. In this case, an appropriate value for the token would be the name of the data structure variable itself, although this is just a programming convention: the interpreter does not associate the token value with the data variable.

    :Hold'Struct'
        ...              ⍝ Update Struct
        Struct ← ...
    :EndHold

The next example guarantees exclusive use of the current namespace:

    :Hold ⎕CS''          ⍝ Hold current space
        ...
    :EndHold

The following example shows code that holds two positions in a vector while the contents are exchanged.

    :Hold ⍕¨to fm
        :If >/vec[fm to]
            vec[fm to]←vec[to fm]
        :End
    :End

Between obtaining the next available file tie number and using it:

    :Hold '⎕FNUMS'
        tie←1+⌈/0,⎕FNUMS
        fname ⎕FSTIE tie
    :End

The above hold is not necessary if the code is combined into a single line:

    fname ⎕FSTIE tie←1+⌈/0,⎕FNUMS

or,

    tie←fname ⎕FSTIE 0

Note that :Hold, like its component file system counterpart ⎕FHOLD, is a device to enable co-operating threads to synchronise their operation.

:Hold does not prevent threads from updating the same data structures concurrently, it prevents threads only from :Holding the same tokens.

High-Priority Callbacks

:Hold is not permitted in a high-priority callback and an attempt to use it will cause the error:

 DOMAIN ERROR: Cannot :Hold within high priority callback

See High-Priority Callback Functions.


Trap Statement :Trap ecode

Formal Definition

:Trap is an error trapping mechanism that can be used in conjunction with, or as an alternative to, the ⎕TRAP system variable. It is equivalent to APL2's ⎕EA, except that the code to be executed is not restricted to a single expression and is not contained within quotes (and so is slightly more efficient).

ecode is an integer scalar or vector containing the list of event codes which are to be handled during execution of the segment of code between the :Trap and :End[Trap] statements. Note that event codes 0 and 1000 are wild cards that means any event code in a given range. See APL Error Messages.

Operation

The segment of code immediately following the :Trap keyword is executed. On completion of this segment, if no error occurs, control passes to the code following :End[Trap].

If an error occurs which is not specified by ecode, it is processed by outer :Traps, ⎕TRAPs, or by the default system processing in the normal fashion.

If an error occurs, whose event code matches ecode:

  • If the error occurred within a sub-function, the system cuts the state indicator back to the function containing the :Trap keyword. In this respect, :Trap behaves like ⎕TRAP with a 'C' qualifier.
  • If the :Trap segment contains a :Case[List] ecode statement whose ecode matches the event code of the error that has occurred, execution continues from the statement following that :Case[List] ecode.
  • Otherwise, if the :Trap segment contains a :Else statement, execution continues from the first statement following the :Else statement.
  • Otherwise, execution continues from the first statement following the :End[Trap] and no error processing occurs.

Note that the error trapping is in effect only during execution of the initial code segment. When a trapped error occurs, further error trapping is immediately disabled (or surrendered to outer level :Traps or ⎕TRAPs). In particular, the error trap is no longer in effect during processing of :Case[List]'s argument or in the code following the :Case[List] or :Else statement. This avoids the situation sometimes encountered with ⎕TRAP where an infinite "trap loop" occurs.

Note that the statement :Trap ⍬ results in no errors being trapped.

Examples

     ∇ lx
[1]    :Trap 1000        ⍝ Cutback and exit on interrupt
[2]        Main ...
[3]    :EndTrap
     ∇

     ∇ ftie←Fcreate file        ⍝ Create null component file
[1]    :Trap 22                 ⍝ Trap FILE NAME ERROR
[2]        ftie←file ⎕FCREATE 0 ⍝ Try to create file.
[3]    :Else
[4]        ftie←file ⎕FTIE 0    ⍝ Tie the file.
[5]        file ⎕FERASE ftie    ⍝ Drop the file.
[6]        file ⎕FCREATE ftie   ⍝ Create new file.
[7]    :EndTrap
     ∇

     ∇ lx ⍝ Distinguish various cases
[1]    :Trap 0 1000
[2]        Main ...
[3]    :Case 1002
[4]        'Interrupted ...'
[5]    :CaseList 1 10 72 76
[6]        'Not enough resources'
[7]    :CaseList 17+⍳20
[8]        'File System Problem'
[9]    :Else
[10]       'Unexpected Error'
[11]   :EndTrap
     ∇

Note that :Traps can be nested:

     ∇ ntie←Ntie file                    ⍝ Tie native file
[1]    :Trap 22                          ⍝ Trap FILE NAME ERROR
[2]        ntie←file ⎕NTIE 0             ⍝ Try to tie file
[3]    :Else
[4]        :Trap 22                      ⍝ Trap FILE NAME ERROR
[5]            ntie←(file,'.txt')⎕NTIE 0 ⍝ Try with .txt extn
[6]        :Else
[7]            ntie←file ⎕NCREATE 0      ⍝ Create null file.
[8]        :EndTrap
[9]    :EndTrap
     ∇


GoTo Statement :GoTo aexp

A :GoTo statement is a direct alternative to → (branch) and causes execution to jump to the line specified by the first element of aexp.

The following are equivalent. See Branch for further details.

      →Exit
      :GoTo Exit

      →(N<I←I+1)/End
      :GoTo (N<I←I+1)/End

      →1+⎕LC
      :GoTo 1+⎕LC

      →10
      :GoTo 10


Return Statement :Return

A :Return statement causes a function to terminate and has exactly the same effect as →0.

The :Return control word takes no argument.

A :Return statement may occur anywhere in a function or operator.


Leave Statement :Leave

A :Leave statement is used to explicitly terminate the execution of a block of statements within a :For, :Repeat or :While control structure.

The :Leave control word takes no argument.


Continue Statement :Continue

A :Continue statement starts the next iteration of the immediately surrounding :For, :Repeat or :While control loop.

When executed within a :For loop, the effect is to start the body of the loop with the next value of the iteration variable.

When executed within a :Repeat or :While loop, if there is a trailing test that test is executed and, if the result is true, the loop is terminated. Otherwise the leading test is executed in the normal fashion.


Section Statement

Section Statement :Section

Functions and scripted objects (classes, namespaces etc.) can be subdivided into Sections with :Section and :EndSection statements. Both statements may be followed by an optional and arbitrary name or description. The purpose is to split the function up into sections that you can open and close in the Editor, thereby aiding readability and code management. Sections have no effect on the execution of the code, but must follow the nesting rules of other control structures.


Disposable Statement

Disposable Statement :Disposable

Formal Definition

The Dyalog interface to .NET involves the creation and removal of .NET objects. Many such objects are managed in that the .NET Common Language RunTime (CLR) automatically releases the memory allocated to the object when that object is no longer used. However, it is not possible to predict when the CLR garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams.

Typically, .NET classes implement a special interface called IDisposable which provides a standard way for applications to release memory and other resources when an instance is removed. Furthermore, the C# language has the using keyword, which "Provides a convenient syntax that ensures the correct use of IDisposable objects."

The :Disposable array statement in Dyalog APL provides a similar facility to C#'s using. array may be a scalar or vector of namespace references.

When the block is exited, any .NET objects in array that implement IDisposable will have IDisposable.Dispose called on them.

Note that exit includes normal exit as the code drops through :EndDisposable, or if an error occurs and is trapped, or if branch (→) is used to exit the block, or anything else.

See also: .NET Interface Guide: .Disposing of .NET Objects.

Example (Normal Exit)

:Disposable f←⎕NEW Font
.
.
:EndDisposable

In the above example, when the :EndDisposable statement is reached, the system disposes of the Font object f (and all the resources associated with it) by calling (IDisposable)f.Dispose(). A subsequent reference to f would generate VALUE ERROR.

Example (Normal Exit)

:Disposable fonts←⎕NEW ¨Font Font
.
.
:EndDisposable

In the above example, Dispose() is called on each of the Font objects in fonts during the processing of :EndDisposable.

Example (Branch Exit)

:Disposable fonts←⎕NEW ¨Font Font
.
→0
.
:EndDisposable

In this example, Dispose() is called on the Font objects in fonts during the processing of the branch statement →0.

Example (TrapExit)

:trap 0

   :Disposable fonts←⎕NEW ¨Font Font
   .
   ÷0
   .
   :EndDisposable

:else

   ⎕←'failed'

:endif

Here, the objects are disposed of when the DOMAIN ERROR generated by the expression ÷0 causes the stack to be cut back to the :Else clause. At this point (just before the execution of the :Else clause) the name class of fonts becomes 0.


Triggers

Triggers provide the ability to have a function called automatically whenever a variable or a Field is assigned. Triggers are actioned by all forms of assignment (←), but only by assignment.

Triggers are designed to allow a class to perform some action when a field is modified – without having to turn the field into a property and use the property setter function to achieve this. Avoiding the use of a property allows the full use of the APL language to manipulate data in a field, without having to copy field data in and out of the class through get and set functions.

Triggers can also be applied to variables outside a class, and there will be situations where this is very useful. However, dynamically attaching and detaching a trigger from a variable is a little tricky at present.

The function that is called when a variable or Field changes is referred to as the Trigger Function. The name of a variable or Field which has an associated Trigger Function is termed a Trigger.

A function is declared as a Trigger function by including the statement:

      :Implements Trigger Name1,Name2,Name3, ...

where Name1, Name2 etc. are the Triggers.

When a Trigger function is invoked, it is passed an Instance of the internal Class TriggerArguments. This Class has 3 Fields:

Member | Description
Name | Name of the Trigger whose change in value has caused the Trigger Function to be invoked.
NewValue | The newly assigned value of the Trigger
OldValue | The previous value of the Trigger. If the Trigger was not previously defined, a reference to this Field causes a VALUE ERROR.

A Trigger Function is called as soon as possible after the value of a Trigger was assigned; typically by the end of the currently executing line of APL code. The precise timing is not guaranteed and may not be consistent because internal workspace management operations can occur at any time.

If the value of a Trigger is changed more than once by a line of code, the Trigger Function will be called at least once, but the number of times is not guaranteed.

A Trigger Function is not called when the Trigger is expunged.

Expunging a Trigger disconnects the name from the Trigger Function and the Trigger Function will not be invoked when the Trigger is reassigned. The connection may be re-established by re-fixing the Trigger Function.

A Trigger may have only a single Trigger Function. If the Trigger is named in more than one Trigger Function, the Trigger Function that was last fixed will apply.

In general, it is inadvisable for a Trigger function to modify its own Trigger, as this will potentially cause the Trigger to be invoked repeatedly and forever.

To associate a Trigger function with a local name, it is necessary to dynamically fix the Trigger function in the function in which the Trigger is localised; for example:

     ∇ TRIG arg
[1]    :Implements Trigger A
[2]    ...

     ∇ TEST;A
[1]    ⎕FX ⎕OR'TRIG'
[2]    A←10


Triggers

Trigger Example

The following function displays information when the value of variables A or B changes.

     ∇ TRIG arg
[1]    :Implements Trigger A,B
[2]    arg.Name'is now 'arg.NewValue
[3]    :Trap 6 ⍝ VALUE ERROR
[4]        arg.Name'was    'arg.OldValue
[5]    :Else
[6]        arg.Name' was     [undefined]'
[7]    :EndTrap
     ∇

Note that on the very first assignment to A, when the variable was previously undefined, arg.OldValue is a VALUE ERROR.

      A←10
 A  is now   10
 A   was     [undefined]

      A+←10
 A  is now   20
 A  was      10

      A←'Hello World'
 A  is now   Hello World
 A  was      20

      A[1]←⊂2 3⍴⍳6
 A  is now    1 2 3 ello World
              4 5 6
 A  was      Hello World

      B←⌽¨A
 B  is now    3 2 1 ello World
              6 5 4
 B   was     [undefined]

      A←⎕NEW MyClass
 A  is now   #.[Instance of MyClass]
 A  was       1 2 3 ello World
              4 5 6

      'F'⎕WC'Form'
      A←F
 A  is now   #.F
 A  was      #.[Instance of MyClass]

Note that Trigger functions are actioned only by assignment, so changing A to a Form using ⎕WC does not invoke TRIG.

      'A'⎕WC'FORM' ⍝ Note that Trigger Function is not invoked

However, the connection (between A and TRIG) remains and the Trigger Function will be invoked if and when the Trigger is re-assigned.

      A←99
 A  is now   99
 A  was      #.A

See Trigger Fields for information on how a Field (in a Class) may be used as a Trigger.


Idiom Recognition

Idioms are commonly used expressions that are recognised and evaluated internally, providing a significant performance improvement.

For example, the idiom BV/⍳⍴A (where BV is a Boolean vector and A is an array) would (in earlier Versions of Dyalog APL) have been evaluated in 3 steps as follows:

  1. Evaluate ⍴A and store result in temporary variable temp1 (temp1 is just an arbitrary name for the purposes of this explanation)
  2. Evaluate ⍳temp1 and store result in temporary variable temp2.
  3. Evaluate BV/temp2
  4. Discard temporary variables

In the current Version of Dyalog APL, the expression is recognised in its entirety and processed in a single step as if it were a single primitive function. In this case, the resultant improvement in performance is between 2 and 4.5.

Idiom recognition is precise; an expression that is almost identical but not exactly identical to an expression given in the Idiom List table will not be recognised.

For example, ⎕AV⍳ will be recognised as an idiom, but (⎕AV)⍳ will not. Similarly, (,)/ would not be recognized as the Join idiom.


Idiom List

In the following table, arguments to the idiom have types and ranks as follows:

Type | Description | Rank | Description
C | Character | S | Scalar or 1-item vector
B | Boolean | V | Vector
N | Numeric | M | Matrix
P | Nested | A | Array of any rank
X | any type |  |

For example: NV: numeric vector, CM: character matrix, PV: nested vector.

Idiom | Description
⍴⍴XA | The rank of XA as a 1-element vector
≢⍴XA | The rank of XA as a scalar
BV/⍳NS | The subset of NS corresponding to the 1s in BV
BV/⍳⍴XV | The positions in XV corresponding to the 1s in BV
NA⊃¨⊂XV | The subset of XV in the index positions defined by NA (equivalent to XV[NA])
XA1{}XA2 | XA1 and XA2 are ignored (no result produced)
XA1{⍺}XA2 | XA1 (XA2 is ignored)
XA1{⍵}XA2 | XA2 (XA1 is ignored)
XA1{⍺ ⍵}XA2 | XA1 and XA2 as a two item vector (XA1 XA2)
{0}XA | 0 irrespective of XA
{0}¨XA | 0 corresponding to each item of XA
,/PV | The enclose of the items of PV (which must be of depth 2) catenated along their last axes
⍪/PV | The enclose of the items of PV (which must be of depth 2) catenated along their first axes
⊃⌽XA | The item in the top right of XA (⎕ML<2)
↑⌽XA | The item in the top right of XA (⎕ML≥2)
⊃⌽,XA | The item in the bottom right of XA (⎕ML<2)
↑⌽,A | The item in the bottom right of XA (⎕ML≥2)
0=⍴XV | 1 if XV has a shape of zero, 0 otherwise
0=⍴⍴XA | 1 if XA has a rank of zero (scalar), 0 otherwise
0=≡XA | 1 if XA has a depth of zero (simple scalar), 0 otherwise
XM1{(↓⍺)⍳↓⍵}XM2 | A simple vector comprising as many items as there are rows in XM2, where each item is the number of the first row in XM1 that matches each row in XM2.
↓⍉↑PV | A nested vector comprising vectors that each correspond to a position in the original vectors of PV – the first vector contains the first item from each vector in PV, padded to be the same length as the largest vector, and so on (⎕ML<2)
↓⍉⊃PV | A nested vector comprising vectors that each correspond to a position in the original vectors of PV – the first vector contains the first item from each vector in PV, padded to be the same length as the largest vector, and so on (⎕ML≥2)
^\' '=CA | A Boolean mask indicating the leading blank spaces in each row of CA
+/^\' '=CA | The number of leading blank spaces in each row of CA
+/^\BA | The number of leading 1s in each row of BA
{(∨\' '≠⍵)/⍵}CV | CV without any leading blank spaces
{(+/^\' '=⍵)↓⍵}CV | CV without any leading blank spaces
~∘' '¨↓CA | A nested vector comprising simple character vectors constructed from the rows of CA (which must be of depth 1) with all blank spaces removed
{(+/∨\' '≠⌽⍵)↑¨↓⍵}CA | A nested vector comprising simple character vectors constructed from the rows of CA (which must be of depth 1) with trailing blank spaces removed
⊃∘⍴¨XA | The length of the first axis of each item in XA (⎕ML<2)
↑∘⍴¨XA | The length of the first axis of each item in XA (⎕ML≥2)
XA1,←XA2 | XA1 redefined to be XA1 with XA2 catenated along its last axis
XA1⍪←XA2 | XA1 redefined to be XA1 with XA2 catenated along its first axis
{(⊂⍋⍵)⌷⍵}XA | XA sorted into ascending order
{(⊂⍒⍵)⌷⍵}XA | XA sorted into descending order
{⍵[⍋⍵]}XV | XV sorted into ascending order
{⍵[⍒⍵]}XV | XV sorted into descending order
{⍵[⍋⍵;]}XM | XM with the rows sorted into ascending
{⍵[⍒⍵;]}XM | XM with the rows sorted into descending order
1=≡XA | 1 if XA has a depth of 1 (simple array), 0 otherwise
1=≡,XA | 1 if XA has a depth of 0 or 1 (simple scalar, vector, etc.), 0 otherwise
0∊⍴XA | 1 if XA is empty, 0 otherwise
~0∊⍴XA | 1 if XA is not empty, 0 otherwise
⊣⌿XA | The first sub-array along the first axis of XA
⊣/XA | The first sub-array along the last axis of XA
⊢⌿XA | The last sub-array along the first axis of XA
⊢/XA | The last sub-array along the last axis of XA
*○NA | Euler's idiom (accurate when NA is a multiple of 0J0.5)
0=⊃⍴XA | 1 if XA has an empty first dimension, 0 otherwise (⎕ML<2)
0≠⊃⍴XA | 1 if XA does not have an empty first dimension, 0 otherwise (⎕ML<2)
⎕AV⍳CA | Classic version only: The character numbers (atomic vector index) corresponding to the characters in CA
⌊0.5+NA | Round to nearest integer
XA↓⍨←NS | This idiom applies only when NS is negative, when it removes the last -NS items from XA along its leading axis. See note below.
{(⊂⍋⍵)⌷⍵}
{(⊂⍒⍵)⌷⍵} 		These idioms provide the fastest way to sort arrays of any rank

Notes

/⍳ and /⍳⍴, as well as providing an execution time advantage, reduce intermediate workspace usage and, consequently, the incidence of memory compactions and the likelihood of a WS FULL.

NA⊃¨⊂XV is implemented as XV[NA], which is significantly faster. The two are equivalent but the former now has no performance penalty.

,/ is special-cased only for vectors of vectors or scalars. Otherwise, the expression is evaluated as a series of concatenations. Recognition of this idiom turns join from an n-squared algorithm into a linear one. In other words, the improvement factor is proportional to the size of the argument vector.

⊃⌽ and ⊃⌽, now take constant time. Without idiom recognition, the time taken depends linearly on the number of items in the argument.

0=≡ takes a small constant time. Without idiom recognition, the time taken would depend on the size and depth of the argument, which in the case of a deeply nested array could be significant.

↓⍉↑ is special-cased only for a vector of nested vectors, each of whose items is of the same length.

{(↓⍺)⍳↓⍵} can accommodate much larger matrices than its constituent primitives. It is particularly effective when bound with a left argument using the compose operator:

      find←mat∘{(↓⍺)⍳↓⍵}     ⍝ find rows in mat table

In this case, the internal hash table for mat is retained so that it does not need to be generated each time the monadic derived function find is applied to a matrix argument.

{(∨\' '≠⍵)/⍵} and {(+/^\' '=⍵)↓⍵} are two codings of the same idiom. Both use the same C code for evaluation.

~∘' '¨↓ typically takes a character matrix argument and returns a vector of character vectors from which all blanks have been removed. An example might be the character matrix of names returned by the system function ⎕NL. In general, this idiom accommodates character arrays of any rank.

{(+/∨\' '≠⌽⍵)↑¨↓⍵} typically takes a character matrix argument and returns a vector of character vectors. Any embedded blanks in each row are preserved but trailing blanks are removed. In general, this idiom accommodates character arrays of any rank.

⊃∘⍴¨A (⎕ML<2) and ↑∘⍴¨A (⎕ML>2) avoid having to create an intermediate nested array of shape vectors.

For an array of vectors, this idiom quickly returns a simple array of the length of each vector.

      ⊃∘⍴¨ 'Hi' 'Pete' ⍝ Vector Lengths
2 4

For an array of matrices, it returns a simple array of the number of rows in each matrix.

      ⊃∘⍴¨⎕CR¨↓⎕NL 3   ⍝ Lines in functions
5 21...

A,←A and A⍪←A optimise the catenation of an array to another array along the last and first dimension respectively.

Among other examples, this idiom optimises repeated catenation of a scalar or vector to an existing vector.

      props,←⊂ 'Posn' 0 0
      props,←⊂'Size' 50 50
      vector,←2+4

Note that the idiom is not applied if the value of vector V is shared with another symbol in the workspace, as illustrated in the following examples:

Example 1: the idiom is used to perform the catenation to V1.

      V1←⍳10
      V1,←11

Example 2: the idiom is not used to perform the catenation to V1, because its value is at that point shared with V2.

      V1←⍳10
      V2←V1
      V1,←11

Example 3: the idiom is not used to perform the catenation to V in Join[1] because its value is, at that point, shared with the array used to call the function.

     ∇ V←V Join A
[1]    V,←A
     ∇
      (⍳10) Join 11
1 2 3 4 5 6 7 8 9 10 11

⊢⌿XA, ⊢/XA, ⊣⌿XA, and ⊣/XA return the first/last rank (0⌈¯1+⍴⍴A) sub-array along the first/last axis of XA. For example, if V is a vector, then:

⊣/V | First item of vector
⊢/V | Last item of vector

Similarly, if M is a matrix, then:

⊣⌿M | First row of matrix
⊣/M | First column of matrix
⊢⌿M | Last row of matrix
⊢/M | Last column of matrix

The idiom generalises uniformly to higher-rank arrays.

Euler's idiom *○NA produces accurate results for right argument values that are a multiple of 0J0.5. This is so that Euler's famous identity 0=1+*○0J1 holds, despite pi being represented as a floating point number.

For clarification; XA↓⍨←NS. If NS is ¯3 then the idiom removes the last -¯3 (i.e. 3) items.


Search Functions and Hash Tables

Primitive dyadic search functions, such as ⍳ (index of) and ∊ (membership) have a principal argument in which items of the other subject argument are located.

In the case of ⍳, the principal argument is the one on the left and in the case of ∊, it is the one on the right. The following table shows the principal (P) and subject (s) arguments for each of the functions.

P ⍳ s | Index of
s ∊ P | Membership
s ∩ P | Intersection
P ∪ s | Union
s ~ P | Without
P {(↓⍺)⍳↓⍵} s | Matrix Iota (idiom)
P∘⍋ and P∘⍒ | Sort

The Dyalog APL implementation of these functions already uses a technique known as hashing to improve performance over a simple linear search. (Note that ⍷ (find) does not employ the same hashing technique, and is excluded from this discussion.)

Building a hash table for the principal argument takes a significant time but is rewarded by a considerably quicker search for each item in the subject. Unfortunately, the hash table is discarded each time the function completes and must be reconstructed for a subsequent call (even if its principal argument is identical to that in the previous one).

For optimal performance of repeated search operations, the hash table may be retained between calls, by binding the function with its principal argument using the primitive ∘ (compose) operator. The retained hash table is then used directly whenever this monadic derived function is applied to a subject argument.

Notice that retaining the hash table pays off only on a second or subsequent application of the derived function. This usually occurs in one of two ways: either the derived function is named for later (and repeated) use, as in the first example below or it is applied repeatedly as the operand of a primitive or defined operator, as in the second example.

Example: naming a derived function.

      words←'red' 'ylo' 'grn' 'brn' 'blu' 'pnk' 'blk'

      find←words∘⍳                 ⍝ monadic find function
      find'blk' 'blu' 'grn' 'ylo'  ⍝
7 5 3 2
      find'grn' 'brn' 'ylo' 'red'  ⍝ fast find
3 4 2 1

Example: repeated application by (¨) each operator.

      ∊∘⎕A¨'This' 'And' 'That'
 1 0 0 0  1 0 0  1 0 0 0


Locked Functions & Operators

A defined operation may be locked by the system function ⎕LOCK. A locked operation may not be displayed or edited. The system function ⎕CR returns an empty matrix of shape 0 0 and the system functions ⎕NR and ⎕VR return an empty vector for a locked operation.

Stop, trace and monitor settings may be established by the system functions ⎕STOP, ⎕TRACE and ⎕MONITOR respectively. Existing stop, trace and monitor settings are cancelled when an operation is locked.

A locked operation may not be suspended, nor may a locked operation remain pendent when execution is suspended. The state indicator is cut back as described below.


The State Indicator

The state of execution is dynamically recorded in the state indicator. The state indicator identifies the chain of execution for operators, functions and the evaluated or character input/output system variables (⎕ and ⍞). At the top of the state indicator is the most recently activated operation.

Execution may be suspended by an interrupt, induced by the user, the system, or by a signal induced by the system function ⎕SIGNAL or by a stop control set by the system function ⎕STOP. If the interrupt (or event which caused the interrupt) is not defined as a trappable event by the system variable ⎕TRAP, the state indicator is cut back to the first of either a defined operation or the evaluated input prompt (⎕) such that there is no locked defined operation in the state indicator. The topmost operation left in the state indicator is said to be SUSPENDED. Other operations in the chain of execution are said to be PENDENT.

The state indicator may be examined when execution is suspended by the system commands )SI and )SINL. The names of the defined operations in the state indicator are given by the system functions ⎕SI and ⎕XSI while the line numbers at which they are suspended or pendent is given by the system variable ⎕LC.

Suspended execution may be resumed by use of the Branch function (see Branch). Whilst execution is suspended, it is permitted to enter any APL expression for evaluation, thereby adding to the existing state indicator. Therefore, there may be more than one LEVEL OF SUSPENSION in the state indicator. If the state indicator is cut back when execution is suspended, it is cut back no further than the prior level of suspension (if any).

Examples

     ∇ F
[1]    G
     ∇

     ∇ G
[1]    'FUNCTION G'+
     ∇

      ⍎'F'
SYNTAX ERROR
G[1] 'FUNCTION G'+
     ^

      )SI
#.G[1]*
#.F[1]
⍎

⎕LOCK'G'

      ⍎'F'
SYNTAX ERROR
F[1] G
     ^

      )SI
#.F[1]*
⍎
#.G[1]*
#.F[1]
⍎

A suspended or pendent operation may be edited by the system editor or redefined using ⎕FX provided that it is visible and unlocked. However, pendent operations retain their original definition until they complete, or are cleared from the state indicator. When a new definition is applied, the state indicator is repaired if necessary to reflect changes to the operations, model syntax, local names, or labels.


Dfns & Dops

Introduction

A dfn (dop)The terms dfn and dop refer to a special type of function (or operator) unique to Dyalog. They were originally named dynamic functions and dynamic operators, later abbreviated to Dfns and Dops or D-Fns and D-Ops, but all these terms have been dropped in favour of the current ones. 1 is an alternative function definition style suitable for defining small to medium sized functions. It bridges the gap between operator expressions: rank←⍴∘⍴ and full "header style" definitions such as:

    ∇ rslt←larg func rarg;local...

In its simplest form, a dfn is an APL expression enclosed in curly braces {}, possibly including the special characters ⍺ and ⍵ to represent the left and right arguments of the function respectively. For example:

      {(+/⍵)÷⍴⍵} 1 2 3 4    ⍝ Arithmetic Mean (Average)
2.5
      3 {⍵*÷⍺} 64           ⍝ ⍺th root
4

dfns can be named in the normal fashion:

      mean←{(+/⍵)÷⍴⍵}
      mean¨(2 3)(4 5)
 2.5  4.5

dfns can be defined and used in any context where an APL function may be found, in particular:

  • In immediate execution mode as in the examples above.
  • Within a defined function or operator.
  • As the operand of an operator such as each (¨).
  • Within another dfn.
  • The last point means that it is easy to define nested local functions.


Multi-Line Dfns

The single expression which provides the result of the dfn may be preceded by any number of assignment statements. Each such statement introduces a name which is local to the function.

For example in the following, the expressions sum← and num← create local definitions sum and num.

      mean←{          ⍝ Arithmetic mean
          sum←+/⍵     ⍝ Sum of items
          num←⍴⍵      ⍝ Number of items
          sum÷num     ⍝ Mean
       }

An assignment to ⍵ is not allowed and will result in an error. For assignment to ⍺, see Default Left Argument.

Note that dfns may be commented in the usual way using ⍝.

When the interpreter encounters a local definition, a new local name is created. The name is shadowed dynamically exactly as if the assignment had been preceded by: ⎕shadow name ⋄.

It is important to note the distinction between the two types of statement above. There can be many assignment statements, each introducing a new local definition, but only a single expression where the result is not assigned. As soon as the interpreter encounters such an expression, it is evaluated and the result returned immediately as the result of the function.

For example, in the following,

      mean←{          ⍝ Arithmetic mean
          sum←+/⍵     ⍝ Sum of items
          num←⍴⍵      ⍝ Number of items
          sum,num     ⍝ Attempt to show sum,num (wrong)!
          sum÷num     ⍝ ... and return result.
       }

... as soon as the interpreter encounters the expression sum,num, the function terminates with the two item result (sum,num) and the following line is not evaluated.

To display arrays to the session from within a dfn, you can use the explicit display forms ⎕← or ⍞← as in:

      mean←{          ⍝ Arithmetic mean
          sum←+/⍵     ⍝ Sum of items
          num←⍴⍵      ⍝ Number of items
          ⎕←sum,num   ⍝ show sum,num.
          sum÷num     ⍝ ... and return result.
       }

Note that local definitions can be used to specify local nested dfns:

      rms←{                ⍝ Root Mean Square
         root←{⍵*0.5}      ⍝ ∇ Square root
         mean←{(+/⍵)÷⍴⍵}   ⍝ ∇ Mean
         square←{⍵×⍵}      ⍝ ∇ Square
         root mean square
       }


Default Left Argument

The special syntax: ⍺←expr is used to give a default value to the left argument if a dfn is called monadically. For example:

      root←{      ⍝ ⍺th root
          ⍺←2     ⍝ default to sqrt
          ⍵*÷⍺
      }

The expression to the right of ⍺← is evaluated only if its dfn is called with no left argument.

Note that the assignment ⍺←⊢ allows an ambivalent function to call an ambivalent sub-function. For example in:

      foo←{
         ⍺←⊢
         ⍺ goo ⍵
      }

If foo is given a left argument, this is passed to goo. Otherwise, ⍺ is assigned ⊢ and the last line is ⊢ goo ⍵, which is a monadic call on goo followed by the ⊢ (Right) of the result of goo, which is the same value.


Guards

A Guard is a Boolean-single valued expression followed on the right by a ':'. For example:

      0≡≡⍵:         ⍝ Right arg simple scalar
      ⍺<0:          ⍝ Left arg negative

The guard is followed by a single APL expression: the result of the function.

      ⍵≥0: ⍵*0.5    ⍝ Square root if non-negative.

A dfn may contain any number of guarded expressions each on a separate line (or collected on the same line separated by diamonds). Guards are evaluated in turn until one of them yields a 1. The corresponding expression to the right of the guard is then evaluated as the result of the function.

If an expression occurs without a guard, it is evaluated immediately as the default result of the function. For example:

      sign←{
          ⍵>0: '+ve'      ⍝ Positive
          ⍵=0: 'zero'     ⍝ zero
               '-ve'      ⍝ Negative (Default)
      }

Local definitions and guards can be interleaved in any order.

Note again that any code following the first unguarded expression (which terminates the function) could never be executed and would therefore be redundant.

See also Error-Guards.


Shy Result

Dfns are usually 'pure' functions that take arguments and return explicit results. Occasionally, however, the main purpose of the function might be a side-effect such as the display of information in the session, or the updating of a file, and the value of a result, a secondary consideration. In such circumstances, you might want to make the result 'shy', so that it is discarded unless the calling context requires it. This can be achieved by assigning a dummy variable after a (true) guard:

      log←{                   ⍝ Append ⍵ to file ⍺.
          tie←⍺ ⎕fstie 0      ⍝ tie number for file,
          cno←⍵ ⎕fappend tie  ⍝ new component number,
          tie←⎕funtie tie     ⍝ untie file,
          1:rslt←cno          ⍝ comp number, shy result.
      }


Lexical Name Scope

When an inner (nested) dfn refers to a name, the interpreter searches for it by looking outwards through enclosing dfns, rather than searching back along the state indicator. This regime, which is more appropriate for nested functions, is said to employ lexical scope instead of APL's usual dynamic scope. This distinction becomes apparent only if a call is made to a function defined at an outer level. For the more usual inward calls, the two systems are indistinguishable.

For example, in the following function, variable type is defined both within which itself and within the inner function fn1. When fn1 calls outward to fn2 and fn2 refers to type, it finds the outer one (with value 'lexical') rather than the one defined in fn1:

      which←{

          type←'lexical'

          fn1←{
              type←'dynamic'
              fn2 ⍵
          }

          fn2←{
              type ⍵
          }

          fn1 ⍵
      }

      which'scope'
 lexical  scope


Error-Guards

An error-guard is (an expression that evaluates to) a vector of error numbers (see APL Error Messages), followed by the digraph: ::, followed by an expression, the body of the guard, to be evaluated as the result of the function. For example:

      11 5 :: ⍵×0 ⍝ Trap DOMAIN and LENGTH errors.

In common with :Trap and ⎕TRAP, error numbers 0 and 1000 are catch-alls for synchronous errors and interrupts respectively.

When an error is generated, the system searches dynamically through the calling functions for an error-guard that matches the error. If one is found, the execution environment is unwound to its state immediately prior to the error-guard's execution and the body of the error-guard is evaluated as the result of the function. This means that, during evaluation of the body, the guard is no longer in effect and so the danger of a hang caused by an infinite "trap loop", is avoided.

Notice that you can provide "cascading" error trapping in the following way:

      0::try_2nd
      0::try_1st
      expr

In this case, if expr generates an error, its immediately preceding: 0:: catches it and evaluates try_1st leaving the remaining error-guard in scope. If try_1st fails, the environment is unwound once again and try_2nd is evaluated, this time with no error-guards in scope.

See also Guards.

Examples:

Open returns a handle for a component file. If the exclusive tie fails, it attempts a share-tie and if this fails, it creates a new file. Finally, if all else fails, a handle of 0 is returned.

open←{                 ⍝ Handle for component file ⍵.
    0::0               ⍝ Fails:: return 0 handle.
    22::⍵ ⎕FCREATE 0   ⍝ FILE NAME:: create new one.
    24 25::⍵ ⎕FSTIE 0  ⍝ FILE TIED:: try share tie.
           ⍵ ⎕FTIE 0   ⍝ Attempt to open file.
}

An error in div causes it to be called recursively with improved arguments.

div←{                  ⍝ Tolerant division:: ⍺÷0 → ⍺.
    ⍺←1                ⍝ default numerator.
    5::↑∇/↓↑⍺ ⍵        ⍝ LENGTH:: stretch to fit.
    11::⍺ ∇ ⍵+⍵=0      ⍝ DOMAIN:: increase divisor.
    ⍺÷⍵                ⍝ attempt division.
}

Notice that some arguments may cause div to recur twice:

       6 4 2 div 3 2
→      6 4 2 div 3 2 0
→      6 4 2 div 3 2 1
→      2 2 2

The final example shows the unwinding of the local environment before the error-guard's body is evaluated. Local name trap is set to describe the domain of its following error-guard. When an error occurs, the environment is unwound to expose trap's statically correct value.

      add←{
          trap←'domain' ⋄ 11::trap
          trap←'length' ⋄  5::trap
          ⍺+⍵
      }

      2 add 3         ⍝ Addition succeeds
5

      2 add 'three'   ⍝ DOMAIN ERROR generated.
domain

      2 3 add 4 5 6   ⍝ LENGTH ERROR generated.
length

Note:

Following the setting of an error-guard, subsequent function calls will disable tail call optimisation:

    {
        22::'Oops!'     ⍝ this error-guard means that ...
        tie←⍵ ⎕ftie 0
        subfn tie       ⍝ ... tail call not optimised
    }

One way to maintain the tail call optimisation in the presence of an error-guard is to isolate it within an inner function:

    {
        tie←{
            22::0        ⍝ error-guard local to inner fn
            ⍵ ⎕ftie 0
        }⍵
        tie=0:'Oops!'
        subfn tie        ⍝ ... so this is a tail call
    }


Dops

The operator equivalent of a dfn is distinguished by the presence of either of the compound symbols ⍺⍺ or ⍵⍵ anywhere in its definition.

The syntax of a dop is:

  • monadic – ⍺ (⍺⍺ op) ⍵
  • dyadic – ⍺ (⍺⍺ op ⍵⍵) ⍵

where ⍺⍺ and ⍵⍵ are the left and right operands (functions or arrays) respectively, and ⍺ and ⍵ are the arguments of the derived function.

Example

The following monadic each operator applies its function operand only to unique elements of its argument. It then distributes the result to match the original argument. This can deliver a performance improvement over the primitive each (¨) operator if the operand function is costly and the argument contains a significant number of duplicate elements. Note however, that if the operand function causes side effects, the operation of dop and primitive versions will be different.

      each←{              ⍝ Fast each:
          shp←⍴⍵          ⍝ Shape and ...
          vec←,⍵          ⍝ ... ravel of arg.
          nub←∪vec        ⍝ Vector of unique elements.
          res←⍺⍺¨nub      ⍝ Result for unique elts.
          idx←nub⍳vec     ⍝ Indices of arg in nub ...
          shp⍴idx⊃¨⊂res   ⍝ ... distribute result.
      }

The dyadic else operator applies its left (else right) operand to its right argument depending on its left argument.

      else←{
          ⍺: ⍺⍺ ⍵     ⍝ True: apply Left operand
             ⍵⍵ ⍵     ⍝ Else,  ..   Right   ..
      }
      0 1 ⌈else⌊¨ 2.5     ⍝ Try both false and true.
2 3


Recursion

A recursive dfn can refer to itself using its name explicitly, but because we allow unnamed functions, we also need a special symbol for implicit self-reference: '∇'. For example:

      fact←{          ⍝ Factorial ⍵.
          ⍵≤1: 1      ⍝ Small ⍵, finished,
          ⍵×∇ ⍵-1     ⍝ Otherwise recur.
      }

Implicit self-reference using '∇' has the further advantage that it incurs less interpretative overhead and is therefore quicker. Tail calls using '∇' are particularly efficient.

Recursive dops refer to their derived functions, that is the operator bound with its operand(s) using ∇ or the operator itself using the compound symbol: ∇∇. The first form of self reference is by far the more frequently used.

      pow←{           ⍝ Function power.
          ⍺=0:⍵       ⍝ Apply function operand ⍺ times.
          (⍺-1)∇ ⍺⍺ ⍵ ⍝ ⍺⍺ ⍺⍺ ⍺⍺ ... ⍵
      }

Example

The following example shows a rather contrived use of the second form of (operator) self reference. The exp operator composes its function operand with itself on each recursive call. This gives the effect of an exponential application of the original operand function:

      exp←{               ⍝ Exponential fn application.
          ⍺=0:⍺⍺ ⍵        ⍝ Apply operand 2*⍺ times.
          (⍺-1)⍺⍺∘⍺⍺ ∇∇ ⍵ ⍝ (⍺⍺∘⍺⍺)∘( ... ) ... ⍵
      }
      succ←{1+⍵}          ⍝ Successor (increment).
      10 succ exp 0
1024

Example

     ∇pow←{ ⍝ Function power.
[1]        ⍺=0:⍵ ⍝ Apply function operand ⍺ times.
[2]        (⍺-1)∇ ⍺⍺ ⍵ ⍝ ⍺⍺ ⍺⍺ ⍺⍺ ... ⍵
[3]    }
     ∇
      4 ⍟ pow 5000
¯0.2720968003

Example: Pythagorean triples

The following sequence shows an example of combining dfns and dops in an attempt to find Pythagorean triples: (3 4 5)(5 12 13) ...

      sqrt←{⍵*0.5}              ⍝ Square root.

      sqrt 9 16 25
3 4 5

      hyp←{sqrt+/⊃⍵*2}          ⍝ Hypoteneuse of triangle.

      hyp(3 4)(4 5)(5 12)
5 6.403124237 13

      intg←{⍵=⌊⍵}               ⍝ Whole number?

      intg 2.5 3 4.5
0 1 0

      pyth←{intg hyp ⍵}         ⍝ Pythagorean pair?

      pyth(3 4)(4 9)(5 12)
1 0 1

      pairs←{,⍳⍵ ⍵}             ⍝ Pairs of numbers 1..⍵.

      pairs 3
 1 1  1 2  1 3  2 1  2 2  2 3  3 1  3 2  3 3

      filter←{(⍺⍺ ⍵)/⍵}         ⍝ Op: ⍵ filtered by ⍺⍺.

      pyth filter pairs 12      ⍝ Pythagorean pairs 1..12
 3 4  4 3  5 12  6 8  8 6  9 12  12 5  12 9

So far, so good, but we have some duplicates: (6 8) is just double (3 4).

      rpm←{                    ⍝ Relatively prime?
          ⍵=0:⍺=1              ⍝ C.f. Euclid's gcd.
          ⍵ ∇ ⍵|⍺
      }/¨                      ⍝ Note the /¨

      rpm(2 4)(3 4)(6 8)(16 27)
0 1 0 1

      rpm filter pyth filter pairs 20
 3 4  4 3  5 12  8 15  12 5  15 8

We can use an operator to combine the tests:

      and←{                    ⍝ Lazy parallel 'And'.
          mask←⍺⍺ ⍵            ⍝ Left predicate selects...
          mask\⍵⍵ mask/⍵       ⍝ args for right predicate.
      }

      pyth and rpm filter pairs 20
 3 4  4 3  5 12  8 15  12 5  15 8

Better, but we still have some duplicates: (3 4) (4 3).

      less←{</⊃⍵}
      less(3 4)(4 3)
1 0

      less and pyth and rpm filter pairs 40
 3 4  5 12  7 24  8 15  9 40  12 35  20 21

And finally, as promised, triples:

      {⍵,hyp ⍵}¨less and pyth and rpm filter pairs 35
 3 4 5  5 12 13  7 24 25  8 15 17  12 35 37  20 21 29

A Larger Example

Function tokens uses nested local dfns to split an APL expression into its constituent tokens. Note that all calls on the inner functions: lex, acc, and the unnamed dfn in each token case, are tail calls. In fact, the only stack calls are those on function: all, and the unnamed function: {⍵∨¯1⌽⍵}, within the "Char literal" case.

    tokens←{                        ⍝ Lex of APL src line.
        alph←⎕A,⎕Á,'_∆⍙',26↑17↓⎕AV  ⍝ Alphabet for names.
        all←{+/^\⍺∊⍵}               ⍝ No. of leading ⍺∊⍵.
        acc←{(⍺,↑/⍵)lex⊃↓/⍵}        ⍝ Accumulate tokens.
        lex←{
            0=⍴⍵:⍺ ⋄ hd←↑⍵          ⍝ Next char else done.

            hd=' ':⍺{               ⍝ White Space.
                size←⍵ all' '
                ⍺ acc size ⍵
            }⍵

            hd∊alph:⍺{              ⍝ Name
                size←⍵ all alph,⎕D
                ⍺ acc size ⍵
            }⍵

            hd∊'⎕:':⍺{              ⍝ System Name/Keyword
                size←⍵ all hd,alph
                ⍺ acc size ⍵
            }⍵

            hd='''':⍺{              ⍝ Char literal
                size←+/^\{⍵∨¯1⌽⍵}≠\hd=⍵
                ⍺ acc size ⍵
            }⍵

            hd∊⎕D,'¯':⍺{            ⍝ Numeric literal
                size←⍵ all ⎕D,'.¯E'
                ⍺ acc size ⍵
            }⍵

            hd='⍝':⍺ acc(⍴⍵)⍵       ⍝ Comment
            ⍺ acc 1 ⍵               ⍝ Single char token.
        }
        (0⍴⊂'')lex,⍵
    }
      display tokens'xtok←size↑srce ⍝ Next token'
.→-------------------------------------------------.
| .→---. .→. .→---. .→. .→---. .→-. .→-----------. |
| |xtok| |←| |size| |↑| |srce| |  | |⍝ Next token| |
| '----' '-' '----' '-' '----' '--' '------------' |
'∊-------------------------------------------------'


Tail Calls

A novel feature of the implementation of dfns is the way in which tail calls are optimised.

When a dfn calls a sub-function, the result of the call may or may not be modified by the calling function before being returned. A call where the result is passed back immediately without modification is termed a tail call.

For example in the following, the first call on function fact is a tail call because the result of fact is the result of the whole expression, whereas the second call isn't because the result is subsequently multiplied by ⍵.

      (⍺×⍵)fact ⍵-1       ⍝ Tail call on fact.
      ⍵×fact ⍵-1          ⍝ Embedded call on fact.

Tail calls occur frequently in dfns, and the interpreter optimises them by re-using the current stack frame instead of creating a new one. This gives a significant saving in both time and workspace usage. It is easy to check whether a call is a tail call by tracing it. An embedded call will pop up a new trace window for the called function, whereas a tail call will re-use the current one.

Using tail calls can improve code performance considerably, although at first the technique might appear obscure. A simple way to think of a tail call is as a branch with arguments. The tail call, in effect, branches to the first line of the function after installing new values for ⍵ and ⍺.

Iterative algorithms can almost always be coded using tail calls.

In general, when coding a loop, we use the following steps; possibly in a different order depending on whether we want to test at the "top" or the "bottom" of the loop.

  1. Initialise loop control variable(s). ⍝ init
  2. Test loop control variable. ⍝ test
  3. Process body of loop. ⍝ proc
  4. Modify loop control variable for next iteration. ⍝ mod
  5. Branch to step 2. ⍝ jump

For example, in classical APL you might find the following:

        ∇ value←limit loop value  ⍝ init
    [1]  top:→(⎕CT>value-limit)/0 ⍝ test
    [2]   value←Next value        ⍝ proc, mod
    [3]   →top⍝ jump
        ∇

Control structures help us to package these steps:

        ∇ value←limit loop value ⍝ init
    [1]   :While ⎕CT<value-limit ⍝ test
    [2]       value←Next value   ⍝ proc, mod
    [3]   :EndWhile              ⍝ jump
        ∇

Using tail calls:

    loop←{⍝ init
        ⎕CT>⍺-⍵:⍵    ⍝ test
        ⍺ ∇ Next ⍵   ⍝ proc, mod, jump
    }


Restrictions

  • Multi-line dfns can't be typed directly into the session. The interpreter attempts to evaluate the first line with its trailing left brace and a SYNTAX ERROR results.
  • Dfns need not return a result. However even a non-result-returning expression will terminate the function, so you can't, for example, call a non-result-returning function from the middle of a dfn.
  • You can trace a dfn only if it is defined on more than one line. Otherwise it is executed atomically in the same way as an execute (⍎) expression. This deliberate restriction is intended to avoid the confusion caused by tracing a line and seeing nothing change on the screen.
  • dfns do not currently support ⎕CS which, if used, generates a NONCE ERROR.
  • ⎕SHADOW ignores dfns when looking down the stack for a traditional function (tradfn) in which to make a new local name.
  • dfns do not support control structures or branch.
  • dfns do not support modified assignment such as X plus←10 where X is an array and plus is a function. In this example, both X and plus would be assigned the value 10.
  • ⎕MONITOR does not apply to dfns and dops.

Supplied Workspaces

You can find many samples of dfns and dops in utility workspace dfns.dws in the ws sub-directory.

Additional examples are in workspaces: min.dws, max.dws, tube.dws and eval.dws.


APL Line Editor

The APL Line Editor described herein is included for completeness and for adherence to the ISO APL standard. Dyalog recommends the use of the more powerful Editor and Tracer in preference to the APL Line Editor. Full details of these facilities can be found in the UI Guides for your version of Dyalog APL, as well as in the descriptions of ⎕ED and )ED which appear in the Dyalog APL Language Reference Guide.

Using the APL Line Editor, functions and operators are defined by entering Definition Mode. This mode is opened and closed by the Del symbol, ∇. Within this mode, all evaluation of input is deferred. The standard APL line editor (described below) is used to create and edit operations within definition mode.

Operations may also be defined using the system function ⎕FX (implicit in a ⎕ED fix) which acts upon the canonical (character), vector, nested or object representation form of an operation. (See Y is the representation form of a function or operator which may be: for details.)

Functions may also be created dynamically or by function assignment.

The line editor recognises three forms for the opening request.

Creating Defined Operation

The opening ∇ symbol is followed by the header line of a defined operation. Redundant blanks in the request are permitted except within names. If acceptable, the editor prompts for the first statement of the operation body with the line-number 1 enclosed in brackets. On successful completion of editing, the defined operation becomes the active definition in the workspace.

Example

      ∇R←FOO
[1]  R←10
[2]  ∇

      FOO
10

The given operation name must not have an active referent in the workspace, otherwise the system reports defn error and the system editor is not invoked:

      )VARS
SALES  X  Y

      ∇R←SALES Y
defn error

The header line of the operation must be syntactically correct, otherwise the system reports defn error and the system editor is not invoked:

      ∇R←A B C D:G
defn error

Listing Defined Operation

The ∇ symbol followed by the name of a defined operation and then by a closing ∇, causes the display of the named operation. Omitting the function name causes the suspended operation (i.e. the one at the top of the state indicator) to be displayed and opened for editing.

Example

      ∇FOO∇
     ∇ R←FOO
[1]    R←10
     ∇

      )SI
#.FOO[1] *

     ∇
     ∇ R←FOO
[1]    R←10
[2]

Editing Active Defined Operation

Definition mode is entered by typing ∇ followed optionally by a name and editing directive.

The ∇ symbol on its own causes the suspended operation (i.e. the one at the top of the state indicator) to be displayed. The editor then prompts for a statement or editing directive with a line-number one greater than the highest line-number in the function. If the state indicator is empty, the system reports defn error and definition mode is not entered.

The ∇ symbol followed by the name of an active defined operation causes the display of the named operation. The editor then prompts for input as described above. If the name given is not the name of an active referent in the workspace, the opening request is taken to be the creation of a new operation as described in paragraph 1. If the name refers to a pendent operation, the editor issues the message warning pendent operation prior to displaying the operation. If the name refers to a locked operation, the system reports defn error and definition mode is not entered.

The ∇ symbol followed by the name of an active defined operation and an editing directive causes the operation to be opened for editing and the editing directive actioned. If the editing directive is invalid, it is ignored by the editor which then prompts with a line-number one greater than the highest line-number in the operation. If the name refers to a pendent operation, the editor issues the message warning pendent operation prior to actioning the editing directive. If the name refers to a locked operation, the system reports defn error and definition mode is not entered.

On successful completion of editing, the defined operation becomes the active definition in the workspace which may replace an existing version of the function. Monitors, and stop and trace vectors are removed.

Example

      ∇FOO[2]
[2]  R←R*2
[3]  ∇

Editing Directives

Editing directives, summarised in Figure 2(iv) are permitted as the first non-blank characters either after the operation name on opening definition mode for an active defined function, or after a line-number prompt.

Syntax | Description
∇ | Closes definition mode
[⎕] | Displays the entire operation
[⎕n] | Displays the operation starting at line n
[n⎕] | Displays only line n
[∆n] | Deletes line n
[n∆m] | Deletes m lines starting at line n
[n] | Prompts for input at line n
[n]s | Replaces or inserts a statement at line n
[n⎕m] | Edits line n placing the cursor at character position m where an Edit Control Symbol performs a specific action.

Line Numbers

Line numbers are associated with lines in the operation. Initially, numbers are assigned as consecutive integers, beginning with [0] for the header line. The number associated with an operation line remains the same for the duration of the definition mode unless altered by editing directives. Additional lines may be inserted by decimal numbering. Up to three places of decimal are permitted. On closing definition mode, operation lines are re-numbered as consecutive integers.

The editor always prompts with a line number. The response may be a statement line or an editing directive. A statement line replaces the existing line (if there is one) or becomes an additional line in the operation:

      ∇R←A PLUS B
[1]  R←A+B
[2]

Position

The editing directive [n], where n is a line number, causes the editor to prompt for input at that line number. A statement or another editing directive may be entered. If a statement is entered, the next line number to be prompted is the previous number incremented by a unit of the display form of the last decimal digit. Trailing zeros are not displayed in the fractional part of a line number:

[2]   [0.8]
[0.8] ⍝ MONADIC OR DYADIC +
[0.9] ⍝ A ←→ OPTIONAL ARGUMENT
[1]

The editing directive [n]s, where n is a line number and s is a statement, causes the statement to replace the current contents of line n, or to insert line n if there is none:

[1] [0] R←{A} PLUS B
[1]

Delete

The editing directive [∆n], where n is a line number, causes the statement line to be deleted. The form [n∆m], where n is a line number and m is a positive integer, causes m consecutive statement lines starting from line number n to be deleted.

Edit

The editing directive [n⎕m], where n is a line number and m is an integer number, causes line number n to be displayed and the cursor placed beneath the m{th} character on a new line for editing. The response is taken to be edit control symbols selected from:

/ | to delete the character immediately above the symbol.
1 to 9 | to insert from 1 to 9 spaces immediately prior to the character above the digit.
A to Z | to insert multiples of 5 spaces immediately prior to the character above the letter, where A = 5, B = 10, C = 15 and so forth.
, | to insert the text after the comma, including explicitly entered trailing spaces, prior to the character above the comma, and then re-display the line for further editing with the text inserted and any preceding deletions or space insertions also effected.
. | to insert the text after the comma, including explicitly entered trailing spaces, prior to the character above the comma, and then complete the edit of the line with the text inserted and any preceding deletions or space insertions also effected.

Invalid edit symbols are ignored. If there are no valid edit symbols entered, or if there are only deletion or space insertion symbols, the statement line is re-displayed with characters deleted and spaces inserted as specified. The cursor is placed at the first inserted space position or at the end of the line if none. Characters may be added to the line which is then interpreted as seen.

The line number may be edited.

Examples

[1]   [1⎕7]
[1]   R←A+B
     ,→(0=⎕NC'A')⍴1←⎕LC ⋄
[1]   →(0=⎕NC'A')⍴1←⎕LC ⋄ R←A+B
                               .⋄→END
[2]   R←B
[3]   END:
[4]

The form [n⎕0] causes the line number n to be displayed and the cursor to be positioned at the end of the displayed line, omitting the edit phase.

Display

The editing directive [⎕] causes the entire operation to be displayed. The form [⎕n] causes all lines from line number n to be displayed. The form [n⎕] causes only line number n to be displayed:

[4]   [0⎕]
[0]   R←{A} PLUS B
[0]
[0]   [⎕]
[0]   R←{A} PLUS B
[0.1] ⍝ MONADIC OR DYADIC +
[1]   →(0=⎕NC'A')⍴1+⎕LC ⋄ R←A+B ⋄→END
[2]   R←B
[3]   'END:
[4]

Close Definition Mode

The editing directive ∇ causes definition mode to be closed. The new definition of the operation becomes the active version in the workspace. If the name in the operation header (which may or may not be the name used to enter definition mode) refers to a pendent operation, the editor issues the message warning pendent operation before exiting. The new definition becomes the active version, but the original one will continue to be referenced until the operation completes or is cleared from the state indicator.

If the name in the operation header is the name of a visible variable or label, the editor reports defn error and remains in definition mode. It is then necessary to edit the header line or quit.

If the header line is changed such that it is syntactically incorrect, the system reports defn error, and re-displays the line leaving the cursor beyond the end of the text on the line. Backspace/linefeed editing may be used to alter or cancel the change:

[3]   [0⎕]             - display line 0
[0]   R←{A} PLUS B
[0]   R←{A} PLUS B:G;H - put syntax error in line 0
defn error
[0]   R←{A} PLUS B:G;H - line redisplayed
                  ;G;H - backspace/linefeed editing
[1]

Local names may be repeated. However, the line editor reports warning messages as follows:

  1. If a name is repeated in the header line, the system reports "warning duplicate name" immediately.
  2. If a label has the same name as a name in the header line, the system reports "warning label name present in line 0" on closing definition mode.
  3. If a label has the same name as another label, the system reports "warning duplicate label" on closing definition mode.

Improper syntax in expressions within statement lines of the function is not detected by the system editor with the following exceptions:

  • If the number of opening parentheses in each entire expression does not equal the number of closing parentheses, the system reports "warning unmatched parentheses", but accepts the line.
  • If the number of opening brackets in each entire expression does not equal the number of closing brackets, the system reports "warning unmatched brackets", but accepts the line.

These errors are not detected if they occur in a comment or within quotes. Other syntactical errors in statement lines will remain undetected until the operation is executed.

Example

[4]   R←(A[;1)=2)⌿⍎EXP,'×2
warning unmatched parentheses
warning unmatched brackets
[5]

Note that there is an imbalance in the number of quotes. This will result in a SYNTAX ERROR when this operation is executed.

Quit Definition Mode

The user may quit definition mode by typing the INTERRUPT character. The active version of the operation (if any) remains unchanged.


Overview

Dyalog APL supports multithreading - the ability to run more than one APL expression at the same time.

This unique capability allows you to perform background processing, such as printing, database retrieval, database update, calculations, and so forth while at the same time perform other interactive tasks.

Multithreading may be used to improve throughput and system responsiveness.

A thread is a strand of execution in the APL workspace.

A thread is created by calling a function asynchronously, using the primitive operator ‘spawn’: & or by the asynchronous invocation of a callback function.

With a traditional APL synchronous function call, execution of the calling environment is paused, pendent on the return of the called function. With an asynchronous call, both calling environment and called function proceed to execute concurrently.

An asynchronous function call is said to start a new thread of execution. Each thread has a unique thread number, with which, for example, its presence can be monitored or its execution terminated.

Any thread can spawn any number of sub-threads, subject only to workspace availability. This implies a hierarchy in which a thread is said to be a child thread of its parent thread. The base thread at the root of this hierarchy has thread number 0.

With multithreading, APL’s stack or state indicator can be viewed as a branching tree in which the path from the base to each leaf is a thread.

At any point in time, only one thread is actually running; the others are paused. Each APL thread has its own state indicator, or SI stack. When APL switches from one thread to another, it saves the current stack (with all its local variables and function calls), restores the new one, and then continues processing.

When a parent thread terminates, any of its children which are still running, become the children of (are ‘adopted’ by) the parent’s parent.

Thread numbers are allocated sequentially from 0 to 2147483647. At this point, the sequence ‘wraps around’ and numbers are allocated from 0 again avoiding any still in use. The sequence is reinitialised when a )RESET command is issued, or the active workspace is cleared, or a new workspace is loaded. A workspace may not be saved with threads other than the base thread: 0, running.


Multi-Threading language elements.

The following language elements are provided to support threads.

  • Primitive operator, spawn: &.
  • System functions: ⎕TID, ⎕TCNUMS, ⎕TNUMS, ⎕TKILL, ⎕TSYNC.
  • An extension to the GUI Event syntax to allow asynchronous callbacks.
  • A control structure: :Hold.
  • System commands: )HOLDS, )TID.
  • Extended )SI and )SINL display.

Running CallBack Functions as Threads

A callback function is associated with a particular event via the Event property of the object concerned. A callback function is executed by ⎕DQ when the event occurs, or by ⎕NQ.

If you append the character & to the name of the callback function in the Event specification, the callback function will be executed asynchronously as a thread when the event occurs. If not, it is executed synchronously as before.

For example, the event specification:

      ⎕WS'Event' 'Select' 'DoIt&'

tells ⎕DQ to execute the callback function DoIt asynchronously as a thread when a Select event occurs on the object.


Thread Switching

Programming with threads requires care.

The interpreter may switch between running threads at the following points:

  • Between any two lines of a defined function or operator
  • On entry to a dfn or dop.
  • While waiting for a ⎕DL to complete.
  • While waiting for a ⎕FHOLD to complete.
  • While awaiting input from:
    • ⎕DQ
    • ⎕SR
    • ⎕ED
  • The session prompt or ⎕: or ⍞.
  • While awaiting the completion of an external operation:
    • A call on an external (AP) function.
    • A call on a ⎕NA (DLL) function
    • A call on an OLE function.
    • A call on a .NET function.

At any of these points, the interpreter might execute code in other threads. If such threads change the global environment; for example by changing the value of, or expunging a name; then the changes will appear to have happened while the thread in question passes through the switch point. It is the task of the application programmer to organise and contain such behaviour!

You can prevent threads from interacting in critical sections of code by using the :Hold control structure.

High Priority Callback Functions

Note that the interpreter cannot perform thread-switching during the execution of a high-priority callback. This is a callback function that is invoked by a high-priority event which demands that the interpreter must return a result to Windows before it may process any other event. Such high-priority events include Configure, ExitWindows, DateTimeChange, DockStart, DockCancel, DropDown. It is therefore not permitted to use a :Hold control structure in a high-priority callback function.


Name Scope

APL's name scope rules apply whether a function call is synchronous or asynchronous. For example when a defined function is called, names in the calling environment are visible, unless explicitly shadowed in the function header.

Just as with a synchronous call, a function called asynchronously has its own local environment, but can communicate with its parent and "sibling" functions via local names in the parent.

This point is important. It means that siblings can run in parallel without danger of local name clashes. For example, a GUI application can accommodate multiple concurrent instances of its callback functions.

However, with an asynchronous call, as the calling function continues to execute, both child and parent functions may modify values in the calling environment. Both functions see such changes immediately they occur.

If a parent function terminates while any of its children are still running, those children will no longer have access to its local names, and references to such names will either generate VALUE ERROR or be replaced by values from the environment that called the parent function. If a child function references variables defined by its parent or relies in any other way on its parent's environment (such as a local value of ⎕IO), the parent function should therefore execute a ⎕TSYNC in order to wait for its children to complete before itself exiting.

If, on the other hand, after launching an asynchronous child, the parent function calls a new function (either synchronously or asynchronously); names in the new function are beyond the purview of the original child. In other words, a function can only ever see its calling stack decrease in size – never increase. This is in order that the parent may call new defined functions without affecting the environment of its asynchronous children.


Stack Considerations

When you start a thread, it begins with the SI stack of the calling function and sees all of the local variables defined in all the functions down the stack. However, unless the calling function specifically waits for the new thread to terminate (see Wait for Threads to Terminate ), the calling functions will (bit by bit, in their turn) continue to execute. The new thread's view of its calling environment may then change. Consider the following example:

Suppose that you had the following functions: RUN[3] calls INIT which in turn calls GETDATA but as 3 separate threads with 3 different arguments:

     ∇ RUN;A;B
[1]    A←1
[2]    B←'Hello World'
[3]    INIT
[4]    CALC
[5]    REPORT
     ∇
     ∇ INIT;C;D
[1]    C←D←0
[2]    GETDATA&'Sales'
[3]    GETDATA&'Costs'
[4]    GETDATA&'Expenses'
     ∇

When each GETDATA thread starts, it immediately sees (via ⎕SI) that it was called by INIT which was in turn called by RUN, and it sees local variables A, B, C and D. However, once INIT[4] has been executed, INIT terminates, and execution of the root thread continues by calling CALC. From then on, each GETDATA thread no longer sees INIT (it thinks that it was called directly from RUN) nor can it see the local variables C and D that INIT had defined. However, it does continue to see the locals A and B defined by RUN, until RUN itself terminates.

Note that if CALC were also to define locals A and B, the GETDATA threads would still see the values defined by RUN and not those defined by CALC. However, if CALC were to modify A and B (as globals) without localising them, the GETDATA threads would see the modified values of these variables, whatever they happened to be at the time.


Globals and the Order of Execution

It is important to recognise that any reference or assignment to a global or semi-global object (including GUI objects) is inherently dangerous (i.e. a source of programming error) if more than one thread is running. Worse still, programming errors of this sort may not become apparent during testing because they are dependent upon random timing differences. Consider the following example:

     ∇ BUG;SEMI_GLOBAL
[1]    SEMI_GLOBAL←0
[2]    FOO& 1
[3]    GOO& 1
     ∇

     ∇ FOO
[1]    :If SEMI_GLOBAL=0
[2]        DO_SOMETHING SEMI_GLOBAL
[3]    :Else
[4]        DO_SOMETHING_ELSE SEMI_GLOBAL
[5]    :EndIf
     ∇

     ∇ GOO
[1]    SEMI_GLOBAL←1
     ∇

In this example, it is formally impossible to predict in which order APL will execute statements in BUG, FOO or GOO from BUG[2] onwards. For example, the actual sequence of execution may be:

      BUG[1] → BUG[2] → FOO[1] → FOO[2] →
               DO_SOMETHING[1]

or

      BUG[1] → BUG[2] → BUG[3] → GOO[1] →
               FOO[1] → FOO[2] → FOO[3] →
               FOO[4] → DO_SOMETHING_ELSE[1]

This is because APL may switch from one thread to another between any two lines in a defined function. In practice, because APL gives each thread a significant time-slice, it is likely to execute many lines, maybe even hundreds of lines, in one thread before switching to another. However, you must not rely on this; thread-switching may occur at any time between lines in a defined function.

Secondly, consider the possibility that APL switches from the FOO thread to the GOO thread after FOO[1]. If this happens, the value of SEMI_GLOBAL passed to DO_SOMETHING will be 1 and not 0. Here is another source of error.

In fact, in this case, there are two ways to resolve the problem. To ensure that the value of SEMI_GLOBAL remains the same from FOO[1] to FOO[2], you may use diamonds instead of separate statements, e.g.

      :If SEMI_GLOBAL=0 ⋄ DO_SOMETHING SEMI_GLOBAL

Even better, although less efficient, you may use :Hold to synchronise access to the variable, for example:

      ∇ FOO
[1]    :Hold 'SEMI_GLOBAL'
[2]        :If SEMI_GLOBAL=0
[3]            DO_SOMETHING SEMI_GLOBAL
[4]        :Else
[5]            DO_SOMETHING_ELSE SEMI_GLOBAL
[6]        :EndIf
[7]    :EndHold
     ∇

     ∇ GOO
[1]    :Hold 'SEMI_GLOBAL'
[2]        SEMI_GLOBAL←1
[3]    :EndHold
     ∇

Now, although you still cannot be sure which of FOO and GOO will run first, you can be sure that SEMI_GLOBAL will not change (because GOO cuts in) within FOO.

Note that the string used as the argument to :Hold is completely arbitrary, so long as threads competing for the same resource use the same string.

A Caution

These types of problems are inherent in all multithreading programming languages, and not just with Dyalog APL. If you want to take advantage of the additional power provided by multithreading, it is advisable to think carefully about the potential interaction between different threads.


Threads & Niladic Functions

In common with other operators, the spawn operator & may accept monadic or dyadic functions as operands, but not niladic functions. This means that, using spawn, you cannot start a thread that consists only of a niladic function

If you wish to invoke a niladic function asynchronously, you have the following choices:

  • Turn your niladic function into a monadic function by giving it a dummy argument which it ignores.
  • Call your niladic function with a dfn to which you give an argument that is implicitly ignored. For example, if the function NIL is niladic, you can call it asynchronously using the expression: {NIL}& 0
  • Call your function via a dummy monadic function, e.g.
          ∇ NIL_M DUMMY
[1]      NIL
      ∇
      NIL_M& ''
  • Use execute, e.g.
          ⍎& 'NIL'

Note that niladic functions can be invoked asynchronously as callback functions. For example, the statement:

      ⎕WS'Event' 'Select' 'NIL&'

will execute correctly as a thread, even though NIL is niladic. This is because callback functions are invoked directly by ⎕DQ rather than as an operand to the spawn operator.


Threads & External Functions

External functions in dynamic link libraries (DLLs) defined using the ⎕NA interface may be run in separate C threads. Such threads:

  • take advantage of multiple processors if the operating system permits.
  • allow APL to continue processing in parallel during the execution of a ⎕NA function.

When you define an external function using ⎕NA, you may specify that the function be run in a separate C thread by appending an ampersand (&) to the function name, for example:

      'beep'⎕NA'user32|MessageBeep& i'
      ⍝ MessageBeep will run in a separate C thread

When APL first comes to execute a multi-threaded ⎕NA function, it starts a new C-thread, executes the function within it, and waits for the result. Other APL threads may then run in parallel.

Note that when the ⎕NA call finishes and returns its result, its new C-thread is retained to be re-used by any subsequent multithreaded ⎕NA calls made within the same APL thread. Thus any APL thread that makes any multi-threaded ⎕NA calls maintains a separate C-thread for their execution. This C-thread is discarded when its APL thread finishes.

Note that there is no point in specifying a ⎕NA call to be multi-threaded, unless you wish to execute other APL threads at the same time.

In addition, if your ⎕NA call needs to access an APL GUI object (strictly, a window or other handle) it should normally run within the same C-thread as APL itself, and not in a separate C-thread. This is because Windows associates objects with the C-thread that created them. Although you can use a multi-threaded ⎕NA call to access (say) a Dyalog APL Form via its window handle, the effects may be different than if the ⎕NA call was not multi-threaded. In general, ⎕NA calls that access APL (GUI) objects should not be multi-threaded.

If you wish to run the same ⎕NA call in separate APL threads at the same time, you must ensure that the DLL is thread-safe. Functions in DLLs which are not thread-safe, must be prevented from running concurrently by using the :Hold control structure. Note that all the standard Windows API DLLs are thread safe.

Notice that you may define two separate functions (with different names), one single-threaded and one multi-threaded, associated with the same function in the DLL. This allows you to call it in either way.


Synchronising Threads

Threads may be synchronised using tokens and a token pool.

An application can synchronise its threads by having one thread add tokens into the pool whilst other threads wait for tokens to become available and retrieve them from the pool.

Tokens possess two separate attributes, a type and a value.

The type of a token is a positive or negative integer scalar. The value of a token is any arbitrary array that you might wish to associate with it.

The token pool may contain up to 2*31 tokens; they do not have to be unique neither in terms of their types nor of their values.

The following system functions are used to manage the token pool:

⎕TPUT | Puts tokens into the pool.
⎕TGET | If necessary waits for, and then retrieves some tokens from the pool.
⎕TPOOL | Reports the types of tokens in the pool
⎕TREQ | Reports the token requests from specific threads

A simple example of a thread synchronisation requirement occurs when you want one thread to reach a certain point in processing before a second thread can continue. Perhaps the first thread performs a calculation, and the second thread must wait until the result is available before it can be used.

This can be achieved by having the first thread put a specific type of token into the pool using ⎕TPUT. The second thread waits (if necessary) for the new value to be available by calling ⎕TGET with the same token type.

Notice that when ⎕TGET returns, the specified tokens are removed from the pool. However, negative token types will satisfy an infinite number of requests for their positive equivalents.

The system is designed to cater for more complex forms of synchronisation. For example, a semaphore to control a number of resources can be implemented by keeping that number of tokens in the pool. Each thread will take a token while processing, and return it to the pool when it has finished.

A second complex example is that of a latch which holds back a number of threads until the coast is clear. At a signal from another thread, the latch is opened so that all of the threads are released. The latch may (or may not) then be closed again to hold up subsequently arriving threads. A practical example of a latch is a ferry terminal.


Semaphore Example

A semaphore to control a number of resources can be implemented by keeping that number of tokens in the pool. Each thread will take a token while processing, and return it to the pool when it has finished.

For example, if we want to restrict the number of threads that can have sockets open at any one time.

    sock←99                  ⍝ socket-token
                               any +ive number will do).
    ⎕TPUT 5/sock             ⍝ add 5 socket-tokens to pool.

    ∇ sock_open ...
[1]   :If sock=⎕TGET sock    ⍝ grab a socket token
[.]       ...                ⍝ do stuff.
[.]       ⎕TPUT sock         ⍝ release socket token
[.]   :Else
[.]       error'sockets off' ⍝ sockets switched off by
                               retract (see below).
[.]   :EndIf
    ∇

    0 ⎕TPUT ⎕treq ⎕tnums     ⍝ retract socket "service"
                               with 0 value.


Latch Example

A latch holds back a number of threads until the coast is clear. At a signal from another thread, the latch is opened so that all of the threads are released. The latch may (or may not) then be closed again to hold up subsequently arriving threads.

A visual example of a latch might be a ferry terminal, where cars accumulate in the queue until the ferry arrives. The barrier is then opened and all (up to a maximum number) of the cars are allowed through it and on to the ferry. When the last car is through, the barrier is re-closed.

    tkt←6                         ⍝ 6-token: ferry ticket.

    ∇ car ...
[1]   ⎕TGET tkt                   ⍝ await ferry.
[2]   ...

    ∇ ferry ...
[1]   arrives in port
[2]   ⎕TPUT(↑,/⎕treq ⎕tnums)∩tkt  ⍝ ferry tickets for all.
[3]   ...

Note that it is easy to modify this example to provide a maximum number of ferry places per trip by inserting max_places↑ between ⎕TPUT and its argument. If fewer cars than the ferry capacity are waiting, the ↑ will fill with trailing 0s. This will not cause problems because zero tokens are ignored.

Let us replace the car ferry with a new road bridge. Once the bridge is ready for traffic, the barrier could be opened permanently by putting a negative ticket in the pool.

    ⎕TPUT -tkt      ⍝ open ferry barrier permanently.

Cars could choose to take the last ferry if there are places:

    ∇ car ...
[1]   :Select ⎕TGET tkt
[2]   :Case  tkt ⋄ take the last ferry.
[3]   :Case -tkt ⋄ ferry full: take the new bridge.
[4]   :End

The above :Select works because by default, ⎕TPUT -tkt puts a value of -tkt into the token.


Debugging Threads

If a thread sustains an untrapped error, its execution is suspended in the normal way. If the Pause on Error option is set, all other threads are paused. If Pause on Error option is not set, other threads will continue running and it is possible for another thread to encounter an error and suspend (see the Dyalog for Microsoft Windows Installation and Configuration Guide).

Using the facilities provided by the Tracer and the Threads Tool (see the Dyalog for Microsoft Windows UI Guide) it is possible to interrupt (suspend) and restart individual threads, and to pause and resume individual threads, so any thread may be in one of three states - running, suspended or paused.

The Tracer and the Session may be connected with any suspended thread and you can switch the attention of the Session and the Tracer between suspended threads using )TID or by clicking on the appropriate tab in the Tracer. At this point, you may:

  • Examine and modify local variables for the currently suspended thread.
  • Trace and edit functions in the current thread.
  • Cut back the stack in the currently suspended thread.
  • Restart execution.
  • Start new threads

The error message from a thread other than the base is prefixed with its thread number:

260:DOMAIN ERROR
Div[2] rslt←num÷div
      ^

State indicator displays: )SI and )SINL have been extended to show threads' tree-like calling structure.

      )SI
·   #.Calc[1]
&5
·   ·   #.DivSub[1]
·   &7
·   ·   #.DivSub[1]
·   &6
·   #.Div[2]*
&4
#.Sub[3]
#.Main[4]

Here, Main has called Sub, which has spawned threads 4 and 5 with functions: Div and Calc. Function Div, after spawning DivSub in each of threads 6 and 7, have been suspended at line [2].

Removing stack frames using Quit from the Tracer or → from the session affects only the current thread. When the final stack frame in a thread (other than the base thread) is removed, the thread is expunged.

)RESET removes all but the base thread.

Note the distinction between a suspended thread and a paused thread.

A suspended thread is stopped at the beginning of a line in a defined function or operator. It may be connected to the Session so that expressions executed in the Session do so in the context of that thread. It may be restarted by executing →line (typically, →⎕LC).

A paused thread is an inactive thread that is currently being ignored by the thread scheduler. A paused thread may be paused within a call to ⎕DQ, a call on an external function, at the beginning of a line, or indeed at any of the thread-switching points described earlier in this chapter.

A paused thread may be resumed only by the action of a menu item or button. A paused thread resumes only in the sense that it ceases to be ignored by the thread scheduler and will therefore be switched back to at some point in the future. It does not actually continue executing until the switch occurs.


Introducing Classes

A Class is a blueprint from which one or more Instances of the Class can be created (instances are sometimes also referred to as Objects).

A Class may optionally derive from another Class, which is referred to as its Base Class.

A Class may contain Methods, Properties and Fields (commonly referred to together as Members) which are defined within the body of the class script or are inherited from other Classes. This version of Dyalog APL does not support Events although it is intended that these will be supported in a future release. However, Classes that are derived from .NET types may generate events using 4 ⎕NQ.

A Class that is defined to derive from another Class automatically acquires the set of Properties, Methods and Fields that are defined by its Base Class. This mechanism is described as inheritance.

A Class may extend the functionality of its Base Class by adding new Properties, Methods and Fields or by substituting those in the Base Class by providing new versions with the same names as those in the Base Class.

Members may be defined to be Private or Public. A Public member may be used or accessed from outside the Class or an Instance of the Class. A Private member is internal to the Class and (in general) may not be referenced from outside.

Although Classes are generally used as blueprints for the creation of instances, a class can have Shared members which can be used without first creating an instance.

Class Names

Class names must adhere to the general rules for naming APL objects, and in addition should not conflict with the name of a .NET Type that is defined in any of the .NET Namespaces on the search path specified by ⎕USING.


Defining Classes

A Class is defined by a script that may be entered and changed using the editor. A class script may also be constructed from a vector of character vectors, and fixed using ⎕FIX.

A class script begins with a :Class statement and ends with a :EndClass statement.

For example, using the editor:

      )CLEAR
clear ws
      )ED ○Animal

[an edit window opens containing the following skeleton Class script ...]

:Class Animal
:EndClass

[the user edits and fixes the Class script]

      )CLASSES
Animal
      ⎕NC⊂'Animal'
9.4


Editing Classes

Between the :Class and :EndClass statements, you may insert any number of function bodies, Property definitions, and other elements. When you fix the Class Script from the editor, these items will be fixed inside the Class namespace.

Note that the contents of the Class Script defines the Class in its entirety. You may not add or alter functions by editing them independently and you may not add variables by assignment or remove objects with ⎕EX.

When you re-fix a Class Script using the Editor or with ⎕FIX, the original Class is discarded and the new definition, as specified by the Script, replaces the old one in its entirety.

Note:

Associated with a Class (or an instance of a class) there is a completely separate namespace which surrounds the class and can contain functions, variables and so forth that are created by actions external to the class.

For example, if X is not a public member of the class MyClass, then the following expression will insert a variable X into the namespace which surrounds the class:

      MyClass.X←99

The namespace is analogous to the namespace associated with a GUI object and will be re-initialised (emptied) whenever the Class is re-fixed. Objects in this parallel namespace are not visible from inside the Class or an Instance of the Class.

For further information, see Changing Scripted Objects Dynamically.


Inheritance

If you want a Class to derive from another Class, you simply add the name of that Class to the :Class statement using colon+space as a separator.

The following example specifies that CLASS2 derives from CLASS1.

:Class CLASS2: CLASS1
:EndClass

Note that CLASS1 is referred to as the Base Class of CLASS2.

If a Class has a Base Class, it automatically acquires all of the Public Properties, Methods and Fields defined for its Base Class unless it replaces them with its own members of the same name. This principle of inheritance applies throughout the Class hierarchy. Note that Private members are not subject to inheritance.

Warning: When a class is fixed, it keeps a reference (a pointer) to its base class. If the global name of the base class is expunged, the derived class will still have the base class reference, and the base class will therefore be kept alive in the workspace. The derived class will be fully functional, but attempts to edit it will fail when it attempts to locate the base class as the new definition is fixed.

At this point, if a new class with the original base class name is created, the derived class has no way of detecting this, and it will continue to use the old and invisible version of the base class. Only when the derived class is re-fixed, will the new base class be detected.

If you edit, re-fix or copy an existing base class, APL will take care to patch up the references, but if the base class is expunged first and recreated later, APL is unable to detect the substitution. You can recover from this situation by editing or re-fixing the derived class(es) after the base class has been substituted.

Copying Classes

See Dependant Objects and Referenced Objects.

Classes that derive from .NET Types

You may define a Class that derives from any of the .NET Types by specifying the name of the .NET Type and including a :USING statement that provides a path to the .NET Assembly in which the .NET Type is located.

Example

:Class APLGreg: GregorianCalendar
:Using System.Globalization
...
:EndClass

Classes that derive from the Dyalog GUI

You may define a Class that derives from any of the Dyalog APL GUI objects by specifying the name of the Dyalog APL GUI Class in quotes.

For example, to define a Class named Duck that derives from a Poly object, the Class specification would be:

:Class Duck:'Poly'
:EndClass

The Base Constructor for such a Class is the ⎕WC system function.

For further details see Dyalog GUI Classes.


Instances

A Class is generally used as a blueprint or model from which one or more Instances of the Class are constructed. Note however that a class can have Shared members which can be used directly without first creating an instance.

You create an instance of a Class using the ⎕NEW system function which is monadic.

The 1-or 2-item argument to ⎕NEW contains a reference to the Class and, optionally, arguments for its Constructor function.

When ⎕NEW executes, it creates a regular APL namespace to contain the Instance, and within that it creates an Instance space, which is populated with any Instance Fields defined by the class (with default values if specified), and pointers to the Instance Method and Property definitions specified by the Class.

If a monadic Constructor is defined, it is called with the arguments specified in the second item of the argument to ⎕NEW. If ⎕NEW was called without Constructor arguments, and the class has a niladic Constructor, this is called instead.

The Constructor function is typically used to initialise the instance and may establish variables in the instance namespace.

The result of ⎕NEW is a reference to the instance namespace. Instances of Classes exhibit the same set of Properties, Methods and Fields that are defined for the Class.


Constructors

A Constructor is a special function defined in the Class script that is to be run when an Instance of the Class is created by ⎕NEW. Typically, the job of a Constructor is to initialise the new Instance in some way.

A Constructor is identified by a :Implements Constructor statement. This statement may appear anywhere in the body of the function after the function header. The significance of this is discussed below.

Note that it is also essential to define the Constructor to be Public, with a :Access Public statement, because like all Class members, Constructors default to being Private. Private Constructors currently have no use or purpose, but it is intended that they will be supported in a future release of Dyalog APL.

A Constructor function may be niladic or monadic and must not return a result.

A Class may specify any number of different Constructors of which one (and only one) may be niladic. This is also referred to as the default Constructor.

There may be any number of monadic Constructors, but each must have a differently defined argument list which specifies the number of items expected in the Constructor argument. See Constructor Overloading for details.

The only way a Constructor function should be invoked is by ⎕NEW. See Base Constructors for further details. If you attempt to call a Constructor function from outside its Class, it will cause a SYNTAX ERROR. A Constructor function should not call another Constructor function within the same Class, although it will not generate an error. This would cause the Base Constructor to be called twice, with unpredictable consequences.

When ⎕NEW is executed with a 2-item argument, the appropriate monadic Constructor is called with the second item of the ⎕NEW argument.

The niladic (default) Constructor is called when ⎕NEW is executed with a 1-item argument, a Class reference alone, or whenever APL needs to create a fill item for the Class.

Note that ⎕NEW first creates a new instance of the specified Class, and then executes the Constructor inside the instance.

Example

The DomesticParrot Class defines a Constructor function egg that initialises the Instance by storing its name (supplied as the 2nd item of the argument to ⎕NEW) in a Public Field called Name.

:Class DomesticParrot: Parrot
    :Field Public Name

    ∇ egg name
      :Implements Constructor
      :Access Public
      Name←name
    ∇
    ...
:EndClass ⍝ DomesticParrot

      pol←⎕NEW DomesticParrot 'Polly'
      pol.Name
Polly


Constructor Overloading

NameList header syntax is used to define different versions of a Constructor each with a different number of parameters, referred to as its signature. See Namelists for details. The Clover Class illustrates this principle.

In deciding which Constructor to call, APL matches the shape of the Constructor argument with the signature of each of the Constructors that are defined. If a constructor with the same number of arguments exists (remembering that 0 arguments will match a niladic Constructor), it is called. If there is no exact match, and there is a Constructor with a general signature (an un-parenthesised right argument), it is called. If no suitable constructor is found, a LENGTH ERROR is reported.

There may be one and only one constructor with a particular signature.

The only way a Constructor function should be invoked is by ⎕NEW. See Base Constructors for further details. If you attempt to call a Constructor function from outside its Class, it will cause a SYNTAX ERROR. A Constructor function should not call another Constructor function within the same Class, although it will not generate an error. This would cause the Base Constructor to be called twice, with unpredictable consequences.

In the Clover Class example Class, the following Constructors are defined:

Constructor | Implied argument
Make1 | 1-item vector
Make2 | 2-item vector
Make3 | 3-item vector
Make0 | No argument
MakeAny | Any array accepted

In the following examples, the Make function (see Clover Class for details) displays:

<shape of argument> <name of Constructor called><argument>
(see function make)

Creating a new Instance of Clover with a 1-element vector as the Constructor argument, causes the system to choose the Make1 Constructor. Note that, although the argument to Make1 is a 1-element vector, this is disclosed as the list of arguments is unpacked into the (single) variable arg1.

      (⎕NEW Clover(,1)).Con
   Make1  1

Creating a new Instance of Clover with a 2- or 3-element vector as the Constructor argument causes the system to choose Make2, or Make3 respectively.

      (⎕NEW Clover(1 2)).Con
 2  Make2  1 2
      (⎕NEW Clover(1 2 3)).Con
 3  Make3  1 2 3

Creating an Instance with any other Constructor argument causes the system to choose MakeAny.

      (⎕NEW Clover(⍳10)).Con
 10  MakeAny  1 2 3 4 5 6 7 8 9 10
      (⎕NEW Clover(2 2⍴⍳4)).Con
 2 2  MakeAny  1 2
               3 4

Note that a scalar argument will call MakeAny and not Make1.

      (⎕NEW Clover 1).Con
   MakeAny  1

and finally, creating an Instance without a Constructor argument causes the system to choose Make0.

      (⎕NEW Clover).Con
   Make0  0


Niladic (Default) Constructors

A Class may define a niladic Constructor and/or one or more Monadic Constructors. The niladic Constructor acts as the default Constructor that is used when ⎕NEW is invoked without arguments and when APL needs a fill item.

:Class Bird
    :Field Public Species

    ∇ egg spec
      :Access Public Instance
      :Implements Constructor
      Species←spec
    ∇
    ∇ default
      :Access Public Instance
      :Implements Constructor
      Species←'Default Bird'
    ∇
    ∇ R←Speak
      :Access Public
      R←'Tweet, tweet!'
    ∇

:EndClass ⍝ Bird

The niladic Constructor (in this example, the function default) is invoked when ⎕NEW is called without Constructor arguments. In this case, the Instance created is no different to one created by the monadic Constructor egg, except that the value of the Species Field is set to 'Default Bird'.

      Birdy←⎕NEW Bird
      Birdy.Species
Default Bird

The niladic Constructor is also used when APL needs to make a fill item of the Class. For example, in the expression (3↑Birdy), APL has to create two fill items of Birdy (one for each of the elements required to pad the array to length 3) and will in fact call the niladic Constructor twice.

In the following statement:

      TweetyPie←3⊃10↑Birdy

The 10↑ (temporarily) creates a 10-element array comprising the single entity Birdy padded with 9 fill-elements of Class Bird. To obtain the 9 fill-elements, APL calls the niladic Constructor 9 times, one for each separate prototypical Instance that it is required to make.

      TweetyPie.Species
Default Bird


Empty Arrays of Instances: Why ?

In APL it is natural to use arrays of Instances. For example, consider the following example.

:Class Cheese
    :Field Public Name←''
    :Field Public Strength←⍬
    ∇ make2(name strength)
      :Access Public
      :Implements Constructor
      Name Strength←name strength
    ∇
    ∇ make1 name
      :Access Public
      :Implements Constructor
      Name Strength←name 1
    ∇
    ∇ make_excuse
      :Access Public
      :Implements Constructor
      ⎕←'The cat ate the last one!'
    ∇
:EndClass

We might create an array of Instances of the Cheese Class as follows:

      cdata←('Camembert' 5)('Caephilly' 2) 'Mild Cheddar'
      cheeses←{⎕NEW Cheese ⍵}¨cdata

Suppose we want a range of medium-strength cheese for our cheese board.

      board←(cheeses.Strength<3)/cheeses
      board.Name
 Caephilly  Mild Cheddar

But look what happens when we try to select really strong cheese:

      board←(cheeses.Strength>5)/cheeses
      board.Name
The cat ate the last one!

Note that this message is not the result of the expression, but was explicitly displayed by the make_excuse function. The clue to this behaviour is the shape of board; it is empty!

      ⍴board
0

When a reference is made to an empty array of Instances (strictly speaking, a reference that requires a prototype), APL creates a new Instance by calling the niladic (default) Constructor, uses the new Instance to satisfy the reference, and then discards it. Hence, in this example, the reference:

      board.Name

caused APL to run the niladic Constructor make_excuse, which displayed:

The cat ate the last one!

Notice that the behaviour of empty arrays of Instances is modelled VERY closely after the behaviour of empty arrays in general. In particular, the Class designer is given the task of deciding what the types of the members of the prototype are.

The full explanation is given in the next topic.


Empty Arrays of Instances: How?

To cater for the need to handle empty arrays of Instances as easily as non-empty arrays, a reference to an empty array of Class Instances is handled in a special way.

Whenever a reference or an assignment is made to the content of an empty array of Instances, the following steps are performed:

  1. APL creates a new Instance of the same Class of which the empty Instance belongs
  2. the default (niladic) Constructor is run in the new Instance
  3. the appropriate value is obtained or assigned:
    • if it is a reference is to a Field, the value of the Field is obtained
    • if it is a reference is to a Property, the PropertyGet function is run
    • if it is a reference is to a Method, the method is executed
    • if it is an assignment, the assignment is performed or the PropertySet function is run
  4. if it is a reference, the result of step 3 is used to generate an empty result array with a suitable prototype by the application of the function {0⍴⊂⍵} to it
  5. the Class Destructor (if any) is run in the new Instance
  6. the New Instance is deleted

Example

:Class Bird
    :Field Public Species

    ∇ egg spec
      :Access Public Instance
      :Implements Constructor
      ⎕DF Species←spec
    ∇
    ∇ default
      :Access Public Instance
      :Implements Constructor
      ⎕DF Species←'Default Bird'
      #.DISPLAY Species
    ∇
    ∇ R←Speak
      :Access Public
      #.DISPLAY R←'Tweet, Tweet, Tweet'
    ∇

:EndClass ⍝ Bird

First, we can create an empty array of Instances of Bird using 0⍴.

      Empty←0⍴⎕NEW Bird 'Robin'

A reference to Empty.Species causes APL to create a new Instance and invoke the niladic Constructor default. This function sets Species to 'Default Bird'and calls #.DISPLAY which displays output to the Session.

      DISPLAY Empty.Species
.→-----------.
|Default Bird|
'------------'

APL then retrieves the value of Species ('Default Bird'), applies the function {0⍴⊂⍵} to it and returns this as the result of the expression.

.⊖---------------.
| .→-----------. |
| |            | |
| '------------' |
'∊---------------'

A reference to Empty.Speak causes APL to create a new Instance and invoke the niladic Constructor default. This function sets Species to 'Default Bird'and calls #.DISPLAY which displays output to the Session.

      DISPLAY Empty.Speak
.→-----------.
|Default Bird|
'------------'

APL then invokes function Speak which displays 'Tweet, Tweet, Tweet' and returns this as the result of the function.

.→------------------.
|Tweet, Tweet, Tweet|
'-------------------'

APL then applies the function {0⍴⊂⍵} to it and returns this as the result of the expression.

.⊖----------------------.
| .→------------------. |
| |                   | |
| '-------------------' |
'∊----------------------'


Base Constructors

Constructors in a Class hierarchy are not inherited in the same way as other members. However, there is a mechanism for all the Classes in the Class inheritance tree to participate in the initialisation of an Instance.

Every Constructor function contains a :Implements Constructor statement which may appear anywhere in the function body. The statement may optionally be followed by the :Base control word and an arbitrary expression.

The statement:

      :Implements Constructor :Base expr

calls a monadic Constructor in the Base Class. The choice of Constructor depends upon the rank and shape of the result of expr (see Constructor Overloading for details).

Whereas, the statement:

      :Implements Constructor

or

      :Implements Constructor :Base

calls the niladic Constructor in the Base Class.

Note that during the instantiation of an Instance, these calls potentially take place in every Class in the Class hierarchy.

If, anywhere down the hierarchy, there is a monadic call and there is no matching monadic Constructor, the operation fails with a LENGTH ERROR.

If there is a niladic call on a Class that defines no Constructors, the niladic call is simply repeated in the next Class along the hierarchy.

However, if a Class defines a monadic Constructor and no niladic Constructor it implies that that Class cannot be instantiated without Constructor arguments. Therefore, if there is a call to a niladic Constructor in such a Class, the operation fails with a LENGTH ERROR. Note that it is therefore impossible for APL to instantiate a fill item or process a reference to an empty array for such a Class or any Class that is based upon it.

A Constructor function may not call another Constructor function and a constructor function may not be called directly from outside the Class or Instance. The only way a Constructor function may be invoked is by ⎕NEW. The fundamental reason for these restrictions is that there must be one and only one call on the Base Constructor when a new Instance is instantiated. If Constructor functions were allowed to call one another, there would be several calls on the Base Constructor. Similarly, if a Constructor could be called directly it would potentially duplicate the Base Constructor call.


Niladic Example

In the following example, DomesticParrot is derived from Parrot which is derived from Bird. They all share the Field Desc (inherited from Bird). Each of the 3 Classes has its own niladic Constructor called egg0.

:Class Bird
    :Field Public Desc
    ∇ egg0
      :Access Public
      :Implements Constructor
      Desc←'Bird'
    ∇
:EndClass ⍝ Bird

:Class Parrot: Bird
    ∇ egg0
      :Access Public
      :Implements Constructor
      Desc,←'→Parrot'
    ∇
:EndClass ⍝ Parrot

:Class DomesticParrot: Parrot
    ∇ egg0
      :Access Public
      :Implements Constructor
      Desc,←'→DomesticParrot'
    ∇
:EndClass ⍝ DomesticParrot

      (⎕NEW DomesticParrot).Desc
Bird→Parrot→DomesticParrot

Explanation

⎕NEW creates the new instance and runs the niladic Constructor DomesticParrot.egg0. As soon as the line:

:Implements Constructor

is encountered, ⎕NEW calls the niladic constructor in the Base Class Parrot.egg0

Parrot.egg0 starts to execute and as soon as the line:

:Implements Constructor

is encountered, ⎕NEW calls the niladic constructor in the Base Class Bird.egg0.

When the line:

:Implements Constructor

is encountered, ⎕NEW cannot call the niladic constructor in the Base Class (there is none) so the chain of Constructors ends. Then, as the state indicator unwinds ...

Bird.egg0 | executes | Desc←'Bird''
Parrot.egg0 | executes | Desc,←'→Parrot''
DomesticParrot.egg0 | execute | Desc,←'→DomesticParrot''


Monadic Example

In the following example, DomesticParrot is derived from Parrot which is derived from Bird. They all share the Field Species (inherited from Bird) but only a DomesticParrot has a Field Name. Each of the 3 Classes has its own Constructor called egg.

:Class Bird
    :Field Public Species
    ∇ egg spec
      :Access Public Instance
      :Implements Constructor
      Species←spec
    ∇
    ...
:EndClass ⍝ Bird

:Class Parrot: Bird
    ∇ egg species
      :Access Public Instance
      :Implements Constructor :Base 'Parrot: ',species
    ∇
    ...
:EndClass ⍝ Parrot

:Class DomesticParrot: Parrot
    :Field Public Name
    ∇ egg(name species)
      :Access Public Instance
      :Implements Constructor :Base species
      ⎕DF Name←name
    ∇
    ...
:EndClass ⍝ DomesticParrot

      pol←⎕NEW DomesticParrot('Polly' 'Scarlet Macaw')
      pol.Name
Polly
      pol.Species
Parrot: Scarlet Macaw

Explanation

⎕NEW creates the new instance and runs the Constructor DomesticParrot.egg. The egg header splits the argument into two items name and species. As soon as the line:

:Implements Constructor :Base species

is encountered, ⎕NEW calls the Base Class constructor Parrot.egg, passing it the result of the expression to the right, which in this case is simply the value in species.

Parrot.egg starts to execute and as soon as the line:

:Implements Constructor :Base 'Parrot: ',species

is encountered, ⎕NEW calls its Base Class constructor Bird.egg, passing it the result of the expression to the right, which in this case is the character vector 'Parrot: ' catenated with the value in species.

Bird.egg assigns its argument to the Public Field Species.

At this point, the state indicator would be:

       )SI
[#.[Instance of DomesticParrot]] #.Bird.egg[3]*
[constructor]
:base
[#.[Instance of DomesticParrot]] #.Parrot.egg[2]
[constructor]
:base
[#.[Instance of DomesticParrot]] #.DomesticParrot.egg[2]
[constructor]

Bird.egg then returns to Parrot.egg which returns to DomesticParrot.egg.

Finally, DomesticParrot.egg[3] is executed, which establishes Field Name and the Display Format (⎕DF) for the instance.


Destructors

A Destructor is a function that is called just before an Instance of a Class ceases to exist and is typically used to close files or release external resources associated with an Instance.

An Instance of a Class is destroyed when:

  • The Instance is expunged using ⎕EX or )ERASE.
  • A function, in which the Instance is localised, exits.

But be aware that a destructor will also be called if:

  • The Instance is re-assigned (see below)
  • The result of ⎕NEW is not assigned (the instance gets created then immediately destroyed).
  • APL creates (and then destroys) a new Instance as a result of a reference to a member of an empty Instance. The destructor is called after APL has obtained the appropriate value from the instance and no longer needs it.
  • The constructor function fails. Note that the Instance is actually created before the constructor is run (inside it), and if the constructor fails, the fledgling Instance is discarded. Note too that this means a destructor may need to deal with a partially constructed instance, so the code may need to check that resources were actually acquired, before releasing them.
  • On the execution of )CLEAR, )LOAD, ⎕LOAD, )OFF or ⎕OFF.

Warning: a Destructor may be executed on any thread.

Note that an Instance of a Class only disappears when the last reference to it disappears. For example, the sequence:

      I1←⎕NEW MyClass
      I2←I1
      )ERASE I1

will not cause the Instance of MyClass to disappear because it is still referenced by I2.

A Destructor is identified by the statement :Implements Destructor which must appear immediately after the function header in the Class script.

:Class Parrot
    ...
    ∇ kill
      :Implements Destructor
      'This Parrot is dead'
    ∇
    ...
:EndClass ⍝ Parrot
       pol←⎕NEW Parrot 'Scarlet Macaw'
      )ERASE pol
This Parrot is dead

Note that reassignment to pol causes the Instance referenced by pol to be destroyed and the Destructor invoked:

      pol←⎕NEW Parrot 'Scarlet Macaw'
      pol←⎕NEW Parrot 'Scarlet Macaw'
This Parrot is dead

If a Class inherits from another Class, the Destructor in its Base Class is automatically called after the Destructor in the Class itself.

So, if we have a Class structure: DomesticParrot => Parrot => Bird containing the following Destructors:

:Class DomesticParrot: Parrot
    ...
    ∇ kill
      :Implements Destructor
      'This ',(⍕⎕THIS),' is dead'
    ∇
     ...
:EndClass ⍝ DomesticParrot

:Class Parrot: Bird
    ...
    ∇ kill
      :Implements Destructor
      'This Parrot is dead'
    ∇
    ...
:EndClass ⍝ Parrot

:Class Bird
    ...
    ∇ kill
      :Implements Destructor
      'This Bird is dead'
    ∇
    ...
:EndClass ⍝ Bird

Destroying an Instance of DomesticParrot will run the Destructors in DomesticParrot, Parrot and Bird and in that order.

      pol←⎕NEW DomesticParrot

      )CLEAR
This Polly is dead
This Parrot is dead
This Bird is dead
clear ws


Class Members

A Class may contain Methods, Fields and Properties (commonly referred to together as Members) which are defined within the body of the Class script or are inherited from other Classes.

Methods are regular APL defined functions, but with some special characteristics that control how they are called and where they are executed. Dfns may not be used as Methods.

Fields are just like APL variables. To get the Field value, you reference its name; to set the Field value, you assign to its name, and the Field value is stored in the Field. However, Fields differ from variables in that they possess characteristics that control their accessibility.

Properties are similar to APL variables. To get the Property value, you reference its name; to set the Property value, you assign to its name. However, Property values are actually accessed via PropertyGet and PropertySet functions that may perform all sorts of operations. In particular, the value of a Property is not stored in the Property and may be entirely dynamic.

All three types of member may be declared as Public or Private and as Instance or Shared.

Public members are visible from outside the Class and Instances of the Class, whereas Private members are only accessible from within.

Instance Members are unique to every Instance of the Class, whereas Shared Members are common to all Instances and Shared Members may be referenced directly on the Class itself.


Fields

A Field behaves just like an APL variable.

To get the value of a Field, you reference its name; to set the value of a Field, you assign to its name. Conceptually, the Field value is stored in the Field. However, Fields differ from variables in that they possess characteristics that control their accessibility.

A Field may be declared anywhere in a Class script by a :Field statement. This specifies:

  • the name of the Field
  • whether the Field is Public or Private
  • whether the Field is Instance or Shared
  • whether or not the Field is ReadOnly
  • optionally, an initial value for the Field.

Note that Triggers may be associated with Fields. See Trigger Fields for details.


Public Fields

A Public Field may be accessed from outside an Instance or a Class. Note that the default is Private.

Class DomesticParrot has a Name Field which is defined to be Public and Instance (by default).

:Class DomesticParrot: Parrot
    :Field Public Name

    ∇ egg nm
      :Access Public
      :Implements Constructor
      Name←nm
    ∇
    ...
:EndClass ⍝ DomesticParrot

The Name field is initialised by the Class constructor.

      pet←⎕NEW DomesticParrot'Polly'
      pet.Name
Polly

The Name field may also be modified directly:

      pet.Name←⌽pet.Name
      pet.Name
ylloP


Initialising Fields

A Field may be assigned an initial value. This can be specified by an arbitrary expression that is executed when the Class is fixed by the Editor or by ⎕FIX.

:Class DomesticParrot: Parrot
    :Field Public Name
        :Field Public Talks←1

    ∇ egg nm
      :Access Public
      :Implements Constructor
      Name←nm
    ∇
    ...
:EndClass ⍝ DomesticParrot

Field Talks will be initialised to 1 in every instance of the Class.

      pet←⎕NEW DomesticParrot 'Dicky'

      pet.Talks
1
      pet.Name
Dicky

Note that if a Field is ReadOnly, this is the only way that it may be assigned a value.

See also: Shared Fields.


Private Fields

A Private Field may only be referenced by code running inside the Class or an Instance of the Class. Furthermore, Private Fields are not inherited.

The ComponentFile Class has a Private Instance Field named tie that is used to store the file tie number in each Instance of the Class.

:Class ComponentFile
    :Field Private Instance tie

    ∇ Open filename
      :Implements Constructor
      :Access Public Instance
      :Trap 0
          tie←filename ⎕FTIE 0
      :Else
          tie←filename ⎕FCREATE 0
      :EndTrap
      ⎕DF filename,'(Component File)'
    ∇

As the field is declared to be Private, it is not accessible from outside an Instance of the Class, but is only visible to code running inside.

      F1←⎕NEW ComponentFile 'test1'
      F1.tie
VALUE ERROR
      F1.tie
     ^


Shared Fields

If a Field is declared to be Shared, it has the same value for every Instance of the Class. Moreover, the Field may be accessed from the Class itself; an Instance is not required.

The following example establishes a Shared Field called Months that contains abbreviated month names which are appropriate for the user's current International settings. It also shows that an arbitrarily complex statement may be used to initialise a Field.

:Class Example
    :Using System.Globalization
    :Field Public Shared ReadOnly Months←12↑(⎕NEW DateTimeFormatInfo).AbbreviatedMonthNames
:EndClass ⍝ Example

A Shared Field is not only accessible from an instance...

      EG←⎕NEW Example
      EG.Months
 Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov...

... but also, directly from the Class itself.

      Example.Months
Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov...

Notice that in this case it is necessary to insert a :Using statement (or the equivalent assignment to ⎕USING) in order to specify the .NET search path for the DateTimeFormatInfo type. Without this, the Class would fail to fix.

You can see how the assignment works by executing the same statements in the Session:

      ⎕USING←'System.Globalization'
    12↑(⎕NEW DateTimeFormatInfo).AbbreviatedMonthNames
 Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov...


Trigger Fields

A field may act as a Trigger so that a function may be invoked whenever the value of the Field is changed.

As an example, it is often useful for the Display Form of an Instance to reflect the value of a certain Field. Naturally, when the Field changes, it is desirable to change the Display Form. This can be achieved by making the Field a Trigger as illustrated by the following example.

Notice that the Trigger function is invoked both by assignments made within the Class (as in the assignment in ctor) and those made from outside the Instance.

:Class MyClass
    :Field Public Name
    :Field Public Country←'England'
    ∇ ctor nm
      :Access Public
      :Implements Constructor
      Name←nm
    ∇
    ∇ format
      :Implements Trigger Name,Country
      ⎕DF'My name is ',Name,' and I live in ',Country
    ∇
:EndClass ⍝ MyClass

      me←⎕NEW MyClass 'Pete'
      me
My name is Pete and I live in England

      me.Country←'Greece'
      me
My name is Pete and I live in Greece

      me.Name←'Kostas'
      me
My name is Kostas and I live in Greece


Methods

Methods are implemented as regular defined functions, but with some special attributes that control how they are called and where they are executed.

A Method is defined by a contiguous block of statements in a Class Script. A Method begins with a line that contains a ∇, followed by a valid APL defined function header. The method definition is terminated by a closing ∇.

The behaviour of a Method is defined by an :Access control statement.

Public or Private

Methods may be defined to be Private (the default) or Public.

A Private method may only be invoked by another function that is running inside the Class namespace or inside an Instance namespace. The name of a Private method is not visible from outside the Class or an Instance of the Class.

A Public method may be called from outside the Class or an Instance of the Class.

Instance or Shared

Methods may be defined to be Instance (the default) or Shared.

An Instance method runs in the Instance namespace and may only be called via the instance itself. An Instance method has direct access to Fields and Properties, both Private and Public, in the Instance in which it runs.

A Shared method runs in the Class namespace and may be called via an Instance or via the Class. However, a Shared method that is called via an Instance does not have direct access to the Fields and Properties of that Instance.

Shared methods are typically used to manipulate Shared Properties and Fields or to provide general services for all Instances that are not Instance specific.

Overridable Methods

Instance Methods may be declared with :Access Overridable.

A Method declared as being Overridable is replaced in situ (i.e. within its own Class) by a Method of the same name that is defined in a higher Class which itself is declared with the Override keyword. See Superseding Base Class Methods.


Shared Methods

A Shared method runs in the Class namespace and may be called via an Instance or via the Class. However, a Shared method that is called via an Instance does not have direct access to the Fields and Properties of that Instance.

Class Parrot has a Speak method that does not require any information about the current Instance, so may be declared as Shared.

:Class Parrot:Bird

    ∇ R←Speak times
      :Access Public Shared
      R←⍕times⍴⊂'Squark!'
    ∇

:EndClass ⍝ Parrot

      wild←⎕NEW Parrot
      wild.Speak 2
 Squark!  Squark!

Note that Parrot.Speak may be executed directly from the Class and does not in fact require an Instance.

      Parrot.Speak 3
 Squark!  Squark!  Squark!


Instance Methods

An Instance method runs in the Instance namespace and may only be called via the instance itself. An Instance method has direct access to Fields and Properties, both Private and Public, in the Instance in which it runs.

Class DomesticParrot has a Speak method defined to be Public and Instance. Where Speak refers to Name, it obtains the value of Name in the current Instance.

Note too that DomesticParrot.Speak supersedes the inherited Parrot.Speak.

:Class DomesticParrot: Parrot
    :Field Public Name

    ∇ egg nm
      :Access Public
      :Implements Constructor
      Name←nm
    ∇

    ∇ R←Speak times
      :Access Public Instance
      R←⊂Name,', ',Name
      R←↑R,times⍴⊂' Who''s a pretty boy, then!'
    ∇

:EndClass ⍝ DomesticParrot

      pet←⎕NEW DomesticParrot'Polly'
      pet.Speak  3
Polly, Polly
 Who's a pretty boy, then!
 Who's a pretty boy, then!
 Who's a pretty boy, then!

      bil←⎕NEW  DomesticParrot'Billy'
      bil.Speak  1
Billy, Billy
 Who's a pretty boy, then!


Superseding Base Class Methods

Normally, a Method defined in a higher Class supersedes the Method of the same name that is defined in its Base Class, but only for calls made from above or within the higher Class itself (or an Instance of the higher Class). The base method remains available in the Base Class and is invoked by a reference to it from within the Base Class. This behaviour can be altered using the Overridable and Override key words in the :Access statement but only applies to Instance Methods.

If a Public Instance method in a Class is marked as Overridable, this allows a Class which derives from the Class with the Overridable method to supersede the Base Class method in the Base Class, by providing a method which is marked Override. The typical use of this is to replace code in the Base Class which handles an event, with a method provided by the derived Class.

For example, the base class might have a method which is called if any error occurs in the base class:

     ∇ ErrorHandler
[1]    :Access Public Overridable
[2]    ⎕←↑⎕DM
     ∇

In your derived class, you might supersede this by a more sophisticated error handler, which logs the error to a file:

     ∇ ErrorHandler;TN
[1]    :Access Public Override
[2]    ⎕←↑⎕DM
[3]    TN←'ErrorLog'⎕FSTIE 0
[4]    ⎕DM ⎕FAPPEND TN
[5]    ⎕FUNTIE TN
     ∇

If the derived class had a function which was not marked Override, then function in the derived class which called ErrorHandler would call the function as defined in the derived class, but if a function in the base class called ErrorHandler, it would still see the base class version of this function. With Override specified, the new function supersedes the function as seen by code in the base class. Note that different derived classes can specify different Overrides.

In C#, Java and some other compiled languages, the term Virtual is used in place of Overridable, which is the term used by Visual Basic and Dyalog APL.


Properties

A Property behaves in a very similar way to an ordinary APL variable. To obtain the value of a Property, you simply reference its name. To change the value of a Property, you assign a new value to the name.

However, under the covers, a Property is accessed via a PropertyGet function and its value is changed via a PropertySet function. Furthermore, Properties may be defined to allow partial (indexed) retrieval and assignment to occur.

There are three types of Property, namely Simple, Numbered and Keyed.

A Simple Property is one whose value is accessed (by APL) in its entirety and re-assigned (by APL) in its entirety.

A Numbered Property behaves like an array (conceptually a vector) which is only ever partially accessed and set (one element at a time) via indices. The Numbered Property is designed to allow APL to perform selections and structural operations on the Property.

A Keyed Property is similar to a Numbered Property except that its elements are accessed via arbitrary keys instead of indices.

The following cases illustrate the difference between Simple and Numbered Properties.

If Instance MyInst has a Simple Property Sprop and a Numbered Property Nprop, the expressions

      X←MyInst.SProp
      X←MyInst.SProp[2]

both cause APL to call the PropertyGet function to retrieve the entire value of Sprop. The second statement subsequently uses indexing to extract just the second element of the value.

Whereas, the expression:

      X←MyInst.NProp[2]

causes APL to call the PropertyGet function with an additional argument which specifies that only the second element of the Property is required. Moreover, the expression:

      X←MyInst.NProp

causes APL to call the PropertyGet function successively, for every element of the Property.

A Property is defined by a :Property ... :EndProperty section in a Class Script.

Within the body of a Property Section there may be:

  • one or more :Access statements which must appear first in the body of the Property.
  • a single PropertyGet function.
  • a single PropertySet function
  • a single PropertyShape function


Simple Instance Properties

A Simple Instance Property is one whose value is accessed (by APL) in its entirety and re-assigned (by APL) in its entirety. The following examples are taken from the ComponentFile Class .

The Simple Property Count returns the number of components on a file.

    :Property Count
    :Access Public Instance
        ∇ r←get
          r←¯1+2⊃⎕FSIZE tie
        ∇
    :EndProperty ⍝ Count

      F1←⎕NEW ComponentFile 'test1'
      F1.Append'Hello World'
1
      F1.Count
1
      F1.Append 42
2
      F1.Count
2

Because there is no set function defined, the Property is read-only and attempting to change it causes SYNTAX ERROR.

      F1.Count←99
SYNTAX ERROR
      F1.Count←99
     ^

The Access Property has both get and set functions which are used, in this simple example, to get and set the component file access matrix.

    :Property Access
    :Access Public Instance
        ∇ r←get
          r←⎕FRDAC tie
        ∇
        ∇ set am;mat;OK
          mat←am.NewValue
          :Trap 0
              OK←(2=⍴⍴mat)^(3=2⊃⍴mat)^^/,mat=⌊mat
          :Else
              OK←0
          :EndTrap
          'bad arg'⎕SIGNAL(~OK)/11
          mat ⎕FSTAC tie
        ∇
    :EndProperty ⍝ Access

Note that the set function must be monadic. Its argument, supplied by APL, will be an Instance of PropertyArguments. This is an internal Class whose NewValue field contains the value that was assigned to the Property.

Note that the set function does not have to accept the new value that has been assigned. The function may validate the value reject or accept it (as in this example), or perform whatever processing is appropriate.

      F1←⎕NEW ComponentFile 'test1'
      ⍴F1.Access
0 3
        F1.Access←3 3⍴28 2105 16385 0 2073 16385 31 ¯1 0
      F1.Access
28 2105 16385
 0 2073 16385
31   ¯1     0

      F1.Access←'junk'
bad arg
      F1.Access←'junk'
     ^

      F1.Access←1 2⍴10
bad arg
      F1.Access←1 2⍴10
     ^


Simple Shared Properties

The ComponentFile Class specifies a Simple Shared Property named Files which returns the names of all the Component Files in the current directory.

The previous examples have illustrated the use of Instance Properties. It is also possible to define Shared properties.

A Shared property may be used to handle information that is relevant to the Class as a whole, and which is not specific to any a particular Instance.

    :Property Files
    :Access Public Shared
        ∇ r←get
          r←⎕FLIB''
        ∇
    :EndProperty

Note that ⎕FLIB (invoked by the Files get function) does not report the names of tied files.

      F1←⎕NEW ComponentFile 'test1'
      ⎕EX'F1'
      F2←⎕NEW ComponentFile 'test2'
      F2.Files ⍝ NB ⎕FLIB does not report tied files
test1
      ⎕EX'F2'

Note that a Shared Property may be accessed from the Class itself. It is not necessary to create an Instance first.

      ComponentFile.Files
test1
test2


Numbered Properties

A Numbered Property behaves like an array (conceptually a vector) which is only ever partially accessed and set (one element at a time) via indices.

To implement a Numbered Property, you must specify a PropertyShape function and either or both a PropertyGet and PropertySet function.

When an expression references or makes an assignment to a Numbered Property, APL first calls its PropertyShape function which returns the dimensions of the Property. Note that the shape of the result of this function determines the rank of the Property.

If the expression uses indexing, APL checks that the index or indices are within the bounds of these dimensions, and then calls the PropertyGet or PropertySet function. If the expression specifies a single index, APL calls the PropertyGet or PropertySet function once. If the expression specifies multiple indices, APL calls the function successively.

If the expression references or assigns the entire Property (without indexing) APL generates a set of indices for every element of the Property and calls the PropertyGet or PropertySet function successively for every element in the Property.

Note that APL generates a RANK ERROR if an index contains the wrong number of elements or an INDEX ERROR if an index is out of bounds.

When APL calls a monadic PropertyGet or PropertySet function, it supplies an argument of type PropertyArguments.


Example

The ComponentFile Class specifies a Numbered Property named Component which represents the contents of a specified component on the file.

    :Property Numbered Component
    :Access Public Instance
        ∇ r←shape
          r←¯1+2⊃⎕FSIZE tie
        ∇
        ∇ r←get arg
          r←⎕FREAD tie arg.Indexers
        ∇
        ∇ set arg
          arg.NewValue ⎕FREPLACE tie,arg.Indexers
        ∇
    :EndProperty

      F1←⎕NEW ComponentFile 'test1'

      F1.Append¨(⍳5)×⊂⍳4
1 2 3 4 5

      F1.Count
5

      F1.Component[4]
 4 8 12 16

      4⊃F1.Component
4 8 12 16

      (⊂4 3)⌷F1.Component
 4 8 12 16  3 6 9 12

Referencing a Numbered Property in its entirety causes APL to call the get function successively for every element.

      F1.Component
 1 2 3 4  2 4 6 8  3 6 9 12  4 8 12 16  5 10 15 20

      ((⊂4 3)⌷F1.Component)←'Hello' 'World'

      F1.Component[3]
 World

Attempting to access a Numbered Property with inappropriate indices generates an error:

      F1.Component[6]
INDEX ERROR
      F1.Component[6]
     ^
      F1.Component[1;2]
RANK ERROR
      F1.Component[1;2]
     ^


The Default Property

A single Numbered Property may be identified as the Default Property for the Class. If a Class has a Default Property, indexing with the ⌷ primitive function and [...] indexing may be applied to the Property directly via a reference to the Class or Instance.

The Numbered Property example of the ComponentFile Class can be extended by adding the control word Default to the :Property statement for the Component Property.

Indexing may now be applied directly to the Instance F1. In essence, F1[n] is simply shorthand for F1.Component[n] and n⌷F1 is shorthand for n⌷F1.Component

    :Property Numbered Default Component
    :Access Public Instance
        ∇ r←shape
          r←¯1+2⊃⎕FSIZE tie
        ∇
        ∇ r←get arg
          r←⎕FREAD tie arg.Indexers
        ∇
        ∇ set arg
          arg.NewValue ⎕FREPLACE tie,arg.Indexers
        ∇
    :EndProperty

      F1←⎕NEW ComponentFile 'test1'
      F1.Append¨(⍳5)×⊂⍳4
1 2 3 4 5
      F1.Count
5

      F1[4]
 4 8 12 16
      (⊂4 3)⌷F1
 4 8 12 16  3 6 9 12
      ((⊂4 3)⌷F1)←'Hello' 'World'
      F1[3]
 World

Note however that this feature applies only to indexing.

      4⊃F1
DOMAIN ERROR
      4⊃F1
     ^


ComponentFile Class

:Class ComponentFile
    :Field Private Instance tie

    ∇ Open filename
      :Implements Constructor
      :Access Public Instance
      :Trap 0
          tie←filename ⎕FTIE 0
      :Else
          tie←filename ⎕FCREATE 0
      :EndTrap
      ⎕DF filename,'(Component File)'
    ∇

    ∇ Close
      :Access Public Instance
      ⎕FUNTIE tie
    ∇

    ∇ r←Append data
      :Access Public Instance
      r←data ⎕FAPPEND tie
    ∇

    ∇ Replace(comp data)
      :Access Public Instance
      data ⎕FREPLACE tie,comp
    ∇

    :Property Count
    :Access Public Instance
        ∇ r←get
          r←¯1+2⊃⎕FSIZE tie
        ∇
    :EndProperty ⍝ Count

:Property Access
    :Access Public Instance
        ∇ r←get arg
          r←⎕FRDAC tie
        ∇
        ∇ set am;mat;OK
          mat←am.NewValue
          :Trap 0
              OK←(2=⍴⍴mat)^(3=2⊃⍴mat)^^/,mat=⌊mat
          :Else
              OK←0
          :EndTrap
          'bad arg'⎕SIGNAL(~OK)/11
          mat ⎕FSTAC tie
        ∇
    :EndProperty ⍝ Access

    :Property Files
    :Access Public Shared
        ∇ r←get
          r←⎕FLIB''
        ∇
    :EndProperty

    :Property Numbered Default Component
    :Access Public Instance
        ∇ r←shape args
          r←¯1+2⊃⎕FSIZE tie
        ∇
        ∇ r←get arg
          r←⊂⎕FREAD tie,arg.Indexers
        ∇
        ∇ set arg
          (⊃arg.NewValue)⎕FREPLACE tie,arg.Indexers
        ∇
    :EndProperty

    ∇ Delete file;tie
      :Access Public Shared
      tie←file ⎕FTIE 0
      file ⎕FERASE tie
    ∇
:EndClass ⍝ Class ComponentFile


Keyed Properties

A Keyed Property is similar to a Numbered Property except that it may only be accessed by indexing (so-called square-bracket indexing) and indices are not restricted to integers but may be arbitrary arrays.

To implement a Keyed Property, only a get and/or a set function are required. APL does not attempt to validate or resolve the specified indices in any way, so does not require the presence of a shape function for the Property.

However, APL does check that the rank and lengths of the indices correspond to the rank and lengths of the array to the right of the assignment (for an indexed assignment) and the array returned by the get function (for an indexed reference). If the rank or shape of these arrays fails to conform to the rank or shape of the indices, APL will issue a RANK ERROR or LENGTH ERROR.

Note too that indices may be elided. If KProp is a Keyed Property of Instance I1, the following expressions are all valid.

      I1.KProp
      I1.KProp[]←10
      I1.KProp[;]←10
      I1.KProp['One' 'Two';]←10
      I1.KProp[;'One' 'Two']←10

When APL calls a monadic get or a set function, it supplies an argument of type PropertyArguments, which identifies which dimensions and indices were specified. See PropertyArguments Class.


Keyed Properties Example 1

The Sparse2 Class illustrates the implementation and use of a Keyed Property.

Sparse2 represents a 2-dimensional sparse array each of whose dimensions are indexed by arbitrary character keys. The sparse array is implemented as a Keyed Property named Values. The following expressions show how it might be used.

      SA1←⎕NEW Sparse2
      SA1.Values[⊂'Widgets';⊂'Jan']←100
      SA1.Values[⊂'Widgets';⊂'Jan']
100
      SA1.Values['Widgets' 'Grommets';'Jan' 'Mar' 'Oct']←10×2 3⍴⍳6
      SA1.Values['Widgets' 'Grommets';'Jan' 'Mar' 'Oct']
10 20 30
40 50 60
      SA1.Values[⊂'Widgets';'Jan' 'Oct']
10 30
      SA1.Values['Grommets' 'Widgets';⊂'Oct']
60
30

Sparse2 Class Example

:Class Sparse2  ⍝ 2D Sparse Array
    :Field Private keys
    :Field Private values
    ∇ make
      :Access Public
      :Implements Constructor
      keys←0⍴⊂'' ''
      values←⍬
    ∇
    :Property Keyed Values
    :Access Public Instance
        ∇ v←get arg;k
          k←arg.Indexers
          ⎕SIGNAL(2≠⍴k)/4
          k←fixkeys k
          v←(values,0)[keys⍳k]
        ∇
        ∇ set arg;new;k;v;n
          v←arg.NewValue
          k←arg.Indexers
          ⎕SIGNAL(2≠⍴k)/4
          k←fixkeys k
          v←(⍴k)(⍴⍣(⊃1=⍴,v))v
          ⎕SIGNAL((⍴k)≠⍴v)/5
          k v←,¨k v
          :If ∨/new←~k∊keys
              values,←new/v
              keys,←new/k
              k v/⍨←⊂~new
          :EndIf
          :If 0<⍴k
              values[keys⍳k]←v
          :EndIf
        ∇
    :EndProperty

    ∇ k←fixkeys k
      k←(2≠≡¨k){,(⊂⍣⍺)⍵}¨k
      k←⊃(∘.{⊃,/⊂¨⍺ ⍵})/k
    ∇
:EndClass ⍝ 2D Sparse Array

Internally, Sparse2 maintains a list of keys and a list of values which are initialised to empty arrays by its constructor.

When an indexed assignment is made, the set function receives a list of keys (indices) in arg.Indexer and values in arg.NewValue. The function updates the values of existing keys, and adds new keys and their values to the internal lists.

When an indexed reference is made, the get function receives a list of keys (indices) in arg.Indexer. The function uses these keys to retrieve the corresponding values, inserting 0s for non-existent keys.

Note that in the expression:

 SA1.Values['Widgets' 'Grommets';'Jan' 'Mar' 'Oct']

the structure of arg.Indexer is:

.→-----------------------------------------------.
| .→---------------------. .→------------------. |
| | .→------. .→-------. | | .→--. .→--. .→--. | |
| | |Widgets| |Grommets| | | |Jan| |Mar| |Oct| | |
| | '-------' '--------' | | '---' '---' '---' | |
| '∊---------------------' '∊------------------' |
'∊-----------------------------------------------'


Example

A second example of a Keyed Property is provided by the KeyedFile Class which is based upon the ComponentFile Class used previously.

:Class KeyedFile: ComponentFile
    :Field Public Keys
    ⎕ML←0

    ∇ Open filename
      :Implements Constructor :Base filename
      :Access Public Instance
      :If Count>0
          Keys←{⊃⍵⊃⎕BASE.Component}¨⍳Count
      :Else
          Keys←0⍴⊂''
      :EndIf
    ∇

    :Property Keyed Component
    :Access Public Instance
        ∇ r←get arg;keys;sink
          keys←⊃arg.Indexers
          ⎕SIGNAL(~^/keys∊Keys)/3
          r←{2⊃⍵⊃⎕BASE.Component}¨Keys⍳keys
        ∇
        ∇ set arg;new;keys;vals
          vals←arg.NewValue
          keys←⊃arg.Indexers
          ⎕SIGNAL((⍴,keys)≠⍴,vals)/5
          :If ∨/new←~keys∊Keys
              sink←Append¨↓⍉↑(⊂new)/¨keys vals
              Keys,←new/keys
              keys vals/⍨←⊂~new
          :EndIf
          :If 0<⍴,keys
              Replace¨↓⍉↑(Keys⍳keys)(↓⍉↑keys vals)
          :EndIf
        ∇
    :EndProperty

:EndClass ⍝ Class KeyedFile

      K1←⎕NEW KeyedFile 'ktest'
      K1.Count
0
      K1.Component[⊂'Pete']←42
      K1.Count
1
      K1.Component['John' 'Geoff']←(⍳10)(3 4⍴⍳12)
      K1.Count
3
      K1.Component['Geoff' 'Pete']
 1  2  3  4  42
 5  6  7  8
 9 10 11 12
      K1.Component['Pete' 'Morten']←(3 4⍴'∘')(⍳⍳3)
      K1.Count
4
      K1.Component['Morten' 'Pete' 'John']
  1 1 1  1 1 2  1 1 3   ∘∘∘∘  1 2 3 4 5 6 7 8 9 10
  1 2 1  1 2 2  1 2 3   ∘∘∘∘
                        ∘∘∘∘


Interfaces

An Interface is defined by a Script that contains skeleton declarations of Properties and/or Methods. These members are only place-holders; they have no specific implementation; this is provided by each of the Classes that support the Interface.

An Interface contains a collection of methods and properties that together represents a protocol that an application must follow in order to manipulate a Class in a particular way.

An example might be an Interface called Icompare that provides a single method (Compare) which compares two Instances of a Class, returning a value to indicate which of the two is greater than the other. A Class that implements Icompare must provide an appropriate Compare method, but every Class will have its own individual version of Compare. An application can then be written that sorts Instances of any Class that supports the ICompare Interface.

An Interface is implemented by a Class if it includes the name of the Interface in its :Class statement, and defines a corresponding set of the Methods and Properties that are declared in the Interface.

To implement a Method, a function defined in the Class must include a :Implements Method statement that maps it to the corresponding Method defined in the Interface:

      :Implements Method <InterfaceName.MethodName>

Furthermore, the syntax of the function (whether it be result returning, monadic or niladic) must exactly match that of the method described in the Interface. The function name, however, need not be the same as that described in the Interface.

Similarly, to implement a Property the type (Simple, Numbered or Keyed) and syntax (defined by the presence or absence of a PropertyGet and PropertySet functions) must exactly match that of the property described in the Interface. The Property name, however, need not be the same as that described in the Interface.


Interfaces

Penguin Class Example

The Penguin Class example illustrates the use of Interfaces to implement multiple inheritance.

FishBehaviour Interface

BirdBehaviour Interface

Penguin Class

In this case, the Penguin Class derives from Animal but additionally supports the BirdBehaviour and FishBehaviour Interfaces, thereby inheriting members from both.

      Pingo←⎕NEW Penguin
      ⎕CLASS Pingo
  #.Penguin  #.FishBehaviour  #.BirdBehaviour    #.Animal

      (FishBehaviour ⎕CLASS Pingo).Swim
I can dive and swim like a fish
      (BirdBehaviour ⎕CLASS Pingo).Fly
Although I am a bird, I cannot fly
      (BirdBehaviour ⎕CLASS Pingo).Lay
I lay one egg every year
      (BirdBehaviour ⎕CLASS Pingo).Sing
Croak, Croak!


Including Namespaces in Classes

A Class may import methods from one or more plain Namespaces. This allows several Classes to share a common set of methods, and provides a degree of multiple inheritance.

To import methods from a Namespace NS, the Class Script must include a statement:

:Include NS

When the Class is fixed by the editor or by ⎕FIX, all the defined functions and operators in Namespace NS are included as methods in the Class. The functions and operators which are brought in as methods from the namespace NS are treated exactly as if the source of each function/operator had been included in the class script at the point of the :Include statement. For example, if a function contains :Signature or :Access statements, these will be taken into account. Note that such declarations have no effect on a function/operator which is in an ordinary namespace.

Dfns and dops in NS are also included in the Class but as Private members, because dfns and dops may not contain :Signature or :Access statements. Variables and Sub-namespaces in NS are not included.

Note that objects imported in this way are not actually copied, so there is no penalty incurred in using this feature. Additions, deletions and changes to the functions in NS are immediately reflected in the Class.

If there is a member in the Class with the same name as a function in NS, the Class member takes precedence and supersedes the function in NS.

Conversely, functions in NS will supersede members of the same name that are inherited from the Base Class, so the precedence is:

Class supersedes

Included Namespace, supersedes

Base Class

Any number of Namespaces may be included in a Class and the :Include statements may occur anywhere in the Class script. However, for the sake of readability, it is recommended that you have :Include statements at the top, given that any definitions in the script will supersede included functions and operators.

For information on copying classes that reference namespaces in this way, see Referenced Objects.


Including Namespaces

Example

In this example, Class Penguin inherits from Animal and includes functions from the plain Namespaces BirdStuff and FishStuff.

:Class Penguin: Animal
    :Include BirdStuff
    :Include FishStuff
:EndClass ⍝ Penguin

Namespace BirdStuff contains 2 functions, both declared as Public methods.

:Namespace BirdStuff
    ∇ R←Fly
      :Access Public Instance
      R←'Fly, Fly ...'
    ∇
    ∇ R←Lay
      :Access Public Instance
      R←'Lay, Lay ...'
    ∇
:EndNamespace ⍝ BirdStuff

Namespace FishStuff contains a single function, also declared as a Public method.

:Namespace FishStuff
    ∇ R←Swim
      :Access Public Instance
      R←'Swim, Swim ...'
    ∇
:EndNamespace ⍝ FishStuff

      Pingo←⎕NEW Penguin
      Pingo.Swim
Swim, Swim ...
      Pingo.Lay
Lay, Lay ...
      Pingo.Fly
Fly, Fly ...

This is getting silly - we all know that Penguin's can't fly. This problem is simply resolved by overriding the BirdStuff.Fly method with Penguin.Fly. We can hide BirdStuff.Fly with a Private method in Penguin that does nothing. For example:

:Class Penguin: Animal
    :Include BirdStuff
    :Include FishStuff
    ∇ Fly ⍝ Override BirdStuff.Fly
    ∇
:EndClass ⍝ Penguin

      Pingo←⎕NEW Penguin
      Pingo.Fly
VALUE ERROR
      Pingo.Fly
     ^

or we can supersede it with a different Public method, as follows:

:Class Penguin: Animal
    :Include BirdStuff
    :Include FishStuff
    ∇ R←Fly ⍝ Override BirdStuff.Fly
      :Access Public Instance
      R←'Sadly, I cannot fly'
    ∇
:EndClass ⍝ Penguin

      Pingo←⎕NEW Penguin
      Pingo.Fly
Sadly, I cannot fly


Nested Classes

It is possible to define Classes within Classes (Nested Classes).

A Nested Class may be either Private or Public. This is specified by a :Access Statement, which must precede the definition of any Class contents. The default is Private.

A Public Nested Class is visible from outside its containing Class and may be used directly in its own right, whereas a Private Nested Class is not and may only be used by code inside the containing Class.

However, methods in the containing Class may return instances of Private Nested Classes and in that way expose them to the calling environment.


GolfService Example

The GolfService Example Class illustrates the use of nested classes. GolfService was originally developed as a Web Service for Dyalog.NET and is one of the samples distributed in samples\asp.net\webservices. This version has been reconstructed as a stand-alone APL Class.

GolfService contains the following nested classes, all of which are Private.

GolfCourse | A Class that represents a Golf Course, having Fields Code and Name.
Slot | A Class that represents a tee-time or match, having Fields Time and Players. Up to 4 players may play together in a match.
Booking | A Class that represents a reservation for a particular tee-time at a particular golf course. This has Fields OK, Course, TeeTime and Message. The value of TeeTime is an Instance of a Slot Class.
StartingSheet | A Class that represents a day's starting-sheet at a particular golf course. It has Fields OK, Course, Date, Slots, Message. Slots is an array of Instances of Slot Class.

The GolfService constructor takes the name of a file in which all the data is stored. This file is initialised by method InitFile if it doesn't already exist.

      G←⎕NEW GolfService 'F:\HELP11.0\GOLFDATA'
      G
#.[Instance of GolfService]

The GetCourses method returns an array of Instances of the internal (nested) Class GolfCourse. Notice how the display form of each Instance is established by the GolfCourse constructor, to obtain the output display shown below.

      G.GetCourses
 St Andrews(1)  Hindhead(2)  Basingstoke(3)

All of the dates and times employ instances of the .NET type System.DateTime, and the following statements just set up some temporary variables for convenience later.

      ⎕←Tomorrow←(⎕NEW DateTime(3↑⎕TS)).AddDays 1
31/03/2006 00:00:00
      ⎕←TomorrowAt7←Tomorrow.AddHours 7
31/03/2006 07:00:00

The MakeBooking method takes between 4 and 7 parameters viz.

  • the code for the golf course at which the reservation is required
  • the date and time of the reservation
  • a flag to indicate whether or not the nearest available time will do
  • a list of up to 4 players who wish to book that time.

The result is an Instance of the internal Class Booking. Once again, ⎕DF is used to make the default display of these Instances meaningful. In this case, the reservation is successful.

      G.MakeBooking 2 TomorrowAt7 1 'Pete' 'Tiger'
  Hindhead(2)   31/03/2006 07:00:00   Pete  Tiger    OK

Bob, Arnie and Jack also ask to play at 7:00 but are given the 7:10 tee-time instead (4-player restriction).

      G.MakeBooking 2 TomorrowAt7 1 'Bob' 'Arnie' 'Jack'
 Hindhead(2)   31/03/2006 07:10:00   Bob  Arnie  Jack    OK

However, Pete and Tiger are joined at 7:00 by Dave and Al.

       G.MakeBooking 2 TomorrowAt7 1 'Dave' 'Al'
  Hindhead(2)   31/03/2006 07:00:00   Pete  Tiger  Dave  Al    OK

Up to now, all bookings have been made with the tee-time flexibility flag set to 1. Inflexible Jim is only interested in playing at 7:00...

      G.MakeBooking 2 TomorrowAt7 0 'Jim'
 Hindhead(2)  31/03/2006 07:00:00  Not available

... so his reservation fails (4-player restriction).

Finally the GetStartingSheet method is used to obtain an Instance of the internal Class StartingSheet for the given course and day.

      G.GetStartingSheet 2 Tomorrow
  Hindhead(2)  31/03/2006 00:00:00
  31/03/2006 07:00:00   Pete  Tiger  Dave  Al
  31/03/2006 07:10:00   Bob  Arnie  Jack
  31/03/2006 07:20:00
  ....


Namespace Scripts

A Namespace Script is a script that begins with a :Namespace statement and ends with a :EndNamespace statement. When a Namespace Script is fixed, it establishes an entire namespace that may contain other namespaces, functions, variables and classes.

The names of Classes defined within a Namespace Script which are parents, children, or siblings are visible both to one another and to code and expressions defined in the same script, regardless of the namespace hierarchy within it. Names of Classes which are nieces or nephews and their descendants are however not visible.

For example:

:Namespace a

    d←⎕NEW a1
    e←⎕NEW bb2

    :Class a1
        ∇ r←foo
          :Access Shared Public
          r←⎕NEW¨b1 b2
        ∇
    :EndClass ⍝ a1

    ∇ r←goo
      r←a1.foo
    ∇

    ∇ r←foo
      r←⎕NEW¨b1 b2
    ∇

    :Namespace b
        :Class b1
        :EndClass ⍝ b1
        :Class b2
            :Class bb2
            :EndClass ⍝ bb2
        :EndClass ⍝ b2
    :EndNamespace ⍝ b

:EndNamespace ⍝ a

      a.d
#.a.[a1]
      a.e
#.a.[bb2]
      a.foo
 #.a.[b1]  #.a.[b2]

Note that the names of Classes b1 (a.b.b1) and b2 (a.b.b2) are not visible from their "uncle" a1 (a.a1).

      a.goo
VALUE ERROR
foo[2] r←⎕NEW¨b1 b2

Notice that Classes in a Namespace Script are fixed before other objects (hence the assignments to d and e are evaluated after Classes a1 and bb2 are fixed), although the order in which Classes themselves are defined is still important if they reference one another during initialisation.

A practical example using :Namespace is given in the next topic.

Changing Scripted Objects Dynamically

The source of a scripted object can only be altered using the Editor, or by refixing it in its entirety using ⎕FIX. Dynamic changes to variables, fields and properties, and calling ⎕FX to generate functions do not alter the source of a scripted object.

Furthermore, if you introduce new objects of any type (functions, variables, or classes) into a namespace or a class defined by a script by any means other than editing the script, then these objects will be lost the next time the script is edited and fixed.

If you fix a function using ⎕FX with the same name as a function defined in the script, this new version will supercede the version defined from the script, although the version in the script will remain unchanged.

If you edit the function (as opposed to editing the script) the Editor will show the new version of the function.

If however you edit the script, the Editor will display the original version of the function embedded in the script.

If you were to edit both the script and the function, the Editor would show the two different versions of the function as illustrated in the example that follows.

When you fix the script, the version of the function in the script will replace the one created using ⎕FX.

Example

:Namespace ns
    ∇ foo
      1
    ∇
:EndNamespace

      ns.foo
1

      ns.⎕fx 'foo' '2'
      ns.foo
2
      )ed ns.foo ns

Note that the Editor displays the description Unscripted Function in the status bar of the window showing the new version of foo.

Similarly, if you were to Trace the execution of ns.foo, the Tracer would display the current (⎕FX'ed) version of foo, with the same description in its status bar.


Namespace Script Example

The DiaryStuff example illustrates the manner in which classes may be defined and used in a Namespace script.

DiaryStuff defines two Classes named Diary and DiaryEntry.

Diary contains a (private) Field named entries, which is simply a vector of instances of DiaryEntry. These are 2-element vectors containing a .NET DateTime object and a description.

The entries Field is initialised to an empty vector of DiaryEntry instances which causes the invocation of the default constructor DiaryEntry.Make0 when Diary is fixed. See Empty Arrays of Instances: Why ? for further explanation.

The entries Field is referenced through the Entry Property, which is defined as the Default Property. This allows individual entries to be referenced and changed using indexing on a Diary Instance.

Note that DiaryEntry is defined in the script first (before Diary) because it is referenced by the initialisation of the Diaries.entries Field

Create a new instance of Diary.

      D←⎕NEW DiaryStuff.Diary

Add a new entry "meeting with John at 09:00 on April 30th"

      D.Add(2006 4 30 9 0)'Meeting with John'
 30/04/2006 09:00:00  Meeting with John

Add another diary entry "Dentist at 10:00 on April 30th".

      D.Add(2006 4 30 10 0)'Dentist'
 30/04/2006 10:00:00  Dentist

One of the benefits of the Namespace Script is that Classes defined within it (which are typically related) may be used independently, so we can create a stand-alone instance of DiaryEntry; "Doctor at 11:00"...

  Doc←⎕NEW DiaryStuff.DiaryEntry((2006 4 30 11 0)'Doctor')
      Doc
 30/04/2006 11:00:00  Doctor

... and then use it to replace the second Diary entry with indexing:

      D[2]←Doc

and just to confirm it is there...

      D[2]
 30/04/2006 11:00:00  Doctor

What am I doing on the 30th?

      D.DoingOn 2006 4 30
  30/04/2006 09:00:00  Meeting with John    ...
  ... 30/04/2006 11:00:00  Doctor

Remove the 11:00 appointment...

      D.Remove 2006 4 30 11 0
1

and the complete Diary is...

      ⌷D
  30/04/2006 09:00:00  Meeting with John


Including Script Files

Including Script Files in Scripts

A Class or Namespace script in the workspace or in a script file may specify that other script files are to be loaded prior to the fixing of the script itself. To do so, it must begin with one or more :Require statements, with the following syntax:

:Require file://[path]/file

If no path is specified, the path is taken to be relative to the current script file or, if in a workspace script, the current working directory. Note that a leading './' or '.\' in path is not allowed, to avoid any potential confusion with "current directory".

:Require is a directive to the Editor (more specifically, to the internal mechanism that fixes a script as an object in the workspace) and can appear in any script containing APL code, but must precede all code in the script. :Require is thus not valid within a function, class, namespace or any other definition.

The prefix file:// allows for the possibility of a future extension of http:// and ftp://.

In version 17.0 ⍝!:require is a synonym for :Require. This allows the user to create scripts which can be used in multiple versions of Dyalog; in 14.1 and earlier SALT parses ⍝!:require statements and loads the appropriate files, in 17.0 it is the interpreter loads the file named in ⍝!:require statements. Dyalog intends to remove support for the ⍝!:require statement from the interpreter in a future version. Note that unlike :Require, ⍝!:require can appear within code.


Class Declaration Statements

This section summarises the various declaration statements that may be included in a Class or Namespace Script. For information on other declaration statements, as they apply to functions and methods, see Function Declaration Statements.


:Interface Statement

:Interface <interface name>
...
:EndInterface

An Interface is defined by a Script containing skeleton declarations of Properties and/or Methods. The script must begin with a :Interface Statement and end with a :EndInterface Statement.

An Interface may not contain Fields.

Properties and Methods defined in an Interface, and the Class functions that implement the Interface, may not contain :Access Statements.


:Namespace Statement

:Namespace <namespace name>
...
:EndNamespace

A Namespace Script may be used to define an entire namespace containing other namespaces, functions, variables and Classes.

A Namespace script must begin with a :Namespace statement and end with a :EndNamespace statement.

Sub-namespaces, which may be nested, are defined by pairs of :Namespace and :EndNamespace statements within the Namespace script.

Classes are defined by pairs of :Class and :EndClass statements within the Namespace script, and these too may be nested.

The names of Classes defined within a Namespace Script are visible both to one another and to code and expressions defined in the same script, regardless of the namespace hierarchy within it.

A Namespace script is therefore particularly useful to group together Classes that refer to one another where the use of nested classes is inappropriate.


:Class Statement

:Class <class name><:base class name> <,interface name...>

:Include <namespace>
...
:EndClass

A class script begins with a :Class statement and ends with a :EndClass statement. The elements that comprise the :Class statement are as follows:

Element | Description
class name | Optionally, specifies the name of the Class, which must conform to the rules governing APL names.
base class name | Optionally specifies the name of a Class from which this Class is derived and whose members this Class inherits.
interface name | The names of one or more Interfaces which this Class supports.

A Class may import methods defined in separate plain Namespaces with one or more :Include statements. For further details, see Including Namespaces in Classes.

Examples:

The following statements define a Class named Penguin that derives from (is based upon) a Class named Animal and which supports two Interfaces named BirdBehaviour and FishBehaviour.

:Class Penguin: Animal,BirdBehaviour,FishBehaviour
...
:EndClass

The following statements define a Class named Penguin that derives from (is based upon) a Class named Animal and includes methods defined in two separate Namespaces named BirdStuff and FishStuff.

:Class Penguin: Animal
:Include BirdStuff
:Include FishStuff
...
:EndClass


:Using Statement

:Using <NameSpace[,Assembly]>

This statement specifies a .NET namespace that is to be searched to resolve unqualified names of .NET types referenced by expressions in the Class.

Element | Description
NameSpace | Specifies a .NET namespace.
Assembly | Specifies the Assembly in which NameSpace is located. If the Assembly is located in the Microsoft.NET installation directory, you need only specify its name. If not, you must specify a full or relative pathname.

If the Microsoft .NET Framework is installed, the System namespace inmscorlib.dll is automatically loaded when Dyalog APL starts. To access this namespace, it is not necessary to specify the name of the Assembly.

When the class is fixed, ⎕USING is inherited from the surrounding space. Each :Using statement appends an element to ⎕USING, with the exception of :Using with no argument:

If you omit <Namespace>, this is equivalent to clearing ⎕USING, which means that no .NET namespaces will be searched (unless you follow this statement with additional :Using statements, each of which will append to ⎕USING).

To set ⎕USING, to a single empty character vector, which only allows references to fully qualified names of classes in mscorlib.dll, you must write:

:Using , (note the presence of the comma)

or

:Using ,mscorlib.dll

i.e. specify an empty namespace name followed by no assembly, or followed by the default assembly, which is always loaded.


:Attribute Statement

:Attribute <Name> [ConstructorArgs]

The :Attribute statement is used to attach .NET Attributes to a Class or a Method.

Attributes are descriptive tags that provide additional information about programming elements. Attributes are not used by Dyalog APL but other applications can refer to the extra information in attributes to determine how these items can be used. Attributes are saved with the metadata of Dyalog APL .NET assemblies.

Element | Description
Name | The name of a .NET attribute
ConstructorArgs | Optional arguments for the Attribute constructor

Example

The following Class has SerializableAttribute and CLSCompliantAttribute attributes attached to the Class as a whole, and ObsoleteAttribute attributes attached to Methods foo and goo within it.

:Class c1
:using System
    :attribute SerializableAttribute
    :attribute CLSCompliantAttribute 1

    ∇ foo(p1 p2)
      :Access public instance
      :Signature foo Object,Object
      :Attribute ObsoleteAttribute
    ∇

    ∇ goo(p1 p2)
      :Access public instance
      :Signature foo Object,Object
      :Attribute ObsoleteAttribute 'Don''t use this' 1

    ∇

:EndClass ⍝ c1

When this Class is exported as a .NET Class, the attributes are saved in its metadata. For example, Visual Studio will warn developers if they make use of a member which has the ObsoleteAttribute.


:Access Statement

:Access <Private|Public><Instance|Shared><Overridable>
                                         <Override>
:Access <WebMethod>

The :Access statement is used to specify characteristics for Classes, Properties and Methods.

Element | Description
Private|Public | Specifies whether or not the (nested) Class, Property or Method is accessible from outside the Class or an Instance of the Class. The default is Private.
Instance|Shared | For a Field, specifies if there is a separate value of the Field in each Instance of the Class, or if there is only a single value that is shared between all Instances. For a Property or Method, specifies whether the code associated with the Property or Method runs in the Class or Instance.
WebMethod | Applies only to a Method and specifies that the method is exported as a web method. This applies only to a Class that implements a Web Service.
Overridable | Applies only to an Instance Method and specifies that the Method may be overridden by a Method in a higher Class. See below.
Override | Applies only to an Instance Method and specifies that the Method overrides the corresponding Overridable Method defined in the Base Class. See below.

Overridable/Override

Normally, a Method defined in a higher Class replaces a Method of the same name that is defined in its Base Class, but only for calls made from above or within the higher Class itself (or an Instance of the higher Class). The base method remains available in the Base Class and is invoked by a reference to it from within the Base Class.

However, a Method declared as being Overridable is replaced in situ (i.e. within its own Class) by a Method of the same name in a higher Class if that Method is itself declared with the Override keyword. For further information, see Superseding Base Class Methods.

Nested Classes

The :Access statement is also used to control the visibility of one Class that is defined within another (a nested Class). A Nested Class may be either Private or Public. Note that the :Access Statement must precede the definition of any Class contents.

A Public Nested Class is visible from outside its containing Class and may be used directly in its own right, whereas a Private Nested Class is not and may only be used by code inside the containing Class.

However, methods in the containing Class may return instances of Private Nested Classes and in that way expose them to the calling environment.

WebMethod

Note that :Access WebMethod is equivalent to:

:Access Public
:Attribute System.Web.Services.WebMethodAttribute


:Implements Statement

The :Implements statement identifies the function to be one of the following types.

:Implements Constructor <[:Base expr]>
:Implements Destructor
:Implements Method <InterfaceName.MethodName>
:Implements Trigger <name1><,name2,name3,...>
:Implements Trigger *
Element | Description
Constructor | Specifies that the function is a Class Constructor.
:Base expr | Specifies that the Base Constructor be called with the result of the expression expr as its argument.
Destructor | Specifies that the function is a Class Destructor.
Method | Specifies that the function implements the Method MethodName whose syntax is specified by Interface InterfaceName.
Trigger | Identifies the function as a Trigger Function which is activated by changes to variable name1, name2, and so forth. Trigger * specifies a Global Trigger that is activated by the assignment of any global variable in the same namespace.


Field Statement

:Field <Private|Public> <Instance|Shared> <ReadOnly>...
       ... FieldName <← expr>

A :Field statement is a single statement whose elements are as follows:

Element | Description
Private|Public | Specifies whether or not the Field is accessible from outside the Class or an Instance of the Class. The default is Private.
Instance|Shared | Specifies if there is a separate value of the Field in each Instance of the Class, or if there is only a single value that is shared between all Instances.
ReadOnly | If specified, this keyword prevents the value in the Field from being changed after initialisation.
FieldName | Specifies the name of the Field (mandatory).
← expr | Specifies an initial value for the Field.

Examples:

The following statement defines a Field called Name. It is (by default), an Instance Field so every Instance of the Class has a separate value. It is a Public Field and so may be accessed (set or retrieved) from outside an Instance.

:Field Public Name

The following statement defines a Field called Months.

:Field Shared ReadOnly Months←12↑(⎕NEW DateTimeFormatInfo.AbbreviatedMonthNames

Months is a Shared Field so there is just a single value that is the same for every Instance of the Class. It is (by default), a Private Field and may only be referenced by code running in an Instance or in the Class itself. Furthermore, it is ReadOnly and may not be altered after initialisation. Its initial value is calculated by an expression that obtains the short month names that are appropriate for the current locale using the .NET Type DateTimeFormatInfo.

Notes

Note that Fields are initialised when a Class script is fixed by the editor or by ⎕FIX. If the evaluation of expr causes an error (for example, a VALUE ERROR), an appropriate message will be displayed in the Status Window and ⎕FIX will fail with a DOMAIN ERROR. Note that a ReadOnly Field may only be assigned a value by its :Field statement.

In the second example above, the expression will only succeed if ⎕USING is set to the appropriate path, in this case System.Globalization.

You may not define a Field with the name of one of the permissible keywords (such as public). In such cases the Class will not fix and an error message will be displayed in the Status Window. For example:

error AC0541: a field must have a name "    :Field Public public"


Property Section

A Property is defined by a :Property ... :EndProperty section in a Class Script. The syntax of the :Property Statement, and its optional :Access statement is as follows:

:Property <Simple|Numbered|Keyed> <Default> Name<,Name>...
:Access <Private|Public><Instance|Shared>
...
:EndProperty

Element | Description
Name | Specifies the name of the Property by which it is accessed. Additional Properties, sharing the same PropertyGet and/or PropertySet functions, and the same access behaviour may be specified by a comma-separated list of names.
Simple|Numbered|Keyed | Specifies the type of Property (see below). The default is Simple.
Default | Specifies that this Property acts as the default property for the Class when indexing is applied directly to an Instance of the Class.
Private|Public | Specifies whether or not the Property is accessible from outside the Class or an Instance of the Class. The default is Private.
Instance|Shared | Specifies if there is a separate value of the Property in each Instance of the Class, or if there is only a single value that is shared between all Instances.

A Simple Property is one whose value is accessed (by APL) in its entirety and re-assigned (by APL) in its entirety.

A Numbered Property behaves like an array (conceptually a vector) which is only ever partially accessed and set (one element at a time) via indices.

A Keyed Property is similar to a Numbered Property except that its elements are accessed via arbitrary keys instead of indices.

Numbered and Keyed Properties are designed to allow APL to perform selections and structural operations on the Property.

Within the body of a Property Section there may be:

  • one or more :Access statements
  • a single PropertyGet function.
  • a single PropertySet function
  • a single PropertyShape function

The three functions are identified by case-independent names Get, Set and Shape.

Errors

When a Class is fixed by the Editor or by ⎕FIX, APL checks the validity of each Property section and the syntax of PropertyGet, PropertySet and PropertyShape functions within them.

  • You may not specify a name which is the same as one of the keywords.
  • There must be at least a PropertyGet, or a PropertySet or a PropertyShape function defined.
  • You may only define a PropertyShape function if the Property is Numbered.

If anything is wrong, the Class is not fixed and an error message is displayed in the Status Window. For example:

error AC0545: invalid or empty property declaration
error AC0595: this property type should not implement a "shape" function


PropertyArguments Class

Where appropriate, APL supplies the PropertyGet and PropertySet functions with an argument that is an instance of the internal class PropertyArguments.

PropertyArguments has just 3 read-only Fields which are as follows:

Name | The name of the property. This is useful when one function is handling several properties.
NewValue | Array containing the new value for the Property or for selected element(s) of the property as specified by Indexers.
IndexersSpecified | A Boolean vector that identifies which dimensions of the Property are to be referenced or assigned.
Indexers | A vector that identifies the elements of the Property that are to be referenced or assigned.


Note:

PropertyGet Function R←Get {ipa}

The name of the PropertyGet function must be Get, but is case-independent. For example, get, Get, gEt and GET are all valid names for the PropertyGet function.

The PropertyGet function must be result returning. For a Simple Property, it may be monadic or niladic. For a Numbered or Keyed Property it must be monadic.

The result R may be any array. However, for a Keyed Property, R must conform to the rank and shape specified by ipa.Indexers or be scalar.

If monadic, ipa is an instance of the internal class PropertyArguments.

In all cases, ipa.Name contains the name of the Property being referenced and NewValue is undefined (VALUE ERROR).

If the Property is Simple, ipa.Indexers is undefined (VALUE ERROR).

If the Property is Numbered, ipa.Indexers is an integer vector of the same length as the rank of the property (as implied by the result of the Shape function) that identifies a single element of the Property whose value is to be obtained. In this case, R must be scalar.

If the Property is Keyed, ipa.IndexersSpecified is a Boolean vector with the same length as the rank of the property (as implied by the result of the Shape function). A value of 1 means that an indexing array for the corresponding dimension of the Property was specified, while a value of 0 means that the corresponding dimension was elided. ipa.Indexers is a vector of the same length containing the arrays that were specified within the square brackets in the reference expression. Specifically, ipa.Indexers will contain one fewer elements than, the number of semi-colon (;) separators. If any index was elided, the corresponding element of ipa.Indexers is ⎕NULL.

Note:

  • It is not possible to predict the number of times that a PropertyGet, PropertySet or PropertyShape function will be called by a particular APL expression, as this depends upon how that expression is implemented internally. You should therefore not rely on the number of times that a Get, Set or Shape function is called, and none should have any side effects on any other APL object


Note:

PropertySet Function Set ipa

The name of the PropertySet function must be Set, but is case-independent. For example, set, Set, sEt and SET are all valid names for the PropertySet function.

The PropertySet function must be monadic and may not return a result.

ipa is an instance of the internal class PropertyArguments.

In all cases, ipa.Name contains the name of the Property being referenced and NewValue contains the new value(s) for the element(s) of the Property being assigned.

If the Property is Simple, ipa.Indexers is undefined (VALUE ERROR).

If the Property is Numbered, ipa.Indexers is an integer vector of the same length as the rank of the property (as implied by the result of the Shape function) that identifies a single element of the Property whose value is to be set.

If the Property is Keyed, ipa.IndexersSpecified is a Boolean vector with the same length as the rank of the property (as implied by the result of the Shape function). A value of 1 means that an indexing array for the corresponding dimension of the Property was specified, while a value of 0 means that the corresponding dimension was elided.ipa.Indexers is a vector containing the arrays that were specified within the square brackets in the assignment expression. Specifically, ipa.Indexers will contain one fewer elements than, the number of semi-colon (;) separators. If any index was elided, the corresponding element of ipa.Indexers is ⎕NULL. However, if the Keyed Property is being assigned in its entirety, without square-bracket indexing, ipa.Indexers is undefined (VALUE ERROR).

Note:

  • It is not possible to predict the number of times that a PropertyGet, PropertySet or PropertyShape function will be called by a particular APL expression, as this depends upon how that expression is implemented internally. You should therefore not rely on the number of times that a Get, Set or Shape function is called, and none should have any side effects on any other APL object


PropertyShape Function R←Shape {ipa}

The name of the PropertyShape function must be Shape, but is case-independent. For example, shape, Shape, sHape and SHAPE are all valid names for the PropertyShape function.

A PropertyShape function is only called if the Property is a Numbered Property.

The PropertyShape function must be niladic or monadic and must return a result.

If monadic, ipa is an instance of the internal class PropertyArguments. ipa.Name contains the name of the Property being referenced and NewValue and Indexers are undefined (VALUE ERROR).

The result R must be an integer vector or scalar that specifies the rank of the Property. Each element of R specifies the length of the corresponding dimension of the Property. Otherwise, the reference or assignment to the Property will fail with DOMAIN ERROR.

Note that the result R is used by APL to check that the number of indices corresponds to the rank of the Property and that the indices are within the bounds of its dimensions. If not, the reference or assignment to the Property will fail with RANK ERROR or LENGTH ERROR.

Note:

  • It is not possible to predict the number of times that a PropertyGet, PropertySet or PropertyShape function will be called by a particular APL expression, as this depends upon how that expression is implemented internally. You should therefore not rely on the number of times that a Get, Set or Shape function is called, and none should have any side effects on any other APL object


Introduction

Most languages store programs and data separately. APL is unusual in that it allows you to store programs and data together in a workspace.

This can be inefficient if your dataset gets very large; when your workspace is loaded, you are loading ALL of your data, whether you need it or not.

It also makes it difficult for other users to access your data, particularly if you want them to be able to update it.

In these circumstances, you must extract your data from your workspace, and write it to a file on disk, thus separating your data from your program. There are many different kinds of file format. This section is concerned with the APL Component File system which preserves the idea that your data consists of APL objects; hence you can only access this type of file from within APL

The Component File system has a set of system functions through which you access the file. Although this means that you have to learn a whole new set of functions in order to use files, you will find that they provide you with a very powerful mechanism to control access to your data.


Component Files

Overview

A component file is a data file maintained by Dyalog APL. It contains a series of APL arrays known as components which are accessed by reference to their relative position or component number within the file. Component files are just like other data files and there are no special restrictions imposed on names or sizes.

A set of system functions is supplied to perform a range of file operations. These provide facilities to create or delete files, and to read and write components. Facilities are also provided for multi-user access, including the capability to determine who may do what, and file locking for concurrent updates.

Tying and Untying Files

To access an existing component file it must be tied, i.e. opened for use. The tie may be exclusive (single-user access) or shared (multi-user access). A file is untied, i.e. closed, using ⎕FUNTIE or on terminating Dyalog APL. File ties survive )LOAD, ⎕LOAD and )CLEAR operations.

Tie Numbers

A file is tied by associating a file name with a tie number. Tie numbers are integers in the range 1 - 2147483647 and, you can supply one explicitly, or have the interpreter allocate the next available one by specifying 0. The system functions which tie files return the tie number as a "shy" result.

Creating and Removing Files

A component file is created using ⎕FCREATE which automatically ties the file for exclusive use. A newly created file is empty, i.e. contains 0 components. A file is removed with ⎕FERASE, although it must be exclusively tied to do so.

Adding and Removing Components

Components are added to a file using ⎕FAPPEND and removed using ⎕FDROP. Component numbers are allocated consecutively starting at 1. Thus a new component added by ⎕FAPPEND is given a component number which is one greater than that of the last component in the file. Components may be removed from the beginning or end of the file, but not from the middle. Component numbers are therefore contiguous.

Reading and Writing Components

Components are read using ⎕FREAD and overwritten using ⎕FREPLACE. There are no restrictions on the size or type of array which may replace an existing component. Components are accessed by component number.

Component Information

In addition to the data held in a component, the user ID that wrote it and the time at which it was written is also recorded.

Multi-User Access

⎕FSTIE ties a file for shared (i.e. multi-user) access. This kind of access would be appropriate for a multi-user UNIX system, a network of single user PCs, or multiple APL tasks under Microsoft Windows.

⎕FHOLD provides the means for the user to temporarily prevent other co-operating users from accessing one or more files. This is necessary to allow a single logical update involving more than one component, and perhaps more than one file, to be completed without interference from another user. ⎕FHOLD is applicable to External Variables as well as Component Files

File Access Control

There are two levels of file access control. As a regular file, the operating system read/write controls for owner and other users apply. In addition, Dyalog manages its own access controls using the access matrix. This is an integer matrix with 3 columns and any number of rows. Column 1 contains user numbers, column 2 an encoding of permitted file operations, and column 3 passnumbers. Each row specifies which file operations may be performed by which user(s) with which passnumber. A value of 0 in column 1 specifies all users. A value of ¯1 in column 2 specifies all file operations. A value of 0 in column 3 specifies no passnumber. If any row of the access matrix contains (0 ¯1 0) it specifies that all users may perform all file operations with no passnumber.

User Number

Under Windows, this is a number which is defined by the aplnid parameter. If you intend to use Dyalog's access matrix to control file access in a multi-user environment, it is desirable to allocate to each user, a distinct user number. However, if you intend to rely on underlying operating system controls, allocating a user number of 0 (the default installation value) to everyone is more appropriate. Under non-Windows platforms the User Number is set to be the effective user-id of the APL process and cannot be altered. In both cases, a user number of 0 causes APL to circumvent the access matrix mechanism described below.

Permission Code

This is an integer representation of a Boolean mask. Each bit in the mask indicates whether or not a particular file operation is permitted as follows:

┌──┬──┬──┬──┬──┬──┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ Bit No.
│15│14│13│12│11│10│9│8│7│6│5│4│3│2│1│
└──┴──┴──┴──┴──┴──┴─┴─┴─┴─┴─┴─┴─┴─┴─┘  File      Access
  ↑  ↑  ↑  ↑  ↑  ↑   ↑   ↑ ↑ ↑ ↑ ↑ ↑   Operation   Code
  │  │  │  │  │  │   │   │ │ │ │ │ │
  │  │  │  │  │  │   │   │ │ │ │ │ └── ⎕FREAD         1
  │  │  │  │  │  │   │   │ │ │ │ └──── ⎕FTIE          2
  │  │  │  │  │  │   │   │ │ │ └────── ⎕FERASE        4
  │  │  │  │  │  │   │   │ │ └──────── ⎕FAPPEND       8
  │  │  │  │  │  │   │   │ └────────── ⎕FREPLACE     16
  │  │  │  │  │  │   │   └──────────── ⎕FDROP        32
  │  │  │  │  │  │   │
  │  │  │  │  │  │   └──────────────── ⎕FRENAME     128
  │  │  │  │  │  │
  │  │  │  │  │  └──────────────────── ⎕FRDCI       512
  │  │  │  │  └─────────────────────── ⎕FRESIZE    1024
  │  │  │  └────────────────────────── ⎕FHOLD      2048
  │  │  └───────────────────────────── ⎕FRDAC      4096
  │  └──────────────────────────────── ⎕FSTAC      8192
  └─────────────────────────────────── ⎕FHIST     16384

For example, if bits 1, 4 and 6 are set and all other relevant bits are zero only ⎕FREAD, ⎕FAPPEND and ⎕FDROP are permitted. A convenient way to set up the mask is to sum the access codes associated with each operation.

For example, the value 41 (1+8+32) authorises ⎕FREAD, ⎕FAPPEND and ⎕FDROP. A value of ¯1 (all bits set) permits all operations. Thus by subtracting the access codes of operations to be forbidden, it is possible to permit all but certain types of access. For example, a value of ¯133 (¯1- 4+128) permits all operations except ⎕FERASE and ⎕FRENAME. Note that the value of unused bits is ignored. Any non-zero permission code allows ⎕FSTIE and ⎕FSIZE. ⎕FCREATE, ⎕FUNTIE, ⎕FLIB, ⎕FNAMES and ⎕FNUMS are not subject to access control. Passnumbers may also be used to establish different levels of access for the same user.

When the user attempts to tie a file using ⎕FTIE or ⎕FSTIE a row of the access matrix is selected to control this and subsequent operations.

If the user is the owner, and the owner's user ID does not appear in the access matrix, the value (⎕AI[1] ¯1 0) is conceptually appended to the access matrix. This ensures that the owner has full access rights unless they are explicitly restricted.

The chosen row is the first row in which the value in column 1 of the access matrix matches the user ID and the value in column 3 matches the supplied passnumber which is taken to be zero if omitted.

If there is no match of user ID and passnumber in the access matrix (including implicitly added rows) then no access is granted and the tie fails with a FILE ACCESS ERROR.

Once the applicable row of the access matrix is selected, it is used to verify all subsequent file operations. The passnumber used to tie the file MUST be used for every subsequent operation. Secondly, the appropriate bit in the permission code corresponding to the file operation in question must be set. If either of these conditions is broken, the operation will fail with FILE ACCESS ERROR.

If the access matrix is changed while a user has the file tied, the change takes immediate effect. When the user next attempts to access the file, the applicable row in the access matrix will be reselected subject to the supplied passnumber being the same as that used to tie the file. If access with that password is rescinded the operation will fail with FILE ACCESS ERROR.

When a file is created using ⎕FCREATE, the access matrix is empty. At this stage, the owner has full access with passnumber 0, but no access with a non-zero passnumber. Other users have no access permissions. Thus only the owner may initialise the access matrix.

User 0

If a user has an aplnid of 0, the access matrix and supplied passnumbers are ignored. This user is granted full and unrestricted access rights to all component files, subject only to underlying operating system restrictions.

General File Operations

⎕FLIB gives a list of component files in a given directory. ⎕FNAMES and ⎕FNUMS give a list of the names and tie numbers of tied files. These general operations which apply to more than one file are not subject to access controls.

Component File System Functions

See Language Reference for full details of the syntax of these system functions.

General
⎕FAVAIL | Report file system availability
File Operations
⎕FCREATE | Create a file
⎕FTIE | Tie an existing file (exclusive)
⎕FSTIE | Tie an existing file (shared)
⎕FUNTIE | Untie file(s)
⎕FCOPY | Copy a file
⎕FERASE | Erase a file
⎕FRENAME | Rename a file
File information
⎕FHIST | Report file events
⎕FNUMS | Report tie numbers of tied files
⎕FNAMES | Report names of tied files
⎕FLIB | Report names of component files
⎕FPROPS | Report file properties
⎕FSIZE | Report size of file
Writing to the file
⎕FAPPEND | Append a component to the file
⎕FREPLACE | Replace an existing component
Reading from a file
⎕FREAD | Read one or more components
⎕FRDCI | Read component information
Manipulating a file
⎕FDROP | Drop a block of components
⎕FRESIZE | Change file size (forces a compaction)
⎕FCHK | Check and repair a file
Access manipulation
⎕FSTAC | Set file access matrix
⎕FRDAC | Read file access matrix
Control multi-user access
⎕FHOLD | Hold file(s) - see later section for details

Using the Component File System

Let us suppose that you have written an APL system that builds a personnel database, containing the name, age and place of birth of each employee. Let us assume that you have created a variable DATA, which is a nested vector with each element containing a person's name, age and place of birth:

      DISPLAY 2↑DATA
.→-------------------------------------------------------.
| .→----------------------. .→-------------------------. |
| | .→-------.    .→----. | | .→------.    .→--------. | |
| | |Jonathan| 42 |Wales| | | |Pauline| 21 |Isleworth| | |
| | '--------'    '-----' | | '-------'    '---------' | |
| '∊----------------------' '∊-------------------------' |
'∊-------------------------------------------------------'

Then the following APL expressions can be used to access the database:

Example 1:

Show record 2

      DISPLAY 2⊃DATA
.→-------------------------.
| .→------.    .→--------. |
| |Pauline| 21 |Isleworth| |
| '-------'    '---------' |
'∊-------------------------'

Example 2:

How many people in the database?

           ⍴DATA
     123

Example 3:

Update Pauline's age

           (2 2⊃DATA)←16

Example 4:

Add a new record to the database

      DATA ,← ⊂'Maurice' 18 'London'

Now let's build a component file to hold our personnel database.

Create a new file, giving the file name, and the number you wish to use to identify it (the file tie number):

      'COMPFILE' ⎕FCREATE 1

If the file already exists, or you have already used this tie number, then APL will respond with the appropriate error message.

Now write the data to the file. We could write a function that loops to do this, but it is neater to take advantage of the fact that our data is a nested vector, and use each (¨).

      DATA ⎕FAPPEND¨ 1

Now we'll try our previous examples using this file.

Example 1:

Show record 2

      DISPLAY ⎕FREAD 1 2
.→-------------------------.
| .→------.    .→--------. |
| |Pauline| 21 |Isleworth| |
| '-------'    '---------' |
'∊-------------------------'

Example 2:

How many people in our database?

      ⎕FSIZE 1        ⍝ First component, next
1 125 10324 4294967295  ⍝ component, file size,
                        ⍝ maximum file size
      ¯1+2⊃⎕FSIZE 1   ⍝ Number of data items

The fourth element of ⎕FSIZE indicates the file size limit. Dyalog APL does not impose a file size limit, although your operating system may do so, but the concept is retained in order to make this version of Component Files compatible with others.

Example 3:

Update Pauline's age

        REC ← ⎕FREAD 1 2       ⍝ Read second component
        REC[2] ← 18            ⍝ Change age
        REC ⎕FREPLACE 1 2      ⍝ And replace component

Example 4:

Add a new record

       ('Janet' 25 'Basingstoke') ⎕FAPPEND 1

Example 5:

Rename our file

       'PERSONNEL' ⎕FRENAME 1

Example 6:

Tie an existing file; give file name and have the interpreter allocate the next available tie number.

       'SALARIES' ⎕FTIE 0
  2

Example 7:

Give everyone access to the PERSONNEL file

       (1 3⍴0 ¯1 0)⎕FSTAC 1

Example 8:

Set different permissions on SALARIES.

       AM ← 1 3⍴1 ¯1 0    ⍝ Owner ID 1 has full access
       AM⍪← 102 1 0       ⍝ User ID 102 has READ only
       AM⍪← 210 2073 0    ⍝ User ID 210 has
                           ⍝ READ+APPEND+REPLACE+HOLD
       AM ⎕FSTAC 2        ⍝ Store access matrix

Example 9:

Report on file names and associated numbers

        ⎕FNAMES,⎕FNUMS
 PERSONNEL  1
 SALARIES   2

Example 10:

Untie all files

       ⎕FUNTIE ⎕FNUMS


Programming Techniques

Controlling Multi-User Access

Obviously, Dyalog APL contains mechanisms that prevent data getting mixed up if two users update a file at the same time. However, it is the programmer's responsibility to control the logic of multi-user updates.

For example, suppose two people are updating our database at the same time. The first checks to see if there is an entry for 'Geoff', sees that there isn't so adds a new record. Meanwhile, the second user is checking for the same thing, and so also adds a record for 'Geoff'. Each user would be running code similar to that shown below:

    ∇  UPDATE;DATA;NAMES
[1]    ⍝ Using the component file
[2]    'PERSONNEL' ⎕FSTIE 1
[3]    NAMES←⊃∘⎕FREAD ¨ 1,¨⍳¯1+2⊃⎕FSIZE 1
[4]    →END×⍳(⊂'Geoff')∊NAMES
[5]    ('Geoff' 41 'Hounslow')⎕FAPPEND 1
[6]    END:⎕FUNTIE 1
    ∇

The system function ⎕FHOLD provides the means for the user to temporarily prevent other co-operating users from accessing one or more files. This is necessary to allow a single logical update, perhaps involving more than one record or more than one file, to be completed without interference from another user.

The code above is replaced by that below:

    ∇ UPDATE;DATA;NAMES
[1] ⍝ Using the component file
[2]  'PERSONNEL' ⎕FSTIE 1
[3]  ⎕FHOLD 1
[4]  NAMES←⊃∘⎕FREAD ¨ 1,¨⍳¯1+2⊃⎕FSIZE 1
[5]  →END×⍳(⊂'Geoff')∊NAMES
[6]  ('Geoff' 41 'Hounslow')⎕FAPPEND 1
[7] END:⎕FUNTIE 1 ⋄ ⎕FHOLD ⍳0
    ∇

Successive ⎕FHOLDs on a file executed by different users are queued by Dyalog APL; once the first ⎕FHOLD is released, the next on the queue holds the file. ⎕FHOLDs are released by return to immediate execution, by ⎕FHOLD ⍬, or by erasing the external variable.

It is easy to misunderstand the effect of ⎕FHOLD. It is NOT a file locking mechanism that prevents other users from accessing the file. It only works if the tasks that wish to access the file co-operate by queuing for access by issuing ⎕FHOLDs. It would be very inefficient to issue a ⎕FHOLD on a file then allow the user to interactively edit the data with the hold in operation. What happens if he goes to lunch? Any other user who wants to access the file and cooperates by issuing a ⎕FHOLD would have to wait in the queue for 3 hours until the first user returns, finishes his update and his ⎕FHOLD is released. It is usually more efficient (as well as more friendly) to issue ⎕FHOLDs around a small piece of critical code.

Suppose we had a control file associated with our personnel data base. This control file could be an external variable, or a component file. In both cases, the concept is the same; only the commands needed to access the file are different. In this example, we will use a component file:

      'CONTROL'⎕FCREATE 1    ⍝ Create control file
      (1 3⍴0 ¯1 0) ⎕FSTAC 1  ⍝ Allow everyone access
      ⍬ ⎕FAPPEND 1           ⍝ Set component 1 to empty
      ⎕FUNTIE 1              ⍝ And untie it

Now we'll allow our man that likes long lunch breaks to edit the file, but will control the hold in a more efficient way:

     ∇  EDIT;CMP;CV
[1]   ⍝ Share-tie the control file
[2]    'CONTROL' ⎕FSTIE 1
[3]   ⍝ Share-tie the data file
[4]    'PERSONNEL' ⎕FSTIE 2
[5]   ⍝ Find out which component the user wants to edit
[6]    ASK:CMP←ASK∆WHICH∆RECORD
[7]   ⍝ Hold the control file
[8]    ⎕FHOLD 1
[9]   ⍝ Read the control vector
[10]   CV←⎕FREAD 1 1
[11]  ⍝ Make control vector as big as the data file
[12]   CV←(¯1+2⊃⎕FSIZE 2)↑CV
[13]  ⍝ Look at flag for this component
[14]   →(FREE,INUSE)[1+CMP⊃CV]
[15]  ⍝ In use - tell user and release hold
[16]  INUSE:'Record in use' ⋄ ⎕FHOLD ⍬ ⋄ →ASK
[17]  ⍝ Ok to use - flag in-use and release hold
[18]  FREE:CV[CMP]←1 ⋄ CV ⎕FREPLACE 1 1⋄ ⎕FHOLD ⍬
[19]  ⍝ Let user edit the record
[20]   EDIT∆RECORD RECORD
[21]  ⍝ When he's finished, clear the control vector
[22]   ⎕FHOLD 1
[23]  CV←⎕FREAD 1 1 ⋄CV[CMP]←0 ⋄ CV ⎕FREPLACE 1 1
[26]   ⎕FHOLD ⍬
[27]  ⍝ And repeat
[28]   →ASK
     ∇

Component 1 of our CONTROL file acts as a control vector. Its length is set equal to the number of components in the PERSONNEL file, and an element is set to 1 if a user wishes to access the corresponding data component. Only the control file is ever subject to a ⎕FHOLD, and then only for a split-second, with no user inter-action being performed whilst the hold is active.

When the first user runs the function, the relevant entry in the control vector will be set to 1. If a second user accesses the database at the same time, he will have to wait briefly whilst the control vector is updated. If he wants the same component as the first user, he will be told that it is in use, and will be given the opportunity to edit something else.

This simple mechanism allows us to lock the components of our file, rather the than entire file. You can set up more informative control vectors than the one above; for example, you could easily put the user name into the control vector and this would enable you to tell the next user who is editing the component he is interested in.


File Design

Our personnel database could be termed a record oriented system. All the information relating to one person is easily obtained, and information relating to a new person is easily added, but if we wish to find the oldest person, we have to read ALL the records in the file.

It is sometimes more useful to have separate components, perhaps stored on separate files, that hold indexes of the data fields that you may wish to search on. For example, suppose we know that we always want to access our personnel database by name. Then it would make sense to hold an index component of names:

        ⍝ Extract name field from each data record
        'PERSONNEL' ⎕FSTIE 1
        NAMES←⊃∘⎕FREAD¨1,¨⍳¯1+2⊃⎕FSIZE 2
        ⍝ Create index file, and append NAMES
        'INDEX' ⎕FCREATE 2
        NAMES ⎕FAPPEND 2

Then if we want to find Pauline's data record:

        NAMES←⎕FREAD 2,1       ⍝ Read index of names
        CMP←NAMES⍳⊂'Pauline'   ⍝ Search for Pauline
        DATA←⎕FREAD 1,CMP      ⍝ Read relevant record

There are many different ways to structure data files; you must design a structure that is the most efficient for your application.


Internal Structure

If you are going to make a lot of use of APL files in your systems, it is useful for you to have a rough idea of how Dyalog APL organises and manages the disk area used by such files.

The internal structure of external variables and component files is the same, and the examples given below apply to both.

Consider a component file with 3 components:

        'TEMP' ⎕FCREATE 1
        'One' 'Two' 'Three' ⎕FAPPEND¨1

Dyalog APL will write these components onto contiguous areas of disk:

.-.   .-.   .-.
|1|   |2|   |3|
.-----.-----.-------.
| One | Two | Three |
--------------------.

Replace the second component with something the same size:

        'Six' ⎕FREPLACE 1 2

This will fit into the area currently used by component 2.

.-.   .-.   .-.
|1|   |2|   |3|
.-----.-----.-------.
| One | Six | Three |
--------------------.

If your system uses fixed length records, then the size of your components never change, and the internal structure of the file remains static.

However, suppose we start replacing larger data objects:

        'Bigger One' ⎕FREPLACE 1 1

This will not fit into the area currently assigned to component 1, so it is appended to the end of the file. Dyalog APL maintains internal tables which contain the location of each component; hence, even though the components may not be physically stored in order, they can always be accessed in order.

      .-.   .-.     .-.
      |2|   |3|     |1|
.-----.-----.-------.------------.
|⎕⎕⎕⎕⎕| Six | Three | Bigger One |
---------------------------------.

The area that was occupied by component 1 now becomes free.

Now we'll replace component 3 with something bigger:

        'BigThree' ⎕FREPLACE 1 3

Component 3 is appended to the end of the file, and the area that was used before becomes free:

      .-.                .-.          .-.
      |2|                |1|          |3|
.-----.------------------.------------.----------.
|⎕⎕⎕⎕⎕| Six |⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕| Bigger One | BigThree |
-------------------------------------------------.

Dyalog APL keeps tables of the size and location of the free areas, as well as the actual location of your data. Now we'll replace component 2 with something bigger:

        'BigTwo' ⎕FREPLACE 1 2

Free areas are used whenever possible, and contiguous holes are amalgamated.

            .-.          .-.          .-.
            |2|          |1|          |3|
.-----------.------------.------------.----------.
|⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕|BigTwo|⎕⎕⎕⎕⎕| Bigger One | BigThree |
-------------------------------------------------.

You can see that if you are continually updating your file with larger data objects, then the file structure can become fragmented. At any one time, the disk area occupied by your file will be greater than the area necessary to hold your data. However, free areas are constantly being reused, so that the amount of unused space in the file will seldom exceed 30%.

Whenever you issue a monadic ⎕FRESIZE command on a component file, Dyalog APL COMPACTS the file; that is, it restructures it by reordering the components and by amalgamating the free areas at the end of the file. It then truncates the file and releases the disk space back to the operating system (note that some versions of UNIX do not allow the space to be released). For a large file with many components, this process may take a significant time.

Error Conditions

FILE SYSTEM NOT AVAILABLE

A FILE SYSTEM NOT AVAILABLE (Error code 28) error will be generated if the operating system returns an unexpected error when attempting to get a lock on a component file. In Windows environments this may indicate that opportunistic locks (aka oplocks) are in use; they should be disabled if Dyalog components files are being used.

FILE SYSTEM TIES USED UP

A FILE SYSTEM TIES USED UP (Error code 30) error will be generated when an attempt is made to open more component files than is possible.

FILE TIED

A FILE TIED error is reported if you attempt to tie a file which another user has exclusively tied.

Limitations

File Tie Quota

The File Tie Quota is the maximum number of files that a user may tie concurrently. Dyalog APL itself allows a maximum of 1024 under UNIX and 512 under Windows, although in either case your installation may impose a lower limit. When an attempt is made to exceed this limit, the report FILE TIE QUOTA (Error code 31) is given. This error will also be generated if an attempt is made to exceed the maximum number of open files that is imposed by the operating system.

File Name Quota

Dyalog APL records the names of each user's tied files in a buffer of 40960 bytes. When this buffer is full, the report FILE NAME QUOTA USED UP (Error code 32) will be given. This is only likely to occur if long pathnames are used to identify files.


The Effect of Buffering

Disk drives are fairly slow devices, so most operating systems take advantage of a facility called buffering. This is shown in simple terms below:

.------------------.
| Operating System |   .--------.    .---------.
| instruction to   |-->| BUFFER |--->| File on |
| write large data |   ---------.    |  disk   |
| object to a file |                 ----------.
-------------------.

When you issue a write to a disk area, the data is not necessarily sent straight to the disk. Sometimes it is written to an internal buffer (or cache), which is usually held in (fast) main memory. When the buffer is full, the contents are passed to the disk. This means that at any one time, you could have data in the buffer, as well as on the disk. If your machine goes down whilst in this state, you could have a partially updated file on the disk. In these circumstances, the operating system generally recovers your file automatically.

If this facility is exploited, it offers very fast file updating. For systems that are I/O bound, this is a very important consideration. However, the disadvantage is that whilst it may appear that a write operation has completed successfully, part of the data may still be residing in the buffer, waiting to be flushed out to the disk. It is usually possible to force the buffer to empty; see your operating system manuals for details (UNIX automatically invokes the sync() command every few seconds to flush its internal buffers).

Dyalog APL exploits this facility, employing buffers internal to APL as well as making use of the system buffers. Of course, these techniques cannot be used when the file is shared with other users; obviously, the updates must be written immediately to the disk. However, if the file is exclusively tied, then several layers of buffers are employed to ensure that file access is as fast as possible.

You can ensure that the contents of all internal buffers are flushed to disk by issuing ⎕FUNTIE ⍬ at any time.


Integrity and Security

The structure of component files, the asynchronous nature of the buffering performed by APL, by the Operating System, and by the external device sub-system, introduces the potential danger that a component file might become damaged. To prevent this happening, the component file system includes optional journaling and check-sum features. These are optional because the additional security these features provide comes at the cost of reduced performance. You can choose the level of security that is appropriate for your application.

When journaling is enabled (see ⎕FPROPS), files are updated using a journal which effectively prevents system or network failures from causing file damage.

Additional security is provided by the check sum facility which enables component files to be repaired using the system function ⎕FCHK. See Language Reference Guide: File Check and Repair.

Level 1 journaling protects a component file from damage caused by an abnormal termination of the APL process. This could occur if the process is deliberately or accidentally terminated by the user or by the Operating System, or by an error in Dyalog APL.

Level 2 journaling provides protection not just against the possibility that the APL process terminates abnormally, but that the Operating System itself fails. However, a damaged component file must be explicitly repaired using the system function ⎕FCHK which will repair any damaged components by rolling them back to their previous states.

Level 3 provides the same level of protection as Level 2, but following the abnormal termination of either APL or the Operating System, the rollback of an incomplete update will be automatic and no explicit repair will be needed.

Higher levels of Journaling inevitably reduce the performance of component file updates.

For further information, see ⎕FPROPS and ⎕FCHK.

Operating System Commands

APL files are treated as normal data files by the operating system, and may be manipulated by any of the standard operating system commands.

Do not use operating system commands to copy, erase or move component files that are tied and in use by an APL session.


Standard Error Action

The standard system action in the event of an error or interrupt whilst executing an expression is to suspend execution and display an error report. If necessary, the state indicator is cut back to a statement such that there is no halted locked function visible in the state indicator.

The error report consists of up to three lines

  1. The error message, preceded by the symbol ⍎ if the error occurred while evaluating the Execute function.
  2. The statement in which the error occurred (or expression being evaluated by the Execute function), preceded by the name of the function and line number where execution is suspended unless the state indicator has been cut back to immediate execution mode. If the state indicator has been cut back because of a locked function in execution, the displayed statement is that from which the locked function was invoked.
  3. The symbol ^ under the last referenced symbol or name when the error occurred. All code to the right of the ^ symbol in the expression will have been evaluated.

Examples

      X PLUS U
VALUE ERROR
      X PLUS U
             ^
      FOO
INDEX ERROR
FOO[2] X←X+A[I]
           ^
      CALC
⍎DOMAIN ERROR
CALC[5] ÷0
        ^


Error Trapping

Error Trapping Concepts

The purpose of this section is to show some of the ways in which the ideas of error trapping can be used to great effect to change the flow of control in a system.

First, we must have an idea of what is meant by error trapping. We are all used to entering some duff APL code, and seeing a (sometimes) rather obscure, esoteric error message echoed back:

         10÷0
   DOMAIN ERROR
         10÷0
        ^

This message is ideal for the APL programmer, but not so for the end user. We need a way to bypass the default action of APL, so that we can take an action of our own, thereby offering the end user a more meaningful message.

Every error message reported by Dyalog APL has a corresponding error number (for a list of error codes and message, see ⎕TRAP, Language Reference). Many of these error numbers plus messages are common across all versions of APL. We can see that the code for DOMAIN ERROR is 11, whilst LENGTH ERROR has code 5.

Dyalog APL provides two distinct but related mechanisms for the trapping and control of errors. The first is based on the control structure :Trap ... :EndTrap, and the second, on the system variable ⎕TRAP. The control structure is easier to administer and so is recommended for normal use, while the system variable provides slightly finer control and may be necessary for specialist applications.

Last Error number and Diagnostic Message

Dyalog APL keeps a note of the last error that occurred, and provides this information through system functions: ⎕EN, ⎕EM and ⎕DM.

         10÷0
   DOMAIN ERROR
         10÷0
        ^

Error Number for last occurring error:

         ⎕EN
   11

Error Message associated with code 11:

         ⎕EM 11
   DOMAIN ERROR

⎕DM (Diagnostic Message) is a 3 element nested vector containing error message, expression and caret:

         ⎕DM
    DOMAIN ERROR         10÷0        ^

Use function DISPLAY to show structure:

         DISPLAY ⎕DM
   ┌→─────────────────────────────────────┐
   │ ┌→───────────┐ ┌→─────────┐ ┌→─────┐ │
   │ │DOMAIN ERROR│ │      10÷0│ │     ∧│ │
   │ └────────────┘ └──────────┘ └──────┘ │
   └∊─────────────────────────────────────┘

Mix (↑) of this vector produces a matrix that displays the same as the error message produced by APL:

         ↑⎕DM
    DOMAIN ERROR
         10÷0
        ^

Error Trapping Control Structure

You can embed a number of lines of code in a :Trap control structure within a defined function.

   [1]   ...
   [2]   :Trap 0
   [3]       ...
   [4]       ...
   [5]   :EndTrap
   [6]   ...

Now, whenever any error occurs in one of the enclosed lines, or in a function called from one of the lines, processing stops immediately and control is transferred to the line following the :EndTrap. The 0 argument to :Trap, in this case represents any error. To trap only specific errors, you could use a vector of error numbers:

   [2]   :Trap 11 2 3

Notice that in this case, no extra lines are executed after an error. Control is passed to line [6] either when an error has occurred, or if all the lines have been executed without error. If you want to execute some code only after an error, you could re-code the example like this:

   [1]   ...
   [2]   :Trap 0
   [3]       ...
   [4]       ...
   [5]   :Else
   [6]       ...
   [7]       ...
   [8]   :EndTrap
   [9]   ...

Now, if an error occurs in lines [3-4], (or in a function called from those lines), control will be passed immediately to the line following the :Else statement. On the other hand, if all the lines between :Trap and :Else complete successfully, control will pass out of the control structure to (in this case) line [9].

The final refinement is that specific error cases can be accommodated using :Case[List] constructs in the same manner as the :Select control structure.

   [1]   :Trap 17+⍳21            ⍝ Component file errors.
   [2]       tie←name ⎕ftie 0    ⍝ Try to tie file
   [3]       'OK'
   [4]   :Case 22
   [5]       'Can''t find ',name
   [6]   :CaseList 25+⍳13
   [7]       'Resource Problem'
   [8]   :Else
   [9]       'Unexpected Problem'
   [10]  :EndTrap

Note that :Trap can be used in conjunction with ⎕SIGNAL described below.

Traps can be nested. In the following example, code in the inner trap structure attempts to tie a component file, and if unsuccessful, tries to create one. In either case, the tie number is then passed to function ProcessFile. If an error other than 22 (FILE NAME ERROR) occurs in the inner trap structure, or an error occurs in function ProcessFile (or any of its called function), control passes to line immediately to line [9].

   [1]   :Trap 0
   [2]       :Trap 22
   [3]           tie←name ⎕ftie 0
   [4]       :Else
   [5]           tie←name ⎕fcreate 0
   [6]       :EndTrap
   [7]       ProcessFile tie
   [8]   :Else
   [9]       'Unexpected Error'
   [10]  :EndTrap

Trap System Variable: ⎕TRAP

The second way of trapping errors is to use the system variable: ⎕TRAP.

⎕TRAP, can be assigned a nested vector of trap specifications. Each trap specification is itself a nested vector, of length 3, with each element defined as:

list of error numbers | The error numbers we are interested in.
action code | Either 'E' (Execute) or 'C' (Cut Back). There are others, but they are seldom used.
action to be taken | APL expression, usually a branch statement or a call to an APL function.

So a single trap specification may be set up as:

         ⎕TRAP←5 'E' 'ACTION1'

and a multiple trap specification as:

         ⎕TRAP←(5 'E' 'ACTION1')((1 2 3) 'C' 'ACTION2')

The action code E tells APL that you want your action to be taken in the function in which the error occurred, whereas the code C indicates that you want your action to be taken in the function where the ⎕TRAP was localised. If necessary, APL must first travel back up the state indicator (cut-back) until it reaches that function.


Error Trapping Examples

Example Traps

Dividing by Zero

Let's try setting a ⎕TRAP on DOMAIN ERROR:

         MSG←'''Please give a non-zero right arg'''
         ⎕TRAP←11 'E' MSG

When we enter:

         10÷0

APL executes the expression, and notes that it causes an error number 11. Before issuing the standard error, it scans its ⎕TRAP table, to see if you were interested enough in that error to set a trap; you were, so APL executes the action specified by you:

         10÷0
   Please give non-zero right arg

Let's reset our ⎕TRAP:

         ⎕TRAP←0⍴⎕TRAP        ⍝ No traps now set

and write a defined function to take the place of the primitive function ÷:

       ∇ R←A DIV B
   [1]   R←A÷B
   [2] ∇

Then run it:

         10 DIV 0
   DOMAIN ERROR
         DIV[1] R←A÷B
                ^

Let's edit our function, and include a localised ⎕TRAP:

       ∇ R←A DIV B;⎕TRAP
   [1] ⍝ Set the trap
   [2]   ⎕TRAP←11 'E' '→ERR1'
   [3] ⍝ Do the work; if it results in error 11,
   [4] ⍝ execute the trap
   [5]   R←A÷B
   [6] ⍝ All OK if we got to here, so exit
   [7]   →0
   [8] ⍝ Will get here only if error 11 occurred
   [9] ERR1:'Please give a non-zero right arg'
       ∇

Running the function with good and bad arguments has the desired effect:

         10 DIV 2
   5
         10 DIV 0
   Please give a non-zero right arg

⎕TRAP is a variable like any other, and since it is localised in DIV, it is only effective in DIV and any other functions that may be called by DIV. So

        10÷0
   DOMAIN ERROR
        10÷0
       ^

still gives an error, since there is no trap set in the global environment.

Other Errors

What happens to our function if we run it with other duff arguments:

         1 2 3 DIV 4 5
   LENGTH ERROR
   DIV [4] R←A÷B
            ^

Here is an error that we have taken no account of.

Change DIV to take this new error into account:

       ∇ R←A DIV B;⎕TRAP
  [1]  ⍝ Set the trap
  [2]    ⎕TRAP←(11 'E' '→ERR1')(5 'E' '→ERR2')
  [3]  ⍝ Do the work; if it results in error 11,
  [4]  ⍝ execute the trap
  [5]    R←A ÷ B
  [6]  ⍝ All OK if we got to here, so exit
  [7]    →0
  [8]  ⍝ Will get here only if error 11 occurred
  [9]  ERR1:'Please give a non-zero right arg'⋄→0
  [10] ⍝ Will get here only if error 5 occurred
  [11] ERR2:'Arguments must be same length'
       ∇
         )RESET
         1 2 3 DIV 4 5
   Arguments must be the same length

But here's yet another problem that we didn't think of:

        (2 3⍴⍳6) DIV (2 3 4⍴⍳24)
   RANK ERROR
   DIV [4] R←A÷B
            ^

Global Traps

Often when we are writing a system, we can't think of everything that may go wrong ahead of time; so we need a way of catching "everything else that I may not have thought of". The error number used for "everything else" is zero:

         )RESET

Set a global trap:

         ⎕TRAP ← 0 'E' ' ''Invalid arguments'' '

And run the function:

         (2 3⍴⍳6) DIV (2 3 4⍴⍳24)
   Invalid arguments

In this case, when APL executed line 4 of our function DIV, it encountered an error number 4 (RANK ERROR). It searched the local trap table, found nothing relating to error 4, so searched further up the stack to see if the error was mentioned anywhere else. It found an entry with an associated Execute code, so executed the appropriate action AT THE POINT THAT THE ERROR OCCURRED. Let's see what's in the stack:

         )SI
   DIV[4]*
         ↑⎕DM
   RANK ERROR
   DIV[4] R←A÷B
           ^

So although our action has been taken, execution has stopped where it normally would after a RANK ERROR.

Dangers

We must be careful when we set global traps; let's call the non-existent function BUG whenever we get an unexpected error:

         )RESET
         ⎕TRAP ← 0 'E' 'BUG'
         (2 3⍴⍳6) DIV (2 3 4⍴⍳24)

Nothing happens, since APL traps a RANK ERROR on line 4 of DIV, so executes the trap statement, which causes a VALUE ERROR, which activates the trap action, which causes a VALUE ERROR, which .... etc. etc. If we had also chosen to trap on 1000 (ALL INTERRUPTS), then we'd be in trouble!

Let's define a function BUG:

       ∇ BUG
   [1] ⍝ Called whenever there is an unexpected error
   [2]   '*** UNEXPECTED ERROR OCCURRED IN: ',⊃1↓⎕SI
   [3]   '*** PLEASE CALL YOUR SYSTEM ADMINISTRATOR'
   [4]   '*** WORKSPACE SAVED AS BUG.',⊃1↓⎕SI
   [5]   ⍝ Tidy up ... reset ⎕LX, untie files ... etc
   [6]   ⎕SAVE 'BUG.',⊃1↓⎕SI
   [7]   '*** LOGGING YOU OFF THE SYSTEM'
   [8]   ⎕OFF
       ∇

Now, whenever we run our system and an unexpected error occurs, our BUG function will be called.

         10 DIV 0
   Please give non-zero right arg
         (2 3⍴⍳6) DIV (2 3 4⍴⍳12)
   *** UNEXPECTED ERROR OCCURRED IN: DIV
   *** PLEASE CALL YOUR SYSTEM ADMINISTRATOR'
   *** WORKSPACE SAVED AS BUG.DIV
   *** LOGGING YOU OFF THE SYSTEM'

The system administrator can then load BUG.DIV, look at the SI stack, discover the problem, and fix it.

Looking out for Specific Problems

In many cases, you can of course achieve the same effect of a trap by using APL code to detect the problem before it happens. Consider the function TIE∆FILE, which checks to see if a file already exists before it tries to access it:

       ∇ R←TIE∆FILE FILE;FILES
   [1]  ⍝ Tie file FILE with next available tie number
   [2]  ⍝
   [3]  ⍝ All files in my directory
   [4]    FILES←⎕FLIB 'mydir'
   [5]  ⍝ Remove trailing blanks
   [6]    FILES←dbr¨↓FILES
   [7]  ⍝ Required file in list?
   [8]    →ERR×⍳~(⊂FILE)∊FILES
   [9]  ⍝ Tie file with next number
   [10]   FILE ⎕FTIE R←1+⌈/0,⎕FNUMS
   [11] ⍝ ... and exit
   [12]    →0
   [13] ⍝ Error message
   [14]  ERR:R←'File does not exist'
       ∇

This function executes the same code whether the file name is right or wrong, and it could take a while to get all the file names in your directory. It would be neater, and more efficient to take action ONLY when the file name is wrong:

       ∇ R←TIE∆FILE FILE;⎕TRAP
   [1] ⍝ Tie file FILE with next available tie number
   [2] ⍝
   [3] ⍝ Set trap
   [4]   ⎕TRAP←22 'E' '→ERR'
   [5] ⍝ Tie file with next number
   [6]   FILE ⎕FTIE R←1+⌈/0,⎕FNUMS
   [7] ⍝ ... and exit if OK
   [8]   →0
   [9] ⍝ Error message
   [10]  ERR:R←'File does not exist'

Cut-Back versus Execute

Let us consider the effect of using Cut-Back instead of Execute. Consider the system illustrated below, in which the function REPORT gives the user the option of 4 reports to be generated:

             REPORT
                |
 .-------------------------.
 |          |      |       |
REP1      REP2    REP3    REP4
                   |
              .----.----.
              |    |    |
             ...  DIV  ...
       ∇  REPORT;OPTIONS;OPTION;⎕TRAP
   [1]  ⍝ Driver functions for report sub-system. If an
   [2]  ⍝ unexpected error occurs, take action in the
   [3]  ⍝ function where the error occurred
   [4]  ⍝
   [5]  ⍝ Set global trap
   [6]   ⎕TRAP←0 'E' 'BUG'
   [7]  ⍝ Available options
   [8]   OPTIONS←'REP1' 'REP2' 'REP3' 'REP4'
   [9]  ⍝ Ask user to choose
   [10] LOOP:→END×⍳0=⍴OPTION←MENU OPTIONS
   [11] ⍝ Execute relevant function
   [12]  ⍎OPTION
   [13] ⍝ Repeat until EXIT
   [14]  →LOOP
   [15] ⍝ Now end
   [16] END:

Suppose the user chooses REP3, and an unexpected error occurs in DIV. The good news is that the System Administrator gets a snapshot copy of the workspace that he can play about with:

         )LOAD BUG.DIV  ⍝ Load workspace
   saved ......
         )SI            ⍝ Where did error occur?
   DIV[4]*
   REP3[6]
   ⍎
   REPORT[7]

         ↑⎕DM           ⍝ What happened?
   RANK ERROR
   DIV[4] R←A÷B
           ^
         ∇              ⍝ Edit function on top of stack
   [0]R←A DIV B
   .........

The bad news is, our user is locked out of the whole system, even though it may only be REP3 that has a problem. We can get around this by making use of the CUT-BACK action code.

      ∇ REPORT;OPTIONS;OPTION;⎕TRAP
   [1] ⍝ Driver functions for report sub-system. If an
   [2] ⍝ unexpected error occurs, cut the stack back
   [3] ⍝ to this function, then take action
   [4] ⍝
   [5] ⍝ Set global trap
   [6]  ⎕TRAP←0 'C' '→ERR'
   [7] ⍝ Available options
   [8]  OPTIONS←'REP1' 'REP2' 'REP3' 'REP4'
   [9] ⍝ Ask user to choose
  [10] LOOP:→END×⍳0=⍴OPTION←MENU OPTIONS
  [11] ⍝ Execute relevant function
  [12]  ⍎OPTION
  [13] ⍝ Repeat until EXIT
  [14]  →LOOP
  [15] ⍝ Tell user ...
  [16] ERR:MESSAGE'Unexpected error in',OPTION
  [17] ⍝ ... what's happening
  [18]  MESSAGE'Removing from list'
  [19] ⍝ Remove option from list
  [20]  OPTIONS←OPTIONS~⊂OPTION
  [21] ⍝ And repeat
  [22]  →LOOP
  [23] ⍝ End
  [24] END:

Suppose the user runs this version of REPORT and chooses REP3. When the unexpected error occurs in DIV, APL will check its trap specifications, and see that the relevant trap was set in REPORT with a cut-back code. APL therefore cuts back the stack to the function in which the trap was localised, THEN takes the specified action. Looking at the SI stack above, we can see that APL must jump out of DIV, then REP3, then ⍎, to return to line 7 of REPORT; THEN it takes the specified action.


Signalling Events

It would be useful to be able to employ the idea of cutting back the stack and taking an alternative route through the code, when a condition other than an APL error occurs. To achieve this, we must be able to trap on errors other than APL errors, and we must be able to define these errors to APL. We do the former by using error codes in the range 500 to 999, and the latter by using ⎕SIGNAL.

Consider our system; ideally, when an unexpected error occurs, we want to save a snapshot copy of our workspace (execute BUG in place), then immediately jump back to REPORT and reduce our options. We can achieve this by changing our functions a little, and using ⎕SIGNAL:

      ∇ REPORT;OPTIONS;OPTION;⎕TRAP
   [1] ⍝ Driver functions for report sub-system. If an
   [2] ⍝ unexpected error occurs, make a snapshot copy
   [3] ⍝ of the workspace, then cutback the stack to
   [4] ⍝ this function, reduce the option list & resume
   [5] ⍝ Set global trap
   [6]  ⎕TRAP←(500 'C' '→ERR')(0 'E' 'BUG')
   [7] ⍝ Available options
   [8]  OPTIONS←'REP1' 'REP2' 'REP3' 'REP4'
   [9] ⍝ Ask user to choose
  [10] LOOP:→END×⍳0=⍴OPTION←MENU OPTIONS
  [11] ⍝ Execute relevant function
  [12]  ⍎OPTION
  [13] ⍝ Repeat until EXIT
  [14]  →LOOP
  [15] ⍝ Tell user ...
  [16] ERR:MESSAGE'Unexpected error in',OPTION
  [17] ⍝ ... what's happening
  [18]  MESSAGE'Removing from list'
  [19] ⍝ Remove option from list
  [20]  OPTIONS←OPTIONS~⊂OPTION
  [21] ⍝ And repeat
  [22]  →LOOP
  [23] ⍝ End
  [24] END:

       ∇ BUG
   [1] ⍝ Called whenever there is an unexpected error
   [2]   '*** UNEXPECTED ERROR OCCURRED IN: ',⊃1↓⎕SI
   [3]   '*** PLEASE CALL YOUR SYSTEM ADMINISTRATOR'
   [4]   '*** WORKSPACE SAVED AS BUG.',⊃1↓⎕SI
   [5]   ⍝ Tidy up ... reset ⎕LX, untie files ... etc
   [6]   ⎕SAVE 'BUG.',⊃1↓⎕SI
   [7]   '*** RETURNING TO DRIVER FOR RESELECTION'
   [8]   ⎕SIGNAL 500
       ∇

Now when the unexpected error occurs, the first trap specification catches it, and the BUG function is executed in place. Instead of logging the user off as before, an error 500 is signalled to APL. APL checks its trap specifications, sees that 500 has been set in REPORT as a cut-back, so cuts back to REPORT before branching to ERR.

Flow Control

Error handling, which employs a combination of all the system functions and variables described, allows us to dynamically alter the flow of control through our system, as well as allow us to handle errors gracefully. It is a very powerful facility, which is simple to use, but is often neglected.


Error Trapping

Handling Unexpected Application Errors in Windows

When running an APL application, it is possible that an unexpected error will occur.

It is advisable to set a trap at the top level of the application which traps all possible errors; in this way the programmer can cater for any errors that are not already explicitly trapped by, for example, writing information to a file, or saving the workspace. On UNIX in particular it may also be useful to call ⎕OFF with a positive integer to the right of the ⎕OFF - this is used as the exit code to APL.

It is also possible to generate an error which it is not possible to trap in APL code; examples include attempting to access the session in a runtime APL, or generating an error which causes APL to crash (for example, by the incorrect use of a shared library function).

By default in such cases, APL will pop up a message box, and cannot continue until the user selects the OK button.

It is possible to override this behaviour by setting the configuration parameter DYALOG_NOPOPUPS to 1. This will cause system popups to be suppressed; it does not suppress application popups generated by APL code.

With DYALOG_NOPOPUPS=1 APL will terminate silently, except that an aplcore file will be generated. The location of the aplcore file can be controlled by the configuration parameter APLCoreName. It may be more useful to ask the operating system to handle the unexpected termination of the APL process, for example, by bringing up a debugger, or Dr Watson. This can be achieved by setting the configuration parameter PassExceptionsToOpSys to 1. In most cases it is useful to set DYALOG_NOPOPUPS=1 too.

It is also possible to log such events to the Windows Event Log. Setting the configuration parameter DYALOG_EVENTLOGGINGLEVEL to a value greater than 0 will cause this to happen. If the configuration parameter DYALOG_EVENTLOGNAME is not set, then an event log called Dyalog will be created which can be viewed from the Windows Event Viewer. The first time that such an event occurs the following entries will be added to the Windows registry:

The key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Dyalog APL with values

Value Name | Value
Sources | Dyalog APL
MaxSize | 150000000

The key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Dyalog APL\Dyalog APL with values

Value Name | Value
EventMessageFile | DYALOG\dyalog.exe
CategoryMessageFile | DYALOG\dyalog.exe
Category Count | 5
TypesSupported | 7

where DYALOG is the directory where Dyalog APL is installed.

If DYALOG_EVENTLOGNAME is set, it should contain the name of the log to which events will be logged. For example

DYALOG_EVENTLOGNAME="MyApp Event Log"

When set, no registry entries are added by Dyalog, but if the above registry entries have been manually created, the events will be logged to an event log which has the name "MyApp Event Log". If the registry entries described above have not been created, the events will instead be logged into the Application Log, and the Event Viewer will display text similar to the following when events are viewed:

The description for Event ID ( 1 ) in Source ( MyApp Event Log ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: Syserror: 995 code: 2 Aplcore "aplcore1" has been created.


Error Messages

Introduction

The error messages reported by APL are described in this section. Standard APL messages that provide information or report error conditions are summarised in APL Error Messages and described later in alphabetical order.

APL also reports messages originating from the Operating System (WINDOWS or UNIX) which are summarised in Typical Operating System Error Messages and Windows Operating System Messages. Only those Operating System error messages that might occur through normal usage of APL operations are described here. Other messages could occur as a direct or indirect consequence of using the Operating System interface functions ⎕CMD and ⎕SH or system commands )CMD and )SH, or when a non-standard device is specified for the system functions ⎕ARBIN or ⎕ARBOUT. Refer to the WINDOWS or UNIX reference manual for further information about these messages.

Most errors may be trapped using the system variable ⎕TRAP, thereby retaining control and inhibiting the standard system action and error report. The table, Trappable Event Codes identifies the error code for trappable errors. The error code is also identified in the heading block for each error message when applicable.

See Dyalog Programming Reference Guide for a full description of the Error Handling facilities in Dyalog APL.


APL Error Messages Table

APL Errors

Table 3: APL Error Messages

 | bad ws
 | cannot create name
 | clear ws
 | copy incomplete
 | defn error
 | incorrect command
 | insufficient resources
 | is name
 | Name already exists
 | name is not a ws
 | name saved date/time
 | Namespace does not exist
 | not copied name
 | not found name
 | not saved this ws is name
 | sys error number
 | too many names
 | warning duplicate label
 | warning duplicate name
 | warning label name present in line 0
 | warning pendent operation
 | warning unmatched brackets
 | warning unmatched parentheses
 | was name
 | ws not found
 | ws too large
1 | WS FULL
2 | SYNTAX ERROR
3 | INDEX ERROR
4 | RANK ERROR
5 | LENGTH ERROR
6 | VALUE ERROR
7 | FORMAT ERROR
10 | LIMIT ERROR
11 | DOMAIN ERROR
12 | HOLD ERROR
16 | NONCE ERROR
18 | FILE TIE ERROR
19 | FILE ACCESS ERROR
20 | FILE INDEX ERROR
21 | FILE FULL
22 | FILE NAME ERROR
23 | FILE DAMAGED
24 | FILE TIED
25 | FILE TIED REMOTELY
26 | FILE SYSTEM ERROR
28 | FILE SYSTEM NOT AVAILABLE
30 | FILE SYSTEM TIES USED UP
31 | FILE TIE QUOTA USED UP
32 | FILE NAME QUOTA USED UP
34 | FILE SYSTEM NO SPACE
35 | FILE ACCESS ERROR - CONVERTING FILE
38 | FILE COMPONENT DAMAGED
52 | FIELD CONTENTS RANK ERROR
53 | FIELD CONTENTS TOO MANY COLUMNS
54 | FIELD POSITION ERROR
55 | FIELD SIZE ERROR
56 | FIELD CONTENTS/TYPE MISMATCH
57 | FIELD TYPE/BEHAVIOUR UNRECOGNISED
58 | FIELD ATTRIBUTES RANK ERROR
59 | FIELD ATTRIBUTES LENGTH ERROR
60 | FULL-SCREEN ERROR
61 | KEY CODE UNRECOGNISED
62 | KEY CODE RANK ERROR
63 | KEY CODE TYPE ERROR
70 | FORMAT FILE ACCESS ERROR
71 | FORMAT FILE ERROR
72 | NO PIPES
76 | PROCESSOR TABLE FULL
84 | TRAP ERROR
90 | EXCEPTION
92 | TRANSLATION ERROR
99 | INTERNAL ERROR
1003 | INTERRUPT
1005 | EOF INTERRUPT
1006 | TIMEOUT
1007 | RESIZE
1008 | DEADLOCK


Operating System Error Messages

Table 4 refers to UNIX Operating Systems under which the error code reported by Dyalog APL is (100 + the UNIX file error number). The text for the error message, which is obtained by calling perror(), will vary from one type of system to another.

Table 5 refers to the equivalent error messages under Windows.

Table 4: Typical Operating System Error Messages

Error Code | Report
101 | FILE ERROR 1 Not owner
102 | FILE ERROR 2 No such file or directory
103 | FILE ERROR 3 No such process
104 | FILE ERROR 4 Interrupted system call
105 | FILE ERROR 5 I/O error
106 | FILE ERROR 6 No such device or address
107 | FILE ERROR 7 Arg list too long
108 | FILE ERROR 8 Exec format error
109 | FILE ERROR 9 Bad file number
110 | FILE ERROR 10 No children
111 | FILE ERROR 11 No more processes
112 | FILE ERROR 12 Not enough code
113 | FILE ERROR 13 Permission denied
114 | FILE ERROR 14 Bad address
115 | FILE ERROR 15 Block device required
116 | FILE ERROR 16 Mount device busy
117 | FILE ERROR 17 File exists
118 | FILE ERROR 18 Cross-device link
119 | FILE ERROR 19 No such device
120 | FILE ERROR 20 Not a directory
121 | FILE ERROR 21 Is a directory
122 | FILE ERROR 22 Invalid argument
123 | FILE ERROR 23 File table overflow
124 | FILE ERROR 24 Too many open files
125 | FILE ERROR 25 Not a typewriter
126 | FILE ERROR 26 Text file busy
127 | FILE ERROR 27 File too large
128 | FILE ERROR 28 No space left on device
129 | FILE ERROR 29 Illegal seek
130 | FILE ERROR 30 Read-only file system
131 | FILE ERROR 31 Too many links
132 | FILE ERROR 32 Broken pipe
133 | FILE ERROR 33 Math argument
134 | FILE ERROR 34 Result too large


Windows Operating System Error Messages

Table 5: Windows Operating System Messages

Error Code | Report
101 | FILE ERROR 1 No such file or directory
102 | FILE ERROR 2 No such file or directory
103 | FILE ERROR 3 Exec format error
105 | FILE ERROR 5 Not enough memory
106 | FILE ERROR 6 Permission denied
107 | FILE ERROR 7 Argument list too big
108 | FILE ERROR 8 Exec format error
109 | FILE ERROR 9 Bad file number
111 | FILE ERROR 11 Too many open files
112 | FILE ERROR 12 Not enough memory
113 | FILE ERROR 13 Permission denied
114 | FILE ERROR 14 Result too large
115 | FILE ERROR 15 Resource deadlock would occur
117 | FILE ERROR 17 File exists
118 | FILE ERROR 18 Cross-device link
122 | FILE ERROR 22 Invalid argument
123 | FILE ERROR 23 File table overflow
124 | FILE ERROR 24 Too many open files
133 | FILE ERROR 33 Argument too large
134 | FILE ERROR 34 Result too large
145 | FILE ERROR 45 Resource deadlock would occur


bad ws

This report is given when an attempt is made to )COPY or )PCOPY from a file that is not a valid workspace file. Invalid files include workspaces that were created by a version of Dyalog APL later than the version currently being used.


cannot create name

This report is given when an attempt is made to )SAVE a workspace with a name that is either the name of an existing, non-workspace file, or the name of a workspace that the user does not have permission to overwrite or create.


clear ws

This message is displayed when the system command )CLEAR is issued.

Example

      )CLEAR
clear ws


copy incomplete

This report is given when an attempted )COPY or )PCOPY fails to complete. Reasons include:

  • Failure to identify the incoming file as a workspace.
  • Not enough active workspace to accommodate the copy.


DEADLOCK

DEADLOCK 1008

If two threads succeed in acquiring a hold of two different tokens, and then each asks to hold the other token, they will both stop and wait for the other to release its token. The interpreter detects such cases and issues an error (1008) DEADLOCK.


defn error

This report is given when either:

  • The system editor is invoked in order to edit a function that does not exist, or the named function is pendent or locked, or the given name is an object other than a function.
  • The system editor is invoked to define a new function whose name is already active.
  • The header line of a function is replaced or edited in definition mode with a line whose syntax is incompatible with that of a header line. The original header line is re-displayed by the system editor with the cursor placed at the end of the line. Back-spacing to the beginning of the line followed by line-feed restores the original header line.

Examples

      X←1
      ∇X
defn error

      ∇FOO[0⎕]
[0]   R←FOO
[0]   R←FOO:X
defn error
[0]   R←FOO:X

      ⎕LOCK'FOO'
      ∇FOO[⎕]
defn error


DOMAIN ERROR

DOMAIN ERROR 11

This report is given when either:

  • An argument of a function is not of the correct type or its numeric value is outside the range of permitted values or its character value does not constitute valid name(s) in the context.
  • An array operand of an operator is not an array, or it is not of the correct type, or its numeric value is outside the range of permitted values. A function operand of an operator is not one of a prescribed set of functions.
  • A value assigned to a system variable is not of the correct type, or its numeric value is outside the range of permitted values
  • The result produced by a function includes numeric elements which cannot be fully represented.

Examples

      1÷0
DOMAIN ERROR
      1÷0
      ^

      (×∘'CAT')2 4 6
DOMAIN ERROR
      (×∘'CAT')2 4 6
      ^

      ⎕IO←5
DOMAIN ERROR
      ⎕IO←5
      ^


EOF INTERRUPT

EOF INTERRUPT 1005

This report is given on encountering the end-of-file when reading input from a file. This condition could occur when an input to APL is from a file.


EXCEPTION

EXCEPTION 90

This report is given when a Microsoft .NET object throws an exception. For details see Exception System Function.


FIELD CONTENTS RANK ERROR

FIELD CONTENTS RANK ERROR 52

This report is given if a field content of rank greater than 2 is assigned to ⎕SM.


FIELD CONTENTS TOO MANY COLUMNS

FIELD CONTENTS TOO MANY COLUMNS 53

This report is given if the content of a numeric or date field assigned to ⎕SM has more than one column.


FIELD POSITION ERROR

FIELD POSITION ERROR 54

This report is given if the location of the field assigned to ⎕SM is outside the screen.


FIELD CONTENTS TYPE MISMATCH

FIELD CONTENTS TYPE MISMATCH 56

This report is given if the field contents assigned to ⎕SM does not conform with the given field type e.g. character content with numeric type.


FIELD TYPE BEHAVIOUR UNRECOGNISED

FIELD TYPE BEHAVIOUR UNRECOGNISED 57

This report is given if the field type or behaviour code assigned to ⎕SM is invalid.


FIELD ATTRIBUTES RANK ERROR

FIELD ATTRIBUTES RANK ERROR 58

This report is given if the current video attribute assigned to ⎕SM is non-scalar but its rank does not match that of the field contents.


FIELD ATTRIBUTES LENGTH ERROR

FIELD ATTRIBUTES LENGTH ERROR 59

This report is given if the current video attribute assigned to ⎕SM is non-scalar but its dimensions do not match those of the field contents.


FULL SCREEN ERROR

FULL SCREEN ERROR 60

This report is given if the required full screen capabilities are not available to ⎕SM. This report is only generated in UNIX environments.


KEY CODE UNRECOGNISED

KEY CODE UNRECOGNISED 61

This report is given if a key code supplied to ⎕SR or ⎕PFKEY is not recognised as a valid code. It will also be generated if you attempt to generate a KeyPress event with an invalid Input Code.


KEY CODE RANK ERROR

KEY CODE RANK ERROR 62

This report is given if a key code supplied to ⎕SR or ⎕PFKEY is not a scalar or a vector.


KEY CODE TYPE ERROR

KEY CODE TYPE ERROR 63

This report is given if a key code supplied to ⎕SR or ⎕PFKEY is numeric or nested; i.e. is not a valid key code.


FORMAT FILE ACCESS ERROR

FORMAT FILE ACCESS ERROR 70

This report is given if the date format file to be used by ⎕SM does not exist or cannot be accessed.


FORMAT FILE ERROR

FORMAT FILE ERROR 71

This report is given if the date format file to be used by ⎕SM is ill-formed.


FILE ACCESS ERROR

FILE ACCESS ERROR 19

This report is given when the user attempts to execute a file system function for which the user is not authorised, or has supplied the wrong passnumber. It also occurs if the file specified as the argument to ⎕FERASE or ⎕FRENAME is not exclusively tied.

Examples

      'SALES' ⎕FSTIE 1

      ⎕FRDAC 1
0 4121 0
0 4137 99

      X ⎕FREPLACE 1
FILE ACCESS ERROR
      X ⎕FREPLACE 1
      ^

      'SALES' ⎕FERASE 1
FILE ACCESS ERROR
      'SALES' ⎕FERASE 1
      ^


FILE ACCESS ERROR CONVERTING

When a new version of Dyalog APL is used, it may be that improvements to the component file system demand that the internal structure of component files must alter. This alteration is performed by the interpreter on the first occasion that the file is accessed. If the operating system file permissions deny the ability to perform such a restructure, this report is given.


FILE COMPONENT DAMAGED

FILE COMPONENT DAMAGED 38

This report is given if an attempt is made to access a component that is not a valid APL object. This will rarely occur, but may happen as a result of a previous computer system failure. Components files may be checked using ⎕FCHK. See Specifying options using Variant.


FILE DAMAGED

FILE DAMAGED 23

This report is given if a component file becomes damaged. This rarely occurs but may result from a computer system failure. Components files may be checked using ⎕FCHK. See Specifying options using Variant.


FILE FULL

FILE FULL 21

This report is given if the file operation would cause the file to exceed its file size limit.


FILE INDEX ERROR

FILE INDEX ERROR 20

This report is given when an attempt is made to reference a non-existent component.

Example

      ⎕FSIZE 1
1 21 16578 4294967295

      ⎕FREAD 1 34
FILE INDEX ERROR
      ⎕FREAD 1 34
      ^
      ⎕FDROP 1 50
FILE INDEX ERROR
      ⎕FDROP 1 50
      ^


FILE NAME ERROR

FILE NAME ERROR 22

This report is given if:

  • the user attempts to ⎕FCREATE using the name of an existing file.
  • the user attempts to ⎕FTIE or ⎕FSTIE a non-existent file, or a file that is not a component file.
  • the user attempts to ⎕FERASE a component file or ⎕NERASE a native file with a name other than the EXACT name that was used when the file was tied.


FILE NAME QUOTA USED UP

FILE NAME QUOTA USED UP 32

This report is given when the user attempts to execute a file system command that would result in the User's File Name Quota (see Dyalog Programming Reference Guide: Component Files) being exceeded.

This can occur with ⎕FCREATE, ⎕FTIE, ⎕FSTIE or ⎕FRENAME .


FILE SYSTEM ERROR

FILE SYSTEM ERROR 26

This report is given if an input/output (I/O) error occurs when reading from or writing to the host file system. Contact your System Administrator.

If this occurs when the file is being written it may become damaged; it is therefore advisable to check the integrity of the file using ⎕FCHK once the source of the I/O errors has been corrected. See Specifying options using Variant.


FILE SYSTEM NO SPACE

FILE SYSTEM NO SPACE 34

This report is given if the user attempts a file operation that cannot be completed because there is insufficient disk space.


FILE SYSTEM NOT AVAILABLE

FILE SYSTEM NOT AVAILABLE 28

This error is generated if the operation system generates an unexpected error when attempting to get a lock on a component file. See Dyalog Programming Reference Guide: Component Files for details.

This error has been seen most frequently in Windows environments which have opportunistic locks (aka oplocks) enabled, either on the server that is running Dyalog APL, or on a server which has access to the same shared drives, or the disk array which contains the shared drives. In this scenario this error is not seen consistently, but rather is interspersed with other file-related errors. Oplocks should be disabled in environments where shared component files are used.


FILE SYSTEM TIES USED UP

FILE SYSTEM TIES USED UP 30

This error is generated when the maximum number of file ties for this APL instance has been reached. See Dyalog Programming Reference Guide: Component Files for details.


FILE TIE ERROR

FILE TIE ERROR 18

This report is given when the argument to a file system function contains a file tie number used as if it were tied when it is not or as if it were available when it is already tied. It also occurs if the argument to ⎕FHOLD contains the names of non-existent external variables. It does not indicate that there is a problem with the underlying operating system's locking mechanism.

Examples

      ⎕FNAMES,⎕FNUMS
SALES  1
COSTS  2
PROFIT 3

      X ⎕FAPPEND 4
FILE TIE ERROR
      X ⎕FAPPEND 4
      ^
      'NEWSALES' ⎕FCREATE 2
FILE TIE ERROR
      'NEWSALES' ⎕FCREATE 2
      ^

      'EXTVFILE' ⎕XT'BIGMAT'
      ⎕FHOLD 'BIGMAT'
FILE TIE ERROR
      ⎕FHOLD 'BIGMAT'
      ^
      ⎕FHOLD⊂'BIGMAT'


FILE TIED

FILE TIED 24

This report is given if the user attempts to tie a file that is exclusively tied by another task, or attempts to exclusively tie a file that is already share-tied by another task.


FILE TIED REMOTELY

FILE TIED REMOTELY 25

This report is given if the user attempts to tie a file that is exclusively tied by another task, or attempts to exclusively tie a file that is already share-tied by another task; and that task is running on other than the user's processor.


FILE TIE QUOTA USED UP

FILE TIE QUOTA USED UP 31

This error is generated if an attempt is made to ⎕FTIE, ⎕FSTIE or ⎕FCREATE a file when the user already has the maximum number of files tied. (See Dyalog Programming Reference Guide:Component Files)


FORMAT ERROR

FORMAT ERROR 7

This report is given when the format specification in the left argument of system function ⎕FMT is ill-formed.

Example

      'A1,1X,I5'⎕FMT CODE NUMBER
FORMAT ERROR
      'A1,1X,I5'⎕FMT CODE NUMBER
       ^

(The correct specification should be 'A1,X1,I5' .)


HOLD ERROR

HOLD ERROR 12

This report is given when an attempt is made to save a workspace using the system function ⎕SAVE if any external arrays or component files are currently held (as a result of a prior use of the system function ⎕FHOLD).

Example

      ∇HOLD∆SAVE
[1]    ⎕FHOLD 1
[2]    ⎕SAVE 'TEST'
      ∇

      'FILE' ⎕FSTIE 1

      HOLD∆SAVE
HOLD ERROR
HOLD∆SAVE[2] ⎕SAVE'TEST'
             ^


incorrect command

This report is given when an unrecognised system command is entered.

Example

      )CLERA
incorrect command


INDEX ERROR

INDEX ERROR 3

This report is given when either:

  • The value of an index, whilst being within comparison tolerance of an integer, is outside the range of values defined by the index vector along an axis of the array being indexed. The permitted range is dependent on the value of ⎕IO.
  • The value specified for an axis, whilst being within comparison tolerance of an integer for a derived function requiring an integer axis value or a non-integer for a derived function requiring a non-integer, is outside the range of values compatible with the rank(s) of the array argument(s) of the derived function. Axis is dependent on the value of ⎕IO.

Examples

      A
1 2 3
4 5 6

      A[1;4]
INDEX ERROR
      A[1;4]
      ^

      ↑ [2]'ABC' 'DEF'
INDEX ERROR
      ↑ [2]'ABC' 'DEF'
      ^


INTERNAL ERROR

INTERNAL ERROR 99

INTERNAL ERROR indicates a severe system error from which Dyalog APL has recovered.

Should you encounter INTERNAL ERROR, Dyalog strongly recommends that you save your work(space), and report the issue.


INTERRUPT

INTERRUPT 1003

This report is given when execution is suspended by entering a hard interrupt. A hard interrupt causes execution to suspend as soon as possible without leaving the environment in a damaged state.

Example

      1 1 2 ⍉(2 100⍴⍳200)∘.|?1000⍴200

(Hard interrupt)

INTERRUPT
      1 1 2 ⍉(2 100⍴⍳200)∘.|?1000⍴200
            ^


is name

This report is given in response to the system command )WSID when used without a parameter. name is the name of the active workspace including directory references given when loaded or named. If the workspace has not been named, the system reports is CLEAR WS.

Example

      )WSID
is WS/UTILITY


LENGTH ERROR

LENGTH ERROR 5

This report is given when the shape of the arguments of a function do not conform, but the ranks do conform.

Example

      2 3+4 5 6
LENGTH ERROR
      2 3+4 5 6
      ^


LIMIT ERROR

LIMIT ERROR 10

This report is given when a system limit is exceeded. System limits are installation dependent.

Example

      (16⍴1)⍴1
LIMIT ERROR
      (16⍴1)⍴1
      ^


NONCE ERROR

NONCE ERROR 16

This report is given when a system function or piece of syntax is not currently implemented but is reserved for future use.


NO PIPES

NO PIPES 72

This message applies to the UNIX environment ONLY.

This message is given when the limit on the number of pipes communicating between tasks is exceeded. An installation-set quota is assigned for each task. An associated task may require more than one pipe. The message occurs on attempting to exceed the account's quota when either:

  • An APL session is started
  • A non-APL task is started by the system function ⎕SH
  • An external variable is used.

It is necessary to release pipes by terminating sufficient tasks before proceeding with the required activity. In practice, the error is most likely to occur when using the system function ⎕SH.

Examples

      'via' ⎕SH 'via'
NO PIPES
      'via' ⎕SH 'via'
      ^

      'EXT/ARRAY' ⎕XT 'EXVAR'
NO PIPES
      'EXT/ARRAY' ⎕XT 'EXVAR'
                  ^


name is not a ws

This report is given when the name specified as the parameter of the system commands )LOAD, )COPY or )PCOPY is a reference to an existing file or directory that is not identified as a workspace.

This will also occur if an attempt is made to )LOAD a workspace that was )SAVE’d using a later version of Dyalog APL.

Example

      )LOAD EXT\ARRAY
EXT\ARRAY is not a ws


Name already exists

This report is given when an )NS command is issued with a name which is already in use for a workspace object other than a namespace.


Namespace does not exist

This report is given when a )CS command is issued with a name which is not the name of a global namespace.


not copied name

This report is given for each object named or implied in the parameter list of the system command )PCOPY which was not copied because of an existing global referent to that name in the active workspace.

Example

      )PCOPY WS/UTILITY A FOO Z
WS/UTILITY saved Mon Nov 1 13:11:19 1993
not copied Z


not found name

This report is given when either:

  • An object named in the parameter list of the system command )ERASE is not erased because it was not found or it is not eligible to be erased.
  • An object named in the parameter list (or implied list) of names to be copied from a saved workspace for the system commands )COPY or )PCOPY is not copied because it was not found in the saved workspace.

Examples

      )ERASE ⎕IO
not found ⎕IO

      )COPY WS/UTILITY UND
WS/UTILITY saved Mon Nov 1 13:11:19 1993
not found UND


not saved this ws is name

This report is given in the following situations:

  • When the system command )SAVE is used without a name, and the workspace is not named. In this case the system reports not saved this ws is CLEAR WS.
  • When the system command )SAVE is used with a name, and that name is not the current name of the workspace, but is the name of an existing file.

In neither case is the workspace renamed.

Examples

      )CLEAR
      )SAVE
not saved this ws is CLEAR WS

      )WSID JOHND
      )SAVE
      )WSID ANDYS
      )SAVE JOHND
not saved this ws is ANDYS


PROCESSOR TABLE FULL

PROCESSOR TABLE FULL 76

This report can only occur in a UNIX environment.

This report is given when the limit on the number of processes (tasks) that the computer system can support would be exceeded. The limit is installation dependent. The report is given when an attempt is made to initiate a further process, occurring when an APL session is started.

It is necessary to wait until active processes are completed before the required task may proceed. If the condition should occur frequently, the solution is to increase the limit on the number of processes for the computer system.

Example

      'prefect' ⎕SH 'prefect'
PROCESSOR TABLE FULL
      'prefect' ⎕SH 'prefect'
      ^


RANK ERROR

RANK ERROR 4

This report is given when the rank of an argument or operand does not conform to the requirements of the function or operator, or the ranks of the arguments of a function do not conform.

Example

      2 3 + 2 2⍴10 11 12 13
RANK ERROR
      2 3 + 2 2⍴10 11 12 13
      ^


RESIZE

RESIZE 1007

This report is given when the user resizes the ⎕SM window. It is only applicable to Dyalog APL/X and Dyalog APL/W.


name saved date time

This report is given when a workspace is saved, loaded or copied.

date/time is the date and time at which the workspace was most recently saved.

Examples

      )LOAD WS/UTILITY
WS/UTILITY saved Fri Sep 11 10:34:35 1998

      )COPY SPACES GEOFF JOHND VINCE
./SPACES saved Wed Sep 30 16:12:56 1998


SYNTAX ERROR

SYNTAX ERROR 2

This report is given when a line of characters does not constitute a meaningful statement. This condition occurs when either:

  • An illegal symbol is found in an expression.
  • Brackets, parentheses or quotes in an expression are not matched.
  • Parentheses in an expression are not matched.
  • Quotes in an expression are not matched.
  • A value is assigned to a function, label, constant or system constant.
  • A strictly dyadic function (or derived function) is used monadically.
  • A monadic function (or derived function) is used dyadically.
  • A monadic or dyadic function (or derived function) is used without any arguments.
  • The operand of an operator is not an array when an array is required.
  • The operand of an operator is not a function (or derived function) when a function is required.
  • The operand of an operator is a function (or derived function) with incorrect valency.
  • A dyadic operator is used with only a single operand.
  • An operator is used without any operands.

Examples

      A>10)/A
SYNTAX ERROR
      A>10)/A
      ^

      ⊤2 4 8
SYNTAX ERROR
      ⊤2 4 8
      ^

      A.+1 2 3
SYNTAX ERROR
      A.+1 2 3
      ^


sys error number

This report is given when an internal error occurs in Dyalog APL.

Under UNIX it may be necessary to enter a hard interrupt to obtain the UNIX command prompt, or even to kill your processes from another screen. Under WINDOWS it may be necessary to reboot your PC.

If this error occurs, please submit a fault report to your Dyalog APL distributor.


TIMEOUT

TIMEOUT 1006

This report is given when the time limit specified by the system variable ⎕RTL is exceeded while awaiting input through character input (⍞) or ⎕SR.

It is usual for this error to be trapped.

Example

      ⎕RTL←5 ⋄ ⍞←'RESPOND WITHIN 5 SECONDS: ' ⋄ R←⍞
RESPOND WITHIN 5 SECONDS:
TIMEOUT
      ⎕RTL←5 ⋄ ⍞←'RESPOND WITHIN 5 SECONDS: ' ⋄ R←⍞
                                                  ^


TRANSLATION ERROR

TRANSLATION ERROR 92

This report is given when the system cannot convert a character from Unicode to an Atomic Vector index or vice versa. Conversion is controlled by the value of ⎕AVU. Note that this error can occur when you reference a variable whose value has been obtained by reading data from a TCPSocket or by calling an external function. This is because in these cases the conversion to/from ⎕AV is deferred until the value is used.


TRAP ERROR

TRAP ERROR 84

This report is given when a workspace full condition occurs whilst searching for a definition set for the system variable ⎕TRAP after a trappable error has occurred. It does not occur when an expression in a ⎕TRAP definition is being executed.


too many names

This report is given by the function editor when the number of distinct names (other than distinguished names beginning with the symbol ⎕) referenced in a defined function exceeds the system limit of 4096.


VALUE ERROR

VALUE ERROR 6

This report is given when either:

  • There is no active definition for a name encountered in an expression.
  • A function does not return a result in a context where a result is required.

Examples

     X
VALUE ERROR
     X
     ^

     ∇ HELLO
[1]    'HI THERE'
[2]  ∇

     2+HELLO
HI THERE
VALUE ERROR
     2+HELLO
      ^


warning duplicate label

This warning message is reported on closing definition mode when one or more labels are duplicated in the body of the defined function. This does not prevent the definition of the function in the active workspace. The value of a duplicated label is the lowest of the line-numbers in which the labels occur.


warning duplicate name

This warning message is reported on closing definition mode when one or more names are duplicated in the header line of the function. This may be perfectly valid. Definition of the function in the active workspace is not prevented. The order in which values are associated with names in the header line is described inDefined Functions & Operators.


warning pendent operation

This report is given on opening and closing definition mode when attempting to edit a pendant function or operator.

Example

[0]   ∇FOO
[1]    GOO
[2]   ∇

[0]   ∇GOO
[1]    ∘
[2]   ∇

      FOO
SYNTAX ERROR
GOO[1] ∘
       ^

      ∇FOO
warning pendent operation
[0]   ∇FOO
[1]    GOO
[2]   ∇
warning pendent operation


warning label name present

This warning message is reported on closing definition mode when one or more label names also occur in the header line of the function. This does not prevent definition of the function in the active workspace. The order in which values are associated with names is described in Defined Functions & Operators.


warning unmatched brackets

This report is given after adding or editing a function line in definition mode when it is found that there is not an opening bracket to match a closing bracket, or vice versa, in an expression. This is a warning message only. The function line will be accepted even though syntactically incorrect.

Example

[3]   A[;B[;2]←0
warning unmatched brackets
[4]


warning unmatched parentheses

This report is given after adding or editing a function line in definition mode when it is found that there is not an opening parenthesis to match a closing parenthesis, or vice versa, in an expression. This is a warning message only. The function line will be accepted even though syntactically incorrect.

Example

[4]   X←(E>2)^E<10)⌿A
warning unmatched parentheses
[5]


was name

This report is given when the system command )WSID is used with a parameter specifying the name of a workspace. The message identifies the former name of the workspace. If the workspace was not named, the given report is was CLEAR WS.

Example

      )WSID TEMP
was UTILITY


WS FULL

WS FULL 1

This report is given when there is insufficient workspace in which to perform an operation. Workspace available is identified by the system constant ⎕WA.

The maximum workspace size allowed is defined by the environment variable MAXWS. See maxws parameter for details.

Example

      ⎕WA⍴1.2
WS FULL
      ⎕WA⍴1.2
      ^


ws not found

This report is given when a workspace named by the system commands )LOAD, )COPY or )PCOPY does not exist as a file, or when the user does not have read access authorisation for the file.

Examples

      )LOAD NOWS
ws not found

      )COPY NOWS A FOO X
ws not found


ws too large

This report is given when:

  • the user attempts to )LOAD a workspace that needs a greater work area than the maximum that the user is currently permitted.
  • the user attempts to )COPY or )PCOPY from a workspace that would require a greater work area than the user is currently permitted if the workspace were to be loaded.

The maximum work area permitted is set using the environment variable MAXWS.


FILE ERROR 1 Not owner

FILE ERROR 1 Not owner 101

This report is given when an attempt is made to modify a file in a way which is forbidden except to the owner or super-user, or in some instances only to a super-user.


FILE ERROR 2 No such file

This report is given when a file (which should exist) does not exist, or when a directory in a path name does not exist.


FILE ERROR 5 I O error

FILE ERROR 5 I O error 105

This report is given when a physical I/O error occurred whilst reading from or writing to a device, indicating a hardware fault on the device being accessed.


FILE ERROR 6 No such device

This report is given when a device does not exist or the device is addressed beyond its limits. Examples are a tape which has not been mounted or a tape which is being accessed beyond the end of the tape.


FILE ERROR 13 Permission denied

FILE ERROR 13 Permission denied 113

This report is given when an attempt is made to access a file in a way forbidden to the account.


FILE ERROR 20 Not a directory

FILE ERROR 20 Not a directory 120

This report is given when the request assumes that a directory name is required but the name specifies a file or is not a legal name.


FILE ERROR 21 Is a directory

FILE ERROR 21 Is a directory 121

This report is given when an attempt is made to write into a directory.


FILE ERROR 23 File table overflow

FILE ERROR 23 File table overflow 123

This report is given when the system limit on the number of open files is full and a request is made to open another file. It is necessary to wait until the number of open files is reduced. If this error occurs frequently, the system limit should be increased.


FILE ERROR 24 Too many open

This report is given when the task limit on the number of open files is exceeded. It may occur when an APL session is started or when a shell command is issued to start an external process through the system command ⎕SH. It is necessary to reduce the number of open files. It may be necessary to increase the limit on the number of open files to overcome the problem.


FILE ERROR 26 Text file busy

FILE ERROR 26 Text file busy 126

This report is given when an attempt is made to write a file which is a load module currently in use. This situation could occur on assigning a value to an external variable whose associated external file name conflicts with an existing load module's name.


FILE ERROR 27 File too large

FILE ERROR 27 File too large 127

This report is given when a write to a file would cause the system limit on file size to be exceeded.


FILE ERROR 28 No space left

This report is given when a write to a file would exceed the capacity of the device containing the file.


FILE ERROR 30 Read only file

This report is given when an attempt is made to write to a device which can only be read from. This would occur with a write-protected tape.


System Errors

Introduction

Dyalog APL will generate a system error and (normally) terminate in one of two circumstances:

  • As a result of the failure of a workspace integrity check
  • As a result of a System Exception

On Windows, if the DYALOG_NOPOPUPS parameter is 0 (the default), it will display the System Error dialog box (see System Error Dialog Box). This is suppressed if DYALOG_NOPOPUPS is 1.

aplcore file

When a system error occurs, APL normally saves an aplcore file which may be sent to Dyalog for diagnosis. The name and location of the aplcore file may be specified by the AplCoreName parameter. If this parameter is not specified, the aplcore file is named aplcore and is saved in the current working directory.

Normally a new aplcore will replace a file of the same name. However, if AplCoreName contains an asterisk (*), the system will create a new file, replacing the asterisk with a number incremented from the largest numbered file present.

The number of aplcore files retained by the system is specified by the MaxAplCores parameter. If MaxAplCores is 0, the system will not save an aplcore. However, under Windows, if DYALOG_NOPOPUPS is 0, and the user checks the Create an aplcore file checkbox when the System Error dialog box is displayed, an aplcore will be saved regardless of the value of MaxAplCores. See System Error Dialog Box.

Be aware that if your application contains any secure data, this data may be present in an aplcore file, and it may be appropriate to set both MaxAplCores and DYALOG_NOPOPUPS to 0 to prevent such data being saved on disk.

Information that may prove useful in debugging the problem, including (where possible) the SI stack at the point where the aplcore was generated, is written to the end of aplcore files; the section begins with the string

'=================== Interesting Information'

Under UNIX, this interesting information section can be extracted from the aplcore as follows:

sed -n '/======== Interesting Information/,$p' aplcore

Workspace Integrity

When you )SAVE your workspace, Dyalog APL first performs a workspace integrity check. If it detects any discrepancy or violation in the internal structure of your workspace, APL does not overwrite your existing workspace on disk. Instead, it displays the System Error dialog box and saves the workspace, together with diagnostic information, in an aplcore file before terminating.

A System Error code is displayed in the dialog box and should be reported to Dyalog for diagnosis. This information also appears in the Interesting Information section of the aplcore file.

Note that the internal error that caused the discrepancy could have occurred at any time prior to the execution of )SAVE and it may not be possible for Dyalog to identify the cause from this aplcore file.

If APL is started in debug mode with the –Dc, -Dw or –DW flags, the Workspace Integrity check is performed more frequently, and it is more likely that the resulting aplcore file will contain information that will allow the problem to be identified and corrected. It is also possible to enable or alter the debugging level from within APL using the SetDFlags method; Dyalog support will direct the use of this feature when necessary.

System Exceptions

Non-specific System Errors are the result of Operating System exceptions that can occur due to a fault in Dyalog APL itself, an error in a Windows or other DLL, or even as a result of a hardware fault. The following system exceptions are separately identified.

Code | Description | Suggested Action
900 | A Paging Fault has occurred | As the most likely cause is a temporary network fault, recommended course of action is to restart your program.
990 & 991 | An exception has occurred in the Development or Run-Time DLL. |
995 | An exception has occurred in a DLL function called via ⎕NA | Carefully check your ⎕NA statement and the arguments that you have passed to the DLL function
996 | An exception has occurred in a DLL function called via a threaded ⎕NA call | As above
997 | An exception has occurred while processing an incoming OLE call |
999 | An exception has been caused by Dyalog APL or by the Operating System |

Recovering Data from aplcore files

Objects may often (but not always) be recovered from aplcore using )COPY or ⎕CY. Note that if the aplcore contains a workspace with more than one instance of the same name on the stack, ⎕CY copies the most local object whereas )COPY copies the global one.

Be aware that in many cases an attempt to )COPY from or )LOAD an aplcore is likely to result in a further syserror; this may result in the original aplcore being overwritten, thus losing the contents of that file. It is therefore worth while taking a copy of the aplcore beforeattempting to )COPY from it. Attempting to copy specific items is more likely to be successful than copying the entire workspace from the aplcore.

Note that in previous versions under Windows because (by default) the aplcore file has no extension, it was necessary to explicitly add a dot, or APL would attempt to find the non-existent file aplcore.dws. This is no longer true in version 14.1 onwards.

Reporting Errors to Dyalog

If APL crashes and saves an aplcore file, please email the following information to support@dyalog.com:

  1. a brief description of the circumstances surrounding the error
  2. details of your version of Dyalog APL: the full version number, whether it is Unicode or Classic Edition, and the BuildID. This information appears in the Help->About box; the Copy button copies this information into the clipboard, from where it can be pasted into an email etc.
  3. a compressed form of the aplcore file itself

If the problem is reproducible, i.e. can be easily repeated, please also send the appropriate description, workspace, and other files required to do so.

System Error Dialog Box

The System Error Dialog illustrated below was produced by deliberately inducing a system exception in the DLL function memcpy(). The functions used were:

     ∇ foo
[1]    goo
     ∇
     ∇ goo
[1]    hoo
     ∇
     ∇ hoo
[1]    crash
     ∇

     ∇ crash
[1]    ⎕NA'dyalog64|MEMCPY u u u'
[2]    MEMCPY 255 255 255
     ∇

Note: Under a 32-bit interpreter the ⎕NA call should refer to dyalog32.

Options

Item | Description
Create a process dump file | Dumps a complete core image, see below.
Create Trappable Error | If you check this box (only enabled on System Error codes 995 and 996), APL will not terminate but will instead generate an error 91 (EXTERNAL DLL EXCEPTION) when you press Dismiss.
Create an aplcore file | If this box is checked, an aplcore file will be created.
Pass exception on to operating system | If this box is checked, the exception will be passed on to your current debugging tool (e.g. Visual Studio). See PassExceptionsToOpSys.
Copy to clipboard | Copies the contents of the APL stack trace window to the Clipboard.

Create a process dump file

Under Windows the Create a process dump file option creates a user-mode process dump file , also known as a minidump file, called dyalog.dmp in the current directory. This file allows post-mortem debugging of a crash in the interpreter or a loaded DLL. It contains much more debug information than a normal aplcore (and is much larger than an aplcore) and can be sent to Dyalog Limited (zip it first please). Alternatively the file can be loaded into Visual Studio .NET to do your own debugging.

Debugging your own DLLs

If you are using Visual Studio, the following procedure should be used to debug your own DLLs when an appropriate Dyalog APL System Error occurs.

Ensure that the Pass Exception box is checked, then click on Dismiss to close the System Error dialog box.

The system exception dialog box appears. Click on Debug to start the process in the Visual Studio debugger.

After debugging, the System Exception dialog box appears again. Click on Don't send to terminate Windows' exception handling.

ErrorOnExternalException Parameter

This parameter allows you to prevent APL from taking the actions described above when an exception caused by an external DLL occurs. The following example illustrates what happens when the functions above are run, but with the ErrorOnExternalException parameter set to 1.

   ⎕←2 ⎕NQ'.' 'GetEnvironment' 'ErrorOnExternalException'
1
     foo
EXTERNAL DLL EXCEPTION
crash[2] MEMCPY 255 255 255
        ^
     ⎕EN
91
     )SI
crash[2]*
hoo[1]
goo[1]
foo[1]

Note: Dyalog recommends that enabling ErrorOnExternalException should only be done while developing or debugging an application; ignoring such errors may result in corruption in the workspace which could result to unexpected errors later in the application.

What should I do if Dyalog hangs?

If Dyalog for Windows hangs, you should generate a process dump file and send it to Dyalog Support, along with your Build ID.

To do this:

  1. Start Task Manager (as a user who has administrative privileges)
  2. Go to the Processes tab
  3. Right click on the dyalog.exe process and choose Create Dump File. Windows will create a process dump file in C:\Users\<your name here>\AppData\Local\Temp\dyalog.DMP
  4. Compress this file and send it to Dyalog. If it is less than 10 Mb in size, send it to Dyalog Support as an email attachment. If it is more than 10 Mb, upload it via the MyDyalog/My Account page or contact Dyalog support to request an account on our FTP server.


Language Elements

Table 6: Primitive Functions

+ | - | × | ÷ | | | ⌈ | ⌊ | * | ⍟ |  |
○ | ! | ? | ~ | ∧ | ∨ | ⍲ | ⍱ |  |  |
< | ≤ | = | > | ≥ | ≠ | ≡ | ≢ |  |  |
⍴ | , | ⍪ | ⌽ | ⊖ | ⍉ | ↑ | ↓ |  |  |
⊂ | ⊆ | ⊃ | ∊ | ⍷ | / | ⌿ | \ | ⍀ |  |
∩ | ∪ | ⍳ | ⍸ | ⌷ | ⍋ | ⍒ | ⍎ | ⍕ | ⊥ | ⊤
⊣ | ⊢ | ⌹ | ⍬ | → | ← |  |  |  |  |

Table 7: Primitive Operators

¨ | ⍨ | ∘ | . | ∘. | /
⌿ | \ | ⍀ | ⍣ | & | ⌶
⍠ | ⌸ | ⌺ | ⍤ | @ |

Table 8: Other Language Elements

Brackets
Special Syntax
Variables
Namespaces
Defined Fns & Ops
Dynamic Fns & Ops
MultiThreading
Object Oriented Programming
Control Structures
Triggers
System Functions
System Commands
Error Messages


Brackets ()[]{}

Round Parentheses

Round brackets or parentheses are used in APL expressions to control the order of execution. They are also used in function/operator headers to indicate Namelists. A right parenthesis is also used to introduce a System Command.

Square Brackets

Square brackets have three distinct meanings in Dyalog APL. They are used to select sub-arrays from an n-dimensional array and to indicate an axis along which a function (operand) is to apply. See Bracket Indexing and Bracket Axis Operator. A right bracket is also used to introduce a User Command.

Curly Brackets

Curly brackets have three distinct meanings in Dyalog APL. They are used to indicate shy results and optional left arguments in defined functions. They are also used to enclose the definition of a dfn and a dop. See Model Syntax and Dfns & Dops.

Language Elements


Special Symbols

Hash is a namespace identifier.
# Root | ## Parent
Alpha identifies left arguments of dfns/dops.
⍺ Left Argument | ⍺⍺ Left Operand
Omega identifies right arguments of dfns/dops.
⍵ Right Argument | ⍵⍵ Right Operand
Del is used for self-reference in dfns/dops (as well as for the traditional APL Line Editor).
∇ Function Self | ∇∇ Operator Self
Quotation marks are used to surround character strings.
' APL Quote | '' Empty Vector
Diamond character is used to separate APL statements on one line.
⋄ Statement Separator
Lamp symbol is used to identify following comments.
⍝ Comment Symbol
Colon is used to indicate end of line label or start of control word. It is also used in dfns and dops to separate the test from the expression in a Guard and Error Guard (two colons).
: End of Label | : Start Control Word
Boolean: Expression | Error Number(s):: Expression
Semicolon is used to separate index selection arrays in simple indexing, and to separate local names in the header of dfns/dops.
; Index Separator | ; Localize Name
High Minus or Overbar is used to indicate that a number is negative.
¯ Negative

The following National Language characters may be used in names:

   À Ä Å Æ É Ñ Ö Ø Ü ß
   à á â ä å æ ç è é ê ë
   í î ï ñ ó ô ö ø ù ú û ü

The three special characters

   _ ∆ ⍙

can also be used in names.


Scalar Functions

There is a class of primitive functions termed scalar functions This class is identified in Table 9 below. Scalar functions are pervasive, i.e. their properties apply at all levels of nesting. Scalar functions have the following properties:

Table 9: Scalar Primitive Functions

Symbol | Monadic | Dyadic
+ | Conjugate | Plus (Add)
- | Negative | Minus (Subtract)
× | Direction (Signum) | Times (Multiply)
÷ | Reciprocal | Divide
| | Magnitude | Residue
⌊ | Floor | Minimum
⌈ | Ceiling | Maximum
* | Exponential | Power
⍟ | Natural Logarithm | Logarithm
○ | Pi Times | Circular
! | Factorial | Binomial
~ | Not | $
? | Roll | $
∊ | Type (See Enlist) | $
^ |  | And
∨ |  | Or
⍲ |  | Nand
⍱ |  | Nor
< |  | Less
≤ |  | Less Or Equal
= |  | Equal
≥ |  | Greater Or Equal
> |  | Greater
≠ |  | Not Equal
$ Dyadic form is not scalar

Monadic Scalar Functions

  • The function is applied independently to each simple scalar in its argument.
  • The function produces a result with a structure identical to its argument.
  • When applied to an empty argument, the function produces an empty result. With the exception of + and ∊, the type of this result depends on the function, not on the type of the argument. By definition + and ∊ return a result of the same type as their arguments.

Example

      ÷2 (1 4)
0.5  1 0.25

Dyadic Scalar Functions

  • The function is applied independently to corresponding pairs of simple scalars in its arguments.
  • A simple scalar will be replicated to conform to the structure of the other argument. If a simple scalar in the structure of an argument corresponds to a non-simple scalar in the other argument, then the function is applied between the simple scalar and the items of the non-simple scalar. Replication of simple scalars is called scalar extension.
  • A simple unit is treated as a scalar for scalar extension purposes. A unit is a single element array of any rank. If both arguments are simple units, the argument with lower rank is extended.
  • The function produces a result with a structure identical to that of its arguments (after scalar extensions).
  • If applied between empty arguments, the function produces a composite structure resulting from any scalar extensions, with type appropriate to the particular function. (All scalar dyadic functions return a result of numeric type.)

Examples

      2 3 4 + 1 2 3
3 5 7

      2 (3 4) + 1 (2 3)
3  5 7

      (1 2) 3 + 4 (5 6)
 5 6  8 9

      10 × 2 (3 4)
20  30 40

      2 4 = 2 (4 6)
1  1 0

      (1 1⍴5) - 1 (2 3)
4  3 2

      1↑''+⍳0
0
       1↑(0⍴⊂' ' (0 0))×''
0  0 0

Note: The Axis operator applies to all scalar dyadic functions.


Mixed Functions

Mixed rank functions are summarised in Table 10. For convenience, they are sub-divided into five classes:

Table 10: Mixed rank functions

Structural | These functions change the structure of the arguments in some way.
Selection | These functions select elements from an argument.
Selector | These functions identify specific elements by a Boolean map or by an ordered set of indices.
Miscellaneous | These functions transform arguments in some way, or provide information about the arguments.
Special | These functions have special properties.

In general, the structure of the result of a mixed primitive function is different from that of its arguments.

Scalar extension may apply to some, but not all, dyadic mixed functions.

Mixed primitive functions are not pervasive. The function is applied to elements of the arguments, not necessarily independently.

Examples

      'CAT' 'DOG' 'MOUSE'⍳⊂'DOG'
2
      3↑ 1 'TWO' 3 'FOUR'
1  TWO  3

In the following tables, note that:

  • [] Implies axis specification is optional
  • $ This function is in another class

Table 11: Structural Primitive Functions

Symbol | Monadic | Dyadic
⍴ | $ | Reshape
, | Ravel [] | Catenate/Laminate []
⍪ | Table | Catenate First / Laminate []
⌽ | Reverse [] | Rotate []
⊖ | Reverse First [] | Rotate First []
⍉ | Transpose | Transpose
↑ | Mix/Disclose (First) [] | $
↓ | Split [] | $
⊂ | Enclose [] | Partitioned Enclose []
⊆ | Nest | Partition []
∊ | Enlist (See Type) | $

Table 12: Selection Primitive Functions

Symbol | Monadic | Dyadic
⊃ | Disclose /Mix | Pick
↑ | $ | Take []
↓ | $ | Drop []
/ |  | Replicate []
⌿ |  | Replicate First []
\ |  | Expand []
⍀ |  | Expand First []
~ | $ | Without (Excluding)
∩ |  | Intersection
∪ | Unique | Union
⊣ | Same | Left
⊢ | Same | Right

Table 13: Selector Primitive Functions

Symbol | Monadic | Dyadic
⍳ | Index Generator | Index Of
⍸ | Where | Interval Index
∊ | $ | Membership
⍋ | Grade Up | Grade Up
⍒ | Grade Down | Grade Down
? | $ | Deal
⍷ |  | Find

Table 14: Miscellaneous Primitive Functions

Symbol | Monadic | Dyadic
⍴ | Shape | $
≡ | Depth | Match
≢ | Tally | Not Match
⍎ | Execute | Execute
⍕ | Format | Format
⊥ |  | Decode (Base)
⊤ |  | Encode (Representation)
⌹ | Matrix Divide | Matrix Inverse

Table 15: Special Primitive Functions

Symbol | Monadic | Dyadic
→ | Abort |
→ | Branch |
← |  | Assignment
[I]← |  | Assignment(Indexed)
(I)← |  | Assignment(Selective)
[] |  | Indexing


Conformability

The arguments of a dyadic function are said to be CONFORMABLE if the shape of each argument meets the requirements of the function, possibly after scalar extension.


Fill Elements

Some primitive functions may include fill elements in their result. The fill element for an array is the enclosed type of the disclose of the array (⊂∊⊃Y for array Y with ⎕ML←0). The Type function (∊ with ⎕ml←0) replaces a numeric value with zero and a character value with ' '.

The Disclose function (⊃) returns the first item of an array. If the array is empty, ⊃Y is the PROTOTYPE of Y. The prototype is the type of the first element of the original array.

Primitive functions which may return an array including fill elements are Expand (\ or ⍀), Replicate (/ or ⌿), Reshape (⍴) and Take (↑).

Examples

      ML←0
      ∊⍳5
0 0 0 0 0

      ∊⊃(⍳3)('ABC')
0 0 0

      ⊂∊⊃(⍳3)('ABC')
 0 0 0

      ⊂∊⊃⊂(⍳3)('ABC')
  0 0 0

      A←'ABC' (1 2 3)
      A←0⍴A
      ⊂∊⊃A

      ' '=⊂∊⊃A
 1 1 1


Axis Operator

The axis operator may be applied to all scalar dyadic primitive functions and certain mixed primitive functions. An integer axis identifies a specific axis along which the function is to be applied to one or both of its arguments. If the primitive function is to be applied without an axis specification, a default axis is implied, either the first or last.

Example

      1 0 1/[1] 3 2⍴⍳6
1 2
5 6

      1 2 3+[2]2 3⍴10 20 30
11 22 33
11 22 33

Sometimes the axis value is fractional, indicating that a new axis or axes are to be created between the axes identified by the lower and upper integer bounds of the value (either of which might not exist).

Example

      'NAMES',[0.5]'='
NAMES
=====

⎕IO is an implicit argument of an axis specification.


Abort

Abort →

This is a special case of the Branch function used in the niladic sense. If it occurs in a statement it must be the only symbol in an expression or the only symbol forming an expression in a text string to be executed by ⍎. It clears the most recently suspended statement and all of its pendent statements from the state indicator.

The Abort function has no explicit result. The function is not in the function domain of operators.

Examples

      ∇ F
[1]    'F[1]'
[2]    G
[3]    'F[3]'
      ∇

      ∇ G
[1]    'G[1]'
[2]    →
[3]    'G[3]'
      ∇

      F
F[1]
G[1]

      ⎕VR'VALIDATE'
     ∇ VALIDATE
 [1]   →(12=1↑⎕AI)⍴0 ⋄ 'ACCOUNT NOT AUTHORISED' ⋄ →
     ∇

      VALIDATE
ACCOUNT NOT AUTHORISED

      1↑⎕AI
52


Add

Add R←X+Y

Y must be numeric. X must be numeric. R is the arithmetic sum of X and Y. R is numeric. This function is also known as Plus.

Examples

      1 2 + 3 4
4 6

      1 2 + 3,⊂4 5
4  6 7

      1J1 2J2 + 3J3
4J4 5J5

      ¯5 + 4J4 5J5
¯1J4 0J5


And Lowest Common Multiple

And, Lowest Common Multiple R←X^Y

Case 1: X and Y are Boolean

R is Boolean is determined as follows:

             X   Y     R

             0   0     0
             0   1     0
             1   0     0
             1   1     1

Note that the ASCII caret (^) will also be interpreted as an APL And (^).

Example

      0 1 0 1 ^ 0 0 1 1
0 0 0 1

Case 2: Either or both X and Y are numeric (non-Boolean)

R is the lowest common multiple of X and Y. Note that in this case, ⎕CT and ⎕DCT are implicit arguments.

Example

      15 1 2 7 ^ 35 1 4 0
105 1 4 0

      2 3 4 ∧ 0j1 1j2 2j3
0J2 3J6 8J12

      2j2 2j4 ∧ 5j5 4j4
10J10 ¯4J12


Assignment

Assignment X←Y

Assignment allocates the result of the expression Y to the name or names in X.

If Y is an array expression, X must contain one or more names which are variables, system variables, or are undefined. Following assignment, the name(s) in X become variable(s) with value(s) taken from the result of the expression Y.

If X contains a single name, the variable assumes the value of Y. If X contains multiple names then Y can be a single-item array of any rank (including a scalar) or a vector. If Y is a single-item array, the scalar value ⊃Y is assigned to all names in X. Otherwise, each element of Y is assigned to the corresponding name in X. Although not mandatory, Dyalog recommends that the names in X are enclosed in parentheses to reduce potential ambiguity in assignment statements.

The assignment arrow (or specification arrow) is often read as 'Is' or 'Gets'.

Examples of single assignment

      A←2.3
      A
2.3

      A←⍳3
      A
1 2 3

Examples of multiple assignment using parentheses

      (A B)←2
      A
2
      B
2

      (P ⎕IO Q)←'TEXT' 1 (1 2 3)
      P
TEXT
      ⎕IO
1
      Q
1 2 3

Example of multiple assignment without parentheses

      year month day←2017 05 24
      day
24
      month
5
      year
2017

Implementation note: erroneous expressions such as var 3←5 will result in 5 being assigned to var, even though a SYNTAX ERROR will be generated. In the case of (var 3)←5 no assignment will be made.

Pass-through assignments are permitted. The value of Y is carried through each assignment:

      I←J←K←0
      I,J,K
0 0 0

Function Assignment

If Y is a function expression, X must be a single name which is either undefined, or is the name of an existing function or defined operator. X may not be the name of a system function, or a primitive symbol.

Examples

      PLUS←+
      PLUS
+

      SUM←+/
      SUM
+/

      MEAN←{(+/⍵)÷⍴⍵}

Namespace Reference Assignment

If an expression evaluates to a namespace reference, or ref, you may assign it to a name. A name assigned to a simple scalar ref, has name class 9, whereas one assigned to an array containing refs has name class 2.

      'f1'⎕WC'Form'
      'ns1' ⎕NS ''

      N←ns1
      ⎕NC'N'           ⍝ name class of a scalar ref
9
      F←f1
      ⎕NC'F'           ⍝ name class of a scalar ref
9
      refs←N F         ⍝ vector of refs.
      ⎕NC'refs'        ⍝ nameclass of vector.
2
      F2←2⊃refs
      ⎕NC 'F2'
9

Re-Assignment

A name that already exists may be assigned a new value if the assignment will not alter its name class, or will change it from 2 to 9 or vice versa. The table of permitted re-assignments is as follows:

 | Ref | Variable | Function | Operator
Ref | Yes | Yes |  |
Variable | Yes | Yes |  |
Function |  |  | Yes | Yes
Operator |  |  | Yes | Yes


Assignment Indexed

Assignment (Indexed) {R}←X[I]←Y

Indexed Assignment is the Assignment function modified by the Indexing function. The phrase [I]← is treated as the function for descriptive purposes.

Y may be any array. X may be the name of any array or a selection from a named array (EXP X)[I]←Y, see Assignment (Selective). I must be a valid index specification. The shape of Y must conform with the shape (implied) of the indexed structure defined by I. If Y is a scalar or a 1-element vector it will be extended to conform. A side effect of Indexed Assignment is to change the value of the indexed elements of X.

R is the value of Y. If the result is not explicitly assigned or used it is suppressed.

⎕IO is an implicit argument of Indexed Assignment.

Three forms of indexing are permitted.

Simple Indexed Assignment

For vector X, I is a simple integer array whose items are from the set ⍳⍴R. Elements of X identified by index positions I are replaced by corresponding elements of Y.

Examples

      +A←⍳5
1 2 3 4 5

      A[2 3]←10 ⋄ A
1 10 10 4 5

The last-most element of Y is assigned when an index is repeated in I:

      A[2 2]←100 101 ⋄ A
1 101 10 4 5

For matrix X, I is composed of two simple integer arrays separated by the semicolon character (;). The arrays select indices from the rows and columns of X respectively.

Examples

      +B←2 3⍴'REDSUN'
RED
SUN

      B[2;2]←'O' ⋄ B
RED
SON

For higher-rank array X, I is a series of simple integer arrays with adjacent arrays separated by a single semicolon character (;). Each array selects indices from an axis of X taken in row-major order.

Examples

      C
11 12 13
14 15 16

21 22 23
24 25 26

      C[1;1;3]←103 ⋄ C
11 12 103
14 15  16

21 22  23
24 25  26

An indexing array may be ELIDED. That is, if an indexing array is omitted from the Kth axis, the indexing vector ⍳(⍴X)[K] is implied:

      C[;1;2 3]←2 2⍴112 113 122 123 ⋄ C
11 112 113
14  15  16

21 122 123
24  25  26

      C[;;]←0 ⋄ C
0 0 0
0 0 0

0 0 0
0 0 0

Choose Indexed Assignment

The index specification I is a non-simple integer array. Each item identifies a single element of X by a set of indices with one element per axis of X in row-major order.

Examples

      C
11 12 13 14
21 22 23 24

      C[⊂1 1]←101 ⋄ C
101 12 13 14
 21 22 23 24

      C[(1 2) (2 3)]←102 203 ⋄ C
101 102  13 14
 21  22 203 24

      C[2 2⍴(1 3)(2 4)(2 1)(1 4)]←2 2⍴103 204 201 104 ⋄ C
101 102 103 104
201  22 203 204

A scalar may be indexed by the enclosed empty vector:

      S
10
      S[⊂⍳0]←⊂'VECTOR' ⋄ S
 VECTOR
      S[⊂⍳0]←5 ⋄ S
5

Choose Indexed Assignment may be used very effectively in conjunction with Index Generator (⍳) and Structural functions in order to assign into an array:

      C
11 12 13 14
21 22 23 24

      ⍳⍴C
1 1  1 2  1 3  1 4
2 1  2 2  2 3  2 4

      C[1 1⍉⍳⍴C]←1 2 ⋄ C
 1 12 13 14
21  2 23 24

      C[2 ¯1↑⍳⍴C]←99 ⋄ C
 1 12 13 99
21  2 23 99

Reach Indexed Assignment

The index specification I is a non-simple integer array, each of whose items reach down to a nested element of X. The items of an item of I are simple vectors (or scalars) forming sets of indices that index arrays at successive levels of X starting at the top-most level. A set of indices has one element per axis at the respective level of nesting of X in row-major order.

Examples

      D←(2 3⍴⍳6)(2 2⍴'SMITH' 'JONES' 'SAM' 'BILL')

      D
 1 2 3   SMITH  JONES
 4 5 6   SAM    BILL

      ≡J←⊂2 (1 2)
¯3

      D[J]←⊂'WILLIAMS' ⋄ D
 1 2 3   SMITH  WILLIAMS
 4 5 6   SAM    BILL

      D[(1 (1 1))(2 (2 2) 1)]←10 'W' ⋄ D
 10 2 3   SMITH  WILLIAMS
  4 5 6   SAM    WILL

      E
 GREEN  YELLOW  RED

      E[⊂2 1]←'M' ⋄ E
 GREEN  MELLOW  RED

The context of indexing is important. In the last example, the indexing method is determined to be Reach rather than Choose since E is a vector, not a matrix as would be required for Choose. Observe that:

      ⊂2 1 ←→ ⊂(⊂2),(⊂1)

Note that for any array A, A[⊂⍬] represents a scalar quantity, which is the whole of A, so:

      A←5⍴0
      A
0 0 0 0 0
      A[⊂⍬]←1
      A
1

Combined Indexed and Selective Assignment

Instead of X being a name, it may be a selection from a named array, and the statement is of the form (EXP X)[I]←Y.

      MAT←4 3⍴'Hello' 'World'
      (2↑¨MAT)[1 2;]←'#'
      MAT
 ##llo  ##rld  ##llo
 ##rld  ##llo  ##rld
 Hello  World  Hello
 World  Hello  World
      MAT←4 3⍴'Hello' 'World'
      ⎕ML←1 ⍝ ∊ is Enlist
     (∊MAT)[2×⍳⌊0.5×⍴∊MAT]←'#'
      MAT
 H#l#o  #o#l#  H#l#o
 #o#l#  H#l#o  #o#l#
 H#l#o  #o#l#  H#l#o
 #o#l#  H#l#o  #o#l#


Assignment Selective

Assignment (Selective) (EXP X)←Y

X is the name of a variable in the workspace, possibly modified by the indexing function (EXP X[I])←Y, see Assignment (Indexed). EXP is an expression that selects elements of X. Y is an array expression. The result of the expression Y is allocated to the elements of X selected by EXP. Note that X may refer to a single name only.

The following functions may appear in the selection expression. Where appropriate these functions may be used with axis [] and with the Each operator ¨.

Functions for Selective Assignment

↑ | Take
↓ | Drop
, | Ravel
⍪ | Table
⌽⊖ | Reverse, Rotate
⍴ | Reshape
⊃ | Disclose, Pick
⍉ | Transpose (Monadic and Dyadic)
/⌿ | Replicate
\⍀ | Expand
⌷ | Index
∊ | Enlist (⎕ML≥1)

Note: Mix and Split (monadic ↑ and ↓), Type (monadic ∊ when ⎕ML<1) and Membership (dyadic ∊) may not be used in the selection expression.

Examples

      A←'HELLO'
      ((A∊'AEIOU')/A)←'*'

      A
H*LL*

      Z←3 4⍴⍳12
      (5↑,Z)←0

      Z
0  0  0  0
0  6  7  8
9 10 11 12

      MAT←3 3⍴⍳9
      (1 1⍉MAT)←0

      MAT
0 2 3
4 0 6
7 8 0

      ⎕ML←1⍝ so ∊ is Enlist
      names←'Andy' 'Karen' 'Liam'
      (('a'=∊names)/∊names)←'*'
      names
 Andy  K*ren  Li*m

Each Operator

The functions listed in the table above may also be used with the Each Operator ¨.

Examples

      A←'HELLO' 'WORLD'
      (2↑¨A)←'*'
      A
 **LLO  **RLD

      A←'HELLO' 'WORLD'
      ((A='O')/¨A)←'*'
      A
 HELL*  W*RLD

      A←'HELLO' 'WORLD'
      ((A∊¨⊂'LO')/¨A)←'*'
      A
 HE***  W*R*D

Bracket Indexing

Bracket indexing may also be applied to the expression on the left of the assignment arrow.

Examples

      MAT←4 3⍴'Hello' 'World'
      (¯2↑¨MAT[;1 3])←'$'
      MAT
 Hel$$  World  Hel$$
 Wor$$  Hello  Wor$$
 Hel$$  World  Hel$$
 Wor$$  Hello  Wor$$


Binomial

Binomial R←X!Y

X and Y may be any numbers except that if Y is a negative integer then X must be a whole number (integer). R is numeric. An element of R is integer if corresponding elements of X and Y are integers. Binomial is defined in terms of the function Factorial for positive integer arguments:

      X!Y ←→ (!Y)÷(!X)×!Y-X

For other arguments, results are derived smoothly from the Beta function:

      Beta(X,Y) ←→ ÷Y×(X-1)!X+Y-1

For positive integer arguments, R is the number of selections of X things from Y things.

Example

      1 1.2 1.4 1.6 1.8 2!5
5 6.105689248 7.219424686 8.281104786 9.227916704 10

      2!3j2
1J5


Branch

Branch →Y

Y may be a scalar or vector which, if not empty, has a simple numeric scalar as its first element. The function has no explicit result. It is used to modify the normal sequence of execution of expressions or to resume execution after a statement has been interrupted. Branch is not in the function domain of operators.

The following distinct usages of the branch function occur:

 | Entered in a Statement in a Defined Function | Entered in Immediate Execution Mode
→LINE | Continue with the specific line | Restart execution at the specific line of the most recently suspended function
→⍳0 | Continue with the next expression | No effect

In a defined function, if Y is non-empty then the first element in Y specifies a statement line in the defined function to be executed next. If the line does not exist, then execution of the function is terminated. For this purpose, line 0 does not exist. (Note that statement line numbers are independent of the index origin ⎕IO).

If Y is empty, the branch function has no effect. The next expression is executed on the same line, if any, or on the next line if not. If there is no following line, the function is terminated.

The :GoTo statement may be used in place of Branch in a defined function.

Example

     ∇ TEST
[1]    1
[2]    →4
[3]    3
[4]    4
     ∇

      TEST
1
4

In general it is better to branch to a LABEL than to a line number. A label occurs in a statement followed by a colon and is assigned the value of the statement line number when the function is defined.

Example

     ∇ TEST
[1]    1
[2]    →FOUR
[3]    3
[4]   FOUR:4
     ∇

The previous examples illustrate unconditional branching. There are numerous APL idioms which result in conditional branching. Some popular idioms are identified in the following table:

Branch Expression | Comment
→TEST/L1 | Branches to label L1 if TEST results in 1 but not if TEST results in 0.
→TEST⍴L1 | Similar to above.
TEST↑L1 | Similar to above.
→L1⍴⍨TEST | Similar to above.
→L1⌈⍳TEST | Similar to above but only if ⎕IO←→1.
→L1×⍳TEST | Similar to above but only if ⎕IO←→1.
→(L1,L2,L3)[N] | Unconditional branch to a selected label.
→(T1,T2,T3)/L1,L2,L3 | Branches to the first selected label dependent on tests T1,T2,T3. If all tests result in 0, there is no branch.
→N⌽L1,L2,L3 | Unconditional branch to the first label after rotation.

A branch expression may occur within a statement including ⋄ separators:

[5]   →NEXT⍴⍨TEST ⋄ A←A+1 ⋄ →END
[6]  NEXT:

In this example, the expressions 'A←A+1' and '→END' are executed only if TEST returns the value 1. Otherwise control branches to label NEXT.

In immediate execution mode, the branch function permits execution to be continued within the most recently suspended function, if any, in the state indicator. If the state indicator is empty, or if the argument Y is the empty vector, the branch expression has no effect. If a statement line is specified which does not exist, the function is terminated. Otherwise, execution is restarted from the beginning of the specified statement line in the most recently suspended function.

Example

     ∇ F
[1]   1
[2]   2
[3]   3
     ∇

      2 ⎕STOP'F'
      F
1

F[2]
      )SI
#.F[2]*
      →2
2
3

The system constant ⎕LC returns a vector of the line numbers of statement lines in the state indicator, starting with that in the most recently suspended function. It is convenient to restart execution in a suspended state by the expression:

      →⎕LC


Catenate Laminate

Catenate/Laminate R←X,[K]Y

Y may be any array. X may be any array. The axis specification is optional. If specified, K must be a numeric scalar or 1-element vector which may have a fractional value. If not specified, the last axis is implied.

The form R←X⍪Y may be used to imply catenation along the first axis.

Two cases of the function catenate are permitted:

  1. With an integer axis specification, or implied axis specification.
  2. With a fractional axis specification, also called laminate.

Catenation with Integer or Implied Axis Specification

The arrays X and Y are joined along the required axis to form array R. A scalar is extended to the shape of the other argument except that the required axis is restricted to a unit dimension. X and Y must have the same shape (after extension) except along the required axis, or one of the arguments may have rank one less than the other, provided that their shapes conform to the prior rule after augmenting the array of lower rank to have a unit dimension along the required axis. The rank of R is the greater of the ranks of the arguments, but not less than 1.

Examples

      'FUR','LONG'
FURLONG

      1,2
1 2

      (2 4⍴'THISWEEK')⍪'='
THIS
WEEK
====

      S,[1]+⌿S←2 3⍴⍳6
1 2 3
4 5 6
5 7 9

If, after extension, exactly one of X and Y have a length of zero along the joined axis, then the data type of R will be that of the argument with a non-zero length. Otherwise, the data type of R will be that of X.

Lamination with Fractional Axis Specification

The arrays X and Y are joined along a new axis created before the ⌈Kth axis. The new axis has a length of 2. K must exceed ⎕IO (the index origin) minus 1, and K must be less than ⎕IO plus the greater of the ranks of X and Y. A scalar argument is extended to the shape of the other argument. Otherwise X and Y must have the same shape.

The rank of R is one plus the greater of the ranks of X and Y.

Examples

      'HEADING',[0.5]'-'
HEADING
-------

      'NIGHT',[1.5]'*'
N*
I*
G*
H*
T*
      ⎕IO←0
      'HEADING',[¯0.5]'-'
HEADING
-------


Catenate First

Catenate First R←X⍪[K]Y

The form R←X⍪Y implies catenation along the first axis whereas the form R←X,Y implies catenation along the last axis (columns). See Catenate/Laminate.


Ceiling

Ceiling R←⌈Y

Ceiling is defined in terms of Floor as ⌈Y←→-⌊-Y

Y must be numeric.

If an element of Y is real, the corresponding element of R is the least integer greater than or equal to the value of Y.

If an element of Y is complex, the corresponding element of R depends on the relationship between the real and imaginary parts of the numbers in Y.

Examples

      ⌈¯2.3  0.1  100  3.3
¯2 1 100 4

      ⌈1.2j2.5 1.2j¯2.5
1J3 1J¯2

For further explanation, see Floor.

⎕CT is an implied argument of Ceiling.


Circular

Circular R←X○Y

Y must be numeric. X must be an integer in the range ¯12 ≤ X ≤ 12. R is numeric.

X determines which of a family of trigonometric, hyperbolic, Pythagorean and complex functions to apply to Y, from the following table. Note that when Y is complex, a and b are used to represent its real and imaginary parts, while θ represents its phase.

(-X) ○ Y | X | X ○ Y
(1-Y*2)*.5 | 0 | (1-Y*2)*.5
Arcsin Y | 1 | Sine Y
Arccos Y | 2 | Cosine Y
Arctan Y | 3 | Tangent Y
Y=¯1:0 Y≠¯1:(Y+1)×((Y-1)÷Y+1)*0.5 | 4 | (1+Y*2)*.5
Arcsinh Y | 5 | Sinh Y
Arccosh Y | 6 | Cosh Y
Arctanh Y | 7 | Tanh Y
-8○Y | 8 | (-1+Y*2)*0.5
Y | 9 | a
+Y | 10 | |Y
Y×0J1 | 11 | b
*Y×0J1 | 12 | θ

Examples

      0 ¯1 ○ 1
0 1.570796327

      1○(PI←○1)÷2 3 4
1 0.8660254038  0.7071067812

      2○PI÷3
0.5

      9 11○3.5J¯1.2
3.5 ¯1.2

      9 11∘.○3.5J¯1.2 2J3 3J4
 3.5 2 3
¯1.2 3 4

      ¯4○¯1
0


Conjugate

Conjugate R←+Y

If Y is complex, R is Y with the imaginary part of all elements negated.

If Y is real or non-numeric, R is the same array unchanged, although ⊣ is faster. See Same.

Examples

      +3j4
3J¯4
      +1j2 2j3 3j4
1J¯2 2J¯3 3J¯4

      3j4++3j4
6
      3j4×+3j4
25

      +A←⍳5
1 2 3 4 5

      +⎕EX'A'
1


Deal

Deal R←X?Y

Y must be a simple scalar or 1-element vector containing a non-negative integer. X must be a simple scalar or 1-element vector containing a non-negative integer and X≤Y.

R is an integer vector obtained by making X random selections from ⍳Y without repetition.

Examples

      13?52
7 40 24 28 12 3 36 49 20 44 2 35 1

      13?52
20 4 22 36 31 49 45 28 5 35 37 48 40

⎕IO and ⎕RL are implicit arguments of Deal. A side effect of Deal is to change the value of ⎕RL. See Random Number Seed.


Decode

Decode R←X⊥Y

Y must be a simple numeric array. X must be a simple numeric array. R is the numeric array which results from the evaluation of Y in the number system with radix X.

X and Y are conformable if the length of the last axis of X is the same as the length of the first axis of Y. A scalar or 1-element vector is extended to a vector of the required length. If the last axis of X or the first axis of Y has a length of 1, the array is extended along that axis to conform with the other argument.

The shape of R is the catenation of the shape of X less the last dimension with the shape of Y less the first dimension. That is:

      ⍴R ←→ (¯1↓⍴X),1↓⍴Y

For vector arguments, each element of X defines the ratio between the units for corresponding pairs of elements in Y. The first element of X has no effect on the result.

This function is also known as Base Value.

Examples

      60 60⊥3 13
193

      0 60⊥3 13
193

      60⊥3 13
193

      2⊥1 0 1 0
10

Polynomial Evaluation

If X is a scalar and Y a vector of length n, decode evaluates the polynomial(Index origin 1):

Examples

      2⊥1 2 3 4
26
      3⊥1 2 3 4
58
      1j1⊥1 2 3 4
5J9

For higher-rank array arguments, each of the vectors along the last axis of X is taken as the radix vector for each of the vectors along the first axis of Y.

Examples

      M
0 0 0 0 1 1 1 1
0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1

      A
1 1 1
2 2 2
3 3 3
4 4 4

      A⊥M
0 1 1 2  1  2  2  3
0 1 2 3  4  5  6  7
0 1 3 4  9 10 12 13
0 1 4 5 16 17 20 21

Scalar extension may be applied:

      2⊥M
0 1 2 3 4 5 6 7

Extension along a unit axis may be applied:

      +A←2 1⍴2 10
 2
10
      A⊥M
0 1  2  3   4   5   6   7
0 1 10 11 100 101 110 111


Depth

Depth (⎕ML) R←≡Y

Y may be any array. R is the maximum number of levels of nesting of Y. A simple scalar (rank-0 number, character or namespace-reference) has a depth of 0.

A higher rank array, all of whose items are simple scalars, is termed a simple array and has a depth of 1. An array whose items are not all simple scalars is nested and has a depth 1 greater than that of its most deeply nested item.

Y is of uniform depth if it is simple or if all of its items have the same uniform depth.

If ⎕ML<2 and Y is not of uniform depth then R is negated (therefore, when ⎕ML<2, a negative value of R indicates non-uniform depth).

Examples

      ≡1
0
      ≡'A'
0
      ≡'ABC'
1
      ≡1 'A'
1

      ⎕ML←0

      ≡A←(1 2)(3 (4 5)) ⍝ Non-uniform array
¯3
      ≡¨A          ⍝ A[1] is uniform, A[2] is non-uniform
1 ¯2
      ≡¨¨A
 0 0  0 1

      ⎕ML←2

      ≡A
3
      ≡¨A
1 2
      ≡¨¨A
 0 0  0 1


Direction Signum

Direction (Signum) R←×Y

Y may be any numeric array.

Where an element of Y is real, the corresponding element of R is an integer whose value indicates whether the value is negative (¯1), zero (0) or positive (1).

Where an element of Y is complex, the corresponding element of R is a number with the same phase but with magnitude (absolute value) 1. It is equivalent to Y÷|Y.

Examples

      ×¯15.3 0 101
¯1 0 1

      ×3j4 4j5
0.6J0.8 0.6246950476J0.7808688094

      {⍵÷|⍵}3j4 4j5
0.6J0.8 0.6246950476J0.7808688094

      |×3j4 4j5
1 1


Disclose

Disclose (⎕ML) R←⊃Y or R←↑Y

The symbol chosen to represent Disclose depends on the current Migration Level.

If ⎕ML<2, Disclose is represented by the symbol: ⊃.

If ⎕ML≥2, Disclose is represented by the symbol: ↑.

Y may be any array. R is an array. If Y is non-empty, R is the value of the first item of Y taken in ravel order. If Y is empty, R is the prototype of Y.

Disclose is the inverse of Enclose. The identity R←→⊃⊂R holds for all R. Disclose is also referred to as First.

Examples

      ⊃1
1

      ⊃2 4 6
2

      ⊃'MONDAY' 'TUESDAY'
MONDAY

      ⊃(1 (2 3))(4 (5 6))
1  2 3

      ⊃⍳0
0

      ' '=⊃''
1

      ⊃1↓⊂1,⊂2 3
0  0 0


Divide

Divide R←X÷Y

Y must be a numeric array. X must be a numeric array. R is the numeric array resulting from X divided by Y. System variable ⎕DIV is an implicit argument of Divide.

If ⎕DIV=0 and Y=0 then if X=0, the result of X÷Y is 1; if X≠0 then X÷Y is a DOMAIN ERROR.

If ⎕DIV=1 and Y=0, the result of X÷Y is 0 for all values of X.

Examples

      2 0 5÷4 0 2
0.5 1 2.5

      3j1 2.5 4j5÷2 1j1 .2
1.5J0.5 1.25J¯1.25 20J25

      ⎕DIV←1
      2 0 5÷4 0 0
0.5 0 0


Drop

Drop R←X↓Y

Y may be any array. X must be a simple scalar or vector of integers. If X is a scalar, it is treated as a one-element vector. If Y is a scalar, it is treated as an array whose shape is (⍴X)⍴1. After any scalar extensions, the shape of X must be less than or equal to the rank of Y. Any missing trailing items in X default to 0.

R is an array with the same rank as Y but with elements removed from the vectors along each of the axes of Y. For the Ith axis:

  • if X[I] is positive, all but the first X[I] elements of the vectors result
  • if X[I] is negative, all but the last X[I] elements of the vectors result

If the magnitude of X[I] exceeds the length of the Ith axis, the result is an empty array with zero length along that axis.

Examples

      4↓'OVERBOARD'
BOARD

      ¯5↓'OVERBOARD'
OVER

      ⍴10↓'OVERBOARD'
0

      M
ONE
FAT
FLY
      0 ¯2↓M
O
F
F

      ¯2 ¯1↓M
ON
      1↓M
FAT
FLY
      M3←2 3 4⍴⎕A

      1 1↓M3
QRST
UVWX
      ¯1 ¯1↓M3
ABCD
EFGH


Drop with Axes

Drop with Axes R←X↓[K]Y

Y may be any non-scalar array. X must be a simple integer scalar or vector. K is a vector of zero or more axes of Y.

R is an array of the elements of Y with the first or last X[i] elements removed. Elements are removed from the beginning or end of Y according to the sign of X[i].

The rank of R is the same as the rank of Y:

       ⍴⍴R ←→ ⍴⍴Y

The size of each axis of R is determined by the corresponding element of X:

      (⍴R)[,K] ←→ 0⌈(⍴Y)[,K]-|,X

Examples

      ⎕←M←2 3 4⍴⍳24
 1  2  3  4
 5  6  7  8
 9 10 11 12

13 14 15 16
17 18 19 20
21 22 23 24

      1↓[2]M
 5  6  7  8
 9 10 11 12

17 18 19 20
21 22 23 24

      2↓[3]M
 3  4
 7  8
11 12

15 16
19 20
23 24

      2 1↓[3 2]M
 7  8
11 12

19 20
23 24


Enclose

Enclose R←⊂Y

Y may be any array. R is a scalar array whose item is the array Y. If Y is a simple scalar, R is the simple scalar unchanged. Otherwise, R has a depth whose magnitude is one greater than the magnitude of the depth of Y.

Examples

      ⊂1
1

      ⊂'A'
A

      ⊂1 2 3
 1 2 3

      ⊂1,⊂'CAT'
 1  CAT

      ⊂2 4⍴⍳8
 1 2 3 4
 5 6 7 8

      ⊂⍳0

      ⊂⊂⍳0

      ⊂⊂10
10

See also: Enclose with Axes.


Enclose with Axes

Enclose with Axes R←⊂[K]Y

Y may be any array. K is a vector of zero or more axes of Y. R is an array of the elements of Y enclosed along the axes K. The shape of R is the shape of Y with the K axes removed:

      ⍴R ←→ (⍴Y)[(⍳⍴⍴R)~K]

The shape of each element of R is the shape of the Kth axes of Y:

      ⍴⊃R ←→ (⍴Y)[,K]

Examples

      ]display A←2 3 4⍴'DUCKSWANBIRDWORMCAKESEED'
┌┌→───┐
↓↓DUCK│
││SWAN│
││BIRD│
││    │
││WORM│
││CAKE│
││SEED│
└└────┘

      ]display ⊂[3]A
┌→─────────────────────┐
↓ ┌→───┐ ┌→───┐ ┌→───┐ │
│ │DUCK│ │SWAN│ │BIRD│ │
│ └────┘ └────┘ └────┘ │
│ ┌→───┐ ┌→───┐ ┌→───┐ │
│ │WORM│ │CAKE│ │SEED│ │
│ └────┘ └────┘ └────┘ │
└∊─────────────────────┘

      ]display ⊂[2 3]A
┌→──────────────┐
│ ┌→───┐ ┌→───┐ │
│ ↓DUCK│ ↓WORM│ │
│ │SWAN│ │CAKE│ │
│ │BIRD│ │SEED│ │
│ └────┘ └────┘ │
└∊──────────────┘

      ]display ⊂[1 3]A
┌→─────────────────────┐
│ ┌→───┐ ┌→───┐ ┌→───┐ │
│ ↓DUCK│ ↓SWAN│ ↓BIRD│ │
│ │WORM│ │CAKE│ │SEED│ │
│ └────┘ └────┘ └────┘ │
└∊─────────────────────┘


Encode

Encode R←X⊤Y

Y must be a simple numeric array. X must be a simple numeric array. R is the numeric array which results from the representation of Y in the number system defined by X.

The shape of R is (⍴X),⍴Y (the catenation of the shapes of X and Y).

If X is a vector or a scalar, the result for each element of Y is the value of the element expressed in the number system defined by radix X. If Y is greater than can be expressed in the number system, the result is equal to the representation of the residue (×/X)|Y. If the first element of X is 0, the value will be fully represented.

This function is also known as Representation.

Examples

      10⊤5 15 125
5 5 5

      0 10⊤5 15 125
0 1 12
5 5  5

If X is a higher-rank array, each of the vectors along the first axis of X is used as the radix vector for each element of Y.

Examples

      A
2 0  0
2 0  0
2 0  0
2 0  0
2 8  0
2 8  0
2 8 16
2 8 16

      A⊤75
0 0  0
1 0  0
0 0  0
0 0  0
1 0  0
0 1  0
1 1  4
1 3 11

The example shows binary, octal and hexadecimal representations of the decimal number 75.

Examples

      0 1⊤1.25 10.5
1    10
0.25  0.5

      4 13⊤13?52
 3 1 0  2 3 2 0 1  3 1 2 3 1
12 2 4 12 1 7 6 3 10 1 0 3 8

⎕IO is not an implicit argument of encode.


Enlist

Enlist (⎕ML≥1) R←∊Y

Migration level must be such that ⎕ML≥1 (otherwise see Type).

Y may be any array, R is a simple vector created from all the elements of Y in ravel order.

Examples

      ⎕ML←1         ⍝  Migration level 1
      MAT←2 2⍴'MISS' 'IS' 'SIP' 'PI' ⋄ MAT
 MISS  IS
 SIP   PI
      ∊MAT
MISSISSIPPI

      M←1 (2 2⍴2 3 4 5) (6(7 8))
      M
1  2 3  6  7 8
   4 5
      ∊M
1 2 3 4 5 6 7 8


Equal

Equal R←X=Y

Y may be any array. X may be any array. R is Boolean.

⎕CT and ⎕DCT are implicit arguments of Equal.

If X and Y are refs, then R is 1 if they are refs to the same object. If X is a ref and Y is not, or vice-versa, then R is 0.

If X and Y are character, then R is 1 if they are the same character. If X is character and Y is numeric, or vice-versa, then R is 0.

If X and Y are numeric, then R is 1 if X and Y are within comparison tolerance of each other.

For real numbers X and Y, X is considered equal to Y if (|X-Y) is not greater than ⎕CT×(|X)⌈|Y.

For complex numbers X=Y is 1 if the magnitude of X-Y does not exceed ⎕CT times the larger of the magnitudes of X and Y; geometrically, X=Y if the number smaller in magnitude lies on or within a circle centred on the one with larger magnitude, having radius ⎕CT times the larger magnitude.

Examples

      3=3.1 3 ¯2 ¯3
0 1 0 0

      a←2+0j1×⎕CT
      a
2J1E¯14
      a=2j.00000000000001 2j.0000000000001
1 0

      'CAT'='FAT'
0 1 1

      'CAT'=1 2 3
0 0 0

      'CAT'='C' 2 3
1 0 0

      ⎕CT←1E¯10
      1=1.000000000001
1

      1=1.0000001
0


Excluding

Excluding R←X~Y

X must be a scalar or vector. R is a vector of the elements of X excluding those elements which occur in Y taken in the order in which they occur in X.

Elements of X and Y are considered the same if X≡Y returns 1 for those elements.

⎕CT and ⎕DCT are implicit arguments of Excluding. Excluding is also known as Without.

Examples

      'HELLO'~'GOODBYE'
HLL
      'MONDAY' 'TUESDAY' 'WEDNESDAY'~'TUESDAY' 'FRIDAY'
 MONDAY  WEDNESDAY

      5 10 15~⍳10
15

For performance information, see Search Functions and Hash Tables.


Execute

Execute R←{X}⍎Y

Y must be a simple character scalar or vector containing an APL expression to be executed. The expression may contain one or more sub-expressions separated by ⋄ (Diamond) characters.

If the result of the expression is used or is assigned to a name, R is the result (if any) of the last-executed sub-expression and the non-shy results of all preceding expressions (that are not assigned within the expression) are displayed. Otherwise the unassigned non-shy results of all of the sub-expressions are displayed.

If the expression is an empty vector or a vector containing only blanks or one that does not produce a result, then ⍎Y has no value and using or assigning it to a name will generate VALUE ERROR.

If Y contains a branch expression, the branch is effected in the environment from which the Execute was invoked, and ⍎Y does not return.

If specified, X must be a namespace reference or a simple character scalar or vector representing the name of a namespace in which the expression is to be executed. If X is omitted or is an empty character vector, the expression is executed in the current space.

Examples

      ⍎'2+2'
4
      ⍎'1+1 ⋄ 2+2'
2
4
      A← ⍎'1+1 ⋄ 2+2'
2
      A
4
      4=⍎'1+1 ⋄ 2+2'
2
1
      ⍎'A←2|¯1↑⎕TS ⋄ →0⍴⍨A ⋄ A'
0
      A
0
      A←⍎''
VALUE ERROR: No result was provided when the context expected one
      A←⍎''
     ∧
      'myspace' ⎕NS''
      myspace⍎'A←⍳6'
      myspace.A
1 2 3 4 5 6


Expand

Expand R←X\[K]Y

Y may be any array. X is a simple integer scalar or vector. The axis specification is optional. If present, K must be a simple integer scalar or 1-element vector. The value of K must be an axis of Y. If absent, the last axis of Y is implied. The form R←X⍀Y implies the first axis. If Y is a scalar, it is treated as a one-element vector.

If Y has length 1 along the Kth (or implied) axis, it is extended along that axis to match the number of positive elements in X. Otherwise, the number of positive elements in X must be the length of the Kth (or implied) axis of Y.

R is composed from the sub-arrays along the Kth axis of Y. If X[I] (an element of X) is the Jth positive element in X, then the Jth sub-array along the Kth axis of Y is replicated X[I] times. If X[I] is negative, then a sub-array of fill elements of Y is replicated |X[I] times and inserted in relative order along the Kth axis of the result. If X[I] is zero, it is treated as the value ¯1. The shape of R is the shape of Y except that the length of the Kth axis is +/1⌈|X.

Examples

      0\⍳0
0

      1 ¯2 3 ¯4 5\'A'
A  AAA    AAAAA

      M
1 2 3
4 5 6

      1 ¯2 2 0 1\M
1 0 0 2 2 0 3
4 0 0 5 5 0 6

      1 0 1⍀M
1 2 3
0 0 0
4 5 6

      1 0 1\[1]M
1 2 3
0 0 0
4 5 6

      1 ¯2 1\(1 2)(3 4 5)
 1 2  0 0  0 0  3 4 5


Expand First

Expand First R←X⍀Y

The form R←X⍀Y implies expansion along the first axis whereas the form R←X\Y implies expansion along the last axis (columns). See Expand.


Exponential

Exponential R←*Y

Y must be numeric. R is numeric and is the Yth power of e, the base of natural logarithms.

Example

      *1 0
2.718281828 1

      *0j1 1j2
0.5403023059J0.8414709848 ¯1.131204384J2.471726672

      1+*○0j1 ⍝ Euler Identity
0


Factorial

Factorial R←!Y

Y must be numeric excluding negative integers. R is numeric. R is the product of the first Y integers for positive integer values of Y. For non-integral values of Y, !Y is equivalent to the gamma function of Y+1.

Examples

      !1 2 3 4 5
1 2 6 24 120

      !¯1.5 0 1.5 3.3
¯3.544907702 1 1.329340388 8.85534336

      !0j1 1j2
0.4980156681J¯0.1549498283 0.1122942423J0.3236128855


Find

Find R←X⍷Y

X and Y may be any arrays. R is a simple Boolean array the same shape as Y which identifies occurrences of X within Y.

If the rank of X is smaller than the rank of Y, X is treated as if it were the same rank with leading axes of size 1. For example a vector is treated as a 1-row matrix.

If the rank of X is larger than the rank of Y, no occurrences of X are found in Y.

⎕CT and ⎕DCT are implicit arguments of Find.

Examples

      'AN'⍷'BANANA'
0 1 0 1 0 0

      'ANA'⍷'BANANA'
0 1 0 1 0 0

      'BIRDS' 'NEST'⍷'BIRDS' 'NEST' 'SOUP'
1 0 0

      MAT
IS YOU IS
OR IS YOU
ISN'T
      'IS'⍷MAT
1 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0 0
1 0 0 0 0 0 0 0 0
      'IS YOU'⍷MAT
1 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0


First

First (⎕ML) R←⊃Y or R←↑Y

See function Disclose.


Floor

Floor R←⌊Y

Y must be numeric.

For real numbers, R is the largest integer value less than or equal to Y within the comparison tolerance ⎕CT.

Examples

      ⌊¯2.3 0.1 100 3.3
¯3 0 100 3

      ⌊0.5 + 0.4 0.5 0.6
0 1 1

For complex numbers, R depends on the relationship between the real and imaginary parts of the numbers in Y.

      ⌊1j3.2 3.3j2.5 ¯3.3j¯2.5
1J3 3J2 ¯3J¯3

Complex Floor

The following (deliberately) simple function illustrates one way to express the rules for evaluating complex Floor.

     ∇ fl←CpxFloor cpxs;a;b
[1]   ⍝ Complex floor of scalar complex number (a+ib)
[2]    a b←9 11○cpxs
[3]    :If 1>(a-⌊a)+b-⌊b
[4]        fl←(⌊a)+0J1×⌊b
[5]    :Else
[6]        :If (a-⌊a)<b-⌊b
[7]            fl←(⌊a)+0J1×1+⌊b
[8]        :Else
[9]            fl←(1+⌊a)+0J1×⌊b
[10]       :EndIf
[11]   :EndIf
     ∇

      CpxFloor¨1j3.2 3.3j2.5 ¯3.3j¯2.5
1J3 3J2 ¯3J¯3

⎕CT and ⎕DCT are implicit arguments of Floor.


Format Monadic

Format (Monadic) R←⍕Y

Y may be any array. R is a simple character array which will display identically to the display produced by Y. The result is independent of ⎕PW. If Y is a simple character array, then R is Y.

Example

      +B←⍕A←2 6⍴'HELLO PEOPLE'
HELLO
PEOPLE

      B ≡ A
1

If Y is a simple numeric scalar, then R is a vector containing the formatted number without any spaces. A floating point number is formatted according to the system variable ⎕PP. ⎕PP is ignored when formatting integers.

Examples

      ⎕PP←5

      ⍴C←⍕⍳0
0

      ⍴C←⍕10
2

      C
10

      ⍴C←⍕12.34
5

      C
12.34

      ⍕123456789
123456789

      ⍕123.456789
123.46

Scaled notation is used if the magnitude of the non-integer number is too large to represent with ⎕PP significant digits or if the number requires more than five leading zeroes after the decimal point.

Examples

      ⍕123456.7
1.2346E5

      ⍕0.0000001234
1.234E¯7

If Y is a simple numeric vector, then R is a character vector in which each element of Y is independently formatted with a single separating space between formatted elements.

Example

      ⍴C←⍕¯123456 1 22.5 ¯0.000000667 5.00001
27

      C
¯1.2346E5 1 22.5 ¯6.67E¯7 5

If Y is a simple numeric array rank higher than one, R is a character array with the same shape as Y except that the last dimension of Y is determined by the length of the formatted data. The format width is determined independently for each column of Y, such that:

  1. the decimal points for floating point or scaled formats are aligned.
  2. the E characters for scaled formats are aligned, with trailing zeros added to the mantissae if necessary.
  3. integer formats are aligned to the left of the decimal point column, if any, or right-adjusted in the field otherwise.
  4. each formatted column is separated from its neighbours by a single blank column.
  5. the exponent values in scaled formats are left-adjusted to remove any blanks.

Examples

      C←22 ¯0.000000123 2.34 ¯212 123456 6.00002 0

      ⍴C←⍕2 2 3⍴C
2 2 29

      C
  22    ¯1.2300E¯7  2.3400E0
¯212     1.2346E5   6.0000E0

   0     2.2000E1  ¯1.2300E¯7
   2.34 ¯2.1200E2   1.2346E5

If Y is non-simple, and all items of Y at any depth are scalars or vectors, then R is a vector.

Examples

      B←⍕A←'ABC' 100 (1 2 (3 4 5)) 10

      ⍴A
4
      ≡A
¯3

      ⍴B
26
      ≡B
1

      A
 ABC  100  1 2  3 4 5   10

      B
 ABC  100  1 2  3 4 5   10

By replacing spaces with ^, it is clearer to see how the result of ⍕ is formed:

^ABC^^100^^1^2^^3^4^5^^^10

If Y is non-simple, and all items of Y at any depth are not scalars, then R is a matrix.

Example

      D←⍕C←1 'AB' (2 2⍴1+⍳4) (2 2 3⍴'CDEFGHIJKLMN')

      C
1  AB  2 3  CDE
       4 5  FGH

            IJK
            LMN

      ⍴C
4

      ≡C
¯2

      D
1  AB  2 3  CDE
       4 5  FGH

            IJK
            LMN

      ⍴D
5 16

      ≡D
1

By replacing spaces with ^, it is clearer to see how the result of ⍕ is formed:

1^^AB^^2^3^^CDE^
^^^^^^^4^5^^FGH^
^^^^^^^^^^^^^^^^
^^^^^^^^^^^^IJK^
^^^^^^^^^^^^LMN^

⎕PP is an implicit argument of Monadic Format.


Format Dyadic

Format (Dyadic) R←X⍕Y

Y must be a simple real (non-complex) numeric array. X must be a simple integer scalar or vector. R is a character array displaying the array Y according to the specification X. R has rank 1⌈⍴⍴Y and ¯1↓⍴R is ¯1↓⍴Y. If any element of Y is complex, dyadic ⍕ reports a DOMAIN ERROR.

Conformability requires that if X has more than two elements, then ⍴X must be 2×¯1↑⍴Y. If X contains one element, it is extended to (2×¯1↑⍴Y)⍴0,X. If X contains 2 elements, it is extended to (2×¯1↑⍴Y)⍴X.

X specifies two numbers (possibly after extension) for each column in Y. For this purpose, scalar Y is treated as a one-element vector. Each pair of numbers in X identifies a format width (W) and a format precision (P).

If P is 0, the column is to be formatted as integers.

Examples

      5 0 ⍕ 2 3⍴⍳6
    1    2    3
    4    5    6

      4 0⍕1.1 2 ¯4 2.547
   1   2  ¯4   3

If P is positive, the format is floating point with P significant digits to be displayed after the decimal point.

Example

      4 1⍕1.1 2 ¯4 2.547
 1.1 2.0¯4.0 2.5

If P is negative, scaled format is used with |P digits in the mantissa.

Example

      7 ¯3⍕5 15 155 1555
5.00E0 1.50E1 1.55E2 1.56E3

If W is 0 or absent, then the width of the corresponding columns of R are determined by the maximum width required by any element in the corresponding columns of Y, plus one separating space.

Example

      3⍕2 3⍴10 15.2346 ¯17.1 2 3 4
 10.000 15.235 ¯17.100
  2.000  3.000   4.000

If a formatted element exceeds its specified field width when W>0, the field width for that element is filled with asterisks.

Example

      3 0 6 2 ⍕ 3 2⍴10.1 15 1001 22.357 101 1110.1
 10 15.00
*** 22.36
101******

If the format precision exceeds the internal precision, low order digits are replaced by the symbol '_'.

Example

      26⍕2*100
1267650600228229_______________.__________________________

      ⍴26⍕2*100
59

      0 20⍕÷3
 0.3333333333333333____

      0 ¯20⍕÷3
 3.333333333333333____E¯1

The shape of R is the same as the shape of Y except that the last dimension of R is the sum of the field widths specified in X or deduced by the function. If Y is a scalar, the shape of R is the field width.

      ⍴5 2 ⍕ 2 3 4⍴⍳24
2 3 20


Grade Down Dyadic

Grade Down (Dyadic) R←X⍒Y

Y must be a simple character array of rank greater than 0. X must be a simple character array of rank 1 or greater. R is a simple integer vector of shape 1↑⍴Y containing the permutation of ⍳1↑⍴Y that places the sub-arrays of Y along the first axis in descending order according to the collation sequence X. The indices of any set of identical sub-arrays in Y occur in R in ascending order.

If X is a vector, the following identity holds:

      X⍒Y ←→ ⍒X⍳Y

A left argument of rank greater than 1 allows successive resolution of duplicate orderings in the following way.

Starting with the last axis:

  • The characters in the right argument are located along the current axis of the left argument. The position of the first occurrence gives the ordering value of the character.
  • If a character occurs more than once in the left argument its lowest position along the current axis is used.
  • If a character of the right argument does not occur in the left argument, the ordering value is one more than the maximum index of the current axis - as with dyadic iota.

The process is repeated using each axis in turn, from the last to the first, resolving duplicates until either no duplicates result or all axes have been exhausted.

For example, if index origin is 1:

Left argument: Right argument:
abc
ABA

ab
ac
Aa
Ac

Along last axis:

Character: Value: Ordering:
ab
ac
Aa
Ac

1 2
1 3
1 1
1 3

3
=1   <-duplicate ordering with
4
=1   <-respect to last axis.

Duplicates exist, so resolve these with respect to the first axis:

Character: Value: Ordering:
ac
Ac

1 1
2 1

2
1

So the final row ordering is:

        ab              3
        ac              2
        Aa              4
        Ac              1

That is, the order of rows is 4 2 1 3 which corresponds to a descending row sort of:

        Ac              1
        ac              2
        ab              3
        Aa              4

Examples

      ⍴S1
2 27
      S1
 ABCDEFGHIJKLMNOPQRSTUVWXYZ
 abcdefghijklmnopqrstuvwxyz
      S2
 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
      S3
 AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz
      S4
 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

The following results are tabulated for comparison:

X       X[S1⍒X;]    X[S2⍒X;]    X[S3⍒X;]    X[S4⍒X;]
FIRsT     TAPE        rAT         TAPE        TAPE
TAP       TAP         fIRST       TAP         TAP
RATE      RATE        TAPE        rAT         RATE
FiRST     rAT         TAP         RATE        rAT
FIRST     RAT         RATE        RAT         RAT
rAT       MAT         RAT         MAT         MAT
fIRST     fIRST       MAT         fIRST       FIRsT
TAPE      FiRST       FiRST       FiRST       FiRST
MAT       FIRsT       FIRsT       FIRsT       FIRST
RAT       FIRST       FIRST       FIRST       fIRST

⎕IO is an implicit argument of Grade Down.


Grade Up Dyadic

Grade Up (Dyadic) R←X⍋Y

Y must be a simple character array of rank greater than 0. X must be a simple character array of rank 1 or greater. R is a simple integer vector being the permutation of ⍳1↑⍴Y that places the sub-arrays of Y along the first axis in ascending order according to the collation sequence X.

If X is a vector, the following identity holds:

      X⍋Y ←→ ⍋X⍳Y

If X is a higher-rank array, each axis of X represents a grading attribute in increasing order of importance (the first axis is the least significant and the last axis is the most significant). If a character is repeated in X, it is treated as though it were located at the position in the array determined by the lowest index in each axis for all occurrences of the character. The character has the same weighting as the character located at the derived position in X.

Examples

      (2 2⍴'ABBA') ⍋ 'AB'[?5 2⍴2] ⍝ A and B are equivalent
1 2 3 4 5

        ]display A←2 14⍴' abcdegiklmnrt ABCDEGIKLMNRT'
┌→─────────────┐
↓ abcdegiklmnrt│
│ ABCDEGIKLMNRT│
└──────────────┘

      V←'Ab' 'AB' 'aba' 'ABA' 'abaca' 'abecedarian'
      V,←'Abelian' 'black' 'blackball' 'black belt'
      V,←'blacking' 'Black Mass'

      ]display M←↑V
┌→──────────┐
↓Ab         │
│AB         │
│aba        │
│ABA        │
│abaca      │
│abecedarian│
│Abelian    │
│black      │
│blackball  │
│black belt │
│blacking   │
│Black Mass │
└───────────┘

      ]display M (M[(,A)⍋M;]) (M[(,⍉A)⍋M;]) (M[A⍋M;])
┌→────────────────────────────────────────────────────────┐
│ ┌→──────────┐ ┌→──────────┐ ┌→──────────┐ ┌→──────────┐ │
│ ↓Ab         │ ↓aba        │ ↓aba        │ ↓Ab         │ │
│ │AB         │ │abaca      │ │abaca      │ │AB         │ │
│ │aba        │ │abecedarian│ │abecedarian│ │aba        │ │
│ │ABA        │ │black      │ │Ab         │ │ABA        │ │
│ │abaca      │ │black belt │ │Abelian    │ │abaca      │ │
│ │abecedarian│ │blackball  │ │AB         │ │abecedarian│ │
│ │Abelian    │ │blacking   │ │ABA        │ │Abelian    │ │
│ │black      │ │Ab         │ │black      │ │black      │ │
│ │blackball  │ │Abelian    │ │black belt │ │black belt │ │
│ │black belt │ │AB         │ │blackball  │ │Black Mass │ │
│ │blacking   │ │ABA        │ │blacking   │ │blackball  │ │
│ │Black Mass │ │Black Mass │ │Black Mass │ │blacking   │ │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
└∊────────────────────────────────────────────────────────┘'


Greater

Greater R←X>Y

Y must be numeric. X must be numeric. R is Boolean. R is 1 if X is greater than Y and X=Y is 0. Otherwise R is 0.

⎕CT and ⎕DCT are implicit arguments of Greater.

Examples

      1 2 3 4 5 > 2
0 0 1 1 1

      ⎕CT←1E¯10

      1 1.00000000001 1.000000001 > 1
0 0 1


Greater Or Equal

Greater Or Equal R←X≥Y

Y must be numeric. X must be numeric. R is Boolean. R is 1 if X is greater than Y or X=Y. Otherwise R is 0.

⎕CT and ⎕DCT are implicit arguments of Greater Or Equal.

Examples

      1 2 3 4 5 ≥ 3
0 0 1 1 1

      ⎕CT←1E¯10

      1≥1
1

      1≥1.00000000001
1

      1≥1.00000001
0


Index

Index R←{X}⌷Y

Dyadic case

X must be a scalar or vector of depth ≤2 of integers each ≥⎕IO. Y may be any array. In general, the result R is similar to that obtained by square-bracket indexing in that:

      (I J ... ⌷ Y) ≡ Y[I;J;...]

The length of left argument X must be less than or equal to the rank of right argument Y. Any missing trailing items of X default to the index vector of the corresponding axis of Y.

Note that in common with square-bracket indexing, items of the left argument X may be of any rank and that the shape of the result is the concatenation of the shapes of the items of the left argument:

      (⍴X⌷Y) ≡ ↑,/⍴¨X

Index is sometimes referred to as squad indexing.

Note that index may be used with selective specification.

⎕IO is an implicit argument of index.

Examples

      ⎕IO←1

      VEC←111 222 333 444
      3⌷VEC
333
      (⊂4 3)⌷VEC
444 333
      (⊂2 3⍴3 1 4 1 2 3)⌷VEC
333 111 444
111 222 333

      ⎕←MAT←10⊥¨⍳3 4
11 12 13 14
21 22 23 24
31 32 33 34

      2 1⌷MAT
21
      2⌷MAT
21 22 23 24

      3(2 1)⌷MAT
32 31
      (2 3)1⌷MAT
21 31
      (2 3)(,1)⌷MAT
21
31
      ⍴(2 1⍴1)(3 4⍴2)⌷MAT
2 1 3 4
      ⍴⍬ ⍬⌷MAT
0 0
      (3(2 1)⌷MAT)←0 ⋄ MAT    ⍝ Selective assignment.
11 12 13 14
21 22 23 24
 0  0 33 34

Monadic case

If Y is an array, Y is returned.

If Y is a ref to an instance of a Class with a Default property, all elements of the Default property are returned. For example, if Item is the default property of MyClass, and imc is an Instance of MyClass, then by definition:

      imc.Item≡⌷imc

NONCE ERROR is reported if the Default Property is Keyed, because in this case APL has no way to determine the list of all the elements.

Note that the values of the index set are obtained or assigned by calls to the corresponding PropertyGet and PropertySet functions. Furthermore, if there is a sequence of primitive functions to the left of the Index function, that operate on the index set itself (functions such as dyadic ⍴,↑,↓,⊃) as opposed to functions that operate on the values of the index set (functions such as +,⌈,⌊,⍴¨), calls to the PropertyGet and PropertySet functions are deferred until the required index set has been completely determined. The full set of functions that cause deferral of calls to the PropertyGet and PropertySet functions is the same as the set of functions that applies to selective specification.

If for example, CompFile is an Instance of a Class with a Default Numbered Property, the expression:

       1↑⌽⌷CompFile

would only call the PropertyGet function (for CompFile) once, to get the value of the last element.

Note that similarly, the expression

      10000⍴⌷CompFile

would call the PropertyGet function 10000 times, on repeated indices if CompFile has less than 10000 elements. The deferral of access function calls is intended to be an optimisation, but can have the opposite effect. You can avoid unnecessary repetitive calls by assigning the result of ⌷ to a temporary variable.


Index with Axes

Index with Axes R←{X}⌷[K]Y

X must be a scalar or vector of depth ≤2, of integers each ≥⎕IO. Y may be any array. K is a simple scalar or vector specifying axes of Y. The length of K must be the same as the length of X:

      (⍴,X) ≡ ⍴,K

In general, the result R is similar to that obtained by square-bracket indexing with elided subscripts. Items of K distribute items of X along the axes of Y. For example:

      I J ⌷[1 3] Y  ←→  Y[I;;J]

Note that index with axis may be used with selective specification. ⎕IO is an implicit argument of index with axis.

Examples

     ⎕IO←1

     ⎕←CUBE←10⊥¨⍳2 3 4
111 112 113 114
121 122 123 124
131 132 133 134

211 212 213 214
221 222 223 224
231 232 233 234

      2⌷[1]CUBE
211 212 213 214
221 222 223 224
231 232 233 234

      2⌷[3]CUBE
112 122 132
212 222 232

      CUBE[;;2] ≡ 2⌷[3]CUBE
1
      (1 3)4⌷[2 3]CUBE
114 134
214 234

      CUBE[;1 3;4] ≡ (1 3)4⌷[2 3]CUBE
1

      (2(1 3)⌷[1 3]CUBE)←0 ⋄ CUBE ⍝ Selective assignment.
111 112 113 114
121 122 123 124
131 132 133 134

  0 212   0 214
  0 222   0 224
  0 232   0 234


Index Generator

Index Generator R←⍳Y

Y must be a simple scalar or vector array of non-negative numbers. R is a numeric array composed of the set of all possible coordinates of an array of shape Y. The shape of R is Y and each element of R occurs in its self-indexing position in R. In particular, the following identity holds:

      ⍳Y ←→ (⍳Y)[⍳Y]

⎕IO is an implicit argument of Index Generator. This function is also known as Interval.

Examples

      ⎕IO
1
      ⍴⍳0
0
      ⍳5
1 2 3 4 5

      ⍳2 3
 1 1  1 2  1 3
 2 1  2 2  2 3

      ⊢A←2 4⍴'MAINEXIT'
MAIN
EXIT
      A[⍳⍴A]
MAIN
EXIT

      ⎕IO←0
      ⍳5
0 1 2 3 4

      ⍳2 3
 0 0  0 1  0 2
 1 0  1 1  1 2

      A[⍳⍴A]
MAIN
EXIT


Index Of

Index Of R←X⍳Y

Y may be any array. X may be any array of rank 1 or more.

In general, the function locates the first occurrence of sub-arrays in Y which match major cells of X, where a major cell is a sub-array on the leading dimension of X with shape 1↓⍴X. The shape of the result R is (1-⍴⍴X)↓⍴Y.

If a sub-array of Y cannot be found in X, then the corresponding element of R will be ⎕IO+⊃⍴X.

In particular, if X is a vector, the result R is a simple integer array with the same shape as Y identifying where elements of Y are first found in X. If an element of Y cannot be found in X, then the corresponding element of R will be ⎕IO+⊃⍴X.

Elements of X and Y are considered the same if X≡Y returns 1 for those elements.

⎕IO, ⎕CT and ⎕DCT are implicit arguments of Index Of.

Examples

      ⎕IO←1

      2 4 3 1 4⍳1 2 3 4 5
4 1 3 2 6

      'CAT' 'DOG' 'MOUSE'⍳'DOG' 'BIRD'
2 4
      X←3 4⍴⍳12
      X
1  2  3  4
5  6  7  8
9 10 11 12
      X⍳1 2 3 4
1

      Y←2 4⍴1 2 3 4 9 10 11 12
      Y
1  2  3  4
9 10 11 12

      X⍳Y
1 3
      X⍳2 3 4 1
4

      X1←10 100 1000∘.+X
      X1
  11   12   13   14
  15   16   17   18
  19   20   21   22

 101  102  103  104
 105  106  107  108
 109  110  111  112

1001 1002 1003 1004
1005 1006 1007 1008
1009 1010 1011 1012

      X1⍳100 1000∘.+X
2 3
      x
United Kingdom
Germany
France
Italy
United States
Canada
Japan
Canada
France
      y
United Kingdom
Germany
France
Italy
USA

Canada
Japan
China
India
Deutschland

      ⍴x
9 14
      ⍴y
2 5 14
      x⍳y
1 2  3  4 10
6 7 10 10 10

      x⍳x
1 2 3 4 5 6 7 6 3

Note that the expression y⍳x signals a LENGTH ERROR because it looks for major cells in the left argument, whose shape is 5 14 (that is 1↓⍴y), which is not the same as the trailing shape of x.

      y⍳x
LENGTH ERROR
      y⍳x
     ∧

For performance information, see Search Functions and Hash Tables.


Indexing

Indexing R←X[Y]

X may be any array. Y must be a valid index specification. R is an array composed of elements indexed from X and the shape of X is determined by the index specification.

This form of Indexing, using brackets, does not follow the normal syntax of a dyadic function. For an alternative method of indexing, see Index.

⎕IO is an implicit argument of Indexing.

Three forms of indexing are permitted. The form used is determined by context.

Simple Indexing

For vector X, Y is a simple integer array composed of items from the set ⍳⍴X.

R consists of elements selected according to index positions in Y. R has the same shape as Y.

Examples

      A←10 20 30 40 50

      A[2 3⍴1 1 1 2 2 2]
10 10 10
20 20 20

      A[3]
30

      'ONE' 'TWO' 'THREE'[2]
 TWO

For matrix X, Y is composed of two simple integer arrays separated by the semicolon character (;). The arrays select indices from the rows and columns of X respectively.

Examples

      +M←2 4⍴10×⍳8
10 20 30 40
50 60 70 80

      M[2;3]
70

For higher-rank array X, Y is composed of a simple integer array for each axis of X with adjacent arrays separated by a single semicolon character (;). The arrays select indices from the respective axes of X, taken in row-major order.

Examples

      ⊢A←2 3 4⍴10×⍳24
 10  20  30  40
 50  60  70  80
 90 100 110 120

130 140 150 160
170 180 190 200
210 220 230 240

      A[1;1;1]
10

      A[2;3 2;4 1]
240 210
200 170

If an indexing array is omitted for the Kth axis, the index vector ⍳(⍴X)[K] is assumed for that axis.

Examples

      A[;2;]
 50  60  70  80
170 180 190 200

      M
10 20 30 40
50 60 70 80

      M[;]
10 20 30 40
50 60 70 80

      M[1;]
10 20 30 40

      M[;1]
10 50

Choose Indexing

The index specification Y is a non-simple array. Each item identifies a single element of X by a set of indices with one element per axis of X in row-major order.

Examples

      M
10 20 30 40
50 60 70 80

      M[⊂1 2]
20

      M[2 2⍴⊂2 4]
80 80
80 80

      M[(2 1)(1 2)]
50 20

A scalar may be indexed by the enclosed empty vector:

      S←'Z'
      S[3⍴⊂⍳0]
ZZZ

Simple and Choose indexing are indistinguishable for vector X:

      V←10 20 30 40

      V[⊂2]
20
      ⊂2
2
      V[2]
20

Reach Indexing

The index specification Y is a non-simple integer array, each of whose items reach down to a nested element of X. The items of an item of Y are simple vectors (or scalars) forming sets of indices that index arrays at successive levels of X starting at the top-most level. A set of indices has one element per axis at the respective level of nesting of X in row-major order.

Examples

      G←('ABC' 1)('DEF' 2)('GHI' 3)('JKL' 4)
      G←2 3⍴G,('MNO' 5)('PQR' 6)
      G
  ABC  1   DEF  2   GHI  3
  JKL  4   MNO  5   PQR  6

      G[((1 2)1)((2 3)2)]
 DEF  6

      G[2 2⍴⊂(2 2)2]
5 5
5 5
      G[⊂⊂1 1]
  ABC  1

      G[⊂1 1]
  ABC  1

      V←,G

      V[⊂⊂1]
  ABC  1

      V[⊂1]
  ABC  1

      V[1]
  ABC  1


Intersection

Intersection R←X∩Y

Y must be a scalar or vector. X must be a scalar or vector. A scalar X or Y is treated as a one-element vector. R is a vector composed of items occurring in both X and Y in the order of occurrence in X. If an item is repeated in X and also occurs in Y, the item is also repeated in R.

Items in X and Y are considered the same if X≡Y returns 1 for those items.

⎕CT and ⎕DCT are implicit arguments of Intersection.

Examples

      'ABRA'∩'CAR'
ARA

      1 'PLUS' 2 ∩ ⍳5
1 2

For performance information, see Search Functions and Hash Tables.


Interval Index

Interval Index R←X⍸Y

Classic Edition: the symbol ⍸ (Iota Underbar) is not available in Classic Edition, and Interval Index is instead represented by ⎕U2378.

X is an ordered non-scalar array that represents a set of intervals or ranges.

Note that the ith interval starts at X[i], then includes all subsequent values up to but not including X[i+1].

For example, if X is (1 3 5) it defines 4 intervals numbered 0 to 3 as follows.

0 | less than 1 | <1
1 | between 1 and 3 | (≥1)∧(<3)
2 | between 3 and 5 | (≥3)∧(<5)
3 | greater than or equal to 5 | ≥5

If X is 'AEIOU' it defines 6 intervals numbered 0 to 5 as follows:

0 | before A | ⎕UCS[0,⍳64]
1 | between A and E | ABCD
2 | between E and I | EFGH
3 | between I and O | IJKLMN
4 | between O and U | OPQREST
5 | U and after | UVWXYZ...

Y is an array of the same type (numeric or character) as X.

The result R is an integer array that identifies into which interval the corresponding value in Y falls.

Like dyadic ⍳ (see Index Of), Interval Index works with major cells. For a vector these are its elements; for a matrix its rows, and so forth.

X and Y are compared using the same logic as monadic ⍋ (see Grade Up (Monadic)) which is independent of ⎕CT and ⎕DCT.

⎕IO is an implicit arguments of Interval Index. In all the following examples, ⎕IO is 1.

Examples

      10 20 30⍸11 1 31 21
1 0 3 2

In the above example:

  • 11 is between X[1] and X[2] so the answer is 1.
  • 1 is less than X[1] so the answer is 0
  • 31 is greater than X[⍴X] so the answer is 3
  • 21 is between X[2] and X[3] so the answer is 2.
      'AEIOU' ⍸ 'DYALOG'
1 5 1 3 4 2

And in the alphabetic example above:

  • "D" is between X[1] and X[2], so the answer is 1
  • "Y" is after X[⍴X] so the answer is 5
  • "A" is between X[1] and X[2], so the answer is 1
  • as so on ...

Example (Classification)

Commercially, olive oil is graded as follows:

  • if its acidity is less than 0.8%, as "Extra Virgin"
  • if its acidity is less than 2%, as "Virgin"
  • if its acidity is less than 3.3%, as "Ordinary"
  • otherwise, as "Lampante"
     grades←'Extra Virgin' 'Virgin' 'Ordinary' 'Lampante'
     acidity←0.8 2 3.3

     samples←1.3 1.9 0.7 4 .6 3.2
     acidity⍸samples
1 1 0 3 0 2
     samples,⍪grades[1+acidity⍸samples]
┌───┬────────────┐
│1.3│Virgin      │
├───┼────────────┤
│1.9│Virgin      │
├───┼────────────┤
│0.7│Extra Virgin│
├───┼────────────┤
│4  │Lampante    │
├───┼────────────┤
│0.6│Extra Virgin│
├───┼────────────┤
│3.2│Ordinary    │
└───┴────────────┘

Example (Data Consolidation by Interval)

x represents some data sampled in chronological order at timestamps t.

      ⍴x
200000
      x
3984300 2020650 819000 1677100 3959200 2177250 3431800 ...
      ⍴t
200000 3
      (10↑t) (¯10↑t)
┌─────┬────────┐
│0 0 0│23 59 54│
│0 0 0│23 59 55│
│0 0 0│23 59 56│
│0 0 0│23 59 56│
│0 0 0│23 59 58│
│0 0 2│23 59 58│
│0 0 3│23 59 59│
│0 0 3│23 59 59│
│0 0 4│23 59 59│
│0 0 5│23 59 59│
└─────┴────────┘

u represents timestamps for 5-minute intervals:

      ⍴u
288 3
      (10↑u) (¯10↑u)
┌──────┬───────┐
│0  0 0│23 10 0│
│0  5 0│23 15 0│
│0 10 0│23 20 0│
│0 15 0│23 25 0│
│0 20 0│23 30 0│
│0 25 0│23 35 0│
│0 30 0│23 40 0│
│0 35 0│23 45 0│
│0 40 0│23 50 0│
│0 45 0│23 55 0│
└──────┴───────┘

Therefore, the expression (u⍸t){+/⍵}⌸x summarises x in 5-minute intervals.

      u ⍸ t
1 1 1 1 1 1 1 1 1 1 ... 288 288 288 288 288 288

      (u⍸t) {+/⍵}⌸ x
1339083050 1365108650 1541944750 1393476000 1454347100 ...

      (u⍸t) {(⍺⌷u),+/⍵}⌸ x
 0  0 0 1339083050
 0  5 0 1365108650
 0 10 0 1541944750
 0 15 0 1393476000
   ...
23 45 0 1388823150
23 50 0 1453472350
23 55 0 1492078850

Higher-Rank Left Argument

If X is a higher rank array, the function compares sub-arrays in Y with the major cells of X, where a major cell is a sub-array on the leading dimension of X with shape 1↓⍴X. In this case, the shape of the result R is (1-⍴⍴X)↓⍴Y.

Example

      x ← ↑ 'Fi' 'Jay' 'John' 'Morten' 'Roger'
      x
Fi
Jay
John
Morten
Roger
      ⍴x
5 6
      y ← x ⍪ ↑ 'JD' 'Jd' 'Geoff' 'Alpha' 'Omega' 'Zeus  '
      y
Fi
Jay
John
Morten
Roger
JD
Jd
Geoff
Alpha
Omega
Zeus

      x ⍸ y
1 2 3 4 5 1 2 1 0 4 5
      y ,⍪ x⍸y
Fi     1
Jay    2
John   3
Morten 4
Roger  5
JD     1
Jd     2
Geoff  1
Alpha  0
Omega  4
Zeus   5

Further Example

      ⍴x
5 6
      ⍴y
3 3 6
      x
Fi
Jay
John
Morten
Roger
      y
Fi
Jay
John

Morten
Roger
JD

Jd
Geoff
Alpha
      x⍸y
1 2 3
4 5 1
2 1 0

Nested Array Example

A card-player likes to sort a hand into suits spades, hearts, diamond, clubs (fortunately alphabetic) and high-to-low within each suit.

      suits←'Clubs' 'Diamonds' 'Hearts' 'Spades'
      pack←,(⊂¨suits)∘.,1↓14 ⍝ 11=Jack ... 14=Ace
      hand←↑(,pack)[7?52]
      hand←hand[⍒hand;]
      hand
┌────────┬──┐
│Spades  │12│
├────────┼──┤
│Hearts  │12│
├────────┼──┤
│Hearts  │7 │
├────────┼──┤
│Hearts  │2 │
├────────┼──┤
│Diamonds│11│
├────────┼──┤
│Diamonds│9 │
├────────┼──┤
│Clubs   │8 │
└────────┴──┘

Another card, the 10 of diamonds is dealt. Where must it go in the hand ?

      (⊖hand)⍸'Diamonds' 10 ⍝ left arg must be sorted up
2
      (¯2↓hand)⍪'Diamonds' 10⍪¯2↑hand
┌────────┬──┐
│Spades  │12│
├────────┼──┤
│Hearts  │12│
├────────┼──┤
│Hearts  │7 │
├────────┼──┤
│Hearts  │2 │
├────────┼──┤
│Diamonds│11│
├────────┼──┤
│Diamonds│10│
├────────┼──┤
│Diamonds│9 │
├────────┼──┤
│Clubs   │8 │
└────────┴──┘

Note that if (∧/Y∊X) and X is sorted and ⎕CT=0 ,then x⍸y is the same as x⍳y.


Left

Left R←X⊣Y

X and Y may be any arrays.

The result R is the left argument X.

Example

      42⊣'abc' 1 2 3
42

Note that when ⊣ is applied using reduction, the derived function selects the first sub-array of the array along the specified dimension. This is implemented as an idiom.

Examples

      ⊣/1 2 3
1

      mat←↑'scent' 'canoe' 'arson' 'rouse' 'fleet'
      ⊣⌿mat  ⍝ first row
scent
      ⊣/mat  ⍝ first column
scarf
      ⊣/[2]2 3 4⍴⍳24 ⍝ first row from each plane
 1  2  3  4
13 14 15 16

Similarly, with expansion:

      ⊣\mat
sssss
ccccc
aaaaa
rrrrr
fffff
      ⊣⍀mat
scent
scent
scent
scent
scent


Less

Less R←X<Y

Y may be any numeric array. X may be any numeric array. R is Boolean. R is 1 if X is less than Y and X=Y is 0. Otherwise R is 0.

⎕CT and ⎕DCT are implicit arguments of Less.

Examples

      (2 4) (6 8 10) < 6
 1 1  0 0 0

      ⎕CT←1E¯10

      1 0.99999999999 0.9999999999<1
0 0 1


Less Or Equal

Less Or Equal R←X≤Y

Y may be any numeric array. X may be any numeric array. R is Boolean. R is 1 if X is less than Y or X=Y. Otherwise R is 0.

⎕CT and ⎕DCT are implicit arguments of Less Or Equal.

Examples

      2 4 6 8 10 ≤ 6
1 1 1 0 0

      ⎕CT←1E¯10

      1  1.00000000001 1.00000001 ≤ 1
1 1 0


Logarithm

Logarithm R←X⍟Y

Y must be a positive numeric array. X must be a positive numeric array. X cannot be 1 unless Y is also 1. R is the base X logarithm of Y.

Note that Logarithm (dyadic ⍟) is defined in terms of Natural Logarithm (monadic ⍟) as:

      X⍟Y←→(⍟Y)÷⍟X

Examples

      10⍟100 2
2 0.3010299957

      2 10⍟0J1 1J2
0J2.266180071 0.3494850022J0.4808285788

      1 ⍟ 1
1
      2 ⍟ 1
0


Magnitude

Magnitude R←|Y

Y may be any numeric array. R is numeric composed of the absolute (unsigned) values of Y.

Note that the magnitude of a complex number [image] is defined to be

Examples

      |2 ¯3.4 0 ¯2.7
2 3.4 0 2.7

      |3j4
5

⎕IO is an implicit argument of magnitude.


Match

Match R←X≡Y

Y may be any array. X may be any array. R is a simple Boolean scalar. If X is identical to Y, then R is 1. Otherwise R is 0.

Non-empty arrays are identical if they have the same structure and the same values in all corresponding locations. Empty arrays are identical if they have the same shape and the same prototype (disclosed nested structure).

⎕CT and ⎕DCT are implicit arguments of Match.

Examples

      ⍬≡⍳0
1
      ''≡⍳0
0
      A
THIS
WORD

      A≡2 4⍴'THISWORD'
1
      A≡⍳10
0
      +B←A A
 THIS  THIS
 WORD  WORD

      A≡⊃B
1

      (0⍴A)≡0⍴B
0

      ' '=⊃0⍴B
1 1 1 1
1 1 1 1

      ' '=⊃0⍴A
1


Matrix Divide

Matrix Divide R←X⌹Y

Y must be a simple numeric array of rank 2 or less. X must be a simple numeric array of rank 2 or less. Y must be non-singular. A scalar argument is treated as a matrix with one-element. If Y is a vector, it is treated as a single column matrix. If X is a vector, it is treated as a single column matrix. The number of rows in X and Y must be the same. Y must have at least the same number of rows as columns.

R is the result of matrix division of X by Y. That is, the matrix product Y+.×R is X.

R is determined such that (X-Y+.×R)*2 is minimised.

The shape of R is (1↓⍴Y),1↓⍴X.

Examples

      ⎕PP←5

      B
3 1 4
1 5 9
2 6 5

      35 89 79 ⌹ B
2.1444 8.2111 5.0889

      A
35 36
89 88
79 75

      A ⌹ B
2.1444 2.1889
8.2111 7.1222
5.0889 5.5778

If there are more rows than columns in the right argument, the least squares solution results. In the following example, the constants a and b which provide the best fit for the set of equations represented by P = a + bQ are determined:

      Q
1 1
1 2
1 3
1 4
1 5
1 6

      P
12.03 8.78 6.01 3.75 ¯0.31 ¯2.79

      P⌹Q
14.941 ¯2.9609

Example: linear regression on complex numbers

      x←j⌿¯50+?2 13 4⍴100
      y←(x+.×3 4 5 6) + j⌿0.0001×¯50+?2 13⍴100
      ⍴x
13 4
      ⍴y
13
      y ⌹ x
3J0.000011066 4J¯0.000018499 5J0.000005745 6J0.000050328
      ⍝ i.e. y⌹x recovered the coefficients 3 4 5 6

Additional Information

      x⌹y ←→ (⌹(⍉y)+.×y)+.×(⍉y)+.×x

(Use +⍉ instead of ⍉ for complex y.)

This equivalence, familiar to mathematicians and statisticians, explains

  • the conformability requirements for ⌹
  • how to compute the result for tall matrices from the better known square matrix case


Matrix Inverse

Matrix Inverse R←⌹Y

Y must be a simple array of rank 2 or less. Y must be non-singular. If Y is a scalar, it is treated as a one-element matrix. If Y is a vector, it is treated as a single-column matrix. Y must have at least the same number of rows as columns.

R is the inverse of Y if Y is a square matrix, or the left inverse of Y if Y is not a square matrix. That is, R+.×Y is an identity matrix.

The shape of R is ⌽⍴Y.

Examples

      M
2 ¯3
4 10

      +A←⌹M
 0.3125 0.09375
¯0.125  0.0625

Within calculation accuracy, A+.×M is the identity matrix.

      A+.×M
1 0
0 1

      j←{⍺←0 ⋄ ⍺+0J1×⍵}
      x←j⌿¯50+?2 5 5⍴100
      x
¯37J¯41  25J015  ¯5J¯09   3J020 ¯29J041
¯46J026  17J¯24  17J¯46  43J023 ¯12J¯18
  1J013  33J025 ¯47J049 ¯45J¯14   2J¯26
 17J048 ¯50J022 ¯12J025 ¯44J015  ¯9J¯43
 18J013   8J038  43J¯23  34J¯07   2J026
      ⍴x
5 5
      id←{∘.=⍨⍳⍵}  ⍝ identity matrix of order ⍵
      ⌈/,| (id 1↑⍴x) - x+.×⌹x
3.66384E¯16


Maximum

Maximum R←X⌈Y

Y may be any numeric array. X may be any numeric array. R is numeric. R is the larger of the numbers X and Y.

Example

      ¯2.01 0.1 15.3 ⌈ ¯3.2 ¯1.1 22.7
¯2.01 0.1 22.7


Membership

Membership R←X∊Y

Y may be any array. X may be any array. R is Boolean. An element of R is 1 if the corresponding element of X can be found in Y.

An element of X is considered identical to an element in Y if X≡Y returns 1 for those elements.

⎕CT and ⎕DCT are implicit arguments of Membership.

Examples

      'THIS NOUN' ∊ 'THAT WORD'
1 1 0 0 1 0 1 0 0

      'CAT' 'DOG' 'MOUSE' ∊ 'CAT' 'FOX' 'DOG' 'LLAMA'
1 1 0

For performance information, see Search Functions and Hash Tables.


Minimum

Minimum R←X⌊Y

Y may be any numeric array. X may be any numeric array. R is numeric. R is the smaller of X and Y.

Example

      ¯2.1 0.1 15.3 ⌊ ¯3.2 1 22
¯3.2 0.1 15.3


Minus

Minus R←X-Y

See Subtract.


Mix

Mix (⎕ML) R←↑[K]Y or R←⊃[K]Y

The symbol chosen to represent Mix depends on the current Migration Level.

If ⎕ML<2, Mix is represented by the symbol: ↑.

If ⎕ML≥2, Mix is represented by the symbol: ⊃.

Y may be any array whose items may be uniform in rank and shape, or differ in rank and shape. If the items of Y are non-uniform, they are extended prior to the application of the function as follows:

  1. If the items of Y have different ranks, each item is extended in rank to that of the greatest rank by padding with leading 1s.
  2. If the items of Y have different shapes, each is padded with the corresponding prototype to a shape that represents the greatest length along each axis of all items in Y.

For the purposes of the following narrative, y represents the virtual item in Y with the greatest rank and shape, with which all other items are extended to conform.

R is an array composed from the items of Y assembled into a higher-rank array with one less level of nesting. ⍴R will be some permutation of (⍴Y),⍴y.

K is an optional axis specification whose value(s) indicate where in the result the axes of y appear. There are three cases:

  1. For all values of ⎕ML, K may be a scalar or 1-element vector whose value is a fractional number indicating the two axes of Y between which new axes are to be inserted for y. The shape of R is the shape of Y with the shape ⍴y inserted between the ⌊Kth and the ⌈Kth axes of Y
  2. If ⎕ML≥2, K may be a scalar or 1-element vector integer whose value specifies the position of the first axis of y in the result. This case is identical to the fractional case where K (in this case) is ⌈K (in the fractional case).
  3. If ⎕ML≥2, K may be a vector, with the same length as ⍴y, each element of which specifies the position in the result of the corresponding axis of the y.

If K is absent, the axes of y appear as the last axes of the result.

Simple Vector Examples

In this example, the shape of Y is 3, and the shape of y is 2. So the shape of the result will be a permutation of 2 and 3, i.e. in this simple example, either (2 3) or (3 2).

If K is omitted, the shape of the result is (⍴Y),⍴y.

      ↑(1 2)(3 4)(5 6)
1 2
3 4
5 6

If K is between 0 and 1, the shape of the result is (⍴y),⍴Y because (⍴y) is inserted between the 0th and the 1st axis of the result, i.e. at the beginning.

      ↑[.5](1 2)(3 4)(5 6)
1 3 5
2 4 6

If K is between 1 and 2, the shape of the result is (⍴Y),⍴y because (⍴y) is inserted between the 1st and 2nd axis of the result, i.e. at the end. This is the same as the case when K is omitted.

      ↑[1.5](1 2)(3 4)(5 6)
1 2
3 4
5 6

If ⎕ML≥2 an integer K may be used instead (Note that ⊃ is used instead of ↑).

      ⎕ML←3
      ⊃(1 2)(3 4)(5 6)
1 2
3 4
5 6
      ⊃[1](1 2)(3 4)(5 6)
1 3 5
2 4 6
      ⊃[2](1 2)(3 4)(5 6)
1 2
3 4
5 6

Shape Extension

If the items of Y are unequal in shape, the shorter ones are extended:

      ⎕ML←3
      ⊃(1)(3 4)(5)
1 0
3 4
5 0
       ⊃[1](1)(3 4)(5)
1 3 5
0 4 0

More Simple Vector Examples:

      ]box on
Was OFF
       'Andy' 'Geoff' 'Pauline'
┌────┬─────┬───────┐
│Andy│Geoff│Pauline│
└────┴─────┴───────┘
      ↑'Andy' 'Geoff' 'Pauline'
Andy
Geoff
Pauline

        ⎕ML←3
        ⊃('andy' 19)('geoff' 37)('pauline' 21)
┌───────┬──┐
│andy   │19│
├───────┼──┤
│geoff  │37│
├───────┼──┤
│pauline│21│
└───────┴──┘
        ⊃[1]('andy' 19)('geoff' 37)('pauline' 21)
┌────┬─────┬───────┐
│andy│geoff│pauline│
├────┼─────┼───────┤
│19  │37   │21     │
└────┴─────┴───────┘
        ⊃('andy' 19)('geoff' 37)(⊂'pauline')
┌───────┬───────┐
│andy   │19     │
├───────┼───────┤
│geoff  │37     │
├───────┼───────┤
│pauline│       │
└───────┴───────┘

Notice that in the last statement, the shape of the third item was extended by catenating it with its prototype.

Example (Matrix of Vectors)

In the following examples, Y is a matrix of shape (5 4) and each item of Y (y) is a matrix of shape (3 2). The shape of the result will be some permutation of (5 4 3 2).

       Y←5 4⍴(⍳20)×⊂3 2⍴1
       Y
┌─────┬─────┬─────┬─────┐
│1 1  │2 2  │3 3  │4 4  │
│1 1  │2 2  │3 3  │4 4  │
│1 1  │2 2  │3 3  │4 4  │
├─────┼─────┼─────┼─────┤
│5 5  │6 6  │7 7  │8 8  │
│5 5  │6 6  │7 7  │8 8  │
│5 5  │6 6  │7 7  │8 8  │
├─────┼─────┼─────┼─────┤
│9 9  │10 10│11 11│12 12│
│9 9  │10 10│11 11│12 12│
│9 9  │10 10│11 11│12 12│
├─────┼─────┼─────┼─────┤
│13 13│14 14│15 15│16 16│
│13 13│14 14│15 15│16 16│
│13 13│14 14│15 15│16 16│
├─────┼─────┼─────┼─────┤
│17 17│18 18│19 19│20 20│
│17 17│18 18│19 19│20 20│
│17 17│18 18│19 19│20 20│
└─────┴─────┴─────┴─────┘

By default, the axes of y appear in the last position in the shape of the result, but this position is altered by specifying the axis K. Notice where the (3 2) appears in the following results:

      ⍴⊃Y
5 4 3 2
      ⍴⊃[1]Y
3 2 5 4
      ⍴⊃[2]Y
5 3 2 4
      ⍴⊃[3]Y
5 4 3 2
      ⍴⊃[4]Y
INDEX ERROR
      ⍴⊃[4]Y
     ∧

Note that ⊃[4]Y generates an INDEX ERROR because 4 is greater than the length of the result.

Example (Vector K)

The axes of y do not have to be contiguous in the shape of the result. By specifying a vector K, they can be distributed. Notice where the 3 and the 2 appear in the following results:

      ⍴⊃[1 3]Y
3 5 2 4
      ⍴⊃[1 4]Y
3 5 4 2
      ⍴⊃[2 4]Y
5 3 4 2
      ⍴⊃[4 2]Y
5 2 4 3

Rank Extension

If the items of Y are unequal in rank, the lower rank items are extended in rank by prefixing their shapes with 1s. Each additional 1 may then be increased to match the maximum shape of the other items along that axis.

      ⎕ML←3
      Y←(1)(2 3 4 5)(2 3⍴10×⍳8)
      Y
┌─┬───────┬────────┐
│1│2 3 4 5│10 20 30│
│ │       │40 50 60│
└─┴───────┴────────┘
       ⍴⊃Y
3 2 4
       ⊃Y
 1  0  0 0
 0  0  0 0

 2  3  4 5
 0  0  0 0

10 20 30 0
40 50 60 0

In the above example, the first item (1) becomes (1 1⍴1) to conform with the 3rd item which is rank 2. It is then extended in shape to become (2 4↑1 1⍴1) to conform with the 2-row 3rd item, and 4-column 2nd item.. Likewise, the 2nd item becomes a 2-row matrix, and the 3rd item gains another column.


Multiply

Multiply R←X×Y

Y may be any numeric array. X may be any numeric array. R is the arithmetic product of X and Y.

This function is also known as Times.

Example

      3 2 1 0 × 2 4 9 6
6 8 9 0

       2j3×.3j.5 1j2 3j4 .5
¯0.9J1.9 ¯4J7 ¯6J17 1J1.5


Nand

Nand R←X⍲Y

Y must be a Boolean array. X must be a Boolean array. R is Boolean. The value of R is the truth value of the proposition "not both X and Y", and is determined as follows:

             X   Y     R

             0   0     1
             0   1     1
             1   0     1
             1   1     0

Example

      (0 1)(1 0) ⍲ (0 0)(1 1)
 1 1  0 1


Natural Logarithm

Natural Logarithm R←⍟Y

Y must be a positive numeric array. R is numeric. R is the natural (or Napierian) logarithm of Y whose base is the mathematical constant e=2.71828....

Example

      ⍟1 2
0 0.6931471806

      ⍟2 2⍴0j1 1j2 2j3 3j4
0.000000000J1.570796327  0.8047189562J1.107148718
1.282474679J0.9827937232 1.6094379120J0.927295218


Negative

Negative R←-Y

Y may be any numeric array. R is numeric and is the negative value of Y. For complex numbers both the real and imaginary parts are negated.

Example

      -4 2 0 ¯3 ¯5
¯4 ¯2 0 3 5

      -1j2 ¯2J3 4J¯5
¯1J¯2 2J¯3 ¯4J5


Nest

Nest R←⊆Y

Classic Edition: the symbol ⊆ (Left Shoe Underbar) is not available in Classic Edition, and Nest is instead represented by ⎕U2286.

Y may be any array.

If Y is simple, R is a scalar array whose item is the array Y. If Y is a simple scalar or is already nested, R is Y unchanged.

Examples

      ⊆1 2 3
┌─────┐
│1 2 3│
└─────┘
      ⊆ 1 (1 2 3)
┌─┬─────┐
│1│1 2 3│
└─┴─────┘
      ⊆'Dyalog'
┌──────┐
│Dyalog│
└──────┘
      ⊆'Dyalog' 'APL'
┌──────┬───┐
│Dyalog│APL│
└──────┴───┘


Nor

Nor R←X⍱Y

Y must be a Boolean array. X must be a Boolean array. R is Boolean. The value of R is the truth value of the proposition "neither X nor Y", and is determined as follows:

             X   Y     R

             0   0     1
             0   1     0
             1   0     0
             1   1     0

Example

      0 0 1 1 ⍱ 0 1 0 1
1 0 0 0


Not

Not R←~Y

Y must be a Boolean array. R is Boolean. The value of R is 0 if Y is 1, and R is 1 if Y is 0.

Example

      ~0 1
1 0


Not Equal

Not Equal R←X≠Y

Y may be any array. X may be any array. R is Boolean. R is 0 if X=Y. Otherwise R is 1.

For Boolean X and Y, the value of R is the exclusive or (XOR) result, determined as follows:

             X   Y     R

             0   0     0
             0   1     1
             1   0     1
             1   1     0

⎕CT and ⎕DCT are implicit arguments of Not Equal.

Examples

      1 2 3 ≠ 1.1 2 3
1 0 0

      ⎕CT←1E¯10

      1≠1 1.00000000001 1.0000001
0 0 1

      1 2 3 ≠'CAT'
1 1 1


Not Match

Not Match R←X≢Y

Y may be any array. X may be any array. R is a simple Boolean scalar. If X is identical to Y, then R is 0. Otherwise R is 1.

Non-empty arrays are identical if they have the same structure and the same values in all corresponding locations. Empty arrays are identical if they have the same shape and the same prototype (disclosed nested structure).

⎕CT and ⎕DCT are implicit arguments of Not Match.

Examples

      ⍬≢⍳0
0
      ''≢⍳0
1
      ⊢A←⊂(⍳3) 'ABC'
  1 2 3  ABC
      A≢(⍳3)'ABC'
1
      A≢⊂(⍳3) 'ABC'
0
      ⍬≢0⍴A
1
      (1↑0⍴A)≢⊂(0 0 0) '   '
1


Or Greatest Common Divisor

Or, Greatest Common Divisor R←X∨Y

Case 1: X and Y are Boolean

R is Boolean and is determined as follows:

             X   Y     R

             0   0     0
             0   1     1
             1   0     1
             1   1     1

Example

      0 0 1 1 ∨ 0 1 0 1
0 1 1 1

Case 2: X and Y are numeric (non-Boolean)

R is the Greatest Common Divisor of X and Y. Note that in this case, ⎕CT and ⎕DCT are implicit arguments.

Examples

      15 1 2 7 ∨ 35 1 4 0
5 1 2 7

      rational←{↑⍵ 1÷⊂1∨⍵} ⍝ rational (⎕CT) approximation
                           ⍝ to floating array.
      rational 0.4321 0.1234 6.66, ÷1 2 3
 4321  617 333 1 1 1
10000 5000  50 1 2 3


Partitioned Enclose

Partitioned Enclose (⎕ML<3) R←X⊂[K]Y

Y may be any array. X must be a simple Boolean scalar or vector.

The axis specification is optional. If present, it must be a simple integer scalar or one-element vector. The value of K must be an axis of Y. If absent, the last axis of Y is implied.

X must have the same length as the Kth axis of Y. However, if X is a scalar or one-element vector, it will be extended to the length of the Kth axis of Y.

R is a vector of items selected from Y. The sub-arrays identified along the Kth axis of Y at positions corresponding to each 1 in X up to the position before the next 1 in X (or the last element of X) become the successive items of R. The length of R is +/X (after possible extension).

Examples

      0 1 0 0 1 1 0 0 0 ⊂⍳9
 2 3 4  5  6 7 8 9

      1 0 1 ⊂[1] 3 4⍴⍳12
 1 2 3 4  9 10 11 12
 5 6 7 8

      1 0 0 1 ⊂[2]3 4⍴⍳12
 1  2  3   4
 5  6  7   8
 9 10 11  12


Pi Times

Pi Times R←○Y

Y may be any numeric array. R is numeric. The value of R is the product of the mathematical constant π=3.14159... (Pi), and Y.

Example

      ○0.5 1 2
1.570796327 3.141592654 6.283185307

      ○0J1
0J3.141592654

      *○0J1 ⍝ Euler
¯1


Pick

Pick R←X⊃Y

Y may be any array.

X is a scalar or vector of indices of Y.

R is an item selected from the structure of Y according to X.

Elements of X select from successively deeper levels in the structure of Y. The items of X are simple integer scalars or vectors which identify a set of indices, one per axis at the particular level of nesting of Y in row-major order. Simple scalar items in Y may be picked by empty vector items in X to any arbitrary depth.

⎕IO is an implicit argument of Pick.

Examples

      G←('ABC' 1)('DEF' 2)('GHI' 3)('JKL' 4)

      G←2 3⍴G,('MNO' 5)('PQR' 6)

      G
  ABC  1   DEF  2   GHI  3
  JKL  4   MNO  5   PQR  6

      ((⊂2 1),1)⊃G
JKL

      (⊂2 1)⊃G
 JKL  4

      ((2 1)1 2)⊃G
K

      (5⍴⊂⍳0)⊃10
10


Plus

Plus R←X+Y

See Add .


Power

Power R←X*Y

Y must be a numeric array. X must be a numeric array. R is numeric. The value of R is X raised to the power of Y.

If Y is zero, R is defined to be 1.

If X is zero, Y must be non-negative.

In general, if X is negative, the result R is likely to be complex.

Examples

      2*2 ¯2
4 0.25

      9 64*0.5
3 8

      ¯27*3 2 1.2 .5
¯19683 729 ¯42.22738244J¯30.67998919 0J5.196152423


Ravel

Ravel R←,Y

Y may be any array. R is a vector of the elements of Y taken in row-major order.

Examples

      M
1 2 3
4 5 6

      ,M
1 2 3 4 5 6

      A
ABC
DEF
GHI
JKL

      ,A
ABCDEFGHIJKL

      ⍴,10
1

See also: Ravel with Axes.


Ravel with Axes

Ravel with Axes R←,[K]Y

Y may be any array.

K is either:

  • A simple fractional scalar adjacent to an axis of Y, or
  • A simple integer scalar or vector of axes of Y, or
  • An empty vector

Ravel with axis can be used with selective specification.

R depends on the case of K above.

If K is a fraction, the result R is an array of the same shape as Y, but with a new axis of length 1 inserted at the Kth position.

      ⍴⍴R ←→ 1+⍴⍴Y
      ⍴R  ←→ (1,⍴Y)[⍋K,⍳⍴⍴Y]

Examples

      ,[0.5]'ABC'
ABC
      ⍴,[0.5]'ABC'
1 3
      ,[1.5]'ABC'
A
B
C
      ⍴,[1.5]'ABC'
3 1

      MAT←3 4⍴⍳12
      ⍴,[0.5]MAT
1 3 4
      ⍴,[1.5]MAT
3 1 4
      ⍴,[2.5]MAT
3 4 1

If K is an integer scalar or vector of axes of Y, then:

  • K must contain contiguous axes of Y in ascending order
  • R contains the elements of Y ravelled along the indicated axes

Note that if K is a scalar or single element vector, R ←→ Y.

      ⍴⍴R ←→ 1+(⍴⍴Y)-⍴,K

Examples

      M
 1  2  3  4
 5  6  7  8
 9 10 11 12

13 14 15 16
17 18 19 20
21 22 23 24
      ⍴M
2 3 4

      ,[1 2]M
 1  2  3  4
 5  6  7  8
 9 10 11 12
13 14 15 16
17 18 19 20
21 22 23 24
      ⍴,[1 2]M
6 4

      ,[2 3]M
 1  2  3  4  5  6  7  8  9 10 11 12
13 14 15 16 17 18 19 20 21 22 23 24

      ⍴,[2 3]M
2 12

If K is an empty vector a new last axis of length 1 is created.

      ⍴R ←→ (⍴Y),1

Examples

      Q1←'January' 'February' 'March'
      ]display Q1
┌→─────────────────────────────┐
│ ┌→──────┐ ┌→───────┐ ┌→────┐ │
│ │January│ │February│ │March│ │
│ └───────┘ └────────┘ └─────┘ │
└∊─────────────────────────────┘
      ]display ,[⍳0]Q1
┌→───────────┐
↓ ┌→──────┐  │
│ │January│  │
│ └───────┘  │
│ ┌→───────┐ │
│ │February│ │
│ └────────┘ │
│ ┌→────┐    │
│ │March│    │
│ └─────┘    │
└∊───────────┘

See also: Ravel.


Reciprocal

Reciprocal R←÷Y

Y must be a numeric array. R is numeric. R is the reciprocal of Y; that is 1÷Y. If ⎕DIV=0, ÷0 results in a DOMAIN ERROR. If ⎕DIV=1, ÷0 returns 0.

⎕DIV is an implicit argument of Reciprocal.

Examples

      ÷4 2 5
0.25 0.5 0.2

      ÷0j1 0j¯1 2j2 4j4
0J¯1 0J1 0.25J¯0.25 0.125J¯0.125

      ⎕DIV←1
      ÷0 0.5
0 2


Replicate

Replicate R←X/[K]Y

Y may be any array. X is a simple integer vector or scalar.

The axis specification is optional. If present, K must be a simple integer scalar or 1-element vector. The value of K must be an axis of Y. If absent, the last axis of Y is implied. The form R←X⌿Y implies the first axis of Y.

If Y has length 1 along the Kth (or implied) axis, it is extended along that axis to match the length of X. Otherwise, the length of X must be the length of the Kth (or implied) axis of Y. However, if X is a scalar or one-element vector, it will be extended to the length of the Kth axis.

R is composed from sub-arrays along the Kth axis of Y. If X[I] (an element of X) is positive, then the corresponding sub-array is replicated X[I] times. If X[I] is zero, then the corresponding sub-array of Y is excluded. If X[I] is negative, then the fill element of Y is replicated |X[I] times. Each of the (replicated) sub-arrays and fill items are joined along the Kth axis in the order of occurrence. The shape of R is the shape of Y except that the length of the (implied) Kth axis is +/|X (after possible extension).

This function is sometimes called Compress when X is Boolean.

Examples

      1 0 1 0 1/⍳5
1 3 5

      1 ¯2 3 ¯4 5/⍳5
1 0 0 3 3 3 0 0 0 0 5 5 5 5 5

      M
1 2 3
4 5 6

      2 0 1/M
1 1 3
4 4 6

      0 1⌿M
4 5 6

      0 1/[1]M
4 5 6

If Y is a singleton (1=×/⍴,Y) its value is notionally extended to the length of X along the specified axis.

      1 0 1/4
4 4
      1 0 1/,3
3 3
      1 0 1/1 1⍴5
5 5


Reshape

Reshape R←X⍴Y

Y may be any array. X must be a simple scalar or vector of non-negative integers. R is an array of shape X whose elements are taken from Y in row-major sequence and repeated cyclically if required. If Y is empty, R is composed of fill elements of Y (⊂∊⊃Y with ⎕ml←0). If X contains at least one zero, then R is empty. If X is an empty vector, then R is scalar.

Examples

      2 3⍴⍳8
1 2 3
4 5 6

      2 3⍴⍳4
1 2 3
4 1 2

      2 3⍴⍳0
0 0 0
0 0 0


Residue

Residue R←X|Y

Y may be any numeric array. X may be any numeric array.

For positive arguments, R is the remainder when Y is divided by X. If X=0, R is Y.

For other argument values, R is given by the expression Y-X×⌊Y÷X+0=X. This expression also applies when X and/or Y are complex if the simple ⌊ is replaced by the CpxFloor function. See Complex Floor.

⎕CT and ⎕DCT are implicit arguments of Residue.

Examples

      3 3 ¯3 ¯3|¯5 5 ¯4 4
1 2 ¯1 ¯2

      0.5|3.12 ¯1 ¯0.6
0.12 0 0.4

      ¯1 0 1|¯5.25 0 2.41
¯0.25 0 0.41

      1j2|2j3 3j4 5j6
1J1 ¯1J1 0J1

Note that the ASCII Broken Bar (⎕UCS 166, U+00A6) is not interpreted as Residue.


Reverse

Reverse R←⌽[K]Y

Y may be any array. The axis specification is optional. If present, K must be an integer scalar or one-element vector. The value of K must be an axis of Y. If absent, the last axis is implied. The form R←⊖Y implies the first axis.

R is the array Y reversed on the Kth or implied axis.

Examples

      ⌽1 2 3 4 5
5 4 3 2 1

      M
1 2 3
4 5 6
      ⌽M
3 2 1
6 5 4
      ⊖M
4 5 6
1 2 3
      ⌽[1]M
4 5 6
1 2 3


Reverse First

Reverse First R←⊖[K]Y

The form R←⊖Y implies reversal along the first axis. See Reverse.


Right

Right R←X⊢Y

X and Y may be any arrays. The result R is the right argument Y.

Examples

      42 ⊢'abc' 1 2 3
 abc  1 2 3
      32+1.8×⊢0 100      ⍝ {32+1.8÷⍵} 0 100
32 212

      (⊢÷+/) 4 3 0 1     ⍝ {⍵÷+/⍵} 4 3 0 1
0.5 0.375 0 0.125

      ↓⍣2⊢2 2 2 2⍴⎕A     ⍝ (↓⍣2)2 2 2 2⍴⎕A
  AB  CD    EF  GH
  IJ  KL    MN  OP

When ⊢ is applied using reduction, the derived function selects the last sub-array of the array along the specified dimension. This is implemented as an idiom.

Examples

      ⊢/1 2 3
3
      mat←↑'scent' 'canoe' 'arson' 'rouse' 'fleet'

      ⊢⌿mat  ⍝ last row
fleet
      ⊢/mat  ⍝ last column
tenet

      ⊢/[2]2 3 4⍴⍳24 ⍝ last row from each plane
 9 10 11 12
21 22 23 24


Roll

Roll R←?Y

Y may be any non-negative integer array. R has the same shape as Y at each depth.

For each positive element of Y the corresponding element of R is an integer, pseudo-randomly selected from the integers ⍳Y with each integer in this population having an equal chance of being selected.

For each zero element of Y, the corresponding element of R is a pseudo-random floating-point value in the range 0 - 1, but excluding 0 and 1, i.e. (0<R[I]<1).

⎕IO and ⎕RL are implicit arguments of Roll. A side effect of Roll is to change the value of ⎕RL.

Note that different random number generators are available; see ⎕RL for more information.

Examples

      ?9 9 9
2 7 5
      ?3⍴0
0.3205466592 0.3772891947 0.5456603511


Rotate

Rotate R←X⌽[K]Y

Y may be any array. X must be a simple integer array. The axis specification is optional. If present, K must be a simple integer scalar or one-element vector.

The value of K must be an axis of Y. If absent, the last axis of Y is implied. The form R←X⊖Y implies the first axis.

X must have the same shape as Y, excluding Y's Kth axis. Otherwise, if X is a one-element array, it will be extended to conform.

R is an array with the same shape as Y, with the elements of each of the vectors along the Kth axis of Y rotated by the value of the corresponding element of X. If the value is positive, the rotation is in the sense of right to left. If the value is negative, the rotation is in the sense of left to right.

Examples

      3 ⌽ 1 2 3 4 5 6 7
4 5 6 7 1 2 3
      ¯2 ⌽ 1 2 3 4 5
4 5 1 2 3

      M
 1  2  3  4
 5  6  7  8

 9 10 11 12
13 14 15 16

      I
0 1 ¯1 0
0 3  2 1

      I⌽[2]M
 1  6  7  4
 5  2  3  8

 9 14 11 16
13 10 15 12

      J
2 ¯3
3 ¯2
      J⌽M
 3  4  1  2
 6  7  8  5

12  9 10 11
15 16 13 14


Rotate First

Rotate First R←X⊖[K]Y

The form R←X⊖Y implies rotation along the first axis. See Rotate.


Same

Same R←⊣Y
R←⊢Y

Y may be any array.

The result R is the argument Y.

Examples

      ⊣'abc' 1 2 3
 abc  1 2 3
      (⊢,⎕size) 'a'⎕nl 4 ⍝ left tine of fork meaning "it"
acc      572
and      492
ascan    740
ascana   716
at      1764
avl    17476


Shape

Shape R←⍴Y

Y may be any array. R is a non-negative integer vector whose elements are the dimensions of Y. If Y is a scalar, then R is an empty vector. The rank of Y is given by ⍴⍴Y.

Examples

      ⍴10

      ⍴'CAT'
3

      ⍴3 4⍴⍳12
3 4

      +G←(2 3⍴⍳6)('CAT' 'MOUSE' 'FLEA')
 1 2 3   CAT  MOUSE  FLEA
 4 5 6

      ⍴G
2

      ⍴⍴G
1

      ⍴¨G
 2 3  3

      ⍴¨¨G
          3  5  4


Split

Split R←↓[K]Y

Y may be any array. The axis specification is optional. If present, K must be a simple integer scalar or one-element vector. The value of K must be an axis of Y. If absent, the last axis is implied.

The items of R are the sub-arrays of Y along the Kth axis. R is a scalar if Y is a scalar. Otherwise R is an array whose rank is ¯1+⍴⍴Y and whose shape is (K≠⍳⍴⍴Y)/⍴Y.

Examples

      ↓3 4⍴'MINDTHATSTEP'
 MIND  THAT  STEP

      ↓2 5⍴⍳10
 1 2 3 4 5  6 7 8 9 10

      ↓[1]2 5⍴⍳10
 1 6  2 7  3 8  4 9  5 10


Subtract

Subtract R←X-Y

Y may be any numeric array. X may be any numeric array. R is numeric. The value of R is the difference between X and Y.

This function is also known as Minus.

Example

      3 ¯2 4 0 - 2 1 ¯2 4
1 ¯3 6 ¯4

      2j3-.3j5  ⍝ (a+bi)-(c+di) = (a-c)+(b-d)i
1.7J¯2


Table

Table R←⍪Y

Y may be any array. R is a 2-dimensional matrix of the elements of Y taken in row-major order, preserving the shape of the first dimension of Y if it exists

Table has been implemented according to the Extended APL Standard (ISO/IEC 13751:2001).

Examples

      ]display {⍵ (⍴⍵)} ⍪'a'
┌→──────────┐
│ ┌→┐ ┌→──┐ │
│ ↓a│ │1 1│ │
│ └─┘ └~──┘ │
└∊──────────┘

      ]display {⍵ (⍴⍵)} ⍪'hello'
┌→──────────┐
│ ┌→┐ ┌→──┐ │
│ ↓h│ │5 1│ │
│ │e│ └~──┘ │
│ │l│       │
│ │l│       │
│ │o│       │
│ └─┘       │
└∊──────────┘

      ]display {⍵ (⍴⍵)} ⍪2 3 4⍴⍳24
┌→─────────────────────────────────────────────┐
│ ┌→──────────────────────────────────┐ ┌→───┐ │
│ ↓ 1  2  3  4  5  6  7  8  9 10 11 12│ │2 12│ │
│ │13 14 15 16 17 18 19 20 21 22 23 24│ └~───┘ │
│ └~──────────────────────────────────┘        │
└∊─────────────────────────────────────────────┘


Take

Take R←X↑Y

Y may be any array. X must be a simple integer scalar or vector.

If Y is a scalar, it is treated as a one-element array of shape (⍴,X)⍴1. The length of X must be the same as or less than the rank of Y. If the length of X is less than the rank of Y, the missing elements of X default to the length of the corresponding axis of Y.

R is an array of the same rank as Y (after possible extension), and of shape |X. If X[I] (an element of X) is positive, then X[I] sub-arrays are taken from the beginning of the Ith axis of Y. If X[I] is negative, then X[I] sub-arrays are taken from the end of the Ith axis of Y.

If more elements are taken than exist on axis I, the extra positions in R are filled with the fill element of Y (⊂∊⊃Y with ⎕ml←0).

Examples

      5↑'ABCDEF'
ABCDE

      5↑1 2 3
1 2 3 0 0

      ¯5↑1 2 3
0 0 1 2 3

      5↑(⍳3) (⍳4) (⍳5)
 1 2 3  1 2 3 4  1 2 3 4 5  0 0 0  0 0 0

      M
1 2 3 4
5 6 7 8

      2 3↑M
1 2 3
5 6 7

      ¯1 ¯2↑M
7 8
      M3←2 3 4⍴⎕A
      1↑M3
ABCD
EFGH
IJKL
      ¯1↑M3
MNOP
QRST
UVWX


Take with Axes

Take with Axes R←X↑[K]Y

Y may be any non-scalar array. X must be a simple integer scalar or vector. K is a vector of zero or more axes of Y.

R is an array of the first or last elements of Y taken along the axes K depending on whether the corresponding element of X is positive or negative respectively.

The rank of R is the same as the rank of Y:

      ⍴⍴R ←→ ⍴⍴Y

The size of each axis of R is determined by the corresponding element of X:

      (⍴R)[,K] ←→ |,X

Examples

      ⎕←M←2 3 4⍴⍳24
 1  2  3  4
 5  6  7  8
 9 10 11 12

13 14 15 16
17 18 19 20
21 22 23 24

      2↑[2]M
 1  2  3  4
 5  6  7  8

13 14 15 16
17 18 19 20

      2↑[3]M
 1  2
 5  6
 9 10

13 14
17 18
21 22

      2 ¯2↑[3 2]M
 5  6
 9 10

17 18
21 22


Tally

Tally R←≢Y

Y may be any array. R is a simple numeric scalar.

Tally returns the number of major cells of Y. See Cells and Sub-arrays.

This can also be expressed as the length of the leading axis or 1 if Y is a scalar. Tally is equivalent to the function {⍬⍴(⍴⍵),1}.

Examples

      ≢2 3 4⍴⍳10
2
      ≢2
1
      ≢⍬
0

Note that ≢V is useful for returning the length of vector V as a scalar. (In contrast, ⍴V is a one-element vector.)


Times

Times R←X×Y

See Multiply.


Transpose Monadic

Transpose (Monadic) R←⍉Y

Y may be any array. R is an array of shape ⌽⍴Y, similar to Y with the order of the axes reversed.

Examples

      M
1 2 3
4 5 6

      ⍉M
1 4
2 5
3 6


Transpose Dyadic

Transpose (Dyadic) R←X⍉Y

Y may be any array. X must be a simple scalar or vector whose elements are included in the set ⍳⍴⍴Y. Integer values in X may be repeated but all integers in the set ⍳⌈/X must be included. The length of X must equal the rank of Y.

R is an array formed by the transposition of the axes of Y as specified by X. The Ith element of X gives the new position for the Ith axis of Y. If X repositions two or more axes of Y to the same axis, the elements used to fill this axis are those whose indices on the relevant axes of Y are equal.

⎕IO is an implicit argument of Dyadic Transpose.

Examples

      A
 1  2  3  4
 5  6  7  8
 9 10 11 12

13 14 15 16
17 18 19 20
21 22 23 24

      2 1 3⍉A
 1  2  3  4
13 14 15 16

 5  6  7  8
17 18 19 20

 9 10 11 12
21 22 23 24

      1 1 1⍉A
1 18

      1 1 2⍉A
 1  2  3  4
17 18 19 20

Alternative Explanation

Assign a distinct letter for each unique integer in X :

0 1 2 3 …
i j k l

If R←X⍉Y, then R[i;j;k;…] equals Y indexed by the letters corresponding to elements of X .

For example:

      ⎕IO←0

      Y← ? 5 13 19 17 11 ⍴ 100

      X← 2 1 2 0 1
      ⍝  k j k i j
      R←X⍉Y
      i←?17 ⋄ j←?11 ⋄ k←?5
      R[i;j;k] = Y[k;j;k;i;j]
1
      R[i;j;k]=Y[⊂⍎¨'ijk'[X]]
1

From the above it can be seen that:

  • the rank of R is 0⌈1+⌈/X
  • the shape of R is (⍴Y)⌊.+(⌈/⍴Y)×X∘.≠⍳0⌈1+⌈/X


Type

Type (⎕ML<1) R←∊Y

Migration level must be such that ⎕ML<1 (otherwise ∊ means Enlist. See Enlist).

Y may be any array. R is an array with the same shape and structure as Y in which a numeric value is replaced by 0 and a character value is replaced by ' '.

Examples

      ∊(2 3⍴⍳6)(1 4⍴'TEXT')
 0 0 0
 0 0 0

      ' '=∊'X'
1


Union

Union R←X∪Y

Y must be a vector. X must be a vector. If either argument is a scalar, it is treated as a one-element vector. R is a vector of the elements of X catenated with the elements of Y which are not found in X.

Items in X and Y are considered the same if X≡Y returns 1 for those items.

⎕CT and ⎕DCT are implicit arguments of Union.

Examples

      'WASH' ∪ 'SHOUT'
WASHOUT

      'ONE' 'TWO' ∪ 'TWO' 'THREE'
 ONE  TWO  THREE

For performance information, see Search Functions and Hash Tables.


Where

Where R←⍸Y

Classic Edition: the symbol ⍸ (Iota Underbar) is not available in Classic Edition, and Where is instead represented by ⎕U2378.

Y must be a simple Boolean array.

R is a vector of the indices of all the 1s in Y. If Y is all zeros, R is an empty vector.

⎕IO is an implicit argument of Where.

Examples

      ⎕IO
1
      ⍸ 1 0 1 0 0 0 0 1 0
1 3 8

      ⍸'e'='Pete'
2 4

      3 4⍴0 1 1
0 1 1 0
1 1 0 1
1 0 1 1

      ⍸ 3 4⍴0 1 1
┌───┬───┬───┬───┬───┬───┬───┬───┐
│1 2│1 3│2 1│2 2│2 4│3 1│3 3│3 4│
└───┴───┴───┴───┴───┴───┴───┴───┘

      ⍸2 3 4⍴0 0 0 0 1
┌─────┬─────┬─────┬─────┐
│1 2 1│1 3 2│2 1 3│2 2 4│
└─────┴─────┴─────┴─────┘

      ⍸3 1 4 2
DOMAIN ERROR
      ⍸3 1 4 2
     ∧


Without

Without R←X~Y

See Excluding.


Zilde

Zilde R←⍬

The empty vector (⍳0) may be represented by the numeric constant ⍬ called ZILDE.


Operator Syntax

Operators take one or two operands. An operator with one operand is monadic. The operand of a monadic operator is to the left of the operator. An operator with two operands is dyadic. Both operands are required for a dyadic operator.

Operators have long scope to the left. That is, the left operand is the longest function or array expression to its left (see Operators). A dyadic operator has short scope on the right. Right scope may be extended by the use of parentheses.

An operand may be an array, a primitive function, a system function, a defined function or a derived function. An array may be the result of an array expression.

An operator with its operand(s) forms a derived function. The derived function may be monadic or dyadic and it may or may not return an explicit result.

Examples

      +/⍳5
15
      (*∘2)⍳3
1 4 9

      PLUS ← + ⋄ TIMES ← ×
      1 PLUS.TIMES 2
2

      ⎕NL 2
A
X
      ⎕EX¨↓⎕NL 2
      ⎕NL 2

Monadic Operators

Like primitive functions, monadic operators can be:

  • named
  • enclosed within parentheses
  • displayed in the session

Examples

      ⎕ ← each ← (¨)      ⍝ name and display
¨
      shape←⍴
      shape each (1 2) (3 4 5)
 2  3

      slash←/
      +slash ⍳10
55
      swap←⍨
      3 -swap 4
1

Right Operand Currying

A dyadic operator may be bound or curried with its right operand to form a monadic operator:

Examples

      ⎕ ← inv ← ⍣¯1  ⍝ produces monadic inverse operator
⍣ ¯1
      +\inv 1 2 3    ⍝ scan-inverse
1 1 1
      lim ← ⍣≡       ⍝ power-limit

      1 +∘÷lim 1     ⍝ Phi
1.61803


Operators Summarised

Table 16 and Table 17 below summarise the Monadic and Dyadic primitive operators whose detailed descriptions follow in alphabetical order in this section.

Some operators may include an axis specification (indicated []in the tables). Note that in these case ⎕IO is an implicit argument of the derived function.

Table 16: Monadic Primitive Operators

Name | Producing Monadic derived function | Producing Dyadic derived function
Assignment (Modified) |  | Xf←Y
Assignment (Indexed Modified) |  | X[I]f←Y
Assignment (Selective Modified) |  | (EXP X)f←Y
Commute | f⍨Y | Xf⍨Y
Each | f¨Y | Xf¨Y
I-Beam | A⌶Y | X(A⌶)Y
Key | f⌸Y | Xf⌸Y
Reduction | f/Y [ ] | Xf/Y [ ]
Reduction First | f⌿Y [ ] | Xf⌿Y [ ]
Scan | f\Y [ ] |
Scan First | f⍀Y [ ] |
Spawn | f&Y | Xf&Y

Table 17: Dyadic Primitive Operators

Name | Producing Monadic derived function | Producing Dyadic derived function
At | f@gY | Xf@gY
Axis | f[B]Y | Xf[B]Y
Composition | f∘gY | Xf∘gY
Composition | A∘gY |
Composition | (f∘B)Y |
Inner Product |  | Xf.gY
Outer Product |  | X∘.gY
Power | f⍣gY | Xf⍣gY
Rank | f⍤kY | Xf⍤kY
Stencil | f⌺gY |
Variant | f⍠gY | Xf⍠gY


Assignment Modified

Assignment (Modified) {R}←Xf←Y

f may be any dyadic function which returns an explicit result. Y may be any array whose items are appropriate to function f. X must be the name of an existing array whose items are appropriate to function f.

R is the “pass-through” value, that is, the value of Y. If the result of the derived function is not assigned or used, there is no explicit result.

The effect of the derived function is to reset the value of the array named by X to the result of XfY.

Examples

      A
1 2 3 4 5

      A+←10

      A
11 12 13 14 15

      ⎕←A×←2
2
      A
22 24 26 28 30

      vec←¯4+9?9 ⋄ vec
3 5 1 ¯1 ¯2 4 0 ¯3 2
      vec/⍨←vec>0 ⋄vec
3 5 1 4 2


Assignment Indexed Modified

Assignment (Indexed Modified) {R}←X[I]f←Y

f may be any dyadic function which returns an explicit result. Y may be any array whose items are appropriate to function f. X must be the name of an existing array. I must be a valid index specification. The items of the indexed portion of X must be appropriate to function f.

Y is either an array of the same shape as the indices specified by I or a scalar that is notionally extended to be the same shape as those indices.

The operator loops through the indices specified by I in ravel order. For each successive index i in the set specified by I, it calculates the result of X[i]fY[i] and assigns it back to X[i].

R is the "pass-through" value, that is, the value of Y. If the result of the derived function is not assigned or used, there is no explicit result.

Examples

      A
1 2 3 4 5

      +A[2 4]+←1
1

      A
1 3 3 5 5

      A[3]÷←2

      A
1 3 1.5 5 5

As the operator performs a loop, if an index in I is repeated, function f will be applied that number of times and successively to the same item of X.

Example

      B←3 5⍴0
      B[1 1 3;1 3 3 5]+←1
      B
2 0 4 0 2
0 0 0 0 0
1 0 2 0 1


Assignment Selective Modified

Assignment (Selective Modified) {R}←(EXP X)f←Y

f may be any dyadic function which returns an explicit result. Y may be any array whose items are appropriate to function f. X must be the name of an existing array. EXP is an expression that selects elements of X. (See Assignment (Selective) for a list of allowed selection functions.) The selected elements of X must be appropriate to function f.

Y is either an array of the same shape as the selected elements of X or a scalar that is notionally extended to be the same shape as the selection.

The operator loops through the selected elements of X in ravel order. For each selected element X[i], it calculates the result of X[i]fY[i] and assigns it back to the same element X[i].

R is the "pass-through" value, that is, the value of Y. If the result of the derived function is not assigned or used, there is no explicit result.

Example

      A
12 36 23 78 30

      ((A>30)/A) ×← 100
      A
12 3600 23 7800 30

As the operator performs a loop, if an element of X is selected more than once, function f will be applied the corresponding number of times and successively to the same element of X.

      a←3⍴0
      (5⍴a)+←1
      a
2 2 1


At

At R←{X}(f@g)Y

This operator substitutes selected items in Y with new values or applies a function to modify selected items in Y.

The right operand g identifies which items of array Y are to be substituted or modified. It is either:

  • an array that specifies a set of indices in Y. If g is a simple scalar or vector, it selects major cells in Y. If nested, it specifies indices for Choose or Reach indexing.
  • or a function that when applied to Y returns a Boolean array of the same shape as Y (a mask) in which a 1 indicates that the corresponding item of Y is to be substituted or modified. Note that the ravel of the mask selects from the ravel of the right argument's index array.

The left operand f is either:

  • an array that contains values to replace those items in Y identified by g
  • or a function to be applied to those items, the result of which is used to replace them. If this function is dyadic, its left argument is the array X. Note that the function is applied to the sub-array of Y selected by gas a whole and not to each item separately.

The result R is the same as Y but with the items specified by g substituted or modified by f.

Examples (array @ array)

Replace the 2nd and 4th items of ⍳5:

      (10 20@2 4)⍳5   ⍝ Note that the expression does not require parentheses because without them, the array 2 4 binds anyway to the @ operator rather than to the ⍳ function.1
1 10 3 20 5

      10 20@2 4⍳5
1 10 3 20 5

Replace the 2nd and 4th items of nested vector with ⍬:

      (⊂⍬)@2 4 ⍳¨⍳5
┌─┬┬─────┬┬─────────┐
│1││1 2 3││1 2 3 4 5│
└─┴┴─────┴┴─────────┘

Replace the 2nd and 4th rows (major cells) of a matrix:

      (2 3⍴10 20)(@2 4)4 3⍴⍳12
 1  2  3
10 20 10
 7  8  9
20 10 20

Replace first and last elements with 0 using Choose Indexing:

      (0@(1 1)(4 3))4 3⍴⍳12
 0  2 3
 4  5 6
 7  8 9
10 11 0

Replace nested items using Reach Indexing:

       G
┌───────┬───────┬───────┐
│┌───┬─┐│┌───┬─┐│┌───┬─┐│
││ABC│1│││DEF│2│││GHI│3││
│└───┴─┘│└───┴─┘│└───┴─┘│
├───────┼───────┼───────┤
│┌───┬─┐│┌───┬─┐│┌───┬─┐│
││JKL│4│││MNO│5│││PQR│6││
│└───┴─┘│└───┴─┘│└───┴─┘│
└───────┴───────┴───────┘
       G[((1 2)1)((2 3)2)]
┌───┬─┐
│DEF│6│
└───┴─┘
       ('' '*' @((1 2)1)((2 3)2)) G
┌───────┬───────┬───────┐
│┌───┬─┐│┌┬─┐   │┌───┬─┐│
││ABC│1││││2│   ││GHI│3││
│└───┴─┘│└┴─┘   │└───┴─┘│
├───────┼───────┼───────┤
│┌───┬─┐│┌───┬─┐│┌───┬─┐│
││JKL│4│││MNO│5│││PQR│*││
│└───┴─┘│└───┴─┘│└───┴─┘│
└───────┴───────┴───────┘

Examples (function @ array)

Replace the 2nd and 4th items of ⍳5 with their reciprocals:

      ÷@2 4 ⍳5
1 0.5 3 0.25 5

Replace the 2nd and 4th items of ⍳5 with their reversal

      ⌽@2 4 ⍳5
1 4 3 2 5

Multiply the 2nd and 4th items of ⍳5 by 10:

      10×@2 4⍳5
1 20 3 40 5

Replace the 2nd and 4th items by their totals:

       +/¨@2 4 ⍳¨⍳5
┌─┬─┬─────┬──┬─────────┐
│1│3│1 2 3│10│1 2 3 4 5│
└─┴─┴─────┴──┴─────────┘

Replace the 2nd and 4th rows (major cells) of a matrix with their accumulatives:

      (+\@2 4)4 3⍴⍳12
 1  2  3
 4  9 15
 7  8  9
10 21 33

Examples (array @ function)

Replace odd elements with 0:

      0@(2∘|)⍳5
0 2 0 4 0

Replace multiples of 3 (note that masked items are substituted in ravel order):

      'abcde'@(0=3|⊢) 4 4⍴⍳16
 1  2  a  4
 5  b  7  8
 c 10 11  d
13 14  e 16

Examples (function @ function)

Replace odd elements with their reciprocals:

      ÷@(2∘|)⍳5
1 2 0.3333333333 4 0.2

Replace odd items of ⍳5 with themselves reversed:

      ⌽@(2∘|)⍳5
5 2 3 4 1


Axis with Monadic Operand

Axis (with Monadic Operand) R←f[B]Y

f must be a monadic primitive mixed function taken from those shown in Table 18 below, or a function derived from the operators Reduction (/) or Scan (\). B must be a numeric scalar or vector. Y may be any array whose items are appropriate to function f. Axis does not follow the normal syntax of an operator.

Table 18: Primitive monadic mixed functions with optional axis.

Function | Name | Range of B
⌽ or ⊖ | Reverse | B∊⍳⍴⍴Y
↑ | Mix | (0≠1|B)^(B>⎕IO-1)^(B<⎕IO+⍴⍴Y)
↓ | Split | B∊⍳⍴⍴Y
, | Ravel | fraction, or zero or more axes of Y
⊂ | Enclose | (B≡⍳0)∨(^/B∊⍳⍴⍴Y)

In most cases, B must be an integer which identifies a specific axis of Y. However, when f is the Mix function (↑), B is a fractional value whose lower and upper integer bounds select an adjacent pair of axes of Y or an extreme axis of Y.

For Ravel (,) and Enclose (⊂), B can be a vector of two or more axes.

⎕IO is an implicit argument of the derived function which determines the meaning of B.

Examples

      ⌽[1]2 3⍴⍳6
4 5 6
1 2 3

      ↑[.1]'ONE' 'TWO'
OT
NW
EO


Axis with Dyadic Operand

Axis (with Dyadic Operand) R←Xf[B]Y

f must be a dyadic primitive scalar function, or a dyadic primitive mixed function taken from Table 19 below. B must be a numeric scalar or vector. X and Y may be any arrays whose items are appropriate to function f. Axis does not follow the normal syntax of an operator.

Table 19: Primitive dyadic mixed functions with optional axis.

Function | Name | Range of B
/ or ⌿ | Replicate | B∊⍳⍴⍴Y
\ or ⍀ | Expand | B∊⍳⍴⍴Y
⊂ | Partitioned Enclose | B∊⍳⍴⍴Y
⌽ or ⊖ | Rotate | B∊⍳⍴⍴Y
, or ⍪ | Catenate | B∊⍳⍴⍴Y
, or ⍪ | Laminate | (0≠1|B)^(B>⎕IO-1)^(B<⎕IO+(⍴⍴X)⌈⍴⍴Y)
↑ | Take | one or more axes of Y
↓ | Drop | one or more axes of Y
⌷ | Index | one or more axes of Y

In most cases, B must be an integer value identifying the axis of X and Y along which function f is to be applied.

Exceptionally, B must be a fractional value for the Laminate function (,) whose upper and lower integer bounds identify a pair of axes or an extreme axis of X and Y. For Take (↑) and Drop (↓), B can be a vector of two or more axes.

⎕IO is an implicit argument of the derived function which determines the meaning of B.

Examples

      1 4 5 =[1] 3 2⍴⍳6
1 0
0 1
1 0

      2 ¯2 1/[2]2 3⍴'ABCDEF'
AA  C
DD  F

      'ABC',[1.1]'='
A=
B=
C=

      'ABC',[0.1]'='
ABC
===

      ⎕IO←O

      'ABC',[¯0.5]'='
ABC
===

Axis with Scalar Dyadic Functions

The axis operator [X] can take a scalar dyadic function as operand. This has the effect of "stretching" a lower rank array to fit a higher rank one. The arguments must be conformable along the specified axis (or axes) with elements of the lower rank array being replicated along the other axes.

For example, if H is the higher rank array, L the lower rank one, X is an axis specification, and f a scalar dyadic function, then the expressions Hf[X]L and Lf[X]H are conformable if (⍴L)←→(⍴H)[X]. Each element of L is replicated along the remaining (⍴H)~X axes of H.

In the special case where both arguments have the same rank, the right one will play the role of the higher rank array. If R is the right argument, L the left argument, X is an axis specification and f a scalar dyadic function, then the expression Lf[X]R is conformable if (⍴L)←→(⍴R)[X].

Examples

      mat
10 20 30
40 50 60

      mat+[1]1 2       ⍝ add along first axis
11 21 31
42 52 62

      mat+[2]1 2 3     ⍝ add along last axis
11 22 33
41 52 63

      cube
 100  200  300
 400  500  600

 700  800  900
1000 1100 1200

      cube+[1]1 2
 101  201  301
 401  501  601

 702  802  902
1002 1102 1202

      cube+[3]1 2 3
 101  202  303
 401  502  603

 701  802  903
1001 1102 1203

      cube+[2 3]mat
 110  220  330
 440  550  660

 710  820  930
1040 1150 1260

      cube+[1 3]mat
 110  220  330
 410  520  630

 740  850  960
1040 1150 1260


Commute

Commute {R}←{X}f⍨Y

f may be any dyadic function. X and Y may be any arrays whose items are appropriate to function f.

The derived function is equivalent to YfX. The derived function need not return a result.

If left argument X is omitted, the right argument Y is duplicated in its place, i.e.

      f⍨Y ←→ Y f⍨Y

Examples

      N
3 2 5 4 6 1 3

      N/⍨2|N
3 5 1 3

      ⍴⍨3
3 3 3

      mean←+/∘(÷∘⍴⍨) ⍝ mean of a vector
      mean ⍳10
5.5

The following statements are equivalent:

      F/⍨←I
      F←F/⍨I
      F←I/F

Commute often eliminates the need for parentheses


Composition Form I

Composition (Form I) {R}←f∘gY

f may be any monadic function. g may be any monadic function which returns a result. Y may be any array whose items are appropriate to function g. The items of gY must be appropriate to function f.

The derived function is equivalent to fgY. The derived function need not return a result.

Composition allows functions to be glued together to build up more complex functions.

Examples

      RANK ← ⍴∘⍴
      RANK ¨ 'JOANNE' (2 3⍴⍳6)
 1  2

      +/∘⍳¨2 4 6
3 10 21

      ⎕VR'SUM'
     ∇ R←SUM X
[1]    R←+/X
     ∇

      SUM∘⍳¨2 4 6
3 10 21


Composition Form II

Composition (Form II) {R}←A∘gY

g may be any dyadic function. A may be any array whose items are appropriate to function g. Y may be any array whose items are appropriate to function g.

The derived function is equivalent to AgY. The derived function need not return a result.

Examples

      2 2∘⍴ ¨ 'AB'
 AA  BB
 AA  BB

      SINE ← 1∘○

      SINE 10 20 30
¯0.5440211109 0.9129452507 ¯0.9880316241

The following example uses Composition Forms I and II to list functions in the workspace:

      ⎕NL 3
ADD
PLUS

      ⎕∘←∘⎕VR¨↓⎕NL 3
     ∇ ADD X
[1]    →LAB⍴⍨0≠⎕NC'SUM' ⋄ SUM←0
[2]   LAB:SUM←SUM++/X
     ∇
     ∇ R←A PLUS B
[1]    R←A+B
     ∇


Composition Form III

Composition (Form III) {R}←(f∘B)Y

f may be any dyadic function. B may be any array whose items are appropriate to function f. Y may be any array whose items are appropriate to function f.

The derived function is equivalent to YfB. The derived function need not return a result.

Examples

      (*∘0.5)4 16 25
2 4 5

      SQRT ← *∘.5

      SQRT 4 16 25
2 4 5

The parentheses are required in order to distinguish between the operand B and the argument Y.


Composition Form IV

Composition (Form IV) {R}←Xf∘gY

f may be any dyadic function. g may be any monadic function which returns a result. Y may be any array whose items are appropriate to function g. Also gY must return a result whose items are appropriate as the right argument of function f. X may be any array whose items are appropriate to function f.

The derived function is equivalent to XfgY. The derived function need not return a result.

Examples

      +∘÷/40⍴1       ⍝ Golden Ratio! (Bob Smith)
1.618033989

      0,∘⍳¨⍳5
0 1  0 1 2  0 1 2 3  0 1 2 3 4  0 1 2 3 4 5


Each with Monadic Operand

Each (with Monadic Operand) {R}←f¨Y

f may be any monadic function. Y may be any array, each of whose items are separately appropriate to function f.

The derived function applies function f separately to each item of Y. The derived function need not return a result. If a result is returned, R has the same shape as Y, and its elements are the items produced by the application of function f to the corresponding items of Y.

If Y is empty, the prototype of R is determined by applying the operand function once to the prototype of Y.

Examples

      G←('TOM' (⍳3))('DICK' (⍳4))('HARRY' (⍳5))
      ⍴G
3
      ⍴¨G
 2  2  2

      ⍴¨¨G
  3  3    4  4    5  5

      +⎕FX¨('FOO1' 'A←1')('FOO2' 'A←2')
 FOO1 FOO2


Each with Dyadic Operand

Each (with Dyadic Operand) {R}←Xf¨Y

f may be any dyadic function. X and Y may be any arrays whose corresponding items (after scalar extension) are appropriate to function f when applied separately.

The derived function is applied separately to each pair of corresponding elements of X and Y. If X or Y is a scalar or single-element array, it will be extended to conform with the other argument. The derived function need not produce an explicit result. If a result is returned, R has the same shape as Y (after possible scalar extension) whose elements are the items produced by the application of the derived function to the corresponding items of X and Y.

If X or Y is empty, the operand function is applied once between the prototypes of X and Y to determine the prototype of R.

Examples

      +G←(1 (2 3))(4 (5 6))(8 9)10
   1  2 3   4  5 6   8 9  10
      1⌽¨G
  2 3  1   5 6  4  9 8  10

      1⌽¨¨G
 1  3 2   4  6 5   8 9  10

      1⌽¨¨¨G
 1  2 3   4  5 6   8 9  10

      1 2 3 4↑¨G
 1  4  5 6   8 9 0  10 0 0 0

      'ABC',¨'XYZ'
 AX  BY  CZ


I-Beam

I-Beam R←{X}(A⌶)Y

I-Beam is a monadic operator that provides a range of system related services.

WARNING: Although documentation is provided for I-Beam functions, any service provided using I-Beam should be considered as "experimental" and subject to change – without notice - from one release to the next. Any use of I-Beams in applications should therefore be carefully isolated in cover-functions that can be adjusted if necessary.

A is an integer that specifies the type of operation to be performed. Y is an array that supplies further information about what is to be done.

X may or may not be required depending on A.

R is the result of the derived function.

For further information, see I-Beam.


Inner Product

Inner Product R←Xf.gY

f and g are dyadic functions. The last axis of X must have the same length as the first axis of Y, or one of X and Y is single (^/1=⍴X or ^/1=⍴Y).

The result of the derived function has shape (¯1↓⍴X),1↓⍴Y; each item is f/x g¨y where x and y are vectors taken from all the combinations of vectors along the last axis of X and the first axis of Y.

Notes:

  • g must return a result.
  • f must return a result with the possible exception of the case when 1=⍴x g¨y.
  • The expression f/x g¨y applies even when R or x g¨y or X or Y is empty. When X or Y is empty, the vector x is X reshaped to the appropriate length (y is Y reshaped to appropriate length).
  • x is just X itself if X is a scalar. Likewise y and Y.

Examples

      1 2 3+.×10 12 14
76
      +/1 2 3×10 12 14
76

      NAMES
HENRY
WILLIAM
JAMES
SEBASTIAN

      NAMES^.='WILLIAM  '
0 1 0 0


Key

Key R←{X}f⌸Y

Classic Edition: the symbol ⌸ is not available in Classic Edition, and the Key operator is instead represented by ⎕U2338.

f may be any dyadic function that returns a result.

If X is specified, it is an array whose major cells specify keys for corresponding major cells of Y. The Key operator ⌸ applies the function f to each unique key in X and the major cells of Y having that key.

If X is omitted, Y is an array whose major cells represent keys. In this case, the Key operator applies the function f to each unique key in Y and the elements of ⍳≢Y having that key. f⌸Y is the same as Y f⌸⍳≢Y.

The elements of R appear in the order in which they first appear in Y.

Key is similar to the GROUP BY clause in SQL.

⎕CT and ⎕DCT are implicit arguments of the Key operator.

Example

      cards←'2' 'Queen' 'Ace' '4' 'Jack'
      suits←'Spades' 'Hearts' 'Spades' 'Clubs' 'Hearts'

      suits,[1.5]cards
 Spades  2
 Hearts  Queen
 Spades  Ace
 Clubs   4
 Hearts  Jack

       suits {⍺':'⍵}⌸ cards
  Spades  : 2 Ace
  Hearts  :  Queen  Jack
  Clubs   : 4

In this example, both arrays are vectors so their major cells are their elements. The function {⍺':'⍵} is applied between the unique elements in suits ('Spades' 'Hearts' 'Clubs') and the elements in cards grouped according to their corresponding elements in suits, i.e. ('2' 'Ace'), ('Queen' 'Jack') and (,'4').

Monadic Examples

      {⍺ ⍵} ⌸ suits ⍝ indices of unique major cells
  Spades   1 3
  Hearts   2 5
  Clubs    4

      {⍺,≢⍵} ⌸ suits ⍝ count of unique major cells
 Spades  2
 Hearts  2
 Clubs   1

       letters←'zabayza'
       {⍺(≢⍵)}⌸letters
z 2
a 3
b 1
y 1

Further Examples

x is a vector of stock codes, y is a corresponding matrix of values.

      ⍴x
10
      ⍴y
10 2
     x,y
 IBM   13 75
 AAPL  45 53
 GOOG  21  4
 GOOG  67 67
 AAPL  93 38
 MSFT  51 83
 IBM    3  5
 AAPL  52 67
 AAPL   0 38
 IBM    6 41

If we apply the function {⍺ ⍵} to x and y using the ⌸ operator, we can see how the rows (its major cells) of y are grouped according to the corresponding elements (its major cells) of x.

      x{⍺ ⍵}⌸y
 IBM   13 75
        3  5
        6 41
 AAPL  45 53
       93 38
       52 67
        0 38
 GOOG  21  4
       67 67
 MSFT  51 83

More usefully, we can apply the function {⍺(+⌿⍵)}, which delivers the stock codes and the corresponding totals in y:

      x{⍺(+⌿⍵)}⌸y
  IBM    22 121
  AAPL   190 196
  GOOG   88 71
  MSFT   51 83

There is no need for the function to use its left argument. So to obtain just the totals in y grouped by the stock codes in x:

       x{+⌿⍵}⌸y
 22 121
190 196
 88  71
 51  83

Defined Function Example

This example appends the data for a stock into a component file named by the symbol.

     ∇ r←stock foo data;fid;file
[1]    file←⊃stock
[2]    :Trap 0
[3]        fid←file ⎕FTIE 0
[4]        file ⎕FERASE fid
[5]    :EndTrap
[6]    fid←file ⎕FCREATE 0
[7]    r←data ⎕FAPPEND fid
[8]    ⎕FUNTIE fid
     ∇
     x foo⌸y
1 1 1 1

Example

      {⍺ ⍵} ⌸ suits ⍝ indices of unique major cells
  Spades   1 3
  Hearts   2 5
  Clubs    4

      {⍺,≢⍵} ⌸ suits ⍝ count of unique major cells
 Spades  2
 Hearts  2
 Clubs   1

Another Example

Given a list of names and scores., the problem is to sum the scores for each unique name. A solution is presented first without using the Key operator, and then with the Key operator.

      names ⍝ 12, some repeat
 Pete  Jay  Bob  Pete  Pete  Jay  Jim  Pete  Pete  Jim
 Pete  Pete

      (∪names)∘.≡names
1 0 0 1 1 0 0 1 1 0 1 1
0 1 0 0 0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 1 0 0

      scores
66 75 71 100 22 10 67 77 55 42 1 78

      b←↓(∪names)∘.≡names
      ]disp b/¨⊂⍳12
┌→──────────────┬───┬─┬────┐
│1 4 5 8 9 11 12│2 6│3│7 10│
└~─────────────→┴~─→┴→┴~──→┘

      +/¨b/¨⊂scores
399 85 71 109

      ]disp {⊂⍵}⌸ names
┌→──────────────┬───┬─┬────┐
│1 4 5 8 9 11 12│2 6│3│7 10│
└~─────────────→┴~─→┴→┴~──→┘

      names {+/⍵}⌸ scores
399 85 71 109


Outer Product

Outer Product {R}←X∘.gY

g may be any dyadic function. The left operand of the operator is the symbol ∘. X and Y may be any arrays whose elements are appropriate to the function g.

Function g is applied to all combinations of the elements of X and Y. If function g returns a result, the shape of R is (⍴X),⍴Y. Each element of R is the item returned by function g when applied to the particular combination of elements of X and Y.

Examples

      1 2 3∘.×10 20 30 40
10 20 30  40
20 40 60  80
30 60 90 120

      1 2 3∘.⍴'AB'
 A    B
 AA   BB
 AAA  BBB

      1 2∘.,1 2 3
 1 1  1 2  1 3
 2 1  2 2  2 3

      (⍳3)∘.=⍳3
1 0 0
0 1 0
0 0 1

If X or Y is empty, the result R is a conformable empty array, and the operand function is applied once between the first items of X and Y to determine the prototype of R.


Power Operator

Power Operator {R}←{X}(f⍣g)Y

If right operand g is a numeric integer scalar, power applies its left operand function f cumulatively g times to its argument. In particular, g may be Boolean 0 or 1 for conditional function application.

If right operand g is a scalar-returning dyadic function, then left operand function f is applied repeatedly until ((f Y) g Y) or until a strong interrupt occurs. Notice that power calls its dyadic right operand g with the next (f Y) and current (Y) values of the iteration as left and right arguments. In particular, if g is = or ≡, the result is sometimes termed a fixpoint of f.

If a left argument X is present, it is bound as left argument to left operand function f:

X (f ⍣ g) Y → (X∘f ⍣ g) Y

A negative right operand g applies the inverse of the operand function f,(|g)times. In this case, f may be a primitive function or an expression of primitive functions combined with primitive operators:

∘ | compose
¨ | each
∘. | outer product
⍨ | commute
\ | scan
[] | axis
⍣ | power

If the function does not have an inverse, a negative argument g generates DOMAIN ERROR.

Examples

    (,∘⊂∘,⍣(1=≡,vec))vec    ⍝ ravel-enclose if simple.

    a b c←1 0 1{(⊂⍣⍺)⍵}¨abc ⍝ enclose first and last.

    cap←{(⍺⍺⍣⍺)⍵}           ⍝ conditional application.

    a b c←1 0 1⊂cap¨abc     ⍝ enclose first and last.

    succ←1∘+                ⍝ successor function.

    (succ⍣4)10              ⍝ fourth successor of 10.
14
    (succ⍣¯3)10             ⍝ third predecessor of 10.
7
    1+∘÷⍣=1                 ⍝ fixpoint: golden mean.
1.618033989

    f←(32∘+)∘(×∘1.8)        ⍝ Fahrenheit from Celsius.
    f 0 100
32 212

    c←f⍣¯1                  ⍝ c is Inverse of f.
    c 32 212                ⍝ Celsius from Fahrenheit.
0 100

    invs←{(⍺⍺⍣¯1)⍵}         ⍝ inverse operator.

    +\invs 1 3 6 10         ⍝ scan inverse.
1 2 3 4

    2∘⊥invs 9               ⍝ decode inverse.
1 0 0 1

    dual←{⍵⍵⍣¯1 ⍺⍺ ⍵⍵ ⍵}    ⍝ dual operator.

    mean←{(+/⍵)÷⍴⍵}         ⍝ mean function.

    mean dual⍟ 1 2 3 4 5    ⍝ geometric mean.
2.605171085

    +/dual÷ 1 2 3 4 5       ⍝ parallel resistance.
0.4379562044

    mean dual(×⍨)1 2 3 4 5  ⍝ root-mean-square.
3.31662479

    ⍉dual↑ 'hello' 'world'  ⍝ vector transpose.
 hw  eo  lr  ll  od

Warning

Some expressions, such as the following, will cause an infinite internal loop and APL will appear to hang. In most cases this can be resolved by issuing a hard INTERRUPT.

      !⍣-1
      !⍣-2

One can ensure that weak interrupts and ⎕TKILL can interrupt by packaging the ⍣ within the dop {⍺←⊢ ⋄ ⍺ (⍺⍺{⍺←⊢ ⋄ ⍺ ⍺⍺ ⍵}⍣⍵⍵) ⍵}.

Example

      PowOp←{⍺←⊢ ⋄ ⍺ (⍺⍺{⍺←⊢ ⋄ ⍺ ⍺⍺ ⍵}⍣⍵⍵) ⍵}
      tnum←!PowOp-&1 ⍝ using naked ⍣ will freeze APL

      ⎕tkill tnum


Rank

Rank R←{X}(f⍤B)Y

Classic Edition: the symbol ⍤ is not available in Classic Edition, and the Rank operator is instead represented by ⎕U2364.

The Rank operator ⍤ applies monadic function f successively to sub-arrays of Y, or dyadic function f between sub-arrays of X and Y. Sub-arrays are selected by right operand B.

B is a numeric scalar or vector of up to three items, specifying the ranks of the cells to which f should be applied. The most general form is a three item vector p q r, where:

  • p specifies the rank of the argument cells when f is applied monadically
  • q specifies the rank of the left argument cells when f is applied dyadically
  • r specifies the rank of the right argument cells when f is applied dyadically

If B is a two item vector q r, it is implicitly extended to r q r. If B has a single item r, it is implicitly extended to r r r.

If an item k of B is zero or positive it selects k-cells of the corresponding argument. If it is negative, it selects (r+k)-cells where r is the rank of the corresponding argument. A value of ¯1 selects major cells. For further information, see Cells and Sub-arrays.

If X is omitted, f may be any monadic function that returns a result. Y may be any array. The Rank operator ⍤ applies function f successively to the sub-arrays in Y specified by p (i.e. the first item of B, as specified or implicitly extended).

If X is specified, it may be any array and f may be any dyadic function that returns a result. Y may be any array. In this case, the Rank operator applies function f successively between the sub-arrays in X specified by q and the sub-arrays in Y specified by r.

The sub-arrays of R are the results of the individual applications of f. If these results differ in rank or shape, they are extended to a common rank and shape in the manner of Mix. See Mix.

Notice that it is necessary to prevent the right operand k binding to the right argument. This can be done using parentheses e.g. (f⍤1)Y. The same can be achieved using ⊢ e.g. f⍤1⊢Y because ⍤ binds tighter to its right operand than ⊢ does to its left argument, and ⊢ therefore resolves to Identity.

Monadic Examples

Using enclose (⊂) as the left operand elucidates the workings of the rank operator.

      Y
36 99 20  5
63 50 26 10
64 90 68 98

66 72 27 74
44  1 46 62
48  9 81 22
      ⍴Y
2 3 4
      ⊂⍤2 ⊢Y
┌───────────┬───────────┐
│36 99 20  5│66 72 27 74│
│63 50 26 10│44  1 46 62│
│64 90 68 98│48  9 81 22│
└───────────┴───────────┘
      ⊂⍤1 ⊢Y
┌───────────┬───────────┬───────────┐
│36 99 20 5 │63 50 26 10│64 90 68 98│
├───────────┼───────────┼───────────┤
│66 72 27 74│44 1 46 62 │48 9 81 22 │
└───────────┴───────────┴───────────┘

The function {(⊂⍋⍵)⌷⍵} sorts a vector.

      {(⊂⍋⍵)⌷⍵} 3 1 4 1 5 9 2 6 5
1 1 2 3 4 5 5 6 9

The rank operator can be used to apply the function to sub-arrays; in this case to sort the 1-cells (rows) of a 3-dimensional array.

      Y
36 99 20  5
63 50 26 10
64 90 68 98

66 72 27 74
44  1 46 62
48  9 81 22
      ({(⊂⍋⍵)⌷⍵}⍤1)Y
 5 20 36 99
10 26 50 63
64 68 90 98

27 66 72 74
 1 44 46 62
 9 22 48 81

Dyadic Examples

      10 20 30 (+⍤0 1)3 4⍴⍳12
10 11 12 13
24 25 26 27
38 39 40 41

Using the function {⍺ ⍵} as the left operand demonstrates how the dyadic case of the rank operator works.

      10 20 30 ({⍺ ⍵}⍤0 1)3 4⍴⍳12
┌──┬─────────┐
│10│0 1 2 3  │
├──┼─────────┤
│20│4 5 6 7  │
├──┼─────────┤
│30│8 9 10 11│
└──┴─────────┘

Note that a right operand of ¯1 applies the function between the major cells (in this case elements) of the left argument, and the major cells (in this case rows) of the right argument.

      10 20 30 ({⍺ ⍵}⍤¯1)3 4⍴⍳12
┌──┬─────────┐
│10│0 1 2 3  │
├──┼─────────┤
│20│4 5 6 7  │
├──┼─────────┤
│30│8 9 10 11│
└──┴─────────┘


Reduce

Reduce R←f/[K]Y

f must be a dyadic function. Y may be any array whose items in the sub-arrays along the Kth axis are appropriate to function f.

The axis specification is optional. If present, K must identify an axis of Y. If absent, the last axis of Y is implied. The form R←f⌿Y implies the first axis of Y.

R is an array formed by applying function f between items of the vectors along the Kth (or implied) axis of Y. For a typical vector Y, the result R is:

       R  ←→ ⊂(1⊃Y)f(2⊃Y)f......f(n⊃Y)

The shape S of R is the shape of Y excluding the Kth axis, i.e.

       S  ←→  ⍴R  ←→  (K≠⍳⍴⍴Y)/⍴Y

If Y is a scalar then for any function f, R is Y.

If the length of the Kth axis of Y is 1, or if the length of any other axis of Y is 0, then f is not applied and R is S⍴Y.

Otherwise, if the length of the Kth axis is 0 then the result depends on f and on ⊃Y (the prototypical item of Y) as follows:

If f is one of the functions listed in Table 20 then R is S⍴⊂I, where I is formed from ⊃Y by replacing each depth-zero item of ⊃Y with the identity element from the table.

Otherwise if f is Catenate, R is S⍴⊂0/⊃Y. If f is Catenate First, R is S⍴⊂0⌿⊃Y. If f is Catenate along the Jth axis, R is S⍴⊂0/[J]⊃Y. See Catenate/Laminate.

Otherwise, DOMAIN ERROR is reported.

Table 20: Identity Elements

Function |  | Identity
Add | + | 0
Subtract | - | 0
Multiply | × | 1
Divide | ÷ | 1
Residue | | | 0
Minimum | ⌊ | MM represents the largest representable value: typically this is 1.7E308, unless ⎕FR is 1287, when the value is 1E6145. 1
Maximum | ⌈ | -M
Power | * | 1
Binomial | ! | 1
And | ∧ | 1
Or | ∨ | 0
Less | < | 0
Less or Equal | ≤ | 1
Equal | = | 1
Greater | > | 0
Greater or Equal | ≥ | 1
Not Equal | ≠ | 0
Encode | ⊤ | 0
Union | ∪ | ⍬
Replicate | /⌿ | 1
Expand | \⍀ | 1
Rotate | ⌽⊖ | 0

Examples

      ∨/0 0 1 0 0 1 0
1
      MAT
1 2 3
4 5 6

      +/MAT
6 15

      +⌿MAT
5 7 9

      +/[1]MAT
5 7 9

      +/(1 2 3)(4 5 6)(7 8 9)
 12 15 18

      ,/'ONE' 'NESS'
 ONENESS

      +/⍳0
0
      (⊂⍬)≡,/⍬
1
      (⊂'')≡,/0⍴'Hello' 'World'
1
      (⊂0 3 4⍴0)≡⍪/0⍴⊂2 3 4⍴0
1


Reduce First

Reduce First R←f⌿Y

The form R←f⌿Y implies reduction along the first axis of Y. See Reduce.


Reduce N Wise

Reduce N-Wise R←Xf/[K]Y

f must be a dyadic function. X must be a simple scalar or one-item integer array. Y may be any array whose sub-arrays along the Kth axis are appropriate to function f.

The axis specification is optional. If present, K must identify an axis of Y. If absent, the last axis of Y is implied. The form R←Xf⌿Y implies the first axis of Y.

R is an array formed by applying function f between items of sub-vectors of length X taken from vectors along the Kth (or implied) axis of Y.

X can be thought of as the width of a "window" which moves along vectors drawn from the Kth axis of Y.

If X is zero, the result is a (⍴Y)+(-⍴⍴Y)↑1 array of identity elements for the function f. See Identity Elements.

If X is negative, each sub-vector is reversed before being reduced.

Examples

      ⍳4
1 2 3 4

      3+/⍳4⍝ (1+2+3) (2+3+4)
6 9
      2+/⍳4⍝ (1+2) (2+3) (3+4)
3 5 7
      1+/⍳4⍝ (1) (2) (3) (4)
1 2 3 4

      0+/⍳4⍝ Identity element for +
0 0 0 0 0
      0×/⍳4⍝ Identity element for ×
1 1 1 1 1

      2,/⍳4⍝ (1,2) (2,3) (3,4)
 1 2  2 3  3 4
      ¯2,/⍳4⍝ (2,1) (3,2) (4,3)
 2 1  3 2  4 3


Reduce First N Wise

Reduce First N-Wise R←Xf⌿[K]Y

The form R←Xf⌿Y implies N-Wise reduction along the first axis of Y. See Reduce N-Wise.


Scan

Scan R←f\[K]Y

f may be any dyadic function that returns a result. Y may be any array whose items in the sub-arrays along the Kth axis are appropriate to the function f.

The axis specification is optional. If present, K must identify an axis of Y. If absent, the last axis of Y is implied. The form R←f⍀Y implies the first axis of Y.

R is an array formed by successive reductions along the Kth axis of Y. If V is a typical vector taken from the Kth axis of Y, then the Ith element of the result is determined as f/I↑V.

The shape of R is the same as the shape of Y. If Y is an empty array, then R is the same empty array.

Examples

      ∨\0 0 1 0 0 1 0
0 0 1 1 1 1 1

      ^\1 1 1 0 1 1 1
1 1 1 0 0 0 0

      +\1 2 3 4 5
1 3 6 10 15

      +\(1 2 3)(4 5 6)(7 8 9)
 1 2 3  5 7 9  12 15 18

      M
1 2 3
4 5 6

      +\M
1 3  6
4 9 15

      +⍀M
1 2 3
5 7 9

      +\[1]M
1 2 3
5 7 9

      ,\'ABC'
A AB  ABC

      T←'ONE(TWO) BOOK(S)'

      ≠\T∊'()'
0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 0

      ((T∊'()')⍱≠\T∊'()')/T
ONE BOOK


Scan First

Scan First R←f⍀Y

The form R←f⍀Y implies scan along the first axis of Y. See Scan.


Spawn

Spawn {R}←{X}f&Y

& is a monadic operator with an ambivalent derived function. & spawns a new thread in which f is applied to its argument Y (monadic case) or between its arguments X and Y (dyadic case). The shy result of this application is the number of the newly created thread.

When function f terminates, its result (if any), the thread result, is returned. If the thread number is the subject of an active ⎕TSYNC, the thread result appears as the result of ⎕TSYNC. If no ⎕TSYNC is in effect, the thread result is displayed in the session in the normal fashion.

Note that & can be used in conjunction with the each operator ¨ to launch many threads in parallel.

Examples

      ÷&4         ⍝ Reciprocal in background
0.25

      ⎕←÷&4       ⍝ Show thread number
1
0.25

      FOO&88      ⍝ Spawn monadic function.

      2 FOO&3     ⍝ dyadic

      {NIL}&0     ⍝ niladic

      ⍎&'NIL'     ⍝ ..

      X.GOO&99    ⍝ thread in remote space.

      ⍎&'⎕dl 2'   ⍝ Execute async expression.

      'NS'⍎&'FOO' ⍝ .. remote .. .. ..

      PRT&¨↓⎕nl 9 ⍝ PRT spaces in parallel.


Variant

Variant {R}←{X}(f⍠B)Y

Classic Edition: the symbol ⍠ is not available in Classic Edition, and the Variant operator is instead represented by ⎕U2360. Note too that ⍠ and ⎕OPT are synonymous though only the latter is available in the Classic Edition.

The Variant operator ⍠ specifies the value of an option to be used by its left operand function f. An option is a named property of a function whose value in some way affects the operation of that function.

For example, the Search and Replace operators include options named IC and Mode which respectively determine whether or not case is ignored and in what manner the input document is processed.

One of the set of options may be designated as the Principal option whose value may be set using a short-cut form of syntax as described below. For example, the Principal option for the Search and Replace operators is IC.

For the operand function with right argument Y and optional left argument X, the right operand B specifies the values of one or more options that are applicable to that function. If B is empty, function f is called with default options. Otherwise, B may be a scalar, a 2-element vector, or a vector of 2-element vectors which specifies values for one or more options as follows:

  • If B is a 2-element vector and the first element is a character vector, it specifies an option name in the first element and the option value (which may be any suitable array) in the second element.
  • If B is a vector of 2-element vectors, each item of B is interpreted as above.
  • If B is a scalar (a rank-0 array of any depth), it specifies the value of the Principal option,

Option names and their values must be appropriate for the left operand function, otherwise DOMAIN ERROR (error code 11) will be reported.

Example

       tn←'Dick'(⎕FCREATE⍠'Z' 1)0

The following illustrations and examples apply to functions derived from the Search and Replace operators.

Examples of operand B

The following expression sets the IC option to 1, the Mode option to 'D' and the EOL option to 'LF'.

      ⍠('Mode' 'D')('IC' 1)('EOL' 'LF')

The following expression sets just the EOL property to 'CR'.

      ⍠'EOL' 'CR'

The following expression sets just the Principal option (which for the Search and Replace operators is IC) to 1.

      ⍠ 1

The order in which options are specified is typically irrelevant but if the same option is specified more than once, the rightmost one dominates. The following expression sets the option IC to 1:

      ⍠('IC' 0) ('IC' 1)

The Variant operator generates a derived function f⍠B and may be assigned to a name. The derived function is effectively function f bound with the option values specified by B.

The derived function may itself be used as a left operand to Variant to produce a second derived function whose options are further modified by the second application of the operator. The following sets the same options as the first example above:

      ⍠'Mode' 'D'⍠'IC' 1⍠'EOL' 'LF'

When the same option is specified more than once in this way, the outermost (rightmost) one dominates. The following expression also sets the option IC to 1:

      ⍠'IC' 0⍠'IC' 1

Further Examples

The following derived function returns the location of the word 'variant' within its right argument using default values for all the options.

      f1 ← 'variant' ⎕S 0
      f1 'The variant Variant operator'
4

It may be modified to perform a case-insensitive search:

      (f1 ⍠ 1) 'The variant Variant operator'
4 12

This modified function may be named:

      f2 ← f1 ⍠ 1
      f2 'The variant Variant operator'
4 12

The modified function may itself be modified, in this case to revert to a case sensitive search:

      f3 ← f2 ⍠ 0
      f3 'The variant Variant operator'
4

This is equivalent to:

      (f1 ⍠ 1 ⍠ 0) 'The variant Variant operator'
4

Variant and .NET

The Variant operator may also be used in conjunction with .NET classes; it can used to cast an array into a specific .NET data type, and to specify which constructor should be used when creating a new instance of a .NET class which has overloaded constructors. For further information, see Advanced Techniques.


I-Beam

I-Beam R←{X}(A⌶)Y

I-Beam is a monadic operator that provides a range of system related services.

WARNING: Although documentation is provided for I-Beam functions, any service provided using I-Beam should be considered as "experimental" and subject to change – without notice - from one release to the next. Any use of I-Beams in applications should therefore be carefully isolated in cover-functions that can be adjusted if necessary. See also: Other I-Beams.

A is an integer that specifies the type of operation to be performed as shown in the table below. Y is an array that supplies further information about what is to be done.

X may or may not be required depending on A.

R is the result of the derived function.

When attempting to use I-Beam with an unsupported operation value, A, one of three different error messages will be reported:

  • Invalid I-Beam function selection
  • I-Beam function xxx has been withdrawn
  • I-Beam function xxx is not supported by this interpreter

This allows the user to distinguish between operation values that have never been used, those that have been used in earlier versions but are no longer included in the current version, and those that are valid in other editions or on other platforms other than the current interpreter.

The column labelled O/S indicates if a function applies only on Windows (W) or only on non-Windows (X) platforms.

A | Derived Function | O/S
8 | Inverted Table Index-of |
85 | Execute Expression |
127 | Overwrite Free Pockets |
180 | Canonical Representation |
181 | Unsqueezed Type |
200 | Syntax Colouring |
201 | Syntax Colour Tokens |
219 | Compress/Decompress Vector of Short Integers |
220 | Serialise/Deserialise Array |
400 | Compiler Control |
600 | Trap Control |
739 | Temporary Directory |
819 | Case Convert |
900 | Called Monadically |
950 | Loaded Libraries |
1111 | Number of Threads |
1112 | Parallel Execution Threshold |
1159 | Update Function Time and User Stamp |
1500 | Hash Array |
2000 | Memory Manager Statistics |
2002 | Specify Workspace Available |
2010 | Update DataTable | W
2011 | Read DataTable | W
2014 | Remove Data Binding | W
2015 | Create Data Binding Source | W
2016 | Create .NET Delegate | W
2017 | Identify .NET Type | W
2022 | Flush Session Caption | W
2023 | Close all Windows |
2035 | Set Dyalog Pixel Type | W
2041 | Override COM Default Value | W
2100 | Export to Memory | W
2101 | Close .NET AppDomain | W
2400 | Set Workspace Save Options |
2401 | Expose Root Properties |
2501 | Discard thread on exit | W
2502 | Discard parked threads | W
2503 | Mark Thread as Uninterruptible |
2520 | Use Separate Thread For .NET |
2704 | Continue Autosave |
3002 | Disable Component Checksum Validation |
3500 | Send Text to RIDE-embedded Browser |
3501 | Connected to the RIDE |
3502 | Manage RIDE Connections |
4000 | Fork New Task | X
4001 | Change User | X
4002 | Reap Forked Tasks | X
4007 | Signal Counts | X
5176 | List Loaded Files |
5177 | List Loaded File Objects |
5178 | Remove Loaded File Object Info |
5179 | Loaded File Object Info |
7162 | JSON Translate Name |
8415 | Singular Value Decomposition |
50100 | Line Count |


Inverted Table Index Of

Inverted Table Index Of R←X(8⌶)Y

This function computes X index-of Y (viz. X⍳Y) where X and Y are compatible inverted tables. R is the indices of Y in X.

An inverted table is a (nested) vector all of whose items have the same number of major cells. That is, 1=⍴⍴⍵ and (≢⊃⍵)=≢¨⍵. An inverted table representation of relational data is more efficient in time and space than other representations.

The following is an example of an inverted table:

      X←(10 3⍴⎕a) (⍳10) 'metalepsis'
      X
┌───┬───────────────────┬──────────┐
│ABC│0 1 2 3 4 5 6 7 8 9│metalepsis│
│DEF│                   │          │
│GHI│                   │          │
│JKL│                   │          │
│MNO│                   │          │
│PQR│                   │          │
│STU│                   │          │
│VWX│                   │          │
│YZA│                   │          │
│BCD│                   │          │
└───┴───────────────────┴──────────┘

Using inverted tables, it is often necessary to perform a table look-up to find the "row" indices of one in another. Suppose there is a second table Y:

      Y←(⊂⊂3 1 4 1 5 9)⌷¨X
      Y
 GHI  3 1 4 1 5 9  tmamli
 ABC
 JKL
 ABC
 MNO
 YZA

To compute the indices of Y in X using dyadic ⍳, it is necessary to first un-invert each of the tables in order to create nested matrices that ⍳ can handle.

      unvert ← {⍉↑⊂⍤¯1¨⍵}
      unvert X
┌───┬─┬─┐
│ABC│0│m│
├───┼─┼─┤
│DEF│1│e│
├───┼─┼─┤
│GHI│2│t│
├───┼─┼─┤
│JKL│3│a│
├───┼─┼─┤
│MNO│4│l│
├───┼─┼─┤
│PQR│5│e│
├───┼─┼─┤
│STU│6│p│
├───┼─┼─┤
│VWX│7│s│
├───┼─┼─┤
│YZA│8│i│
├───┼─┼─┤
│BCD│9│s│
└───┴─┴─┘

      (unvert X) ⍳ (unvert Y)
3 1 4 1 5 9

Each un-inverted table requires considerably more workspace than its inverted form, so if the inverted tables are large, this operation is potentially expensive in terms of both time and workspace.

8⌶ is an optimised version of the above expression.

      X (8⌶) Y
3 1 4 1 5 9


Execute Expression

Execute Expression R←X(85⌶)Y

Executes an expression.

Y is a character vector containing an APL expression.

The function executes the expression in Y exactly as it would be executed by the monadic Execute primitive function ⍎, but handles shy results of the execution rather differently.

The left argument X determines how a shy result from the execution of Y is treated and is either 0 or 1.

If X is 1, and the expression in Y returns an explicit result, R is that result. If the expression in Y returns no result or returns a shy result, the function signals ERROR 85. Effectively, a shy result is discarded.

If X is 0, and the expression in Y returns an explicit result or a shy result, R is that result (but is no longer shy). If the expression in Y returns no result, the function signals ERROR 85.

Examples

      ⍎'a←42'
      ⎕← ⍎'a←42'     ⍝ shy result
42
      0 (85⌶) 'a←42' ⍝ not shy
42
      1 (85⌶) 'a←42'
ERROR 85
      1(85⌶)'a←42'
     ∧


Overwrite Free Pockets

Overwrite Free Pockets R←127⌶Y

Overwrites all free pockets in the workspace.

Some applications (cryptography for example) make use of secure data during execution. The nature of the APL workspace is such that remnants of this secure data may persist in the workspace (and thus the process memory) even after the relevant APL variables have been expunged. This function overwrites all unused data pockets in the workspace so that any potentially secure data is removed.

Y is any empty array, preferably ⍬(zilde). R is always 1.

It is the responsibility of the programmer to ensure that there are no USED pockets in the workspace that reference the data.

Example

     ∇ foo;a
[1]    a←'my secure data'
[2]    ⎕EX'a'
[3]    ⍝ 'my secure data' is now in an
[4]    ⍝ UNUSED pocket in the workspace
[5]    a←127⌶0 ⍝ all unused pockets are overwritten,
[6]            ⍝ 'my secure data' is no longer present
     ∇

Whereas

     ∇ foo;a;b
[1]    a←'my secure data'
[2]    b←a
[3]    ⎕EX'a'
[4]    ⍝ 'my secure data' is now in an
[5]    ⍝ UNUSED pocket in the workspace
[6]    a←127⌶0 ⍝ all unused pockets are overwritten,
[7]            ⍝ but 'my secure data' is still present
[8]            ⍝ because it is referenced by b
     ∇


Canonical Representation

Canonical Representation R←180⌶Y

This function is the same as the system function ⎕CR except that it can be used to obtain the canonical representation of methods in classes. 180⌶ is used by ]PROFILE.

Example

      )load ComponentFile
C:\Program Files\Dyalog\Dyalog APL-64 15.0 Unicode\...

      180⌶'ComponentFile.Close'
 Close
 :Implements Destructor
 :If tie∊⎕FNUMS
     :If temp ⋄ Name ⎕FERASE tie
     :Else ⋄ ⎕FUNTIE tie
     :EndIf
 :EndIf


Unsqueezed Type

Unsqueezed Type R←181⌶Y

Y is any array.

The result R is an integer scalar containing an integer value which indicates the type of the array. For further information see Data Representation (Monadic).

181⌶ is functionally identical to monadic ⎕DR, except that no attempt is made to squeeze the data into smaller data types. ⎕DR always attempts to squeeze the data; 181⌶ does not, but if a workspace compaction occurs during execution of 181⌶, the data may still be squeezed before the type is identified.

Example

      ⎕dr 1↑1 1000
11
      (181⌶) 1↑1 1000
163


Syntax Colouring

Syntax Colouring R←200⌶Y

This function obtains syntax colouring information for a function.

Y is a vector of character vectors containing the ⎕NR representation of a function or operator.

R is a vector of integer vectors with the same shape and structure of Y in which each number identifies the syntax colour element associated with the corresponding character in Y.

      ∇foo∇
     ∇ foo;local
[1]    global
[2]    local←⍴⍴'hello'
     ∇
      ⎕NR 'foo'
  foo;local   global   local←⍴⍴'hello'

     {(↑⍵),↑200⌶⍵}⎕NR 'foo'
 foo;local       3 21 21 21 19 34 34 34 34 34 0 0 0 0 0 0
 global          3  7  7  7  7  7  7  0  0  0 0 0 0 0 0 0
 local←⍴⍴'hello' 3 34 34 34 34 34 19 23 23  4 4 4 4 4 4 4

In this example:

21 | is the syntax identifier for "character constant"
19 | is the syntax identifier for "primitive"
3 | is the syntax identifier for "white space"
34 | is the syntax identifier for "local name"
7 | is the syntax identifier for "global name"
23 | is the syntax identifier for "idiom"

The list of syntax colour elements supported by the current interpreter is given by 201⌶. It is important to note that the values may change within a release, and are very likely to change across releases .. you should always call 201⌶ rather than relying the results from a different interpreter. See Syntax Colour Tokens.


Compress/Uncompress vector of short integers

Compress Vector of Short Integers R←X(219⌶)Y

In this section, the term sint_vector is used to refer to a simple integer vector whose items are all in the range ¯128 to 127 i.e. they are type 83. For further information see Data Representation (Monadic).

In most cases this I-Beam functionality will be used in conjunction with 220⌶ (Serialise/Deserialise Array). However, it may be possible to pass the raw compressed data to and from other applications.

X specifies the operation to be performed, either compression or decompression, the compression library to be used, and any optional parameters. Y contains the data to be operated on.

Compression

Y must be a sint_vector.

R is a two item vector, each of which is a sint_vector. R[1] describes the compression, and R[2] contains the raw data which is the result of applying the compression library to the input data Y.

X is specified as follows:

X[1] | X[2] | Compression Library
1 | n/a | LZ4
2 | 0 .. 9 | zlib
3 | 0 .. 9 | gzip

If LZ4 compression is required, then X must either be a scalar or a one element vector. Otherwise, X[2], if present, specifies the compression level; higher numbers produce better compression, but take longer.

Decompression

R is a sint_vector, containing the output of applying the decompression library to the input data, Y.

If X is a scalar or a one item vector, and has the value 0, then Y must be a vector of two items which is the result of previously calling 219⌶ to compress a sint_vector.

Otherwise, X is a scalar or one or two element vector and Y must be a sint_vector.

The first element of X must be one of the following values.

X[1] | Compression Library
¯1 | LZ4
¯2 | zlib
¯3 | gzip

The second, optional, element of X specifies the length of the uncompressed data. Its presence results in a more efficient use of the compression library.

X may not be a two item vector whose first item has the value 0.

Examples

      sint←{⍵-256×⍵>127}
      utf8←'UTF-8'∘⎕ucs
      str←'empty←⍬'
      ⊣v←sint utf8  str
101 109 112 116 121 ¯30 ¯122 ¯112 ¯30 ¯115 ¯84
      ⊣comp←1 (219⌶) v
8 ¯55 1 0 0 0 0 11  ¯80 101 109 112 116 121 ¯30 ¯122 ¯112 ¯30 ¯115 ¯84

      utf8 256| 0(219⌶)comp
empty←⍬
      utf8 256| ¯1(219⌶)2⊃comp
empty←⍬


Serialise/Deserialise Arrays

Serialise/Deserialise Array R←X(220⌶)Y

In this section, the term sint_vector is used to refer to a simple integer vector whose items are all in the range ¯128 to 127 i.e. they are type 83. For further information see Data Representation (Monadic).

It is expected that in many cases this I-Beam functionality will be used in conjunction with 219⌶ - Compress/Decompress vector of short integers. It would also be possible to encrypt the serialised form and write to a file (either component or native), and reverse the process at a later date.

X is a scalar which can take the value 0 or 1.

When X is 1, Y can be any array. The result R is the serialised form of the array, presented as a sint_vector.

When X is 0, Y must be a sint_vector. The result R is an array whose serialised form is represented by Y.

Typically it is not possible to construct a vector which can be deserialised; it is expected that the only source of a vector which can be deserialised is the result of using 1(220⌶) to serialise an array.

The result of 1(220⌶) will differ between interpreters of differing widths and editions, but the resulting vector can be deserialised in other interpreters, with the exception that, like arrays in component files, it may not be possible to deserialise an array which was serialised in a later interpreter

The following identity holds true:

      A≡ 0(220⌶) 0(219⌶) 1(219⌶) 1(220⌶) A

Example

      a←'ab'
      b←1(220⌶)a
      b
¯33 ¯108 5 0 0 0 31 39 0 0 2 0 0 0 97 98 0 0
      c←0(220⌶)b
      c≡a
1


Compiler Control

Compiler Control R←{X}(400⌶)Y

Controls the actions of the Compiler. For further information, see Compiler User Guide.

The optional left-argument X must be one of the following:

X | Description
0 | Set automatic compilation options (default)
1 | Determine whether the function/operator Y has been successfully compiled
2 | Compile the function/operator Y
3 | Discard compiled form of the function/operator Y
4 | Show bytecode for the compiled function/operator Y
nsref | Compile the function/operator Y using user-defined callbacks in this namespace to provide information about global names

The nature of Y and R depend on the value of X as follows:

X=0 : Control Automatic Compilation (default)

Y must be an integer 0, 1, 2, or 3.

Y | Description
0 | disable automatic compilation (initial setting)
1 | compile functions when they are fixed (with ⎕FX or from the function editor)
2 | compile operators the first time they are executed
3 | compile functions when they are fixed (with ⎕FX or from the function editor) and compile operators the first time they are executed

The result R is the previous value of Y.

The automatic compilation setting is maintained within the workspace, and is saved and loaded with the workspace.

X=1: Query Compilation State

Y must be a character vector, matrix or vector of vectors specifying the name of a function or operator or a list of such names.

The result R is a Boolean scalar or vector, with the value 1 if the corresponding function/operator has been successfully compiled or 0 if it has not.

X=2: Compile

Y must be a character vector, matrix or vector of vectors specifying the name of a function or operator or a list of such names that should be compiled.

The result R is a matrix of diagnostic information or, if Y was either a matrix or a vector of vectors, a vector of such matrices. Each row of the matrix describes a problem that caused the compilation to fail, with four columns corresponding to:

  1. the APL error number
  2. the line number in the function/operator
  3. the column number (currently always 0)
  4. the error message

If the matrix R has zero rows then the compilation was successful.

If this mechanism is used to compile operators, then the compiled bytecode will assume that the operator's operands are functions rather than arrays. At run time, the operands will be checked – if they are functions then the compiled bytecode will be used, otherwise the operator will be interpreted.

X=3: Discard Compiled Form

If Y is empty, discard any compiled bytecode for all functions and operators in the workspace. If Y is a character vector, matrix or vector of vectors specifying the name of a function or operator or a list of such names, discard any compiled bytecode for the name(s) specified by Y. R is always 0

X=4: Show Bytecode

Y must be a character vector, matrix or vector of vectors specifying the name of a function or operator or a list of such names.

The result R is a multi-line string (that is, a character vector with embedded newlines) or, if Y was either a matrix or a vector of vectors, a vector of such strings. Each string is a human-readable representation of the bytecode of a compiled function or operator.

This functionality is provided for information and diagnostic purposes only. The human-readable form of the bytecode is subject to change at any time.

X is a namespace reference: Compile With Callbacks

Y must be a character vector, matrix or vector of vectors specifying the name of a function or operator or a list of such names. The specified functions or operators are compiled in the same way as when X = 2 except that the compiler uses the user-defined callback functions in the namespace X to obtain information about global names. The namespace X can contain any or all of following callback functions:

Callback | Description
quadNC | analogous to the system function ⎕NC. When applied monadically to an enclosed character vector it should return the detailed name class of that name. For example, given the name of a global dfn it should return the value 3.2.
quadAT | analogous to the system function ⎕AT. When applied monadically to an enclosed character vector it should return a 1 by 4 matrix whose first item is a vector of 3 integers describing (respectively) the result, function valence and operator valence of the name.
getValue | used to obtain the value of global constants. When applied monadically to a character vector that is a global constant it should return the enclose of the constant value, otherwise it returns ⍬.

Each of these callback functions returns information about names that should be guaranteed to exist when the compiled functions are executed. The compiler assumes that the information returned by the callbacks is correct, and generates bytecode accordingly. In the case of quadNC and quadAT, if the information returned by the callbacks turns out not to be correct when the compiled function is executed, then a runtime error is generated.

The result R is a matrix of diagnostic information or, if Y was either a matrix or a vector of vectors, a vector of such matrices. Each row of the matrix describes a problem that caused the compilation to fail, with four columns corresponding to:

  1. the APL error number
  2. the line number in the function/operator
  3. the column number (currently always 0)
  4. the error message

If the matrix R has zero rows then the compilation was successful.


Trap Control

Trap Control R←600⌶Y

This function is used to temporarily disable the error trapping mechanism used by :Trap and ⎕TRAP. This can be useful in debugging applications.

Y is an integer 0, 1 or 2 as shown in the following table.

R is the previous value (0, 1, or 2) of the trap state.

Y | Effect
0 | Enable all traps.
1 | Disable all traps.
2 | Disable traps in suspended functions from triggering when an error is generated in the Session.

Note that the Disable traps in session option of the Session Options menu performs the same tasks as (600⌶0) and (600⌶2).

For error-guards in dfns 600⌶0 and 600⌶2 are equivalent; in neither case is an error generated in the session caught by an error guard in a suspended dfn.


Case Convert

Case Convert R←{X}(819⌶)Y

Converts character data in Y to upper or lower-case. This function is considerably faster than any comparable function coded in APL, especially on nested arrays.

Y may be any array of arbitrary depth so long as all the elements are characters.

The optional left-argument X is 0 (convert to lower-case) or 1 (convert to upper-case). If omitted, the default is 0.

The result R has the same structure as Y but each character element is case folded to upper or lower case.

Characters are converted per the default case mappings specified by The Unicode Consortium, described at:

 ftp://ftp.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.html

and using the table at:

 http://unicode.org/Public/UNIDATA/UnicodeData.txt

If conversion is being used to do case-insensitive character comparisons then converting everything to lower case is generally preferable to converting everything to upper. This is because converting to lower case can be faster.

This I-beam is supported in Classic Edition using the same code as the Unicode Edition. This means that any case-folding defined in the input translate tables is ignored, and that TRANSLATION ERRORs will be generated if the folded characters do not appear in ⎕AV.

Examples

      (819⌶) 'How many Roads must a man walk down'
how many roads must a man walk down
      1 (819⌶) 'How many Roads must a man walk down'
HOW MANY ROADS MUST A MAN WALK DOWN

      data←1000⍴⊂'Hello there.'
      lc_data←819⌶ data
      4↑lc_data
 hello there.  hello there.  hello there.  hello there.


Called Monadically

Called Monadically R←900⌶Y

Identifies how the current function was called. 900⌶ applies only when called from within a variadic defined function (not a dfn).

Y may be any array.

The result R is Boolean. 1 means that the current function was called monadically; 0 means that it wasn't. If there is no function on the stack, the result is 0.

Example

     ∇ r←{left}foo right
[1]    r←900⌶⍬
     ∇
      foo 10
1
      0 foo 10
0


Loaded Libraries

Loaded Libraries R←950⌶Y

Reports the names of the dynamic link libraries that are currently loaded as a result of executing ⎕NA.

Y is an empty vector.

The result R is a vector of character vectors containing the names of all the DLLs or shared libraries that have been explicitly loaded by ⎕NA and are still loaded by virtue of the presence of at least one external function reference.

Examples

      )clear
clear ws
      'Aloc'⎕NA'P kernel32∣GlobalAlloc U4 P'
      'Free'⎕NA'P kernel32∣GlobalFree P'
      'Lock'⎕NA'P kernel32∣GlobalLock P'
      'Ulok'⎕NA'U4 kernel32∣GlobalUnlock P'
      'Valu'⎕NA'U4 version∣VerQueryValue* P <0T >U4 >U4'
      'copy'⎕NA'P msvcrt∣memcpy >U4[] P U4'

      950⌶⍬
 KERNEL32.DLL  VERSION.DLL  MSVCRT.DLL
      )fns
Aloc    Free    Lock    Ulok    Valu    copy

      )erase Aloc    Free    Lock    Valu
      950⌶⍬
 KERNEL32.DLL  MSVCRT.DLL
      )fns
Ulok    copy

      )erase Ulok
      950⌶⍬
 MSVCRT.DLL

      )clear
clear ws
      950⌶⍬


Number of Threads

Number of Threads R←1111⌶Y

Specifies how many threads are to be used for parallel execution.

If Y has the value ⍬, R is the number of virtual processors in the machine.

Otherwise, Y is an integer that specifies the number of threads that are to be used henceforth for parallel execution. Prior to this call, the default number of threads is specified by the parameter APL_MAX_THREADS. See APL_MAX_THREADS.

Note that whatever the value of Y, Dyalog limits the number of threads to 64. So the effective number of threads is Y⌊64.

R is the previous value.

To reset the number of threads to be the same as the number of virtual processors run:

      {}1111⌶ 1111⌶⍬

See Parallel Execution and Parallel Execution Threshold.


Parallel Execution Threshold

Parallel Execution Threshold R←1112⌶Y

Y is an integer that specifies the array size threshold at which parallel execution takes place. If a parallel-enabled function is invoked on an array whose number of elements is equal to or greater than this threshold, execution takes place in parallel. If not, it doesn't.

Prior to this call, the default value of the threshold is specified by an environment variable named APL_MIN_PARALLEL. If this variable is not set, the default is 32768.

R is the previous value.

See Parallel Execution and Number of Threads.


Update Function Time Stamp

Update Function Time Stamp {R}←X(1159⌶)Y

Y is an array of function names in the same format as the right argument of ⎕AT. For further information, see Attributes.

X is an array of function attributes in the same format as the output of ⎕AT.

The shy result R is a vector of numeric items, one per each specified function containing the following values:

0 | No change was made; the name is not that of a function, or the function was locked
1 | The time and user stamp were updated

Note that the last item of the function time stamp must be set to 0 otherwise 1159 ⌶ will generate a DOMAIN ERROR. Additionally, the time stamp must be greater than 1970 1 1 0 0 0 0.

Example

      ]disp ⎕AT'Christmas'
┌→────┬───────────────────┬─┬───────┐
│0 0 0│2013 3 1 11 14 58 0│0│Richard│
└~───→┴~─────────────────→┴─┴───────┘

      x←⎕AT 'Christmas'
      x[2 4]←(2012 12 25 11 59 0 0)('Santa')
      x (1159⌶) 'Christmas'

      ]disp ⎕AT'Christmas'
┌→────┬────────────────────┬─┬─────┐
│0 0 0│2012 12 25 11 59 0 0│0│Santa│
└~───→┴~──────────────────→┴─┴────→┘


Hash Array

Hash Array R←{X}1500⌶Y

This function creates a hashed array, returns an unhashed copy of an array or reports the state of hashing of an array.

Y may be any array.

If X is omitted, the result R is a copy of Y that has been invisibly marked as hashed. R behaves the same as Y in all respects. The only difference is that dyadic ⍳ and related functions are expected to run faster when applied to a hashed array. The hash will be created the first time the array is used as an argument to ⍳ or other set functions. The hashed property is preserved across assignments and argument passing, but in general is not preserved by any primitive functions.

If X is 1, the result R returns an indication of whether Y has been marked for hashing or whether the hash has been created:

R | State of Y
0 | Y has not been marked for hashing
1 | Y has been marked for hashing, but the hash tables has not yet been created
2 | Y has a hash table

If X is 2, the result R is the unhashed form of Y.

Examples:

      R←1500⌶1 2 3    ⍝ R is marked for hashing
      1 (1500⌶)R
1
      S←R             ⍝ S is marked for hashing
      {⍵⍳2 3 5}R      ⍝ R is now hashed
      1 (1500⌶)R
2
      U←(⍴R)⍴R        ⍝ U is not hashed
      U←⊃⊂R           ⍝   ditto
      1 (1500⌶)U
0

If R is a hashed array then certain forms of modified assignment will preserve and efficiently update the hash table:

      R,←Y    ⍝ only for scalar or vector R
      R⍪←Y
      R↓⍨←Y   ⍝ only for negative singleton Y

Examples:

      R←1500⌶1 2 3 ⍝ R is hashed

      R,←5    ⍝ ,← preserves and updates
              ⍝ the hash table
      R
1 2 3 5
      R⍳2 4 6
2 5 5

      R↓⍨←¯2  ⍝ ↓⍨← preserves and updates
              ⍝ the hash table
      R
1 2
      R⍳2 4 6
2 3 3

The hashed property survives )SAVE/)LOAD and )SAVE/)COPY. It does not currently survive writing to a component file and reading back again.


Memory Manager Statistics

Memory Manager Statistics R←{X}(2000⌶)Y

This function returns information about the state of the workspace and provides a means to reset certain statistics and to control workspace allocation. This I-Beam is provided for performance tuning and is VERY LIKELY to change in the next release. See also Workspace Management.

Y is a simple integer scalar or vector containing values listed in the table below.

If X is omitted, the result R is an array with the same structure as Y, but with values in Y replaced by the following statistics. For any value in Y outside those listed below, the result is undefined.

Value | Description
0 | Workspace available (a "quick" ⎕WA)
1 | Workspace used
2 | Number of compactions since the workspace was loaded
3 | Number of garbage collections that found garbage
4 | Current number of garbage pockets in the workspace
9 | Current number of free pockets in the workspace
10 | Current number of used pockets in the workspace
12 | Sediment size
13 | Current workspace allocation, i.e. the amount of memory that is actually being used
14 | Workspace allocation high-water mark, i.e. the maximum amount of memory that has been allocated since the workspace was loaded or since this count was reset.
15 | Limit on minimum workspace allocation
16 | Limit on maximum workspace allocation
19 | The number of calls to ⎕WA or 2002⌶ since the last time 2000⌶ was called, or when the process started.

Note that while all other operations are relatively fast, the operation to count the number of garbage pockets (4) may take a noticeable amount of time, depending upon the size and state of the workspace.

See also Specify Workspace Available.

Examples

      2000⌶0
55414796
      2000⌶0,⍳16   ⍝ with MAXWS=95G
1.02004292E11 1181312 1 1 0 ¯1 ¯1 ¯1 ¯1 78 13280 ¯1 1180800 1595016496 1595042464 0 1.020054733E11

If X is specified, it must be either a simple integer scalar, or a vector of the same length as Y, and the result R is ⍬. In this case, the value in Y specifies the item to be set and X specifies its new value according to the table below.

Value | Description
2 | 0 resets the compaction count; no other values allowed
3 | 0 resets the count of garbage collections that found garbage; no other values allowed
14 | 0 resets the workspace allocation high-water mark; no other values allowed. This should be called following a call to ⎕WA (which compacts the workspace and returns unused memory to the operating system).
15 | Sets the minimum workspace allocation to the corresponding value in X; must be between 0 and the current workspace allocation
16 | Sets the maximum workspace allocation to the corresponding value in X; 0 implies MAXWS otherwise must be between the current workspace allocation and MAXWS.
19 | 0 resets the compaction count; no other values allowed

Notes:

  • Note that the workspace allocation high-water mark indicates a minimum value for MAXWS.
  • Limiting the maximum workspace allocation can be used to prevent code which grabs as much workspace as it can from skewing the peak usage result.
  • Limiting the minimum workspace allocation can avoid repeatedly committing and releasing memory to the Operating System when memory usage is fluctuating.

Examples

      2000⌶2 3
6 0 33216252
      0 (2000⌶)2 3 14 ⍝ Reset compaction count

      2000⌶2 3
0 0
      30000000 40000000(2000⌶)15 16 ⍝ Restrict min/max ws

      (2000⌶)15 16
30000000 40000000

      0 (2000⌶)15 16 ⍝ Reset min/max ws

      (2000⌶)15 16
0 65536000

      (2000⌶)13 14 ⍝ Current, peak WS allocation
4072532 4072532

      a←10e6⍴'x' ⍝ Increase WS allocation

      (2000⌶)13 14 ⍝ Current, peak WS allocation
15108580 15108580

      ⎕ex 'a' ⋄ {}⎕wa ⍝ Decrease current WS allocation

      (2000⌶)13 14 ⍝ Current, peak WS allocation
1962856 15108580

      0 (2000⌶) 14 ⍝ Reset High-water mark

      (2000⌶)13 14 ⍝ Current, peak WS allocation
1962856 1962856


Specify Workspace Available

Specify Workspace Available R←2002⌶Y

This function is identical to the system function ⎕WA except that it provides the means to specify the amount of memory The term memory here means virtual memory which includes memory mapped to disk. 1 that is committed for the workspace rather than have it assigned by the internal algorithm. Committed memory is memory that is allocated to a specific process and thereby reduces the amount of memory available for other applications. See also Workspace Management.

Like ⎕WA, 2002⌶ compacts the workspace so that it occupies the minimum number of bytes possible, adds an extra amount, and then de-commits all the remaining memory that it is currently using, allowing it to be allocated by the operating system for use by other applications.

The argument Y is an integer which specifies the size, in bytes, of this extra amount.

The purpose of the extra amount is to reduce the likelihood that APL will immediately have to ask the operating system to re-commit memory that it has just de-committed, something that would have a deleterious effect on performance. At the same time, if the extra amount were to be excessively large, APL could starve other applications of memory which itself could reduce the effective performance of the system. Whereas ⎕WA calculates the size of the extra amount using a simple internal algorithm, 2002⌶ uses a value specified by the programmer.

R is an integer which reports the size in bytes of the memory committed for the workspace, and is the sum of the minimum amount required by the workspace itself and the argument Y.

If the size of the committed workspace would be smaller than the minimum value (specified by 2000⌶) or larger than the maximum value (which defaults to MAXWS), a DOMAIN ERROR is signalled.

See also Memory Manager Statistics.

Note that this function does not change the size of the extra amount that will be applied subsequently by ⎕WA or by an automatic compaction.


Update DataTable

Update DataTable R←{X}2010⌶Y

Windows only.

This function performs a block update of an instance of the ADO.NET object System.Data.DataTable. This object may only be updated using an explicit row-wise loop, which is slow at the APL level. 2010⌶ implements an internal row-wise loop which is much faster on large arrays. Furthermore, the function handles NULL values and the conversion of internal APL data to the appropriate .NET datatype in a more efficient manner than can be otherwise achieved. These 3 factors together mean that the function provides a significant improvement in performance compared to calling the row-wise programming interface directly at the APL level.

Y is a 2, 3 or 4-item array containing:

  1. A reference to an instance of System.Data.DataTable.
  2. A matrix with the same number of columns as the table specified by Y[1].
  3. An optional vector which specifies for each column in the DataTable the values in Y[2]which should be converted to a System.DBNull.
  4. An optional vector which specifies the indices (in zero origin) of the rows of the DataTable which are to be updated. If omitted, the matrix specified by Y[2] will be appended to the DataTable.

The optional argument X is Boolean vector, where a 1 indicates that the corresponding column of Y[2] is a string from which the new values should be converted according to that column's data type.

Example

Shown firstly for comparison is the type of code that is required to update a DataTable by looping:

      ⎕USING←'System' 'System.Data,system.data.dll'
      dt←⎕NEW DataTable
      ac←{dt.Columns.Add ⍺ ⍵}
      'S1' 'S2' 'I1' 'D1' ac¨String String Int32 DateTime
 S1  S2  I1  D1

      NextYear←DateTime.Now+{⎕NEW TimeSpan (4↑⍵)}¨⍳n←365
      data←(⍕¨⍳n),(n⍴'odd' 'even'),(10|⍳n),⍪NextYear
      ¯2 4↑data
 364  even  4  18-01-2011 14:03:29
 365  odd   5  19-01-2011 14:03:29

      ar←{(row←dt.NewRow).ItemArray←⍵ ⋄ dt.Rows.Add row}
      t←3⊃⎕ai ⋄ ar¨↓data ⋄ (3⊃⎕ai)-t
449

This result shows that this code can only insert roughly 800 rows per second (3⊃⎕AI returns elapsed time in milliseconds), because of the need to loop on each row and perform a noticeable amount of work each time around the loop.

2010⌶ does all the looping in compiled code:

      dt.Rows.Clear ⍝ Delete the rows inserted above
      SetDT←2010⌶
      t←3⊃⎕AI ⋄ SetDT dt data ⋄ (3⊃⎕AI)-t
4

So in this case, using 2010⌶ achieves over 90,000 rows per second.

DateTime columns

Creating large arrays of DateTime objects in the workspace takes additional resources, and unless the data is already stored that way, it is not necessary to convert it to .NET objects. Data in ⎕TS format (7-element integer vector) or in a suitable character format may be used directly. The former is a specific Dyalog optimisation; the latter a feature of .NET Version 4.0. The following examples use numeric and character data for the dates:

   months←12⍴31 ⋄ months[2 4 6 9 11]←29 30 30 30 30
   n←⍴NextYear←7↑¨⊃,/(⍳12){(⊂2016,⍺),¨⍳⍵}¨months
   data←(⍕¨⍳n),(n⍴'odd' 'even'),(10|⍳n),⍪NextYear
   SetDT dt data

   n←⍴NextYear←⊃,/(⍳12){(⊂'2016/',(⍕⍺),'/'),∘⍕¨⍳⍵}¨months
   data←(⍕¨⍳n),(n⍴'odd' 'even'),(10|⍳n),⍪NextYear
   SetDT dt data

Using Strings

In circumstances where .NET fails to accept character data automatically, it is possible to force conversion from character format to the corresponding .NET type.

If specified, the optional left argument X instructs the system to pass the corresponding columns of data to the Parse() method of the data type for those columns prior to performing the update.

In the following example, the left argument is not strictly necessary using .NET Version 4.0, but forces parsing for the data in the 4th column:

   months←12⍴31 ⋄ months[2 4 6 9 11]←29 30 30 30 30
   n←⍴NextYear←⊃,/(⍳12){(⊂'2016/',(⍕⍺),'/'),∘⍕¨⍳⍵}¨months
   data←(⍕¨⍳n),(n⍴'odd' 'even'),(10|⍳n),⍪NextYear
   0 0 0 1 SetDT dt data

Handling Nulls

If applicable, Y[3] is a vector with as many elements as the DataTable has columns, indicating the value that should be converted to System.DBNull as data is written. For example, using the same DataTable as above:

      t
 <null>  odd    1  21-01-2010 14:50:19
 two     even   2  22-01-2010 14:50:19
 three   odd   99  23-01-2010 14:50:19

      dt.Rows.Clear ⍝ Clear the contents of dt
      SetDT dt t ('<null>' 'even' 99 '')

Above, we have declared that the string '<null>' should be considered to be a null value in the first column, 'even' in the second column, and the integer 99 in the third.

Updating Selected Rows

Sometimes, you may have read a very large number of rows from a DataTable, but only want to update a single row, or a very small number of rows. Row indices can be provided as the fourth element of the argument to 2010⌶. If you are not using Y[3] explicitly, you can just use an empty vector as a placeholder. Continuing from the example above, we could replace the first row in our DataTable using:

      SetDT←2010⌶
      SetDT dt (1 4⍴'one' 'odd' 1 DateTime.Now) ⍬ 0

Note

  • Y[2] must be provided as a matrix, even if you only want to update a single row,
  • Y[4] specifies row indices using zero origin (the first row has number 0).

Warning

If you are experimenting with writing to a DataTable, note that you should call dt.Rows.Clear each time to clear the current contents of the table. Otherwise you will end up with a very large number of rows after a while.


Read DataTable

Read DataTable R←{X}2011⌶Y

Windows only.

This function performs a block read from an instance of the ADO.NET object System.Data.DataTable. This object may only be read using an explicit row-wise loop, which is slow at the APL level. 2011⌶ implements an internal row-wise loop which is much faster on large arrays. Furthermore, the function handles NULL values and the conversion of .NET datatypes to the appropriate internal APL form in a more efficient manner than can otherwise be achieved. These 3 factors together mean that the function provides a significant improvement in performance compared to calling the row-wise programming interface directly at the APL level.

Y is a scalar or a 2-item array containing:

  1. A reference to an instance of System.Data.DataTable.
  2. An optional vector which specifies the values to which a System.DBNull should be mapped in the corresponding columns of the result

The optional argument X is Boolean vector, where a 1 indicates that the corresponding column of the result should be converted to a string using the ToString method of the data type of column in question. It is envisaged that this argument may be extended in the future, to allow other conversions – for example converting Dates to a floating-point format

The result R is a matrix with the same shape as the DataTable identified in Y.

Example

First for comparison is shown the type of code that is required to read a DataTable by looping:

      t←3⊃⎕AI ⋄ data1←↑(⌷dt.Rows).ItemArray ⋄ (3⊃⎕AI)-t
191

The above expression turns the dt.Rows collection into an array using ⌷, and mixes the ItemArray properties to produce the result. Although here there is no explicit loop, involved, there is an implicit loop required to reference each item of the collection in succession. This operation performs at about 200 rows/sec.

2011⌶ does the looping entirely in compiled code and is significantly faster:

      GetDT←2011⌶
      t←3⊃⎕AI ⋄ data2←GetDT dt ⋄ (3⊃⎕AI)-t
25

Example

In the first example shown above, 2011⌶ created 365 instances of System.DateTime objects in the workspace. If we are willing to receive the timestamps in the form of strings, we can read the data almost an order of magnitude faster:

      t←3⊃⎕AI ⋄ data3←0 0 0 1 GetDT dt ⋄ (3⊃⎕AI)-t
3

The left argument to 2011⌶ allows you to flag columns which should be returned as the ToString() value of each object in the flagged columns. Although the resulting array looks identical to the original, it is not: The fourth column contains character vectors:

      ¯2 4↑data3
 364  even  4  18-01-2011 14:03:29
 365  odd   5  19-01-2011 14:03:29

Depending on your application, you may need to process the text in the fourth column in some way – but the overall performance will probably still be very much better than it would be if DateTime objects were used.

Handling Nulls

Using the DataTable produced by the corresponding example shown for 2010⌶ it can be shown that by default null values will be read back into the APL workspace as instances of System.DBNull.

      GetDT←2011⌶>

      ⎕←z←GetDT dt

        odd  1  21-01-2010 14:50:19
 two         2  22-01-2010 14:50:19
 three  odd     23-01-2010 14:50:19

      (1 1⍉z).GetType

 System.DBNull  System.DBNull  System.DBNull

However, by supplying a left argument to 2011⌶, we can request that nulls in each column are mapped to a corresponding value of our choice; in this case, '<null>', 'even', and 99 respectively.

      GetDT dt ('<null>' 'even' 99 '')
<null>   odd    1  21-01-2010 14:50:19
 two     even   2  22-01-2010 14:50:19
 three   odd   99  23-01-2010 14:50:19


Remove Data Binding

Remove Data Binding R←2014⌶Y

Windows only.

This function disassociates a data-bound variable from its data binding source.

Y is any array.

If Y or an element of Y is a character vector that contains the name of a data-bound variable, that variable is dissociated from its data binding source.

The result R is always 1.

Example

      2014⌶'txtSource'
1


Create Data Binding Source

Create Data Binding Source R←{X}2015⌶Y

Windows only.

Creates an object that may be used as a data source for WPF data binding. It is beyond the scope of this document to fully explain the concepts of WPF data binding. See Microsoft Developer Network, Data Binding Overview. 1

This function connects a Binding Target to a Binding Source. In WPF a Binding Target is a particular property of a user interface object; for example, the Text property of a TextBox object. A Binding Source is a Path to a value in a data object (which may contain other values). The value of the Binding Source determines the value of the Binding Target. If two-way binding is in place, a change in a user-interface component causes the bound data value to change accordingly. In the example of the TextBox, the value in the Binding Source changes as the user types into the TextBox.

Y is a character vector containing one of the following:

  • the name of a variable
  • the name of a namespace containing one or more variables
  • the name of a variable containing a vector of refs to namespaces, each of which contains one or more variables.

If the name specified by Y doesn't exist or represents neither a variable nor a namespace, the function reports DOMAIN ERROR. Currently, no further validation of the structure and contents of Y is performed, but nothing other than the examples described herein is supported.

If the optional left argument X is given and Y is a variable other than a ref, X specifies the binding type for that variable. If Y specifies one or more namespaces, X specifies the names and binding types of each of the variables which are to be bound, contained in the namespaces specified by Y.

The structure of X depends upon the structure of Y and is discussed later in this topic.

If X is omitted, all of the variables specified by Y are bound with default binding types.

Here the term bind variable refers to any variable specified by X and Y to be bound, and the term binding type means the .NET data type to which the value of the bind variable is converted before it is passed to the .NET interface.

2015⌶ creates a Binding Source object R. This is a .NET object which contains Path(s) to one or more bind variables. This object may then be assigned to a property of a WPF object or passed a s as a parameter to a WPF method that requires a Binding Source.

Bind Variables and Bind Types

A bind variable should be of rank 2 or less. Higher rank arrays are not supported.

If not specified by X, the binding type of a bind variable is derived from its content at the time 2015⌶ is executed. The binding type is then stored with the variable in the workspace. There is no mechanism to change a variable's binding type without erasing the variable and re-executing 2015⌶. If you change the type or rank of a bind variable while it is bound (for example from a variable to a namespace), the behaviour of the system is unpredictable.

The default binding type is derived as follow:

If the bind variable is a simple scalar number the default binding type is System.Object. At the point when the value of the variable is passed to the .NET interface this will be cast to a numeric type such as System.Int16, System.Int32, System.Int64, or System.Double, depending upon the internal representation of the data. The .NET property to which it is bound will typically only accept a single Type (for example System.Int32), so to avoid unpredictable behaviour, it is recommended that the left argument X be used to specify the binding type for numeric data.

If the bind variable is a character scalar or vector, the default binding type is also System.Object, but at the point when the value of the variable is passed to the .NET interface it will always be passed as System.String, which is suitable for binding to any property that accepts a System.String, such as the Text property of a TextBox.

If the bind variable is a vector other than a simple character vector, such as a vector of character vectors, a simple numeric vector, or a vector of .NET objects, the bind type will be a collection. This is suitable for binding to any property that represents a collection (list) of items, for example the ItemsSource property of a ListBox.

If the bind variable is a matrix, the default binding type is System.Object.

All the examples that follow assume ⎕USING←'System'.

Binding Single Variables

In this case, Y specifies the name of a variable which is one of the following:

  • character vector (or scalar)
  • numeric scalar
  • scalar .NET object (not currently supported)
  • vector of character vectors
  • numeric vector
  • vector of .NET objects
  • matrix

X (if specified) defines the binding type for the bind variable named by Y and is a single .NET Type.

Note that in the following examples, the reason for expunging the name first is discussed in the section headed Rebinding a Variable.

Binding a Character Vector

This example illustrates how to bind a variable which contains a character vector.

      ⎕EX'txtSource'
      txtSource←HELLO WORLD'
      bindsource←2015⌶'txtSource'

In this example, the binding type of the variable txtSource will be System.String, suitable for binding to any property that accepts a String, such as the Text property of a TextBox.

Binding a Numeric Scalar

This example illustrates how to bind a variable which contains a numeric scalar value.

      ⎕EX'sizeSource'
      sizeSource←36
      bindSource←Int32(2015⌶)'sizeSource'

In this example, the left argument Int32 specifies that the binding type for the variable sizeSource is to be System.Int32. This means that whenever APL passes the value of sizeSource to the control, it will first be cast to an Int32. This makes it suitable, for example, for binding to the FontSize property of a TextBox.

A number of controls have a Value property which must be expressed as a System.Double. The next example shows how to create a Binding Source for such a variable.

      ⎕EX'valSource'
      valSource←42
      bindSource←Double(2015⌶)'valSource'

Binding a Scalar .NET Object

This is currently not supported.

Binding a Vector of Character Vectors

WPF data binding provides the means to bind controls that display lists of items, such as the ListBox, ListView, and TreeView controls, to collections of data. These controls are all based upon the ItemsControl class. To bind an ItemsControl to a collection object, you use its ItemsSource property.

This example illustrates how to bind a variable which contains a vector of character vectors.

      ⎕EX'itemsSource'
      itemsSource←'beer' 'wine' 'water'
      bindsource←2015⌶'itemsSource'

In this example, the binding type of the variable itemsSource will be System.Collection, suitable for binding to the ItemSource property of an ItemsControl.

Binding a Numeric Vector

By default, a numeric vector is bound in the same way as a vector of character vectors, i.e. as a System.Collection, suitable for binding to the ItemSource property of an ItemsControl.

      ⎕EX'yearsSource'
      yearsSource←2000+⍳20
      bindSource←2015⌶'yearsSource'

In principle, a numeric vector may alternatively be bound to a WPF property that requires a 1-dimensional numeric array, by specifying the appropriate data type (e.g. Int32, Double) for the array as the left argument. For example:

      ⎕EX'arraySource'
      arraySource←42 24
      bindSource←Int32 (2015⌶)'arraySource'

Binding a Vector of .NET Objects

A vector of .NET objects is bound in the same way as a vector of character vectors, i.e. as a System.Collection, suitable for binding to the ItemSource property of an ItemsControl.

      ↑Easter
2015 4 12
2016 5  1
2017 4 16
2018 4  8
2019 4 28
2020 4 19
2021 5  2
2022 4 24
2023 4 16
2024 5  5
      dt←{⎕NEW DateTime ⍵}¨Easter
      bindSource←2015⌶'dt'

Note that, as a specific optimisation for binding DateTime data, it is not necessary to create DateTime objects in the workspace. Instead, the data may be represented by 7-element integer vectors (⎕TS format) or character strings that can be parsed by the DateTime.Parse(String) method. However, in both cases it is necessary to explicitly specify the binding type to force the data to be converted to DateTime, as illustrated by the following examples:

      TSEaster←7↑¨Easter
      bindSource←DateTime (2015⌶) 'TSEaster'

      CharEaster←'2015/4/12' '2016/5/1' '2017/4/16'
      bindSource←DateTime (2015⌶) 'CharEaster'

Binding a Matrix

If the bind variable is a matrix, it is bound in a similar way to a vector of namespaces and is discussed below.

Rebinding a Variable

As mentioned earlier, when a variable is bound its binding type is stored with it in the workspace. If you subsequently attempt to rebind the variable there is no mechanism in place to alter the binding type. If the current binding type (whether specified by the left argument X, or by being the default) differs from the saved one, the function will generate a DOMAIN ERROR.

      num←42
      bs←2015⌶'num'

      bs←'Int32'(2015⌶)'num'
DOMAIN ERROR: You cannot redefine the binding types
      bs←'Int32'(2015⌶)'num'
     ∧

In this example, perhaps the programmer realised after binding num (with a default binding type of System.Object) that the binding type should really be System.Int32, and simply was trying to correct the error. To avoid this problem, it is recommended that you expunge the name before using it.

      ⎕EX 'num'
      num←42
      bs←2015⌶'num'⍝ (default) binding type System.Object

      ⎕EX 'num'
      num←42
      bs←Int32(2015⌶)'num'

Binding A Namespace

In this case, Y specifies the name of a namespace that contains one or more variables. By default, each variable is bound using its default binding type as described above. Objects other than variables are ignored.

If it is required to specify the binding type of any of the variables, or if certain variables are to be excluded, the left argument is a 2-column matrix. The first column contains the names of the variables to be bound, and the second column their binding types.

Example

The following code snippet binds a namespace containing two variables named txtSource and sizeSource. In this case, the name of each variable may be specified as the Path for a WPF property that requires a String or an Int32. For example, if bindSource were assigned to the DataContext property of a TextBox, its Text property could be bound to txtSource and its FontSize property to sizeSource.

      src←⎕NS''
      src.txtSource←'Hello World'
      src.sizeSource←36
      options←2 2⍴'txtSource'String'sizeSource'Int32
      bindSource←options(2015⌶)'src'

Binding a Vector of Namespaces

In this case, Y specifies the name of a variable that contains a vector of refs to namespaces. In this case, the result R is of type Dyalog.Data.DataBoundCollectionHandler which is suitable for binding to a WPF property that requires an IEnumerable implementation, such as the ItemsSource property of the DataGrid.

Each namespace in Y represents one of a collection of instances of an object, which exports a particular set of properties for binding purposes. For example, Y could specify a wine database where each namespace represents a different wine, and each namespace contains the same set of variables that contain the name, price (and so forth) of each wine.

Example

 winelist←⎕NS¨(⍴Wines)⍴⊂''
 winelist.Name←Wines
 winelist.Price←0.01×10000+?(⍴Wines)⍴10000

 bindSource←2015⌶'winelist'

Binding a Matrix

Binding a matrix is like binding a vector of namespaces. Each row of Y represents one of a collection of instances of an object, which exports a particular set of properties for binding purposes. Each column of Y represents one of these properties.

Every row in the datasource will be of the same type (which might not be the case with an array of namespaces), and so the collection is a collection of specific things. The specific thing is a .NET type that is created dynamically and has a unique name.

Unlike variables in namespaces, the columns of an APL matrix do not have names which can be exported as properties, so this information must be provided in the left argument to (2015⌶) which also specifies their data types. If the left argument is omitted, the default names are Column1, Column2, ... and so forth and the default data type is System.Object.

So if the right argument of (2015⌶) Y is the name of a matrix, the left argument X is a matrix with as many rows as there are columns in Y. X[;1] contains the names by which each of the columns of Y will be exported as a property, and X[;2] their data types.

Values in the matrix may be scalar numbers, character scalars or vectors, or nested vectors, but each column in the matrix must be uniform.

The result R is a specific type that is created dynamically and assigned a unique name of the form Dyalog.Data.DyalogCollectionNotifyHandler`1[Dyalog.Data.DataBoundRow_nnnnnnnn]. This is suitable for binding to a WPF property that requires an IEnumerable implementation, such as the ItemsSource property of the DataGrid.

Example

mat is a matrix of numbers and is bound with default property/column names Column1, Column2, ... Column10 and the default data type of System.Object.

      mat←?20 10⍴100
      bindSource←2015⌶'mat'

Example

winelist is a matrix whose first column contains a list of wines, and whose second column their prices. The left argument is a matrix. Its first column specifies the property names by which the columns will be exported ('Name' and 'Price') and its second column, their data types (System.Object)

 winelist←Wines,[1.5]0.01×10000+?(⍴Wines)⍴10000
 info←(⍪'Name' 'Price'),⊂Object

 bindSource←info(2015⌶)'winelist'

Example

emp is a 3-column matrix which contains names, numbers and addresses. Each address is made up of two character vectors containing street and town

      emp
┌───────────────────┬──────────────────┬────────────────────┐
│John Smith         │Mary White        │T.W. Penk           │
├───────────────────┼──────────────────┼────────────────────┤
│1                  │2                 │3                   │
├───────────────────┼──────────────────┼────────────────────┤
│┌─────────┬───────┐│┌──────────┬─────┐│┌──────────┬───────┐│
││2 East Rd│Headley│││42 High St│Alton│││23 West St│Farnham││
│└─────────┴───────┘│└──────────┴─────┘│└──────────┴───────┘│
└───────────────────┴──────────────────┴────────────────────┘
      schema
┌───────┬────────────────────────┐
│Name   │(System.Object)         │
├───────┼────────────────────────┤
│Number │(System.Object)         │
├───────┼────────────────────────┤
│Address│┌──────┬───────────────┐│
│       ││Street│(System.Object)││
│       │├──────┼───────────────┤│
│       ││Town  │(System.Object)││
│       │└──────┴───────────────┘│
└───────┴────────────────────────┘

      bindSource←schema(2015⌶)'emp'

Notification Events

The object R generates notification events when the value(s) of the Binding Source are updated as the contents of the Binding Target are changed by the user. These events are generated after the data has changed and there is no mechanism to prevent the change from occurring.

There are two types of event; ElementChanged and CellsChanged. The CellsChanged event applies only to a data bound matrix; the ElementChanged event applies to all other types of binding.

The event message supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref
[2] | EventArgs | ref

EventArgs is an instance of the internal class Dyalog.Data.ElementChangedEventArgs or Dyalog.Data.CellsChangedEventArgs whose fields are described below:

Dyalog.Data.ElementChangedEventArgs fields

Indices | An indication of which member has changed. Typically this will either be ¯1 to indicate that the indices are unavailable or a scalar value indicating (origin 0), which element of an array has been modified or added.
Name | The name of the variable that has been modified. This is especially useful when the datasource corresponds to a namespace.
Path | A path used to locate the variable that has been modified. This is especially useful when the datasource corresponds to a deeply nested namespace, where the value changed is an element of an array inside a namespace which is itself an element of an array within the datasource.

Dyalog.Data.CellsChangedEventArgs fields

Path | Identifies the cell or row that was changed. See below.
SourceName | The name of the matrix that was specified as the right argument to 2015⌶.
Reason | A character vector that describes what in the matrix has changed is 'RowDeleted', 'CellChanged' or 'RowInserted'
Value | The new value in the cell or ⎕NULL

If Reason is 'CellChanged', Path is the row and column number (in origin 0) of the cell that was changed and Value is its new value.

If Reason is 'RowDeleted' or 'RowInserted', Path is the number of the row that has been added or removed (in origin 0) and Value is ⎕NULL.


Create .NET Delegate

Create .NET Delegate R←2016⌶Y

Windows only.

.NET methods (and properties) may specify a parameter to be a delegate. A delegate is a place holder for a function, normally with a particular signature and result type, that should be supplied when the method is called. Sometimes the signature of a .NET method that takes a delegate as a parameter does not provide enough information for Dyalog to determine automatically what type of delegate is required. 2016⌶ allows you to specify the type so that Dyalog can perform the necessary conversion(s) at run-time.

Y is a 2-element array. The first element is a .NET type that inherits from the abstract .NET Class System.Delegate. The second item is either the name of or the ⎕OR of an APL function which is to be invoked via a .NET method or property.

The result R is a ref to an instance of a .NET type specified by the first element of Y, which internally is associated with the function identified by the second element of Y.

Example

      ∇foo∇
     ∇ foo(ev arg)
[1]    ⍝ Callback for .NET method
     ∇
      ⎕USING←'System'
      del←2016⌶ EventHandler'foo'
      del
System.EventHandler

Then, when calling a .NET method that requires a Delegate of type System.Eventhandler, but whose signature is imprecise in this respect, the object del should be used instead.


Identify .NET Type

Identify .NET Type R←2017⌶Y

Windows only.

Returns the .NET Type of a named .NET class that is loaded in the current AppDomain. Note that System.Type.GetType requires the fully qualified name, i.e. prefixed by the assembly name, whereas (2017⌶) does not.

Y is a character string containing the name of a .NET object. Unless the fully qualified name is given, the namespaces in the current AppDomain are searched in the order they are specified by ⎕USING or :Using.

If the object is identified in the current AppDomain, the result R is its Type. If not, the function generates DOMAIN ERROR.

Example

      ⎕USING←'System'
      2017⌶'DateTime'
System.DateTime


Flush Session Caption

Flush Session Caption R←2022⌶Y

Windows only.

Under Windows, the Session Caption displays information such as the name of the current workspace. The contents of the Caption can be modified: see Window Captions in the Installation and Configuration Guide for more details.

However, the Caption is updated only at the six-space prompt; calling ⎕LOAD for example from within a function will not result in the Caption being updated at the end of the ⎕LOAD.

This I-Beam causes the Session Caption to be updated (flushed) when called. Note that this I-Beam does not alter the contents of the Caption.

Example

      2022⌶0


Close all Windows

Close All Windows R←2023⌶Y

Under Windows the option, Windows -> Close All Windows allows the user to close all open Editor and Tracer Windows, but does not reset the state indicator.

This I-beam mimics this behaviour, thus allowing the user to write code which can close all windows before attempting to save the workspace; with the exception of calling 0 ⎕SAVE it is not possible to save a workspace if any editor or tracer windows are open.

Under non-Windows operating systems this is the only mechanism for closing all such windows. This I-beam is effective in RIDE too.

Example

      2023⌶0


Set Dyalog Pixel Type

Set Dyalog Pixel Type R←2035⌶Y

Windows only.

Determines how Coord 'Pixel' is interpreted. This is determined initially by the value of the DYALOG_PIXEL_TYPE parameter and, when altered by this function, applies to all subsequent GUI operations.

Y is a character vector that is either 'ScaledPixel' or 'RealPixel'. Any other value will cause a DOMAIN ERROR.

The result R is the previous value.

Example

      2035⌶'ScaledPixel'
RealPixel
      2035⌶'RealPixel'
ScaledPixel

      2035⌶'realpixel'
DOMAIN ERROR
      2035⌶'realpixel'
     ∧


Override COM Default Value

Override COM Default Value R←{X}(2041⌶)Y

Windows only.

Certain COM objects, for example, VT_BLOBs, cannot be represented in APL or may be in error. By default Dyalog will generate a DOMAIN ERROR in these cases. For COM objects of type VT_EMPTY the interpreter by default returns ⎕NULL.

2041⌶ allows the APL programmer to specify what is returned by the interpreter in these cases.

Y may be 1 or 2.

If Y is 1, then X specifies the value that is returned instead of ⎕NULL when the COM object is of type VT_EMPTY.

If Y is 2, then X specifies the value that is returned when the COM object is in error, or is of a type that cannot be represented in APL.

In both cases, omitting X results in the default behaviour being restored.

R is the previous value specified; if there was no previous value then this function will perform its task but generate a VALUE ERROR.


Export To Memory

Export To Memory R←2100⌶Y

Windows only.

This function exports the current active workspace as an in-memory .NET Assembly.

Y may be any array and is ignored.

The result R is 1 if the operation succeeded or 0 if it failed.


Close .NET AppDomain

Close .NET AppDomain R←2101⌶Y

Windows only.

This function closes the current .NET AppDomain.

Y may be any array and is ignored.

The result R is 0 if the operation succeeded or a non-zero integer if it failed.

This I-Beam is very likely to be changed in future.


Set Workspace Save Options

Set Workspace Save Options R←2400⌶Y

This function sets a flag in the workspace that determines what happens when it is saved. The flag itself is part of the workspace and is saved with it.

If the flag is set, all Trace, Stop and Monitor settings will be cleared whenever the workspace is saved, whether by )SAVE, ⎕SAVE or by File/Save from the Session menubar.

Y must be 1 (set the flag) or 0 (clear the flag).

The result R is the previous value of the flag.

This function may be extended in the future and a left-argument may be added.

Example

      (2400⌶)1
0
      )SAVE
0 Trace bits cleared.
3 Stop bits cleared.
0 Monitor bits cleared.
temp saved Sat Apr 05 17:01:30 2014


Expose Root Properties, Events and Methods

Expose Root Properties R←2401⌶Y

This function is used to expose or hide Root Properties, Event and Methods.

If Y is 1, Root Properties, Events and Methods are exposed.

If Y is 0, no further Root Properties, Events or Methods are exposed; however any that have already been exposed will remain so.

This functionality is available in Windows versions by selecting or unselecting the Expose Root Properties MenuItem in the Options Menu in the Session. Note that deselecting this MenuItem only affects future references to Root Properties, Events or Methods.

This function is the only mechanism available under non-Windows versions of Dyalog APL; the state of this setting is saved in the workspace, and therefore cannot be controlled by an environment variable.

Example

      #.GetEnvironment'MAXWS'
VALUE ERROR
      #.GetEnvironment'MAXWS'
     ∧

      2401⌶1
0
      #.GetEnvironment'MAXWS'
64M

      2401⌶0
1
      #.GetEnvironment'MAXWS'
64M
      #.GetCommandLine
VALUE ERROR
      #.GetCommandLine
     ∧


Discard Thread on Exit

Discard Thread on Exit R←2501⌶Y

APL threads that Dyalog creates to serve incoming .NET requests are not terminated when their work is done. They persist so that if another call comes in on the same .NET thread the same APL thread can handle it. In effect the thread is parked until it is needed again. If the thread is not required, there is a small performance cost in maintaining it in this state.

(2501⌶0) must be called from WITHIN one of these threads and tells the interpreter NOT to park the thread on termination, but to discard the thread completely.


Discard Parked Threads

Discard Parked Threads R←2502⌶Y

APL threads that Dyalog creates to serve incoming .NET requests are not terminated when their work is done. They persist so that if another call comes in on the same .NET thread the same APL thread can handle it. In effect the thread is parked until it is needed again. If the thread is not required, there is a small performance cost in maintaining it in this state.

(2502⌶0) removes all parked threads from the workspace.


Mark Thread as Uninterruptible

Mark Thread as Uninterruptible R←2503⌶Y

This function marks the current thread (the thread in which it is called) as uninterruptible, and/or determines whether or not any child threads, subsequently created by the current thread, will be uninterruptible.

The right argument Y is an integer whose value is the sum of the following (bit-wise) values:

  • 1 : mark thread as uninterruptible
  • 2 : mark its children as uninterruptible

The result R is an integer value that indicates the previous state of the thread.

In many multi-threaded applications a large proportion of the threads are used for communication mechanisms (⎕DQ on TCPSockets, Conga, isolates); but most of the "real work" is done in thread zero.

It is undesirable that a weak interrupt interrupts a seemingly random thread. The mechanism to prevent a thread from being (weak) interrupted allows an application to be configured so that only specific threads would respond to a weak interrupt.


Use Separate Thread For .NET

Use Separate Thread For .NET R←2520⌶Y

This function determines the way that .NET calls are executed in APL thread 0.

The right argument Y is a Boolean value:

  • 1 : run .NET calls in a separate system thread
  • 0 : run .NET calls in the same system thread

The result R is a Boolean value which indicates the previous behaviour.

When an APL thread first makes a .NET call, it creates a unique system thread in which that and subsequent .NET calls are made. If a .NET call results in the creation of a message queue, that queue is associated with that same system thread. So each message queue is also unique. This strategy successfully maintains separation between multiple Windows message queues being executed in different APL threads.

By default, the base APL thread (thread 0) runs .NET code in the same system thread as itself. This is a different system thread to that used to run .NET code from other APL threads, so the separation between message queues associated with APL thread 0 and those associated with other APL threads is maintained. However, in certain circumstances, messages generated by .NET objects interfere with APL's internal message processing (and vice-versa), for example when handling exceptions.

For this reason, Dyalog recommends that APL code that creates instances of .NET objects that generate events (such as Windows Presentation Foundation objects) are run in a separate APL thread.

Where this is not possible, 2520⌶1 may be used to force Dyalog to use a unique system thread for .NET that is associated with APL thread 0. If so, it is recommended that 2520⌶1 is called at application start-up time.


Continue Autosave

Continue Autosave {R}←2704⌶Y

This function enables or disables the automatic saving of a CONTINUE workspace when Dyalog exits. By default this is disabled when Dyalog starts and must be explicitly enabled using this function.

Y is an integer defined as follows:

Value | Description
0 | Disable the automatic saving of a CONTINUE workspace.
1 | Enable the automatic saving of a CONTINUE workspace. This setting applies only to the current session or until disabled by 2704⌶0.

The shy result R is the previous value of this setting.

Circumstances when Dyalog automatically saves a CONTINUE workspace include:

  • a run-time violation. This is most frequently caused by an untrapped APL error which causes Dyalog to return to session-input mode (i.e. an application programming fault).
  • a hang-up signal.


Disable Component Checksum Validation

Disable Component Checksum Validation {R}←3002⌶Y

Checksums allow component files to be validated and repaired using ⎕FCHK.

From Version 13.1 onwards, components which contain checksums are also validated on every component read.

Although not recommended, applications which favour performance over security may disable checksum validation by ⎕FREAD using this function.

Y is an integer defined as follows:

Value | Description
0 | ⎕FREAD will not validate checksums.
1 | ⎕FREAD will validate checksums when they are present. This is the default.

The shy result R is the previous value of this setting.


Send Text to RIDE-embedded Browser

Send Text to RIDE-embedded Browser R←{X}(3500⌶)Y

Optionally, X is a simple character vector or scalar, the contents of which are used as the caption for the tab in the RIDE client that contains the embedded browser. If omitted, then the caption defaults to "3500⌶".

Y is a simple character vector the contents of which are displayed in the embedded browser tab.

To include SVG content, the HTML text in Y must include the following:

 <meta http-equiv="X-UA-Compatible" content="IE=9" >.

The result R identifies whether the write to the RIDE was successful. Possible values are:

  • 0 : the write to the RIDE client was successful
  • ¯1 : the write to the RIDE client was not successful


Connected to the RIDE

Connected to the RIDE R←(3501⌶)Y

Y can be any value and is ignored.

The result R identifies whether the Dyalog Session is running through the RIDE. Possible values are:

  • 0 : the Session is not running through the RIDE
  • 1 : the Session is running through the RIDE

This I-Beam may be extended in future.


Manage RIDE Connections

Manage RIDE Connections R←3502⌶Y

3502⌶ gives control over RIDE connections to the interpreter. More details about RIDE can be found in the RIDE User Guide.

Y may be either 0 or 1 or a simple character vector.

R has the value 0 if the call to 3502⌶ was successful; if unsuccessful the value may be either a positive or negative integer.

If Y is 0, then any active RIDE connections are disconnected, and no future connections may be made.

If Y is 1, then the interpreter attempts to enable RIDE, using the value of the initialisation string to determine the connection details. If the current initialisation string is ill-defined, R will be 64. If the Conga DLL/shared libraries are not available, R will be 32. In previous versions of Dyalog there were separate RIDE and Conga DLLs/shared libraries; these have been merged into one set in 16.0.

If Y is a character vector and RIDE is currently disabled, then the current initialisation string is unconditionally replaced by the contents of Y. If RIDE is currently enabled, the initialisation string is not replaced, and R will have the value ¯2.

The initialisation string has the same syntax as the value of the RIDE_INIT configuration parameter which is described in the RIDE User Guide

If RIDE is currently disabled, and 3502⌶0 is called or if RIDE is currently enabled and 3502⌶1 is called, no action is taken and R will have the value ¯1.

The configuration parameter RIDE_INIT can still be used to establish the initial value of the RIDE initialisation string.

The runtime interpreter has RIDE disabled by default, whether or not RIDE_INIT is set; the only method of enabling RIDE in a runtime interpreter is to call 3502⌶1.

If RIDE_INIT is set when a development interpreter is called, RIDE will be enabled provided that the RIDE DLL/shared library is available and the RIDE_INIT variable is properly formed. If the connection is of type SERVE the port must not be in use. If any of these conditions are not met, then the interpreter fails with a non-zero exit code. If RIDE_INIT is not set then the development interpreter will start, but with RIDE disabled. It is therefore possible to override the RIDE_INIT variable in the development interpreter with code similar to:

      r←3502⌶0             ⍝ Stop RIDE
      r←3502⌶'SERVE::4511' ⍝ Update init string
      r←3502⌶1             ⍝ Start RIDE

And similarly for altering the RIDE settings in an active APL session.

Notes:

In 14.1 and earlier 3502⌶⍬ was used to enable RIDE; this value is still valid, albeit deprecated: code should call 3502⌶1 instead.

Enabling the RIDE to access applications that use the run-time interpreter means that the APL code of those applications can be accessed. The I-beam mechanism described above means that the APL code itself must grant the right for a RIDE client to connect to the run‑time interpreter. Although Dyalog Ltd might change the details of this mechanism, the APL code will always need to grant connection rights. In particular, no mechanism that is only dependent on configuration parameters will be implemented.


Fork New Task

Fork New Task R←4000⌶Y

This applies to AIX only.

Y must be is a simple empty vector but is ignored.

This function forks the current APL task. This means that it initiates a new separate copy of the APL program, with exactly the same APL state indicator.

Following the execution of this function, there will be two identical APL processes running on the machine, each with the same state indicator and set of APL objects and values. However, none of the external interfaces and resources in the parent process will exist in the newly forked child process.

The function will return a result in both processes.

  • In the parent process, R is the process id of the child (forked) process.
  • In the child process, R is a scalar zero.

The following external interfaces and resources that may be present in the parent process are not replicated in the child process:

  • Component file ties
  • Native file ties
  • Mapped file associations
  • Auxiliary Processors
  • .NET objects
  • Edit windows
  • Clipboard entries
  • GUI objects (all children of '.')
  • I/O to the current terminal

Note that External Functions established using ⎕NA are replicated in the child process.

The function will fail with a DOMAIN ERROR if there is more than one APL thread running.

The function will fail with a FILE ERROR 11 Resource temporarily unavailable if an attempt is made to exceed the maximum number of processes allowed per user.


Change User

Change User R←4001⌶Y

UNIX, Linux and macOS only.

Y is a character vector that specifies a valid UNIX user name. The function changes the userid (uid) and groupid (gid) of the process to values that correspond to the specified user name.

Note that it is only possible to change the user name if the effective uid is 0 (that is, the process has root privileges).

If the operation is successful, R is the user name specified in Y. Note that the value of ⎕AN will not be affected, but the value of ⊃⎕AI will be.

If the operation fails, the function generates a FILE ERROR 1 Not Owner error.

If the argument to 4001⌶ is other than a non-empty simple character vector, the function generates a DOMAIN ERROR.

If the argument is not the name of a valid user the function generates a FILE ERROR 3 No such process.

If the argument is the same name as the current effective user, then the function returns that name, but has no effect.

If the argument is a valid name other than the name of the effective user id of the current process, and that effective user id is not root the function generates a FILE ERROR 1 Not owner.


Reap Forked Tasks

Reap Forked Tasks R←4002⌶Y

This applies to AIX only.

Under UNIX, when a child process terminates, it signals to its parent that it has terminated and waits for the parent to acknowledge that signal. 4002⌶ is the mechanism to allow the APL programmer to issue such acknowledgements.

Y must be a simple empty vector but is ignored.

The result R is a matrix containing the list of the newly-terminated processes which have been terminated as a result of receiving the acknowledgement, along with information about each of those processes as described below.

R[;1] is the process ID (PID) of the terminated child

R[;2] is ¯1 if the child process terminated normally, otherwise it is the signal number which caused the child process to terminate.

R[;3] is ¯1 if the child process terminated as the result of a signal, otherwise it is the exit code of the child process

The remaining 15 columns are the contents of the rusage structure returned by the underlying wait3() system call. Note that the two timevalstructs are each returned as a floating point number.

The current rusage structure contains:

struct rusage {
    struct timeval ru_utime; /* user time used */
    struct timeval ru_stime; /* system time used */
    long   ru_maxrss;        /* maximum resident set size */
    long   ru_ixrss;         /* integral shared memory size */
    long   ru_idrss;         /* integral unshared data size */
    long   ru_isrss;         /* integral unshared stack size */
    long   ru_minflt;        /* page reclaims */
    long   ru_majflt;        /* page faults */
    long   ru_nswap;         /* swaps */
    long   ru_inblock;       /* block input operations */
    long   ru_oublock;       /* block output operations */
    long   ru_msgsnd;        /* messages sent */
    long   ru_msgrcv;        /* messages received */
    long   ru_nsignals;      /* signals received */
    long   ru_nvcsw;         /* voluntary context switches */
    long   ru_nivcsw;        /* involuntary context switches */
};

4002⌶ may return the PID of an abnormally terminated Auxiliary Processor; APL code should check that the list of processes that have been reaped is a superset of the list of processes that have been started.

Example

     ∇ tryforks;pid;fpid;rpid
[1]    rpids←fpids←⍬
[2]    :For i :In ⍳5
[3]        fpid←4000⌶'' ⍝ fork() a process
[4]   ⍝ if the child, hang around for a while
[5]        :If fpid=0
[6]            ⎕DL 2×i
[7]            ⎕OFF
[8]        :Else
[9]   ⍝ if the parent, save child's pid
[10]           +fpids,←fpid
[11]       :EndIf
[12]   :EndFor
[13]
[14]   :For i :In ⍳20
[15]       ⎕DL 3
[16]  ⍝ get list of newly terminated child processes
[17]       rpid←4002⌶''
[18]  ⍝ and if not empty, make note of their pids
[19]       :If 0≠⊃⍴rpid
[20]           +rpids,←rpid[;1]
[21]       :EndIf
[22]  ⍝ if all fork()'d child processes accounted for
[23]       :If fpids≡fpids∩rpids
[24]           :Leave  ⍝ quit
[25]       :EndIf
[26]   :EndFor
     ∇


Signal Counts

Signal Counts R←4007⌶Y

UNIX, Linux and macOS only.

Y must be a simple empty vector but is ignored.

The result R is an integer vector of signal counts. The length of the vector is system dependent. On AIX 32-bit it is 63 on AIX 64-bit it is 256 but code should not rely on the length.

Each element is a count of the number of signals that have been generated since the last call to this function, or since the start of the process. R[1] is the number of occurrences of signal 1 (SIGHUP), R[2] the number of occurrences of signal 2, and so forth.

Each time the function is called it zeros the counts; it is therefore inadvisable to call it in more than one APL thread.

Currently, only SIGHUP, SIGINT, SIGQUIT, SIGTERM and SIGWINCH are counted and all other corresponding elements of R are 0.


List Loaded Files

List Loaded Files R←5176⌶Y

The editor may be used to edit Dyalog script files (.dyalog files) and general text files and to save the contents in the workspace. Additionally ⎕FIX can be used to fix scripts held in files. This I-Beam returns a list of all of the files which are associated with objects in the workspace, together with information about each file.

Y may be any value.

R is a vector of vectors, one element per associated file. Each element is a 5 element vector:

Element | Contains
1 | File name
2 | Encoding
3 | Checksum
4 | Newline
5 | Flags

Encoding, newline and flags are defined the same as for ⎕NGET. See File Encodings. Checksum is an 8-character hexadecimal value, see GetBuildID for more information.

Examples:

      )CLEAR
clear ws
      ('' '' (8⍴'0') ⍬ 0)≡⊃5176⌶''
1
      dyalog←2 ⎕NQ '.' 'GetEnvironment' 'DYALOG'
      aedit←'/SALT/spice/aedit.dyalog'
      ⎕FIX 'file:///',dyalog,aedit
#.arrayeditor

      1↓⊃5176⌶⍬      ⍝ Ignore filename
 UTF-8-BOM  18507aa6  13 10  0


List Loaded File Objects

List Loaded File Objects R←5177⌶Y

The editor may be used to edit Dyalog script files (.dyalog files) and general text files and to save the contents in the workspace. Additionally ⎕FIX can be used to fix scripts held in files. This I-Beam returns details about all of the objects in the workspace that are associated with such files.

Y must be an empty array.

R is a vector of 8-element vectors, one vector per object in the workspace that is associated with a file.

Element | Contains
1 | Object name or ref (refs are returned for all types of namespace)
2 | Parent namespace
3 | Name class (see ⎕NC)
4 | File name
5 | Start line (first line in file, 0 origin, of the object)
6 | Line count (number of lines in file occupied by the object)
7 | File Checksum
8 | File modification time (⎕TS format)

If an object occupies a file in its entirety, both Start line and Line count will be 0.

Examples:

      )CLEAR
clear ws
      ⊃5177 ⌶⍬
┌┬──────┬─┬┬─┬─┬────────┬────────────────┐
││[Null]│0││0│0│00000000│1970 1 1 0 0 0 0│
└┴──────┴─┴┴─┴─┴────────┴────────────────┘

      dyalog←2 ⎕NQ '.' 'GetEnvironment' 'DYALOG'
      aedit←'/SALT/spice/aedit.dyalog'
      ⊢⎕FIX 'file://',dyalog,aedit
#.arrayeditor

      1 1 1 0 1 1 1 1/↑5177⌶⍬ ⍝remove file names for brevity
┌─────────────┬─────────────┬─┬──┬──┬────────┬───────────────────┐
│Run          │#.arrayeditor│3│38│4 │008fe4ed│2018 5 11 8 56 10 0│
├─────────────┼─────────────┼─┼──┼──┼────────┼───────────────────┤
│Help         │#.arrayeditor│3│28│9 │008fe4ed│2018 5 11 8 56 10 0│
├─────────────┼─────────────┼─┼──┼──┼────────┼───────────────────┤
│List         │#.arrayeditor│3│22│5 │008fe4ed│2018 5 11 8 56 10 0│
├─────────────┼─────────────┼─┼──┼──┼────────┼───────────────────┤
│DESC         │#.arrayeditor│3│10│11│008fe4ed│2018 5 11 8 56 10 0│
├─────────────┼─────────────┼─┼──┼──┼────────┼───────────────────┤
│#.arrayeditor│#            │9│0 │0 │008fe4ed│2018 5 11 8 56 10 0│
└─────────────┴─────────────┴─┴──┴──┴────────┴───────────────────┘


JSON Translate Name

JSON Translate Name R←X(7162⌶)Y

Converts between JSON names and APL names.

When ⎕JSON imports an entity from JSON text whose name would be an invalid APL name, the function converts the invalid name into a valid APL name using a name mangling algorithm. When ⎕JSON exports an APL namespace as JSON text, the process is reversed.

This function performs the same name mangling allowing the programmer to identify JSON entities as APL names, and vice-versa.

Y is a character vector or scalar.

X is a scalar numeric value which must be 1 or 0.

When X is 0, R is the name in Y converted, if necessary, so that it is a valid APL name. It performs the same translation of JSON object names to APL names that is performed when importing JSON.

When X is 1, R is the name in Y which, if mangled, is converted back to the original form.. It performs the same translation of APL names to JSON object names that is performed when exporting JSON.

Examples:

      0(7162⌶)'2a'
⍙2a
      1(7162⌶)'⍙2a'
2a
      0(7162⌶)'foo'
foo
      1(7162⌶)'foo'
foo

Note that the algorithm can be applied, even when mangling is not required. So:

      1(7162⌶)'⍙97'
a

For further details, see JSON Name Mangling.


Singular Value Decomposition

Singular Value Decomposition R←(8415⌶)Y

Y is a simple numeric matrix.

The result R is a 4 element vector whose elements are as follows.

[1] | U | a unitary matrix
[2] | S | a diagonal matrix
[3] | V | a unitary matrix
[4] | f | a Boolean flag indicating whether the algorithm converged (1)or not (0)

This function computes a factorisation of the matrix Y such that:

      Y ≡ U +.× S +.× ⍉+V

This can be useful for analysing matrices for which ⌹ cannot compute an inverse, because they are singular or nearly singular.

For further information, see https://en.wikipedia.org/wiki/Singular_value_decomposition.


Line Count

Line Count R←50100⌶Y

This function is a compact version of the system function ⎕LC. If an expression requires only the most recent line(s) in the function calling stack, this is a more efficient alternative to using ⎕LC.

Y may be an integer specifying the depth of the function calling stack that is required in the result.

The result R is the same as ⎕LC, but truncated to the number of stack levels specified by Y.

Example

          ∇ Foo
[1]    :If 4=⍴⎕LC
[2]        50100⌶0
[3]        50100⌶1
[4]        50100⌶2
[5]        50100⌶3
[6]        50100⌶4
[7]        50100⌶5
[8]        →
[9]    :Else
[10]       Foo
[11]   :EndIf
     ∇
      Foo

3
4 10
5 10 10
6 10 10 10
7 10 10 10


Other I-Beams

Dyalog APL includes a number of I-Beams which exist in order to support experimental features or features which are documented elsewhere.

The following table lists those I-Beams, together with the document which contains a description of them:

Table 21: Experimental and other I-Beams

A | Purpose | Where documented
8659 | Shared Code Files. These are supported only in 64-bit Unicode interpreters, and were previously known as External Workspaces | Shared Code Files User Guide
8666
8667


System Functions and Variables

Dyalog includes a collection of built-in facilities which provide various services related to both the APL and the external environment. They have distinguished case-insensitive names beginning with the ⎕ symbol and are implicitly available in a clear workspace. Collectively, these facilities are referred to as System Functions but they are variously implemented as constants, variables, functions, operators, and in one case, as a namespace.

⍞ ⎕ | ⎕Á | ⎕A | ⎕AI | ⎕AN
⎕ARBIN | ⎕ARBOUT | ⎕AT | ⎕AV | ⎕AVU
⎕BASE | ⎕CLASS | ⎕CLEAR | ⎕CMD | ⎕CR
⎕CS | ⎕CSV | ⎕CT | ⎕CY | ⎕D
⎕DCT | ⎕DF | ⎕DIV | ⎕DL | ⎕DM
⎕DMX | ⎕DQ | ⎕DR | ⎕ED | ⎕EM
⎕EN | ⎕EX | ⎕EXCEPTION | ⎕EXPORT | ⎕FAPPEND
⎕FAVAIL | ⎕FCHK | ⎕FCOPY | ⎕FCREATE | ⎕FDROP
⎕FERASE | ⎕FHIST | ⎕FHOLD | ⎕FIX | ⎕FLIB
⎕FMT | ⎕FNAMES | ⎕FNUMS | ⎕FPROPS | ⎕FR
⎕FRDAC | ⎕FRDCI | ⎕FREAD | ⎕FRENAME | ⎕FREPLACE
⎕FRESIZE | ⎕FSIZE | ⎕FSTAC | ⎕FSTIE | ⎕FTIE
⎕FUNTIE | ⎕FX | ⎕INSTANCES | ⎕IO | ⎕JSON
⎕KL | ⎕LC | ⎕LOAD | ⎕LOCK | ⎕LX
⎕MAP | ⎕MKDIR | ⎕ML | ⎕MONITOR | ⎕NA
⎕NAPPEND | ⎕NC | ⎕NCOPY | ⎕NCREATE | ⎕NDELETE
⎕NERASE | ⎕NEW | ⎕NEXISTS | ⎕NGET | ⎕NINFO
⎕NL | ⎕NLOCK | ⎕NMOVE | ⎕NNAMES | ⎕NNUMS
⎕NPARTS | ⎕NPUT | ⎕NQ | ⎕NR | ⎕NREAD
⎕NRENAME | ⎕NREPLACE | ⎕NRESIZE | ⎕NS | ⎕NSI
⎕NSIZE | ⎕NTIE | ⎕NULL | ⎕NUNTIE | ⎕NXLATE
⎕OFF | ⎕OPT | ⎕OR | ⎕PATH | ⎕PFKEY
⎕PP | ⎕PROFILE | ⎕PW | ⎕R | ⎕REFS
⎕RL | ⎕RSI | ⎕RTL | ⎕S | ⎕SAVE
⎕SD | ⎕SE | ⎕SH | ⎕SHADOW | ⎕SI
⎕SIGNAL | ⎕SIZE | ⎕SM | ⎕SR | ⎕SRC
⎕STACK | ⎕STATE | ⎕STOP | ⎕SVC | ⎕SVO
⎕SVQ | ⎕SVR | ⎕SVS | ⎕TC | ⎕TCNUMS
⎕TGET | ⎕THIS | ⎕TID | ⎕TKILL | ⎕TNAME
⎕TNUMS | ⎕TPOOL | ⎕TPUT | ⎕TRACE | ⎕TRAP
⎕TREQ | ⎕TS | ⎕TSYNC | ⎕UCS | ⎕USING
⎕VFI | ⎕VR | ⎕WA | ⎕WC | ⎕WG
⎕WN | ⎕WS | ⎕WSID | ⎕WX | ⎕XML
⎕XSI | ⎕XT |  |  |


System Constants

System constants, which can be regarded as niladic system functions, return information from the system. They have distinguished names, beginning with the quad symbol, ⎕. A system constant may not be assigned a value. System constants may not be localised or erased. System constants are summarised in the following table:

Name | Description
⎕Á | Underscored Alphabetic upper case characters
⎕A | Alphabetic upper case characters
⎕AI | Account Information
⎕AN | Account Name
⎕AV | Atomic Vector
⎕D | Digits
⎕DM | Diagnostic Message
⎕DMX | Extended Diagnostic Message
⎕EN | Event Number
⎕EXCEPTION | Reports the most recent Microsoft .NET Exception
⎕LC | Line Count
⎕NULL | Null Item
⎕SD | Screen (or window) Dimensions
⎕TC | Terminal Control (backspace, linefeed, newline)
⎕TS | Time Stamp
⎕WA | Workspace Available


System Variables

System variables retain information used by the system in some way, usually as implicit arguments to functions.

The characteristics of an array assigned to a system variable must be appropriate; otherwise an error will be reported immediately.

Example

      ⎕IO←3
DOMAIN ERROR
      ⎕IO←3
      ^

System variables may be localised by inclusion in the header line of a defined function or in the argument list of the system function ⎕SHADOW. When a system variable is localised, it retains its previous value until it is assigned a new one. This feature is known as "pass-through localisation". The exception to this rule is ⎕TRAP.

A system variable can never be undefined. Default values are assigned to all system variables in a clear workspace.

Name | Description | Scope
⍞ | Character Input/Output | Session
⎕ | Evaluated Input/Output | Session
⎕AVU | Atomic Vector – Unicode | Namespace
⎕CT | Comparison Tolerance | Namespace
⎕DCT | Decimal Comp Tolerance | Namespace
⎕DIV | Division Method | Namespace
⎕FR | Floating-Point Representation | Namespace
⎕IO | Index Origin | Namespace
⎕LX | Latent Expression | Workspace
⎕ML | Migration Level | Namespace
⎕PATH | Search Path | Session
⎕PP | Print Precision | Namespace
⎕PW | Print Width | Session
⎕RL | Random Link | Namespace
⎕RTL | Response Time Limit | Namespace
⎕SM | Screen Map | Workspace
⎕TRAP | Event Trap | Workspace
⎕USING | Microsoft .NET Search Path | Namespace
⎕WSID | Workspace Identification | Workspace
⎕WX | Window Expose | Namespace

In other words, ⎕, ⍞, ⎕PATH and ⎕PW relate to the session. ⎕LX, ⎕SM, ⎕TRAP and ⎕WSID relate to the active workspace. All the other system variables relate to the current namespace.

Session | Workspace | Namespace
⍞ | ⎕LX | ⎕AVU
⎕ | ⎕SM | ⎕CT
⎕PATH | ⎕TRAP | ⎕DCT
⎕PW | ⎕WSID | ⎕DIV
 |  | ⎕FR
 |  | ⎕IO
 |  | ⎕ML
 |  | ⎕PP
 |  | ⎕RL
 |  | ⎕RTL
 |  | ⎕USING
 |  | ⎕WX


System Operators

The following system facilities are for convenience implemented as operators rather than as functions:

Name | Description
⎕R | Replace
⎕S | Search
⎕OPT | Variant (Classic Edition only)


System Namespaces

⎕SE is currently the only system namespace.


System Functions Categorised

Dyalog includes a collection of built-in facilities which provide various services related to both the APL and the external environment. They have distinguished case-insensitive names beginning with the ⎕ symbol and are implicitly available in a clear workspace. Collectively, these facilities are referred to as System Functions but they are variously implemented as constants, variables, functions, operators, and in one case, as a namespace.

The following tables list the system functions divided into appropriate categories. Each is then described in detail in alphabetical order.

Settings Affecting Behaviour of Primitive Functions

Name | Description
⎕CT | Comparison Tolerance
⎕DCT | Decimal Comp Tolerance
⎕DIV | Division Method
⎕FR | Floating-Point Representation
⎕IO | Index Origin
⎕ML | Migration Level
⎕PP | Print Precision
⎕RL | Random Link

The following table describes the dependencies that exist between functions, operators and system variables.

System Variable | Monadic Functions | Dyadic Functions | Operators
⎕CT, ⎕DCT | ⌈ ⌊ ∪ | ⍷ ≡ ≢ ∩ ∪ ~ ⍳ ∊ | < ≤ = ≥ > ≠ ∧ ∨ (non-Boolean) | ⍤
⎕DIV | ÷ | ÷ |
⎕IO | ⍒ ⍋ ⍳ ? | ? ⍋ ⍒ ⌷ ⍳ ⊃ ⍉ | ⌸ []
⎕ML | ∊ ↑ ↓ ≡ | ⊂[K] |
⎕PP | ⍕ |  |
⎕RL | ? | ? |

Session Information/Management

Name | Description
⎕AI | Account Information
⎕AN | Account Name
⎕CLEAR | Clear workspace (WS)
⎕CY | Copy objects into active WS
⎕DL | Delay execution
⎕LOAD | Load a saved WS
⎕OFF | End the session
⎕PATH | Search Path
⎕SAVE | Save the active WS
⎕TS | Time Stamp

Constants

Name | Description
⎕A | Alphabetic upper case characters
⎕D | Digits
⎕NULL | Null Item

Tools and Access to External Utilities

Name | Description
⎕CMD | Execute the Windows Command Processor or another program
⎕CMD | Start a Windows AP
⎕CSV | Comma Separated Values
⎕DR | Data Representation (Monadic)
⎕DR | Data Representation (Dyadic)
⎕FMT | Resolve display
⎕FMT | Format array
⎕JSON | JSON Convert
⎕MAP | Map a file
⎕NA | Declare a DLL function
⎕R | Replace
⎕S | Search
⎕SH | Execute a UNIX command or another program
⎕SH | Start a UNIX AP
⎕UCS | Unicode Convert
⎕USING | Microsoft .NET Search Path
⎕VFI | Verify and Fix numeric
⎕XML | XML Convert

Manipulating Functions and Operators

Name | Description
⎕AT | Object Attributes
⎕CR | Canonical Representation
⎕ED | Edit one or more objects
⎕EX | Expunge objects
⎕FX | Fix definition
⎕LOCK | Lock a function
⎕NR | Nested Representation
⎕PROFILE | Profile Application
⎕REFS | Local References
⎕STOP | Set Stop vector
⎕STOP | Query Stop vector
⎕TRACE | Set Trace vector
⎕TRACE | Query Trace vector
⎕VR | Vector Representation

Namespaces and Objects

Name | Description
⎕BASE | Base Class
⎕CLASS | Class
⎕CS | Change Space
⎕DF | Display Format
⎕FIX | Fix
⎕INSTANCES | Instances
⎕NEW | New Instance
⎕NS | Namespace
⎕SRC | Source
⎕THIS | This

Input/Output

Name | Description
⎕ | Evaluated Input/Output
⍞ | Character Input/Output

Built-in GUI and COM Support

Name | Description
⎕DQ | Await and process events
⎕EXPORT | Export objects
⎕NQ | Place an event on the Queue
⎕WC | Create GUI object
⎕WG | Get GUI object properties
⎕WN | Query GUI object Names
⎕WS | Set GUI object properties

Component Files

Name | Description
⎕FAPPEND | Append a component to File
⎕FAVAIL | File system Availability
⎕FCHK | File Check and Repair
⎕FCOPY | Copy a File
⎕FCREATE | Create a File
⎕FDROP | Drop a block of components
⎕FERASE | Erase a File
⎕FHIST | File History
⎕FHOLD | File Hold
⎕FLIB | List File Library
⎕FNAMES | Names of tied Files
⎕FNUMS | Tie Numbers of tied Files
⎕FPROPS | File Properties
⎕FRDAC | Read File Access matrix
⎕FRDCI | Read Component Information
⎕FREAD | Read a component from File
⎕FRENAME | Rename a File
⎕FREPLACE | Replace a component on File
⎕FRESIZE | File Resize
⎕FSIZE | File Size
⎕FSTAC | Set File Access matrix
⎕FSTIE | Share-Tie a File
⎕FTIE | Tie a File exclusively
⎕FUNTIE | Untie Files

Native Files

Name | Description
⎕MKDIR | Create a directory
⎕NAPPEND | Append to File
⎕NCOPY | Copy files and directories
⎕NCREATE | Create a File
⎕NDELETE | Delete a File or Directory
⎕NERASE | Erase a File
⎕NEXISTS | Discover whether or not a file or directory exists
⎕NGET | Read Text File
⎕NINFO | Obtain information about one or more files and/or directories
⎕NLOCK | Lock a region of a file
⎕NMOVE | Move files and directories
⎕NNAMES | Names of tied Files
⎕NNUMS | Tie Numbers of tied Files
⎕NPARTS | Split a file name into its constituent parts.
⎕NPUT | Write Text File
⎕NREAD | Read from File
⎕NRENAME | Rename a File
⎕NREPLACE | Replace data on File
⎕NRESIZE | File Resize
⎕NSIZE | File Size
⎕NTIE | Tie a File exclusively
⎕NUNTIE | Untie Files
⎕NXLATE | Specify Translation Table

Threads

Name | Description
⎕TCNUMS | Thread Child Numbers
⎕TID | Current Thread Identity
⎕TKILL | Kill Threads
⎕TNAME | Current Thread Name
⎕TNUMS | Thread Numbers
⎕TSYNC | Wait for Threads to Terminate

Synchronisation

Name | Description
⎕TGET | Get Tokens
⎕TKILL | Kill Threads
⎕TPOOL | Token Pool
⎕TPUT | Put Tokens
⎕TREQ | Token Requests

Error Handling

Name | Description
⎕DMX | Extended Diagnostic Message
⎕EM | Event Messages
⎕EXCEPTION | Reports the most recent Microsoft .NET Exception
⎕SIGNAL | Signal event
⎕TRAP | Event Trap

Stack and Workspace Information

Name | Description
⎕LC | Line Count
⎕LX | Latent Expression
⎕NC | Name Classification
⎕NL | Name List
⎕NSI | Namespace Indicator
⎕RSI | Space Indicator
⎕SI | State Indicator
⎕SHADOW | Shadow names
⎕SIZE | Size of objects
⎕STACK | Report Stack
⎕STATE | Return State of an object
⎕WA | Workspace Available
⎕WSID | Workspace Identification
⎕XSI | Extended State Indicator

Shared Variables

Name | Description
⎕SVC | Set access Control
⎕SVC | Query access Control
⎕SVO | Shared Variable Offer
⎕SVO | Query degree of coupling
⎕SVQ | Shared Variable Query
⎕SVR | Retract offer
⎕SVS | Query Shared Variable State

Various Other

Name | Description
⎕Á | Underscored Alphabetic Characters
⎕ARBIN | Arbitrary Input
⎕ARBOUT | Arbitrary Output
⎕AV | Atomic Vector
⎕AVU | Atomic Vector - Unicode
⎕DM | Diagnostic Message
⎕EN | Event Number
⎕KL | Key Labels
⎕PFKEY | Programmable Function Keys
⎕SD | Screen Dimensions
⎕SM | Screen Map
⎕SR | Screen Read
⎕MONITOR | Monitor set
⎕MONITOR | Monitor query
⎕NXLATE | Specify Translation Table
⎕OPT | Variant Operator
⎕OR | Object Representation
⎕RTL | Response Time Limit
⎕TC | Terminal Control
⎕XT | Associate External variable
⎕XT | Query External variable
⎕WX | Expose GUI property names


Comparison Tolerance

Comparison Tolerance ⎕CT

The value of ⎕CT determines the precision with which two numbers are judged to be equal. Two numbers, X and Y, are judged to be equal if (|X-Y)≤⎕CT×(|X)⌈|Ywhere ≤ is applied without tolerance.

Thus ⎕CT is not used as an absolute value in comparisons, but rather specifies a relative value that is dependent on the magnitude of the number with the greater magnitude. It then follows that ⎕CT has no effect when either of the numbers is zero.

⎕CT may be assigned any value in the range from 0 to 2*¯32 (about 2.3E¯10). A value of 0 ensures exact comparison. The value in a clear workspace is 1E¯14.

If ⎕FR is 1287, the system uses ⎕DCT. See Decimal Comparison Tolerance .

⎕CT and ⎕DCT are implicit arguments of the monadic primitive functions Ceiling (⌈), Floor (⌊) and Unique (∪), and of the dyadic functions Equal (=), Excluding (~), Find (⍷), Greater (>), Greater or Equal (≥), Greatest Common Divisor (∨), Index of (⍳), Intersection (∩), Less (<), Less or Equal (≤), Lowest Common Multiple (∧), Match (≡), Membership (∊), Not Match (≢), Not Equal (≠), Residue (|) and Union (∪), as well as ⎕FMT O-format.

Examples

      ⎕CT←1E¯10
      1.00000000001 1.0000001 = 1
1 0


Decimal Comparison Tolerance

Decimal Comparison Tolerance ⎕DCT

The value of ⎕DCT determines the precision with which two numbers are judged to be equal when the value of ⎕FR is 1287. If ⎕FR is 645, the system uses ⎕CT.

⎕DCT may be assigned any value in the range from 0 to 2*¯32 (about 2.3283064365386962890625E¯10). A value of 0 ensures exact comparison. The value in a clear workspace is 1E¯28.

⎕CT and ⎕DCT are implicit arguments of the monadic primitive functions Ceiling (⌈), Floor (⌊) and Unique (∪), and of the dyadic functions Equal (=), Excluding (~), Find (⍷), Greater (>), Greater or Equal (≥), Greatest Common Divisor (∨), Index of (⍳), Intersection (∩), Less (<), Less or Equal (≤), Lowest Common Multiple (∧), Match (≡), Membership (∊), Not Match (≢), Not Equal (≠), Residue (|) and Union (∪), as well as ⎕FMT O-format.

For further information, see Comparison Tolerance .

Examples

      ⎕DCT←1E¯10
      1.00000000001 1.0000001 = 1
1 0


Division Method

Division Method ⎕DIV

The value of ⎕DIV determines how division by zero is to be treated. If ⎕DIV=0, division by 0 produces a DOMAIN ERROR except that the special case of 0÷0 returns 1.

If ⎕DIV=1, division by 0 returns 0.

⎕DIV may be assigned the value 0 or 1. The value in a clear workspace is 0.

⎕DIV is an implicit argument of the monadic function Reciprocal (÷) and the dyadic function Divide (÷).

Examples

      ⎕DIV←0

      1 0 2 ÷ 2 0 1
0.5 1 2

      ÷0 1
DOMAIN ERROR
      ÷0 1
      ^

      ⎕DIV←1

      ÷0 2
0 0.5

      1 0 2 ÷ 0 0 4
0 0 0.5


Floating Point Representation

Floating-Point Representation ⎕FR

The value of ⎕FR determines the way that floating-point operations are performed.

If ⎕FR is 645, all floating-point calculations are performed using IEEE 754 64-bit floating-point operations and the results of these operations are represented internally using binary64http://en.wikipedia.org/wiki/Double_precision_floating-point_format 1 floating-point format.

If ⎕FR is 1287, all floating-point calculations are performed using IEEE 754-2008 128-bit decimal floating-point operations and the results of these operations are represented internally using decimal128http://en.wikipedia.org/wiki/Decimal128_floating-point_format 2 format.

Note that when you change ⎕FR, its new value only affects subsequent floating-point operations and results. Existing floating-point values stored in the workspace remain unchanged.

The default value of ⎕FR (its value in a clear ws) is configurable.

⎕FR may be localised. If so, like most other system variables, it inherits its initial value from the global environment.

However: Although ⎕FR can vary, the system is not designed to allow "seamless" modification during the running of an application and the dynamic alteration of is not recommended. Strange effects may occur. For example, the type of a constant contained in a line of code (in a function or class), will depend on the value of ⎕FR when the function is fixed.

Also note:

      ⎕FR←1287
      x←1÷3

      ⎕FR←645
      x=1÷3
1

The decimal number has 17 more 3's. Using the tolerance which applies to binary floats (type 645), the numbers are equal. However, the "reverse" experiment yields 0, as tolerance is much narrower in the decimal universe:

      ⎕FR←645
      x←1÷3
      ⎕FR←1287
      x=1÷3
0

Since ⎕FR can vary, it will be possible for a single workspace to contain floating-point values of both types (existing variables are not converted when ⎕FR is changed). For example, an array that has just been brought into the workspace from external storage may have a different type from ⎕FR in the current namespace. Conversion (if necessary) will only take place when a new floating-point array is generated as the result of "a calculation". The result of a computation returning a floating-point result will not depend on the type of the arrays involved in the expression: ⎕FR at the time when a computation is performed decides the result type, alone.

Structural functions generally do NOT change the type, for example:

      ⎕FR←1287
      x←1.1 2.2 3.3

      ⎕FR←645
      ⎕DR x
1287
      ⎕DR 2↑x
1287

128-bit decimal numbers not only have greater precision (roughly 34 decimal digits); they also have significantly larger range – from ¯1E6145 to 1E6145. Loss of precision is accepted on conversion from 645 to 1287, but the magnitude of a number may make the conversion impossible, in which case a DOMAIN ERROR is issued:

      ⎕FR←1287
      x←1E1000
      ⎕FR←645 ⋄ x+0
DOMAIN ERROR

When experimenting with ⎕FR it is important to note that numeric constants entered into the Session are evaluated (and assigned a data type) before the line is actually executed. This means that constants are evaluated according to the value of ⎕FR that pertained before the line was entered. For example:

      ⎕FR←645
      ⎕FR
645

      ⎕FR←1287 ⋄ ⎕DR 0.1
645
      ⎕DR 0.1
1287

WARNING: The use of COMPLEX numbers when ⎕FR is 1287 is not recommended, because:

any 128-bit decimal array into which a complex number is inserted or appended will be forced in its entirety into complex representation, potentially losing precision.

All comparisons are done using ⎕DCT when ⎕FR is 1287, and the default value of 1E¯28 is equivalent to 0 for complex numbers.


Index Origin

Index Origin ⎕IO

⎕IO determines the index of the first element of a non-empty vector.

⎕IO may be assigned the value 0 or 1. The value in a clear workspace is 1.

⎕IO is an implicit argument of any function derived from the Axis operator ([K]), of the monadic functions Fix (⎕FX), Grade Down (⍒), Grade Up (⍋), Index Generator (⍳), Roll (?), and of the dyadic functions Deal (?), Grade Down (⍒), Grade Up (⍋), Index (⌷), Index Of (⍳), Indexed Assignment, Indexing, Pick (⊃) and Transpose (⍉).

Examples

        ⎕IO←1
        ⍳5
1 2 3 4 5

        ⎕IO←0
        ⍳5
0 1 2 3 4

        +/[0]2 3⍴⍳6
3 5 7

        'ABC',[¯.5]'='
ABC
===


Migration Level

Migration Level ⎕ML

⎕ML determines the degree of migration of the Dyalog APL language towards IBM's APL2. Setting this variable to other than its default value of 1 changes the interpretation of certain symbols and language constructs.

⎕ML←0 |  | Original Native Dyalog
⎕ML←1 | Z←∊R | Monadic '∊' is interpreted as 'enlist' rather than 'type'.
⎕ML←2 | Z←↑R | Monadic '↑' is interpreted as 'first' rather than 'mix'.
 | Z←⊃R | Monadic '⊃' is interpreted as 'mix' rather than 'first'.
 | Z←≡R | Monadic '≡' returns a positive rather than a negative value, if its argument has non-uniform depth.
⎕ML←3 | R←X⊂[K]Y | Dyadic '⊂' follows the APL2 (rather than the original Dyalog APL) convention.
 | ⎕TC | The order of the elements of ⎕TC is the same as in APL2.

Subsequent versions of Dyalog APL may provide further migration levels.

Examples

      X←2(3 4)

      ⎕ML←0
      ∊X
0  0 0
      ↑X
2 0
3 4
      ⊃X
2
      ≡X
¯2

      ⎕ML←1
      ∊X
2 3 4
      ↑X
2 0
3 4
      ⊃X
2
      ≡X
¯2

      ⎕ML←2
      ∊X
2 3 4
      ↑X
2
      ⊃X
2 0
3 4
      ≡X
2


Print Precision

Print Precision ⎕PP

⎕PP is the number of significant digits in the display of numeric output. ⎕PP may be assigned any integer value in the range 1 to 34.

⎕PP is used to format numbers displayed directly. It is an implicit argument of monadic function Format (⍕), monadic ⎕FMT and for display of numbers via ⎕ and ⍞ output. ⎕PP is ignored for the display of integers.

Examples:

      ⎕PP←10

      ÷3 6
0.3333333333 0.1666666667

      ⎕PP←3

      ÷3 6
0.333 0.167

If ⎕PP is set to a value ≥17 (when ⎕FR is 645) or 34 (when ⎕FR is 1287), floating-point numbers may be converted between binary and character representation without loss of precision. Then, if ⎕CT is 0 (to ensure exact comparison), for any floating-point number N the expression N=⍎⍕N is true.


Random Link

Random Link ⎕RL

⎕RL is a 2-element vector. Its first element contains the base or random number seed and its second element is an integer that identifies the random number generator that is currently in use. Together these items define how the system generates random numbers using Roll and Deal.

In a clear ws ⎕RL is (⍬ 1).

Random Number Seed

The facility to set the seed to a specific value provides the means to generate a repeatable sequence of random numbers, such as might be required by certain types of simulation modelling. This capability is not provided by RNG2.

If the seed is set to 0, the seed is set randomly but may be retrieved and subsequently re-assigned to create a repeatable sequence.

If the seed is set to ⍬, Dyalog is able to take advantage of certain optimisations which deliver maximum performance. In this case, the actual seed in use is intentionally hidden and ⎕RL[1] always reports ⍬, regardless of the Random Number Generator in use.

Random Number Generators

The 3 random number generators are listed in the table below. The 4th column of the table contains the values of seeds that may be assigned to them.

Id | Name | Algorithm | Valid Seed Values
0 | RNG0 | Lehmer linear congruential generator. | 0, ⍬, or an integer in the range 1 to ¯2+2*31
1 | RNG1 | Mersenne Twister. | 0, ⍬, an integer in the range 1 to ¯2+2*31 or a 625-element integer vector
2 | RNG2 | Operating System random number generator. | ⍬

Note that assigning an invalid value to the seed will cause DOMAIN ERROR.

The default random number generator in a CLEAR WS is 1 (Mersenne Twister). This algorithm RNG1 produces 64-bit values with good distribution.

The Lehmer linear congruential generator RNG0 was the only random number generator provided in versions of Dyalog APL prior to Version 13.1. The implementation of this algorithm has several limitations including limited value range (2*31), short period and non-uniform distribution (some values may appear more frequently than others). It is retained for backwards compatibility.

Under Windows, the Operating System random number generator algorithm RNG2 uses the CryptGenRandom() function. Under UNIX/Linux it uses /dev/urandom.

Random Number Sequences

Random number sequences may be predictable or not and repeatable or not. A predictable and repeatable sequence is obtained by starting with the same specific value for the seed. A non-predictable sequence is obtained by starting with a seed which is itself chosen at random, but such a sequence is repeatable if the value of the seed (chosen at random) is visible. A non-predictable and non-repeatable sequence of random numbers is obtained where the initial seed is chosen completely at random and is unknown.

Using RNG0 or RNG1:

  • To obtain an entirely predictable random sequence, set the seed to a non-zero value
  • To obtain a non-predictable, but repeatable sequence, set the seed to 0
  • To obtain a non-predictable, non-repeatable series of random numbers, set the seed to ⍬

RNG2 does not support a user modifiable random number seed, so when using this scheme, it is not possible to obtain a repeatable random number series and the seed must always be ⍬.

Implementation Note:

⎕RL does not behave quite like a regular 2-element variable; it has its own rules relating to assignment and reference.

Reference

⎕RL returns a 2-element vector whose second element identifies the scheme in use (0, 1 or 2).

If ⎕RL[1] is set to ⍬, ⎕RL[1]always reports ⍬.

Otherwise if the seed ⎕RL[1] is set to a value other than ⍬:

  • using RNG0, ⎕RL[1] is an integer which represents the seed for the next random number in the sequence.
  • using RNG1, the system internally retains a block of 312 64-bit numbers which are used one by one to generate the results of roll and deal. When the first block of 312 have been used up, the system generates a second block. In this case, ⎕RL[1] is an integer vector of 32-bit numbers of length 625 (the first is an index into the block of 312) which represents the internal state of the random number generator. This means that, as with RNG0, you may save the value of ⎕RL in a variable and reassign it later.
  • Using RNG2, the seed is purely internal and ⎕RL[1] is always zilde.

Assignment

⎕RL may only be assigned in its entirety. Indexed and selective assignment may not be used to assign values to individual elements.

To preserve compatibility with Versions of Dyalog prior to Version 15.0 (in which ⎕RL specifies just the seed) if the value assigned to ⎕RL represents a valid seed for the random number generator in use, it is taken to be the new seed. Otherwise, the value assigned to ⎕RL must be a 2-element vector, whose first item is the seed and whose second item is 0, 1 or 2 and specifies the random number generator to be used subsequently.

Examples (specific seeds for repeatable sequences)

      )CLEAR
clear ws
      ⎕RL←16807
      10?10
4 1 6 5 2 9 7 10 3 8
      5↑⊃⎕RL
10 0 16807 1819658750 ¯355441828
      X←?1000⍴1000
      5↑⊃⎕RL
100 ¯465541037 ¯1790786136 ¯205462449 996695303
      ⎕RL←16807
      10?10
4 1 6 5 2 9 7 10 3 8
      Y←?1000⍴1000
      X≡Y
1
      5↑⊃⎕RL
100 ¯465541037 ¯1790786136 ¯205462449 996695303
      ⎕RL←16807 0 ⍝ Select RNG0
      ⎕RL
16807 0
      ?9 9 9
2 7 5
      ?9
7
      ⎕RL
984943658 0

      ⎕RL←16807
      ?9 9 9
2 7 5
      ?9
7
      ⎕RL
984943658 0
      ⎕RL←16807 1 ⍝ Select RNG1
      5↑⊃⎕RL
100 ¯465541037 ¯1790786136 ¯205462449 996695303

Examples (0 seed)

When you set the seed to 0, a random seed is created for you:

      ⎕RL←0 0
      ⎕RL
865618822 0
      ⎕RL←0
      ⎕RL
1100783275 0

Setting the seed to 0 gives you a new, unpredictable random sequence yet it is repeatable because you can retrieve (and subsequently re-use) the actual seed after you set it:

      ?10⍴100
14 22 18 30 42 22 71 32 32 12
      ⎕RL←1100783275
      ?10⍴100
14 22 18 30 42 22 71 32 32 12

Example (zilde)

When you set the seed to zilde, you get the same random initialisation as setting it to 0 but you can't retrieve the actual value of the seed. When it is set to ⍬ it is subsequently reported as ⍬ and the internal value of the seed is hidden.

      ⎕RL←⍬
      ⎕RL
┌┬─┐
││0│
└┴─┘


Account Information

Account Information R←⎕AI

This is a simple integer vector, whose four elements are:

⎕AI[1] | user identification.Under Windows, this is the aplnid (network ID from configuration dialog box). Under UNIX and Linux this is the effective UID of the account whereas ⎕AN returns the real name. 1
⎕AI[2] | compute time for the APL session in milliseconds.
⎕AI[3] | connect time for the APL session in milliseconds.
⎕AI[4] | keying time for the APL session in milliseconds.

Elements beyond 4 are not defined but reserved.

Example

     ⎕AI
52 7396 2924216 2814831


Account Name

Account Name R←⎕AN

This is a simple character vector containing the user (login) name. Under UNIX and Linux this is the real user name, whereas ⎕AI returns the effective user id.

Example

      ⎕AN
Pete

      ⍴⎕AN
4


Clear Workspace

Clear Workspace ⎕CLEAR

A clear workspace is activated, having the name CLEAR WS. The active workspace is lost. All system variables assume their default values. The maximum size of workspace is available.

The contents of the session namespace ⎕SE are not affected.

Example

      ⎕CLEAR
      ⎕WSID
CLEAR WS


Copy Workspace

Copy Workspace {R}←{X}⎕CY Y

Y must be a simple character scalar or vector identifying a saved workspace (or Session file). X is optional. If present, it must be a simple character scalar, vector or matrix or a vector of character vectors that specifies one or more APL names.

Each name in X is taken to be the name of an active object in the workspace identified by Y. If X is omitted, the names of all defined active objects in that workspace are implied (defined functions and operators, variables, labels and namespaces).

Each object named in X (or implied) is copied from the workspace identified by Y to become the active object referenced by that name in the active workspace if the object can be copied. A copied label is re-defined to be a variable of numeric type. If the name of the copied object has an active referent in the active workspace, the name is disassociated from its value and the copied object becomes the active referent to that name. In particular, a function in the state indicator which is disassociated may be executed whilst it remains in the state indicator, but it ceases to exist for other purposes, such as editing.

The shy result R is 0⍴⊂''.

You may copy an object from a namespace by specifying its full pathname. The object will be copied to the current namespace in the active workspace, losing its original parent and gaining a new one in the process. You may only copy a GUI object into a namespace that is a suitable parent for that object. For example, you could only copy a Group object from a saved workspace if the current namespace in the active workspace is itself a Form, SubForm or Group.

See Copy Workspace for further information and, in particular, the manner in which dependant and referenced objects are copied, and copying objects from Session (.dse) files.

A DOMAIN ERROR is reported in any of the following cases:

  • Y is ill-formed, or is not the name of a workspace with access authorised for the active user account.
  • Any name in X is ill-formed.
  • An object named in X does not exist as an active object in workspace named in Y.

An object being copied has the same name as an active label.

When copying data between Classic and Unicode Editions, ⎕CY will fail and a TRANSLATION ERROR will be reported if any object in workspace Y fails conversion between Unicode and ⎕AV indices, whether or not that object is specified by X. See Note for further details.

A WS FULL is reported if the active workspace becomes full during the copying process.

Example

      ⎕VR'FOO'
     ∇ R←FOO
[1]    R←10
     ∇
      'FOO' ⎕CY 'BACKUP'
      ⎕VR'FOO'
     ∇ R←FOO X
[1]    R←10×X
     ∇

System variables are copied if explicitly included in the left argument, but not if the left argument is omitted.

Example

      ⎕LX

      ('⎕LX' 'X')⎕CY'WS/CRASH'
      ⎕LX
→RESTART

A copied object may have the same name as an object being executed. If so, the name is disassociated from the existing object, but the existing object remains defined in the workspace until its execution is completed.

Example

      )SI
#.FOO[1]*

      ⎕VR'FOO'
     ∇ R←FOO
[1]    R←10
     ∇

      'FOO'⎕CY'WS/MYWORK'

      FOO
1 2 3
      )SI
#.FOO[1]*
      →⎕LC
10


Delay

Delay {R}←⎕DL Y

Y must be a simple non-negative single numeric value (of any rank). A pause of approximately Y seconds is caused.

The shy result R is a scalar numeric value indicating the length of the pause in seconds.

The pause may be interrupted by a strong interrupt.


Load Workspace

Load Workspace ⎕LOAD Y

Y must be a simple character scalar or vector containing the identification of a saved workspace.

If Y is ill-formed or does not identify a saved workspace or the user account does not have access permission to the workspace, a DOMAIN ERROR is reported.

Otherwise, the active workspace is replaced by the workspace identified in Y. The active workspace is lost. If the loaded workspace was saved by the )SAVE system command, the latent expression (⎕LX) is immediately executed, unless APL was invoked with the -x option. If the loaded workspace was saved by the ⎕SAVE system function, execution resumes from the point of exit from the ⎕SAVE function, with the result of the ⎕SAVE function being 0, running in the same namespace in which the ⎕SAVE was executed.

The workspace identification and time-stamp when saved is not displayed.

If the workspace contains any GUI objects whose Visible property is 1, these objects will be displayed. If the workspace contains a non-empty ⎕SM but does not contain an SM GUI object, the form defined by ⎕SM will be displayed in a window on the screen.

Under UNIX, the interpreter attempts to open the file whose name matches the contents of Y. Under Windows, unless Y contains at least one ".", the interpreter will append the file extension ".DWS" to the name.


Sign Off APL

Sign Off APL ⎕OFF

This niladic system function terminates the APL session, returning to the shell command level. The active workspace does not replace the last continuation workspace.

Although ⎕OFF is niladic, you may specify an optional integer I to the right of the system function which will be reported to the Operating System as the exit code. If I is an expression generating an integer, you should put the expression in parentheses. I must be in the range 0..255, but note that on UNIX processes use values greater than 127 to indicate the signal number which was used to terminate a process, and that currently APL itself generates values 0..8; this list may be extended in future. This list is documented in the Dyalog for Microsoft Windows Installation and Configuration Guide: APL Exit Codes.


Search Path

Search Path ⎕PATH

⎕PATH is a simple character vector representing a blank-separated list of namespaces. It is approximately analogous to the PATH variable in Windows or UNIX

The ⎕PATH variable can be used to identify a namespace in which commonly used utility functions reside. Functions or operators (NOT variables) which are copied into this namespace and exported (see Export Object) can then be used directly from anywhere in the workspace without giving their full path names.

Example

To make the DISPLAY function available directly from within any namespace.

      ⍝ Create and reference utility namespace.
      ⎕PATH←'⎕se.util'⎕ns''
      ⍝ Copy DISPLAY function from UTIL into it.
      'DISPLAY'⎕se.util.⎕cy'UTIL'
      ⍝ (Remember to save the session to file).

In detail, ⎕PATH works as follows:

When a reference to a name cannot be found in the current namespace, the system searches for it from left to right in the list of namespaces indicated by ⎕PATH. In each namespace, if the name references a defined function (or operator) and the export type of that function is non-zero (see ⎕EXPORT is used to set or query the export type of a defined function (or operator) referenced by the ⎕PATH mechanism. ), then it is used to satisfy the reference. If the search exhausts all the namespaces in ⎕PATH without finding a qualifying reference, the system issues a VALUE ERROR in the normal manner.

The special character ↑ stands for the list of namespace ancestors:

       ## ##.## ##.##.## ...

In other words, the search is conducted upwards through enclosing namespaces, emulating the static scope rule inherent in modern block-structured languages.

Note that the ⎕PATH mechanism is used ONLY if the function reference cannot be satisfied in the current namespace. This is analogous to the case when the Windows or UNIX PATH variable begins with a '.'.

Examples

   ⎕PATH               Search in ...

1. '⎕se.util'          Current space,   then
                       ⎕se.util,        then
                       VALUE ERROR

2. '↑'                 Current space
                       Parent space: ##
                       Parent's parent space:  ##.##
                       ...
                       Root: # (or ⎕se if current space
                                was inside ⎕se)
                       VALUE ERROR

3. 'util ↑ ⎕se.util'   Current space
                       util (relative to current space)
                       Parent space: ##
                       ...
                       Root: # or ⎕se
                       ⎕se.util
                       VALUE ERROR

Note that ⎕PATH is a session variable. This means that it is workspace-wide and survives )LOAD and )CLEAR. It can of course, be localised by a defined function or operator.


Save Workspace

Save Workspace {R}←{X}⎕SAVE Y

Y must be a simple character scalar or vector that identifies a full or relative path name to the file in which the workspace will be written.

Unless the path specified by Y is a full pathname, it is taken to be relative to the current working directory which may be obtained by the expression: ⊃1 ⎕NPARTS ''.

See Workspaces for the rules for specifying a workspace name.

The active workspace is saved with the file name specified by Y, whether or not a workspace file of that name already exists.

A DOMAIN ERROR is reported if the name in Y :

  • is not a valid workspace name
  • is not a valid file name
  • refers to an unauthorised directory
  • specifies an existing file that does not already contain a Dyalog workspace or session file

The shy result R is a simple Boolean scalar 1. However, when the workspace is subsequently loaded using ⎕LOAD and execution restarts, the result is 0, as described below.

The optional left argument X is either 0 or 1. If X is omitted or 1, the saved version of the workspace has execution suspended at the point of exit from the ⎕SAVE function. If the saved workspace is subsequently loaded by ⎕LOAD, execution is resumed, and the value 0 is returned if the result is used or assigned, or otherwise the result is suppressed. In this case, the latent expression value (⎕LX) is ignored.

If X is 0, the workspace is saved without any state indicator in effect. The effect is the same as if you first executed )RESET and then )SAVE. In this case, when the workspace is subsequently loaded, the value of the latent expression (⎕LX) is honoured if applicable.

As is the case for )SAVE (see Save Workspace ), monadic ⎕SAVE will fail and issue DOMAIN ERROR if any threads (other than the root thread 0) are running or if there are any Edit or Trace windows open. However, neither of these restrictions apply if the left argument X is 0.

Note that the values of all system variables (including ⎕SM) and all GUI objects are saved.

Example

      (⊃'SAVED' 'ACTIVE' [⎕IO+⎕SAVE'TEMP']),' WS'
ACTIVE WS
      ⎕LOAD 'TEMP'
SAVED WS

Additional operations may be performed before saving the workspace. For further information, see Set Workspace Save Options.


Time Stamp

Time Stamp R←⎕TS

This is a seven element vector which identifies the clock time set on the particular installation as follows:

⎕TS[1] | Year
⎕TS[2] | Month
⎕TS[3] | Day
⎕TS[4] | Hour
⎕TS[5] | Minute
⎕TS[6] | Second
⎕TS[7] | Millisecond

Example

      ⎕TS
1989 7 11 10 42 59 123

Note that on some systems, where time is maintained only to the nearest second, a zero is returned for the seventh (millisecond) field.


Alphabetic Characters

Alphabetic Characters R←⎕A

This is a simple character vector, composed of the letters of the alphabet.

Example

      ⎕A
ABCDEFGHIJKLMNOPQRSTUVWXYZ


Digits

Digits R←⎕D

This is a simple character vector of the digits from 0 to 9.

Example

      ⎕D
0123456789


Null Item

Null Item R←⎕NULL

This is a reference to a null item, such as may be returned across the COM interface to represent a null value. A null might be returned as the result of a .NET method or as the value of an empty cell in a spreadsheet

⎕NULL may be used in any context that accepts a namespace reference, in particular:

  • As the argument to a defined function
  • As an item of an array.
  • As the argument to those primitive functions that take character data arguments, for example: =, ≠, ≡, ≢, ,, ⍴, ⊃, ⊂

Example

      'EX'⎕WC'OLEClient' 'Excel.Application'
      WB←EX.Workbooks.Open 'simple.xls'

      (WB.Sheets.Item 1).UsedRange.Value2
 [Null]  [Null]  [Null]  [Null]  [Null]
 [Null]    Year  [Null]  [Null]  [Null]
 [Null]    1999    2000    2001    2002
 [Null]  [Null]  [Null]  [Null]  [Null]
 Sales      100      76     120     150
 [Null]  [Null]  [Null]  [Null]  [Null]
 Costs       80      60     100     110
 [Null]  [Null]  [Null]  [Null]  [Null]
 Margin      20      16      20      40

To determine which of the cells are filled, you can compare the array with ⎕NULL.

      ⎕NULL≢¨(WB.Sheets.Item 1).UsedRange.Value2
0 0 0 0 0
0 1 0 0 0
0 1 1 1 1
0 0 0 0 0
1 1 1 1 1
0 0 0 0 0
1 1 1 1 1
0 0 0 0 0
1 1 1 1 1


Execute Windows Command

Execute Windows Command {R}←⎕CMD Y

⎕CMD executes the Windows Command Processor or UNIX shell or starts another Windows application program. ⎕CMD is a synonym of ⎕SH. Either system function may be used in either environment (Windows or UNIX) with exactly the same effect. ⎕CMD is probably more natural for the Windows user. This section describes the behaviour of ⎕CMD and ⎕SH under Windows. See Execute (UNIX) Command for a discussion of the behaviour of these system functions under UNIX.

The system commands )SH and )CMD provide similar facilities.

Executing the Windows Command Processor

If Y is a simple character vector, ⎕CMD invokes the Windows Command Processor (normally cmd.exe) and passes the command specified by character vector Y to it for execution. The term command means here an instruction recognised by the Command Processor, or the pathname of a program (with optional parameters) to be executed by it. In either case, APL waits for the command to finish and then returns the result R, a vector of character vectors containing its result. Each element in R corresponds to a line of output produced by the command.

Example

      Z←⎕CMD'dir'
      ⍴Z
12
      ↑Z
 Volume in drive C is OS
 Volume Serial Number is B438-9B76

 Directory of C:\Users\Pete\Documents\Dyalog APL-64 17.0 Unicode Files

23/06/2018  15:59    <DIR>          .
23/06/2018  15:59    <DIR>          ..
23/06/2018  14:53           181,488 default.dlf
13/06/2018  20:13         1,262,296 def_uk.dse
14/06/2018  14:36           108,976 UserCommand20.cache
               3 File(s)      1,552,760 bytes
               2 Dir(s)  101,371,097,088 bytes free

If the command specified in Y already contains the redirection symbol (>) the capture of output through a pipe is avoided and the result R is empty. If the command specified by Y issues prompts and expects user input, it is ESSENTIAL to explicitly redirect input and output to the console.

If this is done, APL detects the presence of a ">" in the command line, runs the command processor in a visible window, and does not direct output to the pipe. If you fail to do this your system will appear to hang because there is no mechanism for you to receive or respond to the prompt.

Example

      ⎕CMD 'DATE <CON >CON'

(Command Prompt window appears)

Current date is Wed 19-07-1995

Enter new date (dd-mm-yy): 20-07-95

(COMMAND PROMPT window disappears)

Spaces in pathnames

If Y specifies a program (with or without parameters) and the pathname to the program contains spaces, you must enclose the string in double-quotes.

For example, to start a version of Excel to which the pathname is:

   C:\Program Files\Microsoft Office\OFFICE11\excel.exe

the argument to ⎕CMD should be:

⎕CMD '"c:\program files\microsoft office\office11\excel.exe"'

Double-Quote Restriction

The Windows Command Processor does not permit more than one set of double-quotes in a command string.

The following statements are all valid:

⎕CMD 'c:\windows\system32\notepad.exe c:\myfile.txt'
⎕CMD 'c:\windows\system32\notepad.exe "c:\myfile.txt"'
⎕CMD '"c:\windows\system32\notepad.exe" c:\myfile.txt'

Whereas the next statement, which contains two sets of double-quotes, will fail:

⎕CMD '"c:\windows\system32\notepad.exe" "c:\myfile.txt"'

Such a statement can however be executed using the second form of ⎕CMD(where the argument is a 2-element vector of character vectors) which does not use the Windows Command Processor and is not subject to this restriction. However, the call to ⎕CMD will return immediately, and no output from the command will be returned.

⎕CMD'"c:\windows\system32\notepad.exe" "c:\myfile.txt"' ''

Implementation Notes

The right argument of ⎕CMD is simply passed to the appropriate command processor for execution and its output is received using an unnamed pipe.

By default, ⎕CMD will execute the string ('cmd.exe /c',Y); where Y is the argument given to ⎕CMD. However, the implementation permits the use of alternative command processors as follows:

Before execution, the argument is prefixed and postfixed with strings defined by the APL parameters CMD_PREFIX and CMD_POSTFIX. The former specifies the name of your command processor and any parameters that it requires. The latter specifies a string which may be required. If CMD_PREFIX is not defined, it defaults to the name defined by the environment variable COMSPEC followed by "/c". If COMSPEC is not defined, it defaults to cmd.exe. If CMD_POSTFIX is not defined, it defaults to an empty vector.

⎕CMD treats certain characters as having special meaning as follows:

# | marks the start of a trailing comment,
; | divides the command into sub-commands,
> | if found within the last sub-command, causes ⎕CMD to use a visible window.

If you simply wish to open a Command Prompt window, you may execute the command as a Windows Program (see below). For example:

      ⎕CMD 'cmd.exe' ''

Starting a Windows Program

If Y is a 2-element vector of character vectors, ⎕CMD starts the executable program named by Y[1] with the initial window parameter specified by Y[2]. The shy result is an integer scalar containing the window handle allocated by the window manager. Note that in this case APL does not wait for the program specified by Y to finish, but returns immediately. The shy result R is the process identifier (PID).

Y[1] must specify the name or complete pathname of an executable program. If the name alone is specified, Windows will search the following directories:

  1. the current directory,
  2. the Windows directory,
  3. the Windows system directory,
  4. the directories specified by the PATH variable,
  5. the list of directories mapped in a network.

Note that Y[1] may contain the complete command line, including any suitable parameters for starting the program. If Windows fails to find the executable program, ⎕CMD will fail and report FILE ERROR 2.

Y[2] specifies the window parameter and may be one of the following. If not, a DOMAIN ERROR is reported.

'Normal' '' | Application is started in a normal window, which is given the input focus
'Unfocused' | Application is started in a normal window, which is NOT given the input focus
'Hidden' | Application is run in an invisible window
'Minimized' 'Minimised' | Application is started as an icon which is NOT given the input focus
'Maximized' 'Maximised' | Application is started maximized (full screen) and is given the input focus

An application started by ⎕CMD may ONLY be terminated by itself or by the user. There is no way to close it from APL. Furthermore, if the window parameter is HIDDEN, the user is unaware of the application (unless it makes itself visible) and has no means to close it.

Examples

      Path←'c:\Program Files\Microsoft Office\Office\'
      ⎕←⎕CMD (Path,'excel.exe') ''
33
      ⎕CMD (Path,'winword /mMyMacro') 'Minimized'

Executing Programs

Either form of ⎕CMD may be used to execute a program. The difference is that when the program is executed via the Command Processor, APL waits for it to complete and returns any result that the program would have displayed in the Command Window had it been executed from a Command Window. In the second case, APL starts the program (in parallel).

Note:

This function is disabled and instead generates a DOMAIN ERROR if the RIDE_SPAWNED parameter is non-zero. This is designed to prevent it being invoked from a RIDE session which does not support this type of user interface. For further details, see the RIDE User Guide.


Start Windows Auxiliary Processor

Start Windows Auxiliary Processor {R}←X ⎕CMD Y

Used dyadically, ⎕CMD starts an Auxiliary Processor. The effect, as far as the APL workspace is concerned, is identical under both Windows and UNIX, although the method of implementation differs. ⎕CMD is a synonym of ⎕SH. Either function may be used in either environment (Windows or UNIX) with exactly the same effect. ⎕CMD is probably more natural for the Windows user. This section describes the behaviour of ⎕CMD and ⎕SH under Windows. See Examples for a discussion of the behaviour of these system functions under UNIX.

X must be a simple character vector containing the name (or pathname) of a Dyalog APL Auxiliary Processor (AP). Although it is possible for users to create their own APs, Dyalog recommends that user write their own DLLs/shared libraries instead.

Y may be a simple character scalar or vector, or a vector of character vectors. Under Windows the contents of Y are ignored.

⎕CMD loads the Auxiliary Processor into memory. If no other APs are currently running, ⎕CMD also allocates an area of memory for communication between APL and its APs.

The shy result R is the process id of the Auxiliary Processor task.

The effect of starting an AP is that one or more external functions are defined in the workspace. These appear as locked functions and may be used in exactly the same way as regular defined functions.

When an external function is used in an expression, the argument(s) (if any) are passed to the AP for processing via the communications area described above. APL halts whilst the AP is processing, and waits for a result. Under Windows, unlike under UNIX, it is not possible for external functions to run in parallel with APL.


Data Representation Monadic

Data Representation (Monadic) R←⎕DR Y

Monadic ⎕DR returns the type of its argument Y. The result R is an integer scalar containing one of the following values. Note that the internal representation and data types for character data differ between the Unicode and Classic Editions.

Table 22: Unicode Edition

Value | Data Type
11 | 1 bit Boolean
80 | 8 bits character
83 | 8 bits signed integer
160 | 16 bits character
163 | 16 bits signed integer
320 | 32 bits character
323 | 32 bits signed integer
326 | Pointer (32-bit or 64-bit as appropriate)
645 | 64 bits Floating
1287 | 128 bits Decimal
1289 | 128 bits Complex

Table 23: Classic Edition

Value | Data Type
11 | 1 bit Boolean
82 | 8 bits character
83 | 8 bits signed integer
163 | 16 bits signed integer
323 | 32 bits signed integer
326 | Pointer (32-bit or 64-bit as appropriate)
645 | 64 bits Floating
1287 | 128 bits Decimal
1289 | 128 bits Complex


Data Representation Dyadic

Data Representation (Dyadic) R←X ⎕DR Y

Dyadic ⎕DR converts the data type of its argument Y according to the type specification X. See Data Representation (Monadic) for a list of data types but note that 1287 is not a permitted value in X.

Case 1:

X is a single integer value. The bits in the right argument are interpreted as elements of an array of type X. The shape of the resulting new array will typically be changed along the last axis. For example, a character array interpreted as Boolean will have 8 times as many elements along the last axis.

Case 2:

X is a 2-element integer value. Y is any array.

X[1] is either 0 or a data type. If X[1] is 0, Y is converted to data type X[2]. If X[1] is non-zero, the bits in Y are first interpreted as being of type X[1] before being converted to type X[2]. If Y is a scalar it is ravelled. Conversion of Y from one internal data type to another is performed so as to preserve its values without loss of precision.

The result R is a two element nested array comprised of:

  1. The converted elements or a fill element (0 or blank) where the conversion failed
  2. A Boolean array of the same shape indicating which elements were successfully converted.

Examples

      bits← 0 1 0 0 1 0 0 0 , 0 1 0 0 1 0 1 1
      80 ⎕DR bits
HK
      83 ⎕DR bits
72 75
      163 ⎕DR bits
19272

      0 645 ⎕DR 72 75
┌─────┬───┐
│72 75│1 1│
└─────┴───┘
      163 645 ⎕DR 72 75
┌─────┬─┐
│19272│1│
└─────┴─┘

Case 3: Classic Edition Only

X is a 3-element integer value and X[2 3] is 163 82. The bits in the right argument are interpreted as elements of an array of type X[1]. The system then converts them to the character representation of the corresponding 16 bit integers. This case is provided primarily for compatibility with APL*PLUS. For new applications, the use of the [conv] field with ⎕NAPPEND and ⎕NREPLACE is recommended.

Conversion to and from character (data type 82) uses the translate vector given by ⎕NXLATE 0. By default this is the mapping defined by the current output translate table (usually WIN.DOT).

Notes:

  • The internal representation of data may be modified during workspace compaction. For example, numeric arrays and (in the Unicode Edition) character arrays will, if possible, be squeezed to occupy the least possible amount of memory. However, the internal representation of the result R is guaranteed to remain unmodified until it is re-assigned (or partially re-assigned) with the result of any function.
  • The precise operation of dyadic ⎕DR depends upon the byte-ordering scheme of the computer system. The examples below assume a big-endian architecture.


Format Monadic

Format (Monadic) R←⎕FMT Y

Y may be any array. R is a simple character matrix which appears the same as the default display of Y. If Y contains control characters from ⎕TC, they will be resolved.

Examples

      A←⎕FMT '∩' ,⎕TC[1],'∘'

      ⍴A
1 1
      A
⍝

      A←⎕VR 'FOO'

      A
     ∇ R←FOO
[1]    R←10
     ∇

      ⍴A
31
      B←⎕FMT A

      B
     ∇ R←FOO
[1]    R←10
     ∇

      ⍴B
3 12


Format Dyadic

Format (Dyadic) R←X ⎕FMT Y

Y must be a simple array of rank not exceeding two, or a non-simple scalar or vector whose items are simple arrays of rank not exceeding two. The simple arrays in Y must be homogeneous, either character or numeric. All numeric values in Y must be simple; if Y contains any complex numbers, dyadic ⎕FMT will generate a DOMAIN ERROR. X must be a simple character vector. R is a simple character matrix.

X is a format specification that defines how columns of the simple arrays in Y are to appear. A simple scalar in Y is treated as a one-element matrix. A simple vector in Y is treated as a one-column matrix. Each column of the simple arrays in Y is formatted in left-to-right order according to the format specification in X taken in left-to-right order and used cyclically if necessary.

R has the same number of rows as the longest column (or implied column) in Y, and the number of columns is determined from the format specification.

The format specification consists of a series of control phrases, with adjacent phrases separated by a single comma, selected from the following:

rAw | Alphanumeric format
rEw.s | Scaled format
rqFw.d | Decimal format
rqG⍞pattern⍞ | Pattern
rqIw | Integer format
Tn | Absolute tabulation
Xn | Relative tabulation
⍞t⍞ | Text insertion

(Alternative surrounding pairs for Pattern or Text insertion are < >, ⊂ ⊃, ⎕ ⎕ or ¨ ¨.)

where:

r | is an optional repetition factor indicating that the format phrase is to be applied to r columns of Y
q | is an optional usage of qualifiers or affixtures from those described below.
w | is an integer value specifying the total field width per column of Y, including any affixtures.
s | is an integer value specifying the number of significant digits in Scaled format; s must be less than w-1
d | is an integer value specifying the number of places of decimal in Decimal format; d must be less than w.
n | is an integer value specifying a tab position relative to the notional left margin (for T-format) or relative to the last formatted position (for X-format) at which to begin the next format.
t | is any arbitrary text excluding the surrounding character pair. Double quotes imply a single quote in the result.
pattern | see following section G format

Qualifiers q are as follows:

B | leaves the field blank if the result would otherwise be zero.
C | inserts commas between triads of digits starting from the rightmost digit of the integer part of the result.
Km | scales numeric values by 1Em where m is an integer; negation may be indicated by ¯ or - preceding the number.
L | left justifies the result in the field width.
Ov⍞t⍞ | replaces specific numeric value v with the text t.
S⍞p⍞ | substitutes standard characters. p is a string of pairs of symbols enclosed between any of the Text Insertion delimiters. The first of each pair is the standard symbol and the second is the symbol to be substituted. Standard symbols are: * overflow fill character . decimal point , triad separator for C qualifier 0 fill character for Z qualifier _ loss of precision character
Z | fills unused leading positions in the result with zeros (and commas if C is also specified).
9 | digit selector

Affixtures are as follows:

M⍞t⍞ | prefixes negative results with the text t instead of the negative sign.
N⍞t⍞ | post-fixes negative results with the text t
P⍞t⍞ | prefixes positive or zero results with the text t.
Q⍞t⍞ | post-fixes positive or zero results with the text t.
R⍞t⍞ | presets the field with the text t which is repeated as necessary to fill the field. The text will be replaced in parts of the field filled by the result, including the effects of other qualifiers and affixtures except the B qualifier

The surrounding affixture delimiters may be replaced by the alternative pairs described for Text Insertion.

Examples

A vector is treated as a column:

      'I5' ⎕FMT 10 20 30
   10
   20
   30

The format specification is used cyclically to format the columns of the right argument:

      'I3,F5.2' ⎕FMT 2 4⍴⍳8
  1 2.00  3 4.00
  5 6.00  7 8.00

The columns of the separate arrays in the items of a non-simple right argument are formatted in order. Rows in a formatted column beyond the length of the column are left blank:

      '2I4,F7.1' ⎕FMT (⍳4)(2 2⍴ 0.1×⍳4)
   1   0    0.2
   1   0    0.4
   3
   4

Characters are right justified within the specified field width, unless the L qualifier is specified:

      'A2' ⎕FMT 1 6⍴'SPACED'
 S P A C E D

If the result is too wide to fit within the specified width, the field is filled with asterisks:

      'F5.2' ⎕FMT 0.1×5 1000 ¯100
  0.50
*****
*****

Relative tabulation (X-format) identifies the starting position for the next format phrase relative to the finishing position for the previous format, or the notional left margin if none. Negative values are permitted providing that the starting position is not brought back beyond the left margin. Blanks are inserted in the result, if necessary:

      'I2,X3,3A1' ⎕FMT (⍳3)(2 3⍴'TOPCAT')
 1   TOP
 2   CAT
 3

Absolute tabulation (T-format) specifies the starting position for the next format relative to the notional left margin. If position 0 is specified, the next format starts at the next free position as viewed so far. Blanks are inserted into the result as required. Over-written columns in the result contain the most recently formatted array columns taken in left-to-right order:

      X←'6I1,T5,A1,T1,3A1,T7,F5.1'

      X ⎕FMT (1 6⍴⍳6)('*')(1 3⍴'ABC')(22.2)
ABC4*6 22.2

If the number of specified significant digits exceeds the internal precision, low order digits are replaced by the symbol _:

      'F20.1' ⎕FMT 1E18÷3
3333333333333333__._

The Text Insertion format phrase inserts the given text repeatedly in all rows of the result:

      MEN←3 5⍴'FRED BILL JAMES'
      WOMEN←2 5⍴'MARY JUNE '

      '5A1,<|>' ⎕FMT MEN WOMEN
FRED |MARY |
BILL |JUNE |
JAMES|     |

The last example also illustrates that a Text Insertion phrase is used even though the data is exhausted. The following example illustrates effects of the various qualifiers:

      X←'F5.1,BF6.1,X1,ZF5.1,X1,LF5.1,K3CS<.,,.>F10.1'

      X ⎕FMT ⍉5 3⍴¯1.5 0 25
 ¯1.5  ¯1.5 ¯01.5 ¯1.5   ¯1.500,0
  0.0       000.0 0.0         0,0
 25.0  25.0 025.0 25.0   25.000,0

Affixtures allow text to be included within a field. The field width is not extended by the inclusion of affixtures. N and Q affixtures shift the result to the left by the number of characters in the text specification. Affixtures may be used to enclose negative results in parentheses in accordance with common accounting practice:

      'M<(>N<)>Q< >F9.2' ⎕FMT 150.3 ¯50.25 0 1114.9
  150.30
  (50.25)
    0.00
 1114.90

One or more format phrases may be surrounded by parentheses and preceded by an optional repetition factor. The format phrases within parentheses will be re-used the given number of times before the next format phrase is used. A Text Insertion phrase will not be re-used if the last data format phrase is preceded by a closing parenthesis:

      'I2,2(</>,ZI2)' ⎕FMT 1 3⍴⌽100|3↑⎕TS
20/07/89

G Format

Only the B, K, S and O qualifiers are valid with the G option

⍞pattern⍞ is an arbitrary string of characters, excluding the delimiter characters. Characters '9' and 'Z' (unless altered with the S qualifier) are special and are known as digit selectors.

The result of a G format will have length equal to the length of the pattern.

The data is rounded to the nearest integer (after possible scaling). Each digit of the rounded data replaces one digit selector in the result. If there are fewer data digits than digit selectors, the data digits are padded with leading zeros. If there are more data digits than digit selectors, the result will be filled with asterisks.

A '9' digit selector causes a data digit to be copied to the result.

A 'Z' digit selector causes a non-zero data digit to be copied to the result. A zero data digit is copied if and only if digits appear on each side of it. Otherwise a blank appears. Similarly text between digit selectors appears only if digits appear on each side of the text. Text appearing before the first digit selector or after the last will always appear in the result.

Examples

      'G⊂99/99/99⊃'⎕FMT 0 100 100 ⊥8 7 89
08/07/89

      'G⊂ZZ/ZZ/ZZ⊃'⎕FMT 80789 + 0 1
 8/07/89
 8/07/9

      'G⊂Andy ZZ Pauline ZZ⊃' ⎕FMT 2721.499 2699.5
Andy 27 Pauline 21
Andy 27

      ⍴⎕←'K2G⊂DM Z.ZZZ.ZZ9,99⊃' ⎕FMT 1234567.89 1234.56
DM 1.234.567,89
DM     1.234,56
2 15

An error will be reported if:

  • Numeric data is matched against an A control phrase.
  • Character data is matched against other than an A control phrase.
  • The format specification is ill-formed.
  • For an F control phrase, d>w-2
  • For an E control phrase, s>w-2

O Format Qualifier

The O format qualifier replaces a specific numeric value with a text string and may be used in conjunction with the E, F, I and G format phrases.

An O-qualifier consists of the letter "O" followed by the optional numeric value which is to be substituted (if omitted, the default is 0) and then the text string within pairs of symbols such as "<>". For example:

O - qualifier | Description
O<nil> | Replaces the value 0 with the text "nil"
O42<N/A> | Replaces the value 42 with the text "N/A"
O0.001<1/1000> | Replaces the value 0.001 with the text "1/1000"

The replacement text is inserted into the field in place of the numeric value. The text is normally right-aligned in the field, but will be left-aligned if the L qualifier is also specified.

It is permitted to specify more than one O-qualifier within a single phrase.

The O-qualifier is ⎕CT sensitive.

Examples

      'O<NIL>F7.2'⎕FMT 12.3 0 42.5
  12.30
    NIL
  42.50

      'O<NIL>LF7.2'⎕FMT 12.3 0 42.5
12.30
NIL
42.50

      'O<NIL>O42<N/A>I6'⎕FMT 12 0 42 13
    12
   NIL
   N/A
    13

      'O99<replace>F20.2'⎕fmt 99 100 101
             replace
              100.00
              101.00

⎕CT and ⎕DCT are implicit arguments of ⎕FMT with the O format qualifier.


JSON Convert

JSON Convert R←{X}⎕JSON Y

This function imports and exports data in JavaScript Object Notation (JSON) Data Interchange FormatIETF RFC 7159 - The JavaScript Object Notation (JSON) Data Interchange Format - is a widely supported, text based data interchange format for the portable representation of structured data; any application which conforms to the standard may exchange data with any other. 1.

If specified, X must be a numeric scalar with the value 0 (import JSON) or 1 (export JSON). If X is not specified and Y is a character array, X is assumed to be 0 (import); otherwise it is assumed to be 1 (export).

Other options for ⎕JSON are Format and Compact which are specified using the Variant operator ⍠. See Variant.The Principle Option is Format.

JSON Import (X is 0)

Y is a character vector or matrix in JSON format. There is an implied newline character between each row of a matrix.

The content of the result R depends upon the Format variant which may be 'D' (the default) or 'M'.

If Format is 'D' (which stands for "data") the JSON described by Y is converted to APL object(s) and R is an array or a namespace containing arrays and sub-namespaces.

  • JSON objects are created as APL namespaces.
  • JSON null is converted to the enclosed character vector ⊂'null'.
  • JSON true is converted to the enclosed character vector ⊂'true'
  • JSON false is converted to the enclosed character vector ⊂'false'.
  • If the JSON source contains object names which are not valid APL names they are converted to APL objects with mangled names. See JSON Name Mangling. 7162⌶ can be used to obtain the original name. See JSON Translate Name.

If Format is 'M' (which stands for "matrix") the result R is a matrix whose columns contain the following:

[;1] | depth
[;2] | name (for JSON object members)
[;3] | value
[;4] | JSON type (integer: see below)
  • The representation of null, true and false are the same as for Format 'D'.
  • Object names are reported as specified in the JSON text; they are not mangled as they are for Format 'D'.

JSON types are as follows:

Type | Description
1 | Object
2 | Array
3 | Numeric
4 | String
5 | Null
6 | Boolean (true / false)
7 | JavaScript Object (export only)

Table 24: JSON data types

Duplicate Names

The JSON standard says that members of a JSON object should have unique names and that different implementations behave differently when there are duplicates. Dyalog handles duplicate names as follows:

  • No error is generated
  • For Format 'D', the last member encountered is used and all previous members with the same name are discarded
  • For Format 'M' all duplicate members are recorded in the result matrix

Examples

      ⍴JSON
18 19
      JSON
{
  "a": {
    "b": [
      "string 1",
      "string 2"
    ],
    "c": true,
    "d": {
      "e": false,
      "f⍺": [
        "string 3",
        123,
        1000.2,
        null
      ]
    }
  }
}

Import as Data (Format 'D')

      j←⎕JSON JSON
      j
#.[JSON object]
      j.⎕NL 9
a
      j.a.⎕NL 2
b
c
      j.a.b
┌────────┬────────┐
│string 1│string 2│
└────────┴────────┘
      j.a.c
┌────┐
│true│
└────┘
      j.a.⎕NL 9
d
      j.a.d.⎕NL 2 ⍝ Note that f⍺ is an invalid APL name
e
⍙f⍙9082⍙
      j.a.d.e
┌─────┐
│false│
└─────┘
      j.a.d.⍙f⍙9082⍙
┌────────┬───┬──────┬──────┐
│string 3│123│1000.2│┌────┐│
│        │   │      ││null││
│        │   │      │└────┘│
└────────┴───┴──────┴──────┘

Import as Matrix (Format 'M')

      (⎕JSON⍠'M')JSON
┌─┬──┬────────┬─┐
│0│  │        │1│
├─┼──┼────────┼─┤
│1│a │        │1│
├─┼──┼────────┼─┤
│2│b │        │2│
├─┼──┼────────┼─┤
│3│  │string 1│4│
├─┼──┼────────┼─┤
│3│  │string 2│4│
├─┼──┼────────┼─┤
│2│c │┌────┐  │6│
│ │  ││true│  │ │
│ │  │└────┘  │ │
├─┼──┼────────┼─┤
│2│d │        │1│
├─┼──┼────────┼─┤
│3│e │┌─────┐ │6│
│ │  ││false│ │ │
│ │  │└─────┘ │ │
├─┼──┼────────┼─┤
│3│f⍺│        │2│
├─┼──┼────────┼─┤
│4│  │string 3│4│
├─┼──┼────────┼─┤
│4│  │123     │3│
├─┼──┼────────┼─┤
│4│  │1000.2  │3│
├─┼──┼────────┼─┤
│4│  │┌────┐  │5│
│ │  ││null│  │ │
│ │  │└────┘  │ │
└─┴──┴────────┴─┘

JSON Export (X is 1)

Y is the data to be exported as JSON and may be an array, a namespace or a matrix representation of JSON such as would have been produced by JSON Import with Format 'M'. Y is interpreted according to the Format variant which may be 'D'(the default) or 'M'.

⎕JSON will signal DOMAIN ERROR if Y is incompatible with the specified (or implied) value of Format.

If Format is M, the data values in Y[;3] must correspond precisely with the JSON types specified in Y[;4]as specified in the following table.

Y[;4] (Type) | Y[;3] (Value)
1 | Empty array
2 | Empty array
3 | Numeric scalar
4 | Character vector
5 | Null
6 | Enclosed character vector
7 | Enclose character vector

R is a character vector whose content depends upon the value of the Compact variant.

If Compact is 0, the JSON text is padded with spaces and new lines for readability.

If Compact is 1 (the default) the JSON text is compacted into its minimal form.

The name of any namespace member that begins with ⍙ and otherwise conforms to the conversion format used for JSON object names will be demangled.

Example

      j             ⍝ See above
#.[JSON object]
      ⍴JS←1 ⎕JSON j
94
      JS
{"a":{"b":["string 1","string 2"],"c":true,"d":{"e":false,"f⍺":["string 3",123,1000.2,null]}}}

      1(⎕JSON⍠'Compact' 0) j
{
  "a": {
    "b": [
      "string 1",
      "string 2"
    ],
    "c": true,
    "d": {
      "e": false,
      "f⍺": [
        "string 3",
        123,
        1000.2,
        null
      ]
    }
  }
}

If there are any mis-matches between the values in Y[;3] and the types in Y[;4], ⎕JSON will signal DOMAIN ERROR and report the first row where there is a mis-match (⎕IO sensitive) as illustrated in the following example.

Example

      M←(⎕JSON⍠'Format' 'M')'{"values": [ 75, 300 ]}'
      M
┌─┬──────┬───┬─┐
│0│      │   │1│
├─┼──────┼───┼─┤
│1│values│   │2│
├─┼──────┼───┼─┤
│2│      │75 │3│
├─┼──────┼───┼─┤
│2│      │300│3│
└─┴──────┴───┴─┘

      M[3;3]←⊂'75' ⍝ character not numeric

      M            ⍝ but looks the same as before
┌─┬──────┬───┬─┐
│0│      │   │1│
├─┼──────┼───┼─┤
│1│values│   │2│
├─┼──────┼───┼─┤
│2│      │75 │3│
├─┼──────┼───┼─┤
│2│      │300│3│
└─┴──────┴───┴─┘
      1 (⎕JSON⍠ 'Format' 'M')M
DOMAIN ERROR: Value does not match the specified type in row 3
      1(⎕JSON⍠'Format' 'M')M
     ∧

JavaScript Objects

The following example illustrates how JavaScript objects may be exported.

In the example, the object is a JavaScript function which is specified by the contents of an enclosed character vector. Note that in this case Dyalog performs no validation of the code itself.

Example

     'Slider' ⎕NS ''
      Slider.range←⊂'true'         ⍝ Note the ⊂
      Slider.min←0
      Slider.max←500
      Slider.values←75 300

      fn1←' function( event, ui ) {'
      fn2←'$( "#amount" ).val( "$" + ui.values[ 0 ] +'
      fn2,←' " - $" + ui.values[ 1 ] );}'

      Slider.slide←,/fn1 fn2 ⍝ Enclosed character vec
      ⍴JS←1 ⎕JSON Slider
159
      JS
{"max":500,"min":0,"range":true,"slide": function( event, ui ) {$( \"#amount\" ).val( \"$\" + ui.values[ 0 ] + \" - $\" + ui.values[ 1 ] );},"values":[75,300]}

Restrictions and Limitations

The JSON standard describes a limited set of data types and JSON does not provide a general APL import/export mechanism. In particular:

Not all APL arrays are representable in JSON.

For example, arrays with more than one dimension cannot be represented in JSON. Of course, this does mean that applications using JSON are unlikely to use such objects; you probably will need rearrange your data into the format that is expected by the receiving application. In the case of a 2-dimensional matrix, a split will give you a vector of tuples that a JSON application is likely to expect:

      ⎕JSON 3 4⍴⍳12
DOMAIN ERROR: Array unsupported by JSON
      ⎕JSON 3 4⍴⍳12
     ∧
      ⎕JSON ↓3 4⍴⍳12
[[1,2,3,4],[5,6,7,8],[9,10,11,12]]

Not all JSON types have exact APL equivalents

The JSON standard includes Boolean values true and false which are distinct from numeric values 1 and 0, and have no direct APL equivalent.

To represent JSON true and false types this implementation adopts the convention of using APL arrays ⊂'true' and ⊂'false' respectively. These arrays cannot otherwise be represented in JSON and allow true and false to be uniquely identified.

Not all names are valid APL names.

The names of JSON object members which would not be valid for APL are modified. See JSON Name Mangling.

JSON Name Mangling

When Dyalog converts from JSON to APL data, and a member of a JSON object has a name which is not a valid APL name, it is renamed.

Example:

In this example, the JSON describes an object containing two numeric items, one named a (which is a valid APL name) and the other named 2a (which is not):

{"a": 1, "2a": 2}

When this JSON is imported as an APL namespace using ⎕JSON, Dyalog converts the name 2a to a valid APL name. The name mangling algorithm creates a name beginning with ⍙.

      (⎕JSON'{"a": 1, "2a": 2}').⎕NL 2
a
⍙2a

When Dyalog exports JSON it performs the reverse name mangling, so:

      1 ⎕JSON ⎕JSON'{"a": 1, "2a": 2}'
{"a":1,"2a":2}

Should you need to create and decode these names directly,7162⌶ provides the same name mangling and un-mangling operations. See JSON Translate Name.

      0(7162⌶)'2a'
⍙2a
      1(7162⌶)'⍙2a'
2a


Map File

Map File R←{X}⎕MAP Y

⎕MAP function associates a mapped file with an APL array in the workspace.

Two types of mapped files are supported; APL and raw. An APL mapped file contains the binary representation of a Dyalog APL array, including its header. A file of this type must be created using the utility function ∆MPUT (supplied in the util workspace). When you map an APL file, the rank, shape and data type of the array is obtained from the information on the file.

A raw mapped file is an arbitrary collection of bytes. When you map a raw file, you must specify the characteristics of the APL array to be associated with this data. In particular, the data type and its shape.

The type of mapping is determined by the presence (raw) or absence (APL) of the left argument to ⎕MAP.

The right argument Y specifies the name of the file to be mapped and, optionally, the access type and a start byte in the file. Y may be a simple character vector, or a 2 or 3-element nested vector containing:

  1. file name (character scalar/vector)
  2. access code (character scalar/vector) : one of : 'R' or 'r' (read-only access), 'W' or 'w' (read-write access). If not specified, the file is mapped read-only.
  3. start byte offset (integer scalar/vector). This is only applicable for read-only access and is not supported for read-write access. It must be a multiple of the word size (4 on 32-bit systems, 8 on 64-bit systems). The default is 0.

If you map a file with read-only access you may modify the corresponding array in the workspace, however your changes are not written back to the file.

If X is specified, it defines the type and shape to be associated with raw data on file. X must be an integer scalar or vector. The first item of X specifies the data type and must be one of the following values:

Classic Edition | 11, 82, 83, 163, 323 or 645
Unicode Edition | 11, 80, 83, 160, 163, 320, 323 or 645

The values are more fully explained in Data Representation (Monadic).

Following items determine the shape of the mapped array. A value of ¯1 on any (but normally the first) axis in the shape is replaced by the system to mean: read as many complete records from the file as possible. Only one axis may be specified in this way. Note that if X is a singleton, the data on the file is mapped as a scalar and only the first value on the file is accessible.

If no left argument is given, file is assumed to contain a simple APL array, complete with header information (type, rank, shape, etc.). Such mapped files may only be updated by changing the associated array using indexed/pick assignment: var[a]←b, the new values must be of the same type as the originals.

Note that a raw mapped file may be updated only if its file offset is 0.

Examples

Map raw file as a read-only vector of doubles:

      vec←645 ¯1 ⎕MAP'c:\myfile'

Map raw file as a 20-column read-write matrix of 1-byte integers:

      mat←83 ¯1 20 ⎕MAP'c:\myfile' 'W'

Replace some items in mapped file:

      mat[2 3;4 5]←2 2⍴⍳4

Map bytes 100-160 in raw file as a 5×2 read-only matrix of doubles:

      dat←645 5 2 ⎕MAP'c:\myfile' 'R' 80

Put simple 4-byte integer array on disk ready for mapping:

      (⊃83 323 ⎕DR 2 3 4⍴⍳24)∆MPUT'c:\myvar'

Then, map a read-write variable:

      var←⎕MAP'c:\myvar' 'w'

Note that a mapped array need not be named. In the following example, a 'raw' file is mapped, summed and released, all in a single expression:

      +/163 ¯1 ⎕MAP'c:\shorts.dat'
42

If you fail to specify the shape of the data, the data on file will be mapped as a scalar and only the first value in the file will be accessible:

      83 ⎕MAP 'myfile'   ⍝ map FIRST BYTE of file.
¯86

Compatibility between Editions

In the Unicode Edition ⎕MAP will fail with a TRANSLATION ERROR (event number 92) if you attempt to map an APL file which contains character data type 82.

In order for the Unicode Edition to correctly interpret data in a raw file that was written using data type 82, the file may be mapped with data type 83 and the characters extracted by indexing into ⎕AVU.


Name Association

Name Association {R}←{X}⎕NA Y

⎕NA provides access from APL to compiled functions within a library. A library is implemented according to the Operating System as follows:

  • a Dynamic Link Library(DLL) under Windows
  • a Shared Library (.so or .dylib) under Linux or macOS
  • a static library (.a) under AIX

A DLL The term DLL is used herein as a generic name for one of these libraries. 1 is a collection of functions typically written in C (or C++) each of which may take arguments and return a result.

Instructional examples using ⎕NA can be found in the supplied workspace quadna.

The DLL may be part of the standard operating system software, a library purchased from a third party supplier, or one that you have written yourself.

The right argument Y is a character vector that identifies the name and syntax of the function to be associated. The left argument X is a character vector that contains the name to be associated with the external function. If the ⎕NA is successful, a function (name class 3) is established in the active workspace with name X. If X is omitted, the name of the external function itself is used for the association.

The shy result R is a character vector containing the name of the external function that was fixed.

For example, math.dll might be a library of mathematical functions containing a function divide. To associate the APL name div with this external function:

      'div' ⎕NA 'F8 math|divide I4 I4'

where F8 and I4, specify the types of the result and arguments expected by divide. The association has the effect of establishing a new function: div in the workspace, which when called, passes its arguments to divide and returns the result.

      )fns
div
      div 10 4
2.5

Type Declaration

In a compiled language such as C, the types of arguments and results of functions must be declared explicitly. Typically, these types will be published with the documentation that accompanies the DLL. For example, function divide might be declared:

double divide(int32_t, int32_t);

which means that it expects two long (4-byte) integer arguments and returns a double (8-byte) floating point result. Notice the correspondence between the C declaration and the right argument of ⎕NA:

C:             double    divide       (int32_t,  int32_t);
APL:'div' ⎕NA 'F8   math|divide        I4        I4 '

It is imperative that care be taken when coding type declarations. A DLL cannot check types of data passed from APL. A wrong type declaration will lead to erroneous results or may even cause the workspace to become corrupted and crash. During development, you may wish to prevent this happening. See: ErrorOnExternalException.

The full syntax for the right argument of ⎕NA is:

    [result] library|function [arg1] [arg2] ...

Note that functions associated with DLLs are never dyadic. All arguments are passed as items of a (possibly nested) vector on the right of the function.

Locating the DLL

The DLL may be specified using a full pathname, file extension, and function type.

Be aware

A 32-bit interpreter can only load 32-bit DLLs/shared libraries; a 64-bit interpreter can only load 64-bit DLLs/shared libraries.

If a DLL/shared library has a missing dependency, the error generated by the operating system, and therefore reported by Dyalog will suggest that the DLL/shared library that was explicitly called in the ⎕NA call is missing.

Pathname:

APL uses the LoadLibrary() system function under Windows or dlopen() under UNIX, Linux and macOS to load the DLL. If a full or relative pathname is omitted, these functions search a list of directories determined by the operating system. This list always includes the directory which contains the Dyalog program, and on all non-Windows platforms, $DYALOG/lib. For further details, see the operating system documentation about these functions.

Alternatively, a full or relative pathname may be supplied in the usual way:

      ⎕NA'... c:\mydir\mydll|foo ...'

Errors:

If the specified DLL (or a dependent DLL) fails to load it will generate:

FILE ERROR 2 No such file or directory

It is frequently the case that this error is a result of a missing dependency; operating systems do not return error codes which allow the interpreter to generate a more specific error.

If the DLL loads successfully, but the specified library function is not accessible, it will generate:

VALUE ERROR

File Extension:

Under Windows, if the file extension is omitted, .dll is assumed. Note that some DLLs are in fact .exe files, and in this case the extension must be specified explicitly:

      ⎕NA'... mydll.exe|foo ...'

Name Mangling

C++ and some other languages will by default mangle (or decorate) function names which are exported from a DLL file. The given external function name must exactly match the exported name, either by matching the name mangling or by ensuring the names exported from the library are not mangled.

Call by Ordinal Number

Under Windows, a DLL may associate an ordinal number with any of its functions. This number may then be used to call the function as an alternative to calling it by name. Using ⎕NA to call by ordinal number uses the same syntax but with the function name replaced with its ordinal number. For example:

      ⎕NA'... mydll|57 ...'

libc.a on Non-Windows Platforms

On non-Windows platforms many of the most useful system library functions appear in libc.a. The quadna workspace includes the function NonWindows.Setup which has code which will locate libc.a on each platform.

Multi-Threading

Appending the '&' character to the function name causes the external function to be run in its own system thread. For example:

      ⎕NA'... mydll|foo& ...'

This means that other APL threads can run concurrently with the one that is calling the ⎕NA function.

Data Type Coding Scheme

The type coding scheme introduced above is of the form:

[direction] [special] type [width] [array][[count]]

The options are summarised in the following table and their functions detailed below.

Description | Symbol | Meaning
Direction | < | Pointer to array input to DLL function.
 | > | Pointer to array output from DLL function
 | = | Pointer to input/output array.
Special | 0 | Null-terminated string.
 | # | Byte-counted string
Type | I | int
 | U | unsigned int
 | C | char
 | T | charClassic Edition: - translated to/from ANSI 2
 | F | float
 | D | decimal
 | J | complex
 | P | uintptr-t equivalent to U4 on 32-bit versions and U8 on 64-bit versions 3
 | A | APL array
 | Z | APL array with header (as passed to a TCP/IP socket)
Width | 1 | 1-byte
 | 2 | 2-byte
 | 4 | 4-byte
 | 8 | 8-byte
 | 16 | 16-byte (128-bit)
Array | [n] | Array of length n elements
 | [] | Array, length determined at call-time
Structure | {...} | Structure.
Count | [int] | Rather than explicitly declaring multiple adjacent occurrences of the same the count option may be used

In the Classic Edition, C specifies untranslated character, whereas T specifies that the character data will be translated to/from ⎕AV.

In the Unicode Edition, C and T are identical (no translation of character data is performed) except that for C the default width is 1 and for T the default width is "wide" (2 bytes under Windows, 4 bytes under UNIX, Linux or macOS).

The use of T with default width is recommended to ensure portability between Editions.

Direction

C functions accept data arguments either by value or by address. This distinction is indicated by the presence of a '*' or '[]' in the argument declaration:

int  num1;       // value of num1 passed.
int *num2;       // Address of num2 passed.
int num3[];      // Address of num3 passed.

An argument (or result) of an external function of type pointer, must be matched in the ⎕NA call by a declaration starting with one of the characters: <, >, or =.

In C, when an address is passed, the corresponding value can be used as either an input or an output variable. An output variable means that the C function overwrites values at the supplied address. Because APL is a call-by-value language, and doesn't have pointer types, we accommodate this mechanism by distinguishing output variables, and having them returned explicitly as part of the result of the call.

This means that where the C function indicates a pointer type, we must code this as starting with one of the characters: <, > or =.

< | indicates that the address of the argument will be used by C as an input variable and values at the address will not be over-written.
> | indicates that C will use the address as an output variable. In this case, APL must allocate an output array over which C can write values. After the call, this array will be included in the nested result of the call to the external function.
= | indicates that C will use the address for both input and output. In this case, APL duplicates the argument array into an output buffer whose address is passed to the external function. As in the case of an output only array, the newly modified copy will be included in the nested result of the call to the external function.

Examples

<I2 | Pointer to 2-byte integer - input to external function
>C | Pointer to character output from external function.
=T | Pointer to character input to and output from function.
=A | Pointer to APL array modified by function.

Special

In C it is common to represent character strings as null-terminated or byte counted arrays. These special data types are indicated by inserting the symbol 0 (null-terminated) or # (byte counted) between the direction indicator (<, >, =) and the type (T or C) specification. For example, a pointer to a null-terminated input character string is coded as <0T[], and an output one coded as >0T[].

Note that while appending the array specifier '[]' is formally correct, because the presence of the special qualifier (0 or #) implies an array, the '[]' may be omitted: <0T, >0T, =#C, etc.

Note also that the 0 and # specifiers may be used with data of all types (excluding A and Z) and widths. For example, in the Classic Edition, <0U2 may be useful for dealing with Unicode.

Type

The data type of the argument may be one of the following characters and may be specified in lower or upper case:

Code | Type | Description
I | Integer | The value is interpreted as a 2s complement signed integer
U | Unsigned integer | The value is interpreted as an unsigned integer
C | Character | The value is interpreted as a character. In the Unicode Edition, the value maps directly onto a Unicode code point. In the Classic Edition, the value is interpreted as an index into ⎕AV. This means that ⎕AV positions map onto corresponding ANSI positions. For example, with ⎕IO=0: ⎕AV[35] = 's', maps to ANSI[35] = '
T | Translated character | The value is interpreted as a character. In the Unicode Edition, the value maps directly onto a Unicode code point. In the Classic Edition, the value is translated using standard Dyalog ⎕AV to ANSI translation. This means that ⎕AV characters map onto corresponding ANSI characters. For example, with ⎕IO=0: ⎕AV[35] = 's' maps to ANSI[115] = 's'
UTF | Unicode encoded | >0UTF8[] will translate to a UTF-8 encoded string <0UTF16[] will translate from a UTF-16LE encoded string
F | Float | The value is interpreted as an IEEE 754-2008 binary64 floating point number
D | Decimal | The value is interpreted as an IEEE 754-2008 decimal128 floating point number (DPD format on AIX, BID format on other platforms)
J | Complex |
P | uintptr-t | This is equivalent to U4 on 32-bit versions and U8 on 64-bit versions
∇ | Function pointer | This allows the passing of an APL function for the function to call
A | APL array | This is the same format as is used to transmit APL arrays to an Auxiliary Processor (AP)
Z | APL array with header | This is the same format as is used to transmit APL arrays over TCP/IP Sockets

Width

The type specifier may be followed by the width of the value in bytes. For example:

I4 | 4-byte signed integer.
U2 | 2-byte unsigned integer.
F8 | 8-byte floating point number.
F4 | 4-byte floating point number.
D16 | 16-byte decimal floating-point number
Type | Possible values for Width | Default value for Width
I | 1, 2, 4, 8 | 4
U | 1, 2, 4, 8 | 4
C | 1,2,4 | 1
T | 1,2,4 | wide character(see below)
UTF | 8,16 | none
F | 4, 8 | 8
D | 16 | 16
J | 16 | 16
P | Not applicable |
∇ | Not applicable |
A | Not applicable |
Z | Not applicable |

In the Unicode Edition, the default width is the width of a wide character according to the convention of the host operating system. This translates to T2 under Windows and T4 under UNIX, Linux or macOS.

Note that 32-bit versions can support 64-bit integer arguments, but not 64-bit integer results.

Examples

I2 | 16-bit integer
<I4 | Pointer to input 4-byte integer
U | Default width unsigned integer
=F4 | Pointer to input/output 4-byte floating point number.

Arrays

Arrays are specified by following the basic data type with [n] or [], where n indicates the number of elements in the array. In the C declaration, the number of elements in an array may be specified explicitly at compile time, or determined dynamically at runtime. In the latter case, the size of the array is often passed along with the array, in a separate argument. In this case, n, the number of elements is omitted from the specification. Note that C deals only in scalars and rank 1 (vector) arrays.

int vec[10];               // explicit vector length.
unsigned size, list[];     // undetermined length.

could be coded as:

I[10] | vector of 10 ints.
U U[] | unsigned integer followed by an array of unsigned integers.

Confusion sometimes arises over a difference in the declaration syntax between C and ⎕NA. In C, an argument declaration may be given to receive a pointer to either a single scalar item, or to the first element of an array. This is because in C, the address of an array is deemed to be the address of its first element.

   void foo (char *string);
   char ch = 'a', ptr = "abc";
   foo(&ch);// call with address of scalar.
   foo(ptr);// call with address of array.

However, from APL's point of view, these two cases are distinct and if the function is to be called with the address of (pointer to) a scalar, it must be declared: '<T'. Otherwise, to be called with the address of an array, it must be declared: '<T[]'. Note that it is perfectly acceptable in such circumstances to define more than one name association to the same DLL function specifying different argument types:

      'FooScalar'⎕NA'mydll|foo <T'   ⋄ FooScalar'a'
      'FooVector'⎕NA'mydll|foo <T[]' ⋄ FooVector'abc'

Structures

Arbitrary data structures, which are akin to nested arrays, are specified using the symbols {}. For example, the code {F8 I2} indicates a structure comprised of an 8-byte float followed by a 2-byte int. Furthermore, the code <{F8 I2}[3] means an input pointer to an array of 3 such structures.

For example, this structure might be defined in C thus:

typedef struct
{
    double  f;
    short   i;
} mystruct;

A function defined to receive a count followed by an input pointer to an array of such structures:

void foo(unsigned count, mystruct *str);

An appropriate ⎕NA declaration would be:

      ⎕NA'mydll.foo U <{F8 I2}[]'

A call on the function with two arguments - a count followed by a vector of structures:

      foo 4,⊂(1.4 3)(5.9 1)(6.5 2)(0 0)

Notice that for the above call, APL converts the two Boolean (0 0) elements to an 8-byte float and a 2-byte int, respectively.

Note that if the C compiler would add extra space for alignment within a structure the ⎕NA syntax will need to code that explicitly. For example:

typedef struct
{
    short i;
    /* most C compilers would add 6 bytes of alignment here */
    double d;
} mystruct;

An appropriate ⎕NA declaration would be:

      ⎕NA'mydll.foo U <{I2  {I1[6]} F8}[]'

A call on the function with two arguments - a count followed by a vector of structures:

      pad←⊂6⍴0
      foo 4,⊂(3 pad 1.4)(1 pad 5.9 )(2 pad 6.5 )(0 pad 0)

A library designer tries to avoid defining structures that induce padding.

Count

If a definition includes multiple adjacent occurrences of the same item, the count syntax may be used rather than explicitly repeating the same definition.

For example:

>I8[3] rather than >I8 >I8 >I8

{I8 U8 I8 P}[2] rather than {I8 U8 I8 P} {I8 U8 I8 P}

Specifying Pointers Explicitly

⎕NA syntax enables APL to pass arguments to DLL functions by value or address as appropriate. For example if a function requires an integer followed by a pointer to an integer:

void fun(int valu, int *addr);

You might declare and call it:

      ⎕NA'mydll|fun I <I' ⋄ fun 42 42

The interpreter passes the value of the first argument and the address of the second one.

Two common cases occur where it is necessary to pass a pointer explicitly. The first is if the DLL function requires a null pointer, and the second is where you want to pass on a pointer which itself is a result from a DLL function.

In both cases, the pointer argument should be coded as P. This causes APL to pass the pointer unchanged, by value, to the DLL function.

In the previous example, to pass a null pointer, (or one returned from another DLL function), you must code a separate ⎕NA definition.

      'fun_null'⎕NA'mydll|fun I P' ⋄ fun_null 42 0

Now APL passes the value of the second argument (in this case 0 - the null pointer), rather than its address.

Note that by using P, which is 4-byte for 32-bit processes and 8-byte for 64-bit processes, you will ensure that the code will run unchanged under both 32-bit and 64-bit versions of Dyalog APL.

Using a Function

A DLL function may or may not return a result, and may take zero or more arguments. This syntax is reflected in the coding of the right argument of ⎕NA. However, notice that the corresponding associated APL function is a result-returning niladic (if it takes no arguments) or monadic function. It cannot be dyadic and it must always return a vector result - a null one if there is no output from the DLL function. See Result Vector section below. Examples of the various combinations are:

DLL function Non-result-returning:

⎕NA    'mydll|fn1'          ⍝ Niladic
⎕NA    'mydll|fn2 <0T'      ⍝ Monadic - 1-element arg
⎕NA    'mydll|fn3 =0T <0T'  ⍝ Monadic - 2-element arg

DLL function Result-returning:

⎕NA 'I4 mydll|fn4'          ⍝ Niladic
⎕NA 'I4 mydll|fn5 F8'       ⍝ Monadic - 1-element arg
⎕NA 'I4 mydll|fn6 >I4[] <0T'⍝ Monadic - 2-element arg

When the external function is called, the number of elements in the argument must match the number defined in the ⎕NA definition. Using the examples above:

      fn1                   ⍝ Niladic Function.
      fn2, ⊂'Single String' ⍝ 1-element arg
      fn3 'This' 'That'     ⍝ 2-element arg

Note in the second example, that you must enclose the argument string to produce a single item (nested) array in order to match the declaration. Dyalog converts the type of a numeric argument if necessary, so for example in fn5 defined above, a Boolean value would be converted to double floating point (F8) prior to being passed to the DLL function.

Pointer Arguments

When passing pointer arguments there are three cases to consider.

< Input pointer:

In this case you must supply the data array itself as argument to the function. A pointer to its first element is then passed to the DLL function.

      fn2 ⊂'hello'

> Output pointer:

Here, you must supply the number of elements that the output will need in order for APL to allocate memory to accommodate the resulting array.

      fn6 10 'world'  ⍝ 1st arg needs space for 10 ints.

Note that if you were to reserve fewer elements than the DLL function actually used, the DLL function would write beyond the end of the reserved array and may cause the interpreter to crash with a System Error (syserror 999 on Windows or SIGSEGV on UNIX, Linux or Mac OS).

= Input/Output:

As with the input-only case, a pointer to the first element of the argument is passed to the DLL function. The DLL function then overwrites some or all of the elements of the array, and the new value is passed back as part of the result of the call. As with the output pointer case, if the input array were too short, so that the DLL wrote beyond the end of the array, the interpreter would almost certainly crash.

      fn3 '.....' 'hello'

Result Vector

In APL, a function cannot overwrite its arguments. This means that any output from a DLL function must be returned as part of the explicit result, and this includes output via 'output' or 'input/output' pointer arguments.

The general form of the result from calling a DLL function is a nested vector. The first item of the result is the defined explicit result of the external function, and subsequent items are implicit results from output, or input/output pointer arguments.

The length of the result vector is therefore: 1 (if the function was declared to return an explicit result) + the number of output or input/output arguments.

⎕NA Declaration | Result | Output Arguments | Result Length
mydll|fn1 | 0 |  | 0
mydll|fn2 <0T | 0 | 0 | 0
mydll|fn3 =0T <0T | 0 | 1 0 | 1
I4 mydll|fn4 | 1 |  | 1
I4 mydll|fn5 F8 | 1 | 0 | 1
I4 mydll|fn6 >I4[] <0T | 1 | 1 0 | 2

Note that the result vector from a function that is declared void() and has no output parameters is ⍬ (zilde).

As a convenience, if the result would otherwise be a 1-item vector, it is disclosed. Using the third example above:

      ⍴fn3 '.....' 'abc'
5

fn3 has no explicit result; its first argument is input/output pointer; and its second argument is input pointer. Therefore as the length of the result would be 1, it has been disclosed.

64 bit integer results

When a 64 bit integer result is returned it is converted into 128 bit decimal floating point, because this is the only APL data type that can fully preserve all 64 bits of the result. If you wish to perform arithmetic with this value, you must set ⎕FR to 1287 in order to preserve the same precision. If this is not done then the precision will be 53 bits which might not be enough.

Callbacks (∇)

Currently, support for a ⎕NA function to call an APL function is limited to the use of the NAG (National Algorithms Group) library of functions. This library is a FORTRAN library and FORTRAN passes arguments by reference (address) rather than by value. The expression:

   ∇f8←(P P P P)

declares a callback function that returns a double and takes 4 pointer arguments. The result can be any of the normal results. It is not possible to return a pointer. The arguments can be from 0 to 16 P values.

The argument when passed can be the name of an APL function or the ⎕OR of a function.

The function when called can then decode the pointer arguments appropriately using a ⎕NA of MEMCPY().

ANSI /Unicode Versions of Library Calls

Under Windows, most library functions that take character arguments, or return character results have two forms: one Unicode (Wide) and one ANSI. For example, a function such as MessageBox(), has two forms MessageBoxA() and MessageBoxW(). The A stands for ANSI (1-byte) characters, and the W for wide (2-byte Unicode) characters.

It is essential that you associate the form of the library function that is appropriate for the Dyalog Edition you are using, i.e. MessageBoxA() for the Classic Edition, but MessageBoxW() for the Unicode Edition.

Whilst this is convenient it is not complete. It is adequate for character arrays that consist of characters from UCS-2 (i.e. those that will fit in an array with a ⎕DR of 80 or 160). If a more complete support is required then the W form of the function would be required and explicit use of UTF16 specified.

To simplify writing portable code for both Editions, you may specify the character * instead of A or W at the end of a function name. This will be replaced by A in the Classic Edition and W in the Unicode Edition.

The default name of the associated function (if no left argument is given to ⎕NA), will be without the trailing letter (MessageBox).

Type Definitions (typedefs)

The C language encourages the assignment of defined names to primitive and complex data types using its #define and typedef mechanisms. Using such abstractions enables the C programmer to write code that will be portable across many operating systems and hardware platforms.

Windows software uses many such names and Microsoft documentation will normally refer to the type of function arguments using defined names such as HANDLE or LPSTR rather than their equivalent C primitive types: int or char*.

It is beyond the scope of this manual to list all the Microsoft definitions and their C primitive equivalents, and indeed, DLLs from sources other than Microsoft may well employ their own distinct naming conventions.

In general, you should consult the documentation that accompanies the DLL in order to convert typedefs to primitive C types and thence to ⎕NA declarations. The documentation may well refer you to the 'include' files which are part of the Software Development Kit, and in which the types are defined.

The following table of some commonly encountered Windows typedefs and their ⎕NA equivalents might prove useful.

Windows typedef | ⎕NA equivalent
HWND | P
HANDLE | P
GLOBALHANDLE | P
LOCALHANDLE | P
DWORD | U4
WORD | U2
BYTE | U1
LPSTR | =0T[] (note 1)
LPCSTR | <0T[] (note 2)
WPARAM | U (note 3)
LPARAM | U4 (note 3)
LRESULT | I4
BOOL | I
UINT | U
ULONG | U4
ATOM | U2
HDC | P
HBITMAP | P
HBRUSH | P
HFONT | P
HICON | P
HMENU | P
HPALETTE | P
HMETAFILE | P
HMODULE | P
HINSTANCE | P
COLORREF | {U1[4]}
POINT | {I I}
POINTS | {I2 I2}
RECT | {I I I I}
CHAR | T or C

Notes

  1. LPSTR is a pointer to a null-terminated string. The definition does not indicate whether this is input or output, so the safest coding would be =0T[] (providing the vector you supply for input is long enough to accommodate the result). You may be able to improve simplicity or performance if the documentation indicates that the pointer is 'input only' (<0T[]) or 'output only' (>0T[]). See Direction above.
  2. LPCSTR is a pointer to a constant null-terminated string and therefore coding <0T[] is safe.
  3. WPARAM is an unsigned value, LPARAM is signed. They are 32 bit values in a 32-bit APL, and 64-bit in a 64 bit APL. You should consult the documentation for the specific function that you intend to call to determine what type they represent
  4. The use of type T with default width ensures portability of code between Classic and Unicode Editions. In the Classic Edition, T (with no width specifier) implies 1-byte characters which are translated between ⎕AV and ASCII, while in the Unicode Edition, T (with no width specifier) implies 2-byte (Unicode) characters.

The Dyalog DLL

The Dyalog DLL (see Run-Time Applications and Components) contains three functions: MEMCPY, STRNCPY and STRLEN.

MEMCPY

MEMCPY is an extremely versatile function used for moving arbitrary data between memory buffers.

Its C definition is:

void *MEMCPY(       // copy memory
      void *to,     // target address
      void *fm,     // source address
      size_t size   // number of bytes to copy
      );

MEMCPY copies size bytes starting from source address fm, to destination address to. The source and destination areas should not overlap; if they do the behaviour is undefined and the result is the first argument.

MEMCPY's versatility stems from being able to associate to it using many different type declarations.

Example

Suppose a global buffer (at address: addr) contains (numb) double floating point numbers. To copy these to an APL array, we could define the association:

      'doubles' ⎕NA 'dyalog32|MEMCPY >F8[] I4 U4'
      doubles numb addr (numb×8)

Notice that:

  • As the first argument to doubles is an output argument, we must supply the number of elements to reserve for the output data.
  • MEMCPY is defined to take the number of bytes to copy, so we must multiply the number of elements by the element size in bytes.

Example

Suppose that a database application requires that we construct a record in global memory prior to writing it to file. The record structure might look like this:

typedef struct {
        int empno;// employee number.
        float salary;// salary.
        char name[20];// name.
        } person;

Then, having previously allocated memory (addr) to receive the record, we can define:

      'prec' ⎕NA 'dyalog64|MEMCPY P <{P F4 T[20]} P'
      prec addr(99 12345.60 'Charlie Brown')(4+4+20)

STRNCPY

STRNCPY is used to copy null-terminated strings between memory buffers.

Its C definition is:

void *STRNCPY(// copy null-terminated string
        char *to,// target address
        char *fm,// source address
        size_t size// MAX number of chars to copy
        );

STRNCPY copies a maximum of size characters from the null-terminated source string at address fm, to the destination address to. If the source and destination strings overlap, the result is the first argument.

If the source string is shorter than size, a null character is appended to the destination string.

If the source string (including its terminating null) is longer than size, only size characters are copied and the resulting destination string is not null-terminated

Example

Suppose that a database application returns a pointer (addr) to a structure that contains two pointers to (max 20-char) null-terminated strings.

typedef struct {  // null-terminated strings:
        char *first;  // first name (max 19 chars + 1 null).
        char *last;  // last name. (max 19 chars + 1 null).
        } name;

To copy the names from the structure:

      'get'⎕NA'dyalog64|STRNCPY >0T[] P U4'
      get 20 addr 20
Charlie
      get 20 (addr+4) 20
Brown

Note that (as this is a 64-bit example), ⎕FR must be 1287 for the addition to be reliable.

To copy data from the workspace into an already allocated (new) structure:

      'put'⎕NA'dyalog32|STRNCPY I4 <0T[] U4'
      put new 'Bo' 20
      put (new+4) 'Peep' 20

Notice in this example that you must ensure that names no longer than 19 characters are passed to put. More than 19 characters would not leave STRNCPY enough space to include the trailing null, which would probably cause the application to fail.

STRNCPYA

This is a synonym for STRNCPY. It is there so that STRNCPY* (on Windows) selects between STRNCPYA and STRNCPYW.

STRNCPYW

This is a cover for the C standard function wcsncpy(). It is named this way so that (on Windows) STRNCPY* will behave helpfully.

STRLEN

STRLEN calculates the length of a C string (a 0-terminated string of bytes in memory). Its C declaration is:

size_t STRLEN(         // calculate length of string
        const char *s    // address of string
        );

Example

Suppose that a database application returns a pointer (addr) to a null-terminated string and you do not know the upper bound on the length of the string.

To copy the string into the workspace:

      'len'⎕NA'P dyalog32|STRLEN P'
      'cpy'⎕NA'dyalog32|MEMCPY >T[] P P'
      cpy l addr (l←len addr)
Bartholemew

Examples

The following examples all use functions from the Microsoft Windows user32.dll.

This DLL should be located in a standard Windows directory, so you should not normally need to give the full path name of the library. However if trying these examples results in the error message FILE ERROR 1 No such file or directory, you must locate the DLL and supply the full path name (and possibly extension).

Example 1

The Windows function GetCaretBlinkTime retrieves the caret blink rate. It takes no arguments and returns an unsigned int and is declared as follows:

UINT GetCaretBlinkTime(void);

The following statements would provide access to this routine through an APL function of the same name.

      ⎕NA 'U user32|GetCaretBlinkTime'
      GetCaretBlinkTime
530

The following statement would achieve the same thing, but using an APL function called BLINK.

      'BLINK' ⎕NA 'U user32|GetCaretBlinkTime'
      BLINK
530

Example 2

The Windows function SetCaretBlinkTime sets the caret blink rate. It takes a single unsigned int argument, does not return a result and is declared as follows:

void SetCaretBlinkTime(UINT);

The following statements would provide access to this routine through an APL function of the same name:

      ⎕NA 'user32|SetCaretBlinkTime U'
      SetCaretBlinkTime 1000

Example 3

The Windows function MessageBox displays a standard dialog box on the screen and awaits a response from the user. It takes 4 arguments. The first is the window handle for the window that owns the message box. This is declared as an unsigned int. The second and third arguments are both pointers to null-terminated strings containing the message to be displayed in the Message Box and the caption to be used in the window title bar. The 4th argument is an unsigned int that specifies the Message Box type. The result is an int which indicates which of the buttons in the message box the user has pressed. The function is declared as follows:

int MessageBox(HWND, LPCSTR, LPCSTR, UINT);

The following statements provide access to this routine through an APL function of the same name. Note that the 2nd and 3rd arguments are both coded as input pointers to type T null-terminated character arrays which ensures portability between Editions.

      ⎕NA 'I user32|MessageBox* P <0T <0T U'

The following statement displays a Message Box with a stop sign icon together with 2 push buttons labelled OK and Cancel (this is specified by the value 19).

      MessageBox 0 'Message' 'Title' 19

The function works equally well in the Unicode Edition because the <0T specification is portable.

      MessageBox 0 'Το Μήνυμα' 'Ο Τίτλος' 19

Note that a simpler, portable (and safer) method for displaying a Message Box is to use Dyalog APL's primitive MsgBox object.

Example 4

The Windows function FindWindow obtains the window handle of a window which has a given character string in its title bar. The function takes two arguments. The first is a pointer to a null-terminated character string that specifies the window's class name. However, if you are not interested in the class name, this argument should be a NULL pointer. The second is a pointer to a character string that specifies the title that identifies the window in question. This is an example of a case described above where two instances of the function must be defined to cater for the two different types of argument. However, in practice this function is most often used without specifying the class name. The function is declared as follows:

HWND FindWindow(LPCSTR, LPCSTR);

The following statement associates the APL function FW with the second variant of the FindWindow call, where the class name is specified as a NULL pointer. To indicate that APL is to pass the value of the NULL pointer, rather than its address, we need to code this argument as I4.

      'FW' ⎕NA 'P user32|FindWindow* P <0T'

To obtain the handle of the window entitled "CLEAR WS - Dyalog APL/W":

      ⎕←HNDL←FW 0 'CLEAR WS - Dyalog APL/W'
59245156

Example 5

The Windows function GetWindowText retrieves the caption displayed in a window's title bar. It takes 3 arguments. The first is an unsigned int containing the window handle. The second is a pointer to a buffer to receive the caption as a null-terminated character string. This is an example of an output array. The third argument is an int which specifies the maximum number of characters to be copied into the output buffer. The function returns an int containing the actual number of characters copied into the buffer and is declared as follows:

int GetWindowText(HWND, LPSTR, int);

The following associates the "GetWindowText" DLL function with an APL function of the same name. Note that the second argument is coded as ">0T" indicating that it is a pointer to a character output array.

      ⎕NA 'I user32|GetWindowText* P >0T I'

Now change the Session caption using )WSID :

      )WSID MYWS
was CLEAR WS

Then retrieve the new caption (max length 255) using window handle HNDL from the previous example:

      ]display GetWindowText HNDL 255 255
.→-------------------------.
|    .→------------------. |
| 19 |MYWS - Dyalog APL/W| |
|    '-------------------' |
'∊-------------------------'

There are three points to note.

  1. Firstly, the number 255 is supplied as the second argument. This instructs APL to allocate a buffer large enough for a 255-element character vector into which the DLL routine will write.
  2. Secondly, the result of the APL function is a nested vector of 2 elements. The first element is the result of the DLL function. The second element is the output character array.
  3. Finally, notice that although we reserved space for 255 elements, the result reflects the length of the actual text (19).

An alternative way of coding and using this function is to treat the second argument as an input/output array.

e.g.

      ⎕NA 'I User32|GetWindowText* P =0T I'

      ]display GetWindowText HNDL (255⍴' ') 255
.→-------------------------.
|    .→------------------. |
| 19 |MYWS - Dyalog APL/W| |
|    '-------------------' |
'∊-------------------------'

In this case, the second argument is coded as =0T, so when the function is called an array of the appropriate size must be supplied. This method uses more space in the workspace, although for small arrays (as in this case) the real impact of doing so is negligible.

Example 6

The function GetCharWidth returns the width of each character in a given range. Its first argument is a device context (handle). Its second and third arguments specify font positions (start and end). The third argument is the resulting integer vector that contains the character widths (this is an example of an output array). The function returns a Boolean value to indicate success or failure. The function is defined as follows. Note that this function is provided in the library: gdi32.dll.

BOOL GetCharWidth(HDC, UINT, UINT, LPINT);

The following statements provide access to this routine through an APL function of the same name:

      ⎕NA 'U4 gdi32|GetCharWidth* P U U >I[]'

     'Prin'⎕WC'Printer'

      ]display GetCharWidth ('Prin' ⎕WG 'Handle') 65 67 3
.→-------------.
|   .→-------. |
| 1 |50 50 50| |
|   '~-------' |
'∊-------------'

Note: 'Prin'⎕WG'Handle' returns a handle which is represented as a number. The number will be in the range (0 - 2*32] on a 32-bit version and (0 - 2*64] on a 64-bit version. These can be passed to a P type parameter. Older versions used a 32-bit signed integer.

Example 7

The following example from the supplied workspace: quadna.dws. quadna illustrates several techniques which are important in advanced ⎕NA programming. Function DllVersion returns the major and minor version number for a given DLL. Note that this example assumes that the computer is running the 64-bit version of Dyalog.

In advanced DLL programming, it is often necessary to administer memory outside APL's workspace. In general, the procedure for such use is:

  1. Allocate global memory.
  2. Lock the memory.
  3. Copy any DLL input information from workspace into memory.
  4. Call the DLL function.
  5. Copy any DLL output information from memory to workspace.
  6. Unlock the memory.
  7. Free the memory.

Notice that steps 1 and 7 and steps 2 and 6 complement each other. That is, if you allocate global system memory, you must free it after you have finished using it. If you continue to use global memory without freeing it, your system will gradually run out of resources. Similarly, if you lock memory (which you must do before using it), then you should unlock it before freeing it. Although on some versions of Windows, freeing the memory will include unlocking it, in the interests of good style, maintaining the symmetry is probably a good thing.

    ∇ version←DllVersion file;Alloc;Free;Lock;Unlock;Size
                  ;Info;Value;Copy;size;hndl;addr;buff;ok
[1]
[2]  'Alloc'⎕NA'P kernel32|GlobalAlloc U4 P'
[3]   'Free'⎕NA'P kernel32|GlobalFree P'
[4]   'Lock'⎕NA'P kernel32|GlobalLock P'
[5] 'Unlock'⎕NA'U4 kernel32|GlobalUnlock P'
[6]
[7]  'Size'⎕NA'U4 version|GetFileVersionInfoSize* <0T >U4'
[8]  'Info'⎕NA'U4 version|GetFileVersionInfo*<0T U4 U4 P'
[9] 'Value'⎕NA'U4 version|VerQueryValue* P <0T >P >U4'
[10]
[11] 'Copy'⎕NA'dyalog64|MEMCPY >U4[] P P'
[12]
[13]  :If ×size←⊃Size file 0               ⍝ Size of info
[14]  :AndIf ×hndl←Alloc 0 size            ⍝ Alloc memory
[15]    :If ×addr←Lock hndl                ⍝ Lock memory
[16]      :If ×Info file 0 size addr       ⍝ Version info
[17]        ok buff size←Value addr'\' 0 0 ⍝ Version value
[18]        :If ok
[19]          buff←Copy(size÷4)buff size   ⍝ Copy info
[20]          version←(2/2*16)⊤⊃2↓buff     ⍝ Split version
[21]        :EndIf
[22]      :EndIf
[23]      ok←Unlock hndl                   ⍝ Unlock memory
[24]    :EndIf
[25]    ok←Free hndl                       ⍝ Free memory
[26]  :EndIf
    ∇

Lines [2-11] associate APL function names with the DLL functions that will be used.

Lines [2-5] associate functions to administer global memory.

Lines [7-9] associate functions to extract version information from a DLL.

Line[11] associates Copy with MEMCPY function from dyalog64.dll.

Lines [13-26] call the DLL functions.

Line [13] requests the size of buffer required to receive version information for the DLL. A size of 0 will be returned if the DLL does not contain version information.

Notice that care is taken to balance memory allocation and release:

On line [14], the :If clause is taken only if the global memory allocation is successful, in which case (and only then) a corresponding Free is called on line [25].

Unlock on line[23] is called if and only if the call to Lock on line [15] succeeds.

A result is returned from the function only if all the calls are successful Otherwise, the calling environment will sustain a VALUE ERROR.

More Examples

⎕NA'I4 advapi32 |RegCloseKey          P'
⎕NA'I4 advapi32 |RegCreateKeyEx*      P <0T U4 <0T U4 U4 P >P >U4'
⎕NA'I4 advapi32 |RegEnumValue*        P U4 >0T =U4 =U4 >U4 >0T =U4'
⎕NA'I4 advapi32 |RegOpenKey*          P <0T >P'
⎕NA'I4 advapi32 |RegOpenKeyEx*        P <0T U4 U4 >P'
⎕NA'I4 advapi32 |RegQueryValueEx*     P <0T =U4 >U4 >0T =U4'
⎕NA'I4 advapi32 |RegSetValueEx*       P <0T =U4 U4 <0T U4'
⎕NA'P  dyalog32 |STRNCPY              P P P'
⎕NA'P  dyalog32 |STRNCPYA             P P P'
⎕NA'P  dyalog32 |STRNCPYW             P P P'
⎕NA'P  dyalog32 |MEMCPY               P P P'
⎕NA'I4 gdi32    |AddFontResource*     <0T'
⎕NA'I4 gdi32    |BitBlt               P I4 I4 I4 I4 P I4 I4 U4'
⎕NA'U4 gdi32    |GetPixel             P I4 I4'
⎕NA'P  gdi32    |GetStockObject       I4'
⎕NA'I4 gdi32    |RemoveFontResource*  <0T'
⎕NA'U4 gdi32    |SetPixel             P I4 I4 U4'
⎕NA'   glu32    |gluPerspective       F8 F8 F8 F8'
⎕NA'I4 kernel32 |CopyFile*            <0T <0T I4'
⎕NA'P  kernel32 |GetEnvironmentStrings'
⎕NA'U4 kernel32 |GetLastError'
⎕NA'U4 kernel32 |GetTempPath*         U4 >0T'
⎕NA'P  kernel32 |GetProcessHeap'
⎕NA'I4 kernel32 |GlobalMemoryStatusEx ={U4 U4 U8 U8 U8 U8 U8 U8}'
⎕NA'P  kernel32 |HeapAlloc            P U4 P'
⎕NA'I4 kernel32 |HeapFree             P U4 P'
⎕NA'   opengl32 |glClearColor         F4 F4 F4 F4'
⎕NA'   opengl32 |glClearDepth         F8'
⎕NA'   opengl32 |glEnable             U4'
⎕NA'   opengl32 |glMatrixMode         U4'
⎕NA'I4 user32   |ClientToScreen       P ={I4 I4}'
⎕NA'P  user32   |FindWindow*          <0T <0T'
⎕NA'I4 user32   |ShowWindow           P I4'
⎕NA'I2 user32   |GetAsyncKeyState     I4'
⎕NA'P  user32   |GetDC                P'
⎕NA'I4 User32   |GetDialogBaseUnits'
⎕NA'P  user32   |GetFocus'
⎕NA'U4 user32   |GetSysColor          I4'
⎕NA'I4 user32   |GetSystemMetrics     I4'
⎕NA'I4 user32    |InvalidateRgn        P P I4'
⎕NA'I4 user32   |MessageBox*          P <0T <0T U4'
⎕NA'I4 user32   |ReleaseDC            P P'
⎕NA'P  user32   |SendMessage*         P U4 P P'
⎕NA'P  user32   |SetFocus             P'
⎕NA'I4 user32   |WinHelp*             P <0T U4 P'
⎕NA'I4 winnm    |sndPlaySound         <0T U4'


Replace

Replace R←{X}(A ⎕R B) Y

⎕R (Replace) and ⎕S (Search) are system operators which take search pattern(s) as their left arguments and transformation rule(s) as their right arguments; the derived function operates on text data to perform either a search, or a search and replace operation.

The search patterns may include Regular Expressions so that complex searches may be performed. ⎕R and ⎕S utilise the open-source regular-expression search engine PCRE, which is built into Dyalog APL and distributed according to the PCRE licence which is published separately.

The transformation rules are applied to the text which matches the search patterns; they may be given as a simple character vector, numeric codes, or a function.

The two system operators, ⎕R for replace and ⎕S for search, are syntactically identical. With ⎕R, the input document is examined; text which matches the search pattern is amended and the remainder is left unchanged. With ⎕S, each match in the input document results in an item in the result whose type is dependent on the transformation specified. The operators use the Variant operator to set options.

A specifies one or more search patterns, being given as a single character, a character vector, a vector of character vectors or a vector of both characters and character vectors. See search pattern following.

B is the transformation to be performed on matches within the input document; it may be either one or more transformation patterns (specified as a character, a character vector, a vector of character vectors, or a vector of both characters and character vectors), one or more transformation codes (specified as a numeric scalar or a numeric vector) or a function; see transformation pattern, transformation codes and transformation function following.

Y specifies the input document; see input document below.

X optionally specifies an output stream; see output below.

R is the result value; see output below.

Examples of replace operations

      ('.at' ⎕R '\u0') 'The cat sat on the mat'
The CAT SAT on the MAT

In the search pattern the dot matches any character, so the pattern as a whole matches sequences of three characters ending 'at'. The transformation is given as a character string, and causes the entire matching text to be folded to upper case.

      ('\w+' ⎕R {⌽⍵.Match}) 'The cat sat on the mat'
ehT tac tas no eht tam

The search pattern matches each word. The transformation is given as a function, which receives a namespace containing various variables describing the match, and it returns the match in reverse, which in turn replaces the matched text.

Examples of search operations

      STR←'The cat sat on the mat'
      ('.at' ⎕S '\u0') STR
CAT  SAT  MAT

The example is identical to the first, above, except that after the transformation is applied to the matches the results are returned in a vector, not substituted into the source text.

      ('.at' ⎕S {⍵.((1↑Offsets),1↑Lengths)}) STR
4 3  8 3  19 3

When searching, the result vector need not contain only text and in this example the function returns the numeric position and length of the match given to it; the resultant vector contains these values for each of the three matches.

      ('.at' ⎕S 0 1) STR
4 3  8 3  19 3

Here the transformation is given as a vector of numeric codes which are a short-hand for the position and length of each match; the overall result is therefore identical to the previous example.

These examples all operate on a simple character vector containing text, but the text may be given in several forms - character vectors, vectors of character vectors, and external data streams. These various forms constitute a 'document'. When the result also takes the form of a document it may be directed to a stream.

Input Document

The input document may be an array or a data stream.

When it is an array it may be given in one of two forms:

  1. A character scalar or vector
  2. A vector of character vectors

Currently, the only supported data stream is a native file, specified as tie number, which is read from the current position to the end. If the file is read from the start, and there is a valid Byte Order Mark (BOM) at the start of it, the data encoding is determined by this BOM. Otherwise, data in the file is assumed to be encoded as specified by the InEnc option.

Hint: once a native file has been read to the end by ⎕R or ⎕S it is possible to reset the file position to the start so that it may be read again using:

      {} ⎕NREAD tienum 82 0 0

The input document is comprised of lines of text. Line breaks may be included in the data:

Implicitly

  • Between each item in the outer vector (type 2, above)

Explicitly, as

  • carriage return
  • line feed
  • carriage return and line feed together, in that order
  • vertical tab (U+000B)
  • newline (U+0085)
  • form Feed (U+000C)
  • line Separator (U+2028)
  • paragraph Separator (U+2029)

The implicit line ending character may be set using the EOL option. Explicit line ending characters may also be replaced by this character - so that all line endings are normalised - using the NEOL option.

The input document may be processed in line mode, document mode or mixed mode. In document mode and mixed mode, the entire input document, line ending characters included, is passed to the search engine; in line mode the document is split on line endings and passed to the search engine in sections without the line ending characters. The choice of mode affects both memory usage and behaviour, as documented in the section 'Line, document and mixed modes'.

Output

The format of the output is dependent on whether ⎕S or ⎕R are in use, whether an output stream is specified and, for ⎕R, the form of the input and whether the ResultText option is specified.

An output data stream may optionally be specified. Currently, the only supported data stream is a native file, specified as tie number, and all output will be appended to it. Data in the stream is encoded as specified by the OutEnc option. If this encoding specifies a Byte Order Mark and the file is initially empty then the Byte Order Mark will be written at the start. Appending to existing data using a different encoding is permitted but unlikely to produce desirable results. If an input stream is also used, care must be taken to ensure the input and output streams are not the same.

⎕R

With no output stream specified and unless overridden by the ResultText option, the derived function result will be a document which closely matches the format of the input document, as follows:

A character scalar or vector input will result in a character vector output. Any and all line endings in the output will be represented by line ending characters within the character vector.

A vector of character vectors as input will result in a vector of character vectors as document output. Any and all line endings in the output document will be implied at the end of each character vector.

A stream as input will result in a vector of character vectors document output. Any and all line endings in the output document will be implied at the end of each character vector.

Note that the shape of the output document may be significantly different to that of the input document.

If the ResultText option is specified, the output type may be forced to be a character vector or vector of character vectors as described above, regardless of the input document.

With an output stream specified the text is appended to the stream. If the appended text does not end with a line ending character then the line ending character specified by the EOL option is also appended. The resulting length of the file is returned as a shy result.

⎕S

With no output stream specified, the result will be a vector containing one item for each match in the input document, of types determined by the transformation performed on each match.

With an output stream specified there is no result - instead each match is appended to the stream. If any match does not end with a line ending character then the line ending character specified by the EOL option is also appended. Only text may be written to the stream, which means:

  • When a transformation function is used, the function may only generate a character vector result.
  • Transformation codes may not be used.

Search pattern

A summary of the syntax of the search pattern is reproduced from the PCRE documentation. See PCRE Regular Expression Syntax Summary.

A full description is provided in PCRE Regular Expression Details.

There may be multiple search patterns. If more than one search pattern is specified and more than one pattern matches the same part of the input document then priority is given to the pattern specified first.

Note that when anchoring a search to the beginning of a line, it is essential to use ^ (⎕UCS 94), not ∧ (⎕UCS 8743).

Transformation pattern

For each match in the input document, the transformation pattern causes the creation of text which, for ⎕R, replaces the matching text and, for ⎕S, generates one item in the result.

There may be either one transformation pattern, or the same number of transformation patterns as search patterns. If there are multiple search patterns and multiple transformation patterns then the transformation pattern used corresponds to the search pattern which matched the input text.

Transformation patterns may not be mixed with transformation codes or functions.

The following characters have special meaning:

% | acts as a placeholder for the entire line (line mode) or document (document mode or mixed mode) which contained the match
& | acts as a placeholder for the entire portion of text which matched
\n | represents a line feed character
\r | represents a carriage return
\0 | equivalent to &
\n | acts as a placeholder for the text which matched the first to ninth subpattern; n may be any single digit value from 1 to 9
\(n) | acts as a placeholder for the text which matched the numbered subpattern; n may have an integer value from 0 to 63.
\<name> | acts as a placeholder for the text which matched the named subpattern
\\ | represents the backslash character
\% | represents the percent character
\& | represents the ampersand character
\x{nnnn} | represents a Unicode code point; nnnn is a hexadecimal sequence of characters yielding a value between 0x1 and 0x10FFFF.

The above may be qualified to fold matching text to upper- or lower-case by using the u and l modifiers respectively. Character sequences beginning with the backslash place the modifier after the backslash; character sequences with no leading backslash add both a backslash and the modifier to the start of the sequence, for example:

\u& | acts as a placeholder for the entire portion of text which matched, folded to upper case
\l0 | equivalent to \l&

Character sequences beginning with the backslash other that those shown are invalid. All characters other than those shown are literal values and are included in the text without modification.

Transformation codes

The transformation codes are a numeric scalar or vector. Transformation codes may only be used with ⎕S. For each match in the input document, a numeric scalar or vector of the same shape as the transformation codes is created, with the codes replaced with values as follows:

0 | The offset from the start of the line (line mode) or document (document mode or mixed mode) of the start of the match.
1 | The length of the match.
2 | In line mode, the block number in the source document of the start of the match. The value is origin zero. In document mode or mixed mode this value is always zero.
3 | The pattern number which matched the input document, origin zero.

Transformation Function

The transformation function is called for each match within the input document. The function is monadic and is passed a namespace, containing the following variables:

Block | The entire line (line mode) or document (document mode or mixed mode) in which the match was found.
BlockNum | With line mode, the block (line) number in the source document of the start of the match. The value is origin zero. With document mode or mixed mode the entire document is contained within one block and this value is always zero.
Pattern | The search pattern which matched.
PatternNum | The index-zero pattern number which matched.
Match | The text within Block which matched Pattern.
Offsets | A vector of one or more offsets relative to the start of Block. The first value is the offset of the entire match; any and all additional values are the offsets of the portions of the text which matched the subpatterns, in the order of the subpatterns within Pattern. ¯1 indicates no match, see below.
Lengths | A vector of one or more lengths, corresponding to each value in Offset. ¯1 indicates no match, see below.
Names | A vector of one or more character vectors corresponding to each of the values in Offsets, specifying the names given to the subpatterns within Pattern. The first entry (corresponding to the match) and all subpatterns with no name are included as length zero character vectors.
ReplaceMode | A Boolean indicating whether the function was called by ⎕R (value 1) or ⎕S (value 0).
TextOnly | A Boolean indicating whether the return value from the function must be a character vector (value 1) or any value (value 0).

The return value from the function is used as follows:

With ⎕R the function must return a character vector. The contents of this vector are used to replace the matching text.

With ⎕S the function may return no value. If it does return a value:

  • When output is being directed to a stream it must be a character vector.
  • Otherwise, it may be any value. The overall result of the derived function is the catenation of the enclosure of each returned value into a single vector.

The passed namespace exists over the lifetime of ⎕R or ⎕S; the function may therefore preserve state by creating variables in the namespace.

The function may itself call ⎕R or ⎕S.

There may be only one transformation function, regardless of the number of search patterns.

The locations of the match within Block and subpatterns within Match are given as offsets rather than positions, i.e. the values are the number of characters preceding the data, and are not affected by the Index Origin.

The value of ¯1 may appear in both the Offsets and Fields items (in corresponding positions). They indicate that the subpattern to which they refer did not appear in the match at all.

Example

      {}('(A)|(B)'⎕R{⎕←⍵.(Offsets Lengths)⋄'x'})'ABC'
 0 0  1 1
 1 ¯1 1  1 ¯1 1

The pattern has two subpatterns - (A) and (B). Therefore Offsets and Lengths would be expected to have three elements each - one for the entire match, one for the first subpattern and one for the second subpattern. But these subpatterns have a | between them which means they are alternates - only one can match.

When ABC is searched the first match is the A in the first subpattern. The second subpattern does not feature. Offsets is 0 0 and Lengths is 1 1: the entire pattern matched from offset 0 length 1 and the first subpattern also matched from offset 0 length 1. The second subpattern did not feature in the match.

Note that ¯1 is only used as a "filler" when there are higher-numbered subpatterns that did match.

The second match is the B in the second subpattern. Offsets is 1 ¯1 1 and Lengths is 1 ¯1 1: the entire pattern matched from offset 1 length 1 and the second subpattern also matched from offset 1 length 1. The first subpattern did not feature in the match and this is indicated by the ¯1s. There has to be something between the offset/length for the entire pattern and the second subpattern.

Options

Options are specified using the Variant operator. The Principal option is IC.

Default values are highlighted thus.

IC Option

When set, case is ignored in searches.

1 | Matches are not case sensitive.
0 | Matches are case sensitive.

Example:

      ('[AEIOU]' ⎕R 'X' ⍠ 'IC' 1) 'ABCDE abcde'
XBCDX XbcdX
      ('[AEIOU]' ⎕R 'X' ⍠ 1)'ABCDE abcde'
XBCDX XbcdX

Mode Option

Specifies whether the input document is interpreted in line mode, document mode or mixed mode.

L | When line mode is set, the input document is split into separate lines (discarding the line ending characters themselves), and each line is processed separately. This means that the ML option applies per line, and the '^' and '$' anchors match the start and end respectively of each line. Because the document is split, searches can never match across multiple lines, nor can searches for line ending characters ever succeed. Setting line mode can result in significantly reduced memory requirements compared with the other modes.
D | When document mode is set, the entire input document is processed as a single block. The ML option applies to this entire block, and the '^' and '$' anchors match the start and end respectively of the block - not the lines within it. Searches can match across lines, and can match line ending characters.
M | When mixed mode is set, the '^' and '$' anchors match the start and end respectively of each line, as if line mode is set, but in all other respects behaviour is as if document mode is set - the entire input document is processed in a single block.

Examples:

      ('$' ⎕R '[Endline]' ⍠ 'Mode' 'L') 'ABC' 'DEF'
 ABC[Endline]  DEF[Endline]

      ('$' ⎕R '[Endline]' ⍠ 'Mode' 'D') 'ABC' 'DEF'
 ABC  DEF[Endline]

      ('$' ⎕R '[Endline]' ⍠ 'Mode' 'M') 'ABC' 'DEF'
 ABC[Endline]  DEF[Endline]

DotAll Option

Specifies whether the dot ('.') character in search patterns matches line ending characters.

0 | The '.' character in search patterns matches most characters, but not line endings.
1 | The '.' character in search patterns matches all characters.

This option is invalid in line mode, because line endings are stripped from the input document.

Example:

      ('.' ⎕R 'X' ⍠'Mode' 'D') 'ABC' 'DEF'
 XXX  XXX
      ('.' ⎕R 'X' ⍠('Mode' 'D')('DotAll' 1)) 'ABC' 'DEF'
 XXXXXXXX

EOL Option

Sets the line ending character which is implicitly present between character vectors, when the input document is a vector of character vectors.

CR | Carriage Return (U+000D)
LF | Line Feed (U+000A)
CRLF | Carriage Return followed by Line Feed
VT | Vertical Tab (U+000B)
NEL | New Line (U+0085)
FF | Form Feed (U+000C)
LS | Line Separator (U+2028)
PS | Paragraph Separator (U+2029)

In the Classic Edition, setting a value which is not in ⎕AVU may result in a TRANSLATION ERROR.

Example:

      ('\n' ⎕R'X' ⍠('Mode' 'D')('EOL' 'LF')) 'ABC' 'DEF'
 ABCXDEF

Here, the implied line ending between 'ABC' and 'DEF' is '\n', not the default '\r\n'.

NEOL Option

Specifies whether explicit line ending sequences in the input document are normalised by replacing them with the character specified using the EOL option.

0 | Line endings are not normalised.
1 | Line endings are normalised.

Example:

      a←'ABC',(1↑2↓⎕AV),'DEF',(1↑3↓⎕AV),'GHI'
      ('\n'⎕S 0 ⍠ 'Mode' 'D' ⍠ 'NEOL' 1 ⍠ 'EOL' 'LF') a
3 7

'\n' has matched both explicit line ending characters in the input, even though they are different.

ML Option

Sets a limit to the number of processed pattern matches per line (line mode) or document (document mode and mixed mode).

Positive value n | Sets the limit to the first n matches.
0 | Sets no limit.
Negative value ¯n | Sets the limit to exactly the nth match.

Examples:

      ('.' ⎕R 'x' ⍠ 'ML' 2) 'ABC' 'DEF'
 xxC  xxF
      ('.' ⎕R 'x' ⍠ 'ML' ¯2) 'ABC' 'DEF'
 AxC  DxF
      ('.' ⎕R 'x' ⍠ 'ML' ¯4 ⍠ 'Mode' 'D') 'ABC' 'DEF'
 ABC  xEF

Greedy Option

Controls whether patterns are "greedy" (and match the maximum input possible) or are not (and match the minimum). Within the pattern itself it is possible to specify greediness for individual elements of the pattern; this option sets the default.

1 | Greedy by default.
0 | Not greedy by default.

Examples:

      ('[A-Z].*[0-9]' ⎕R 'X' ⍠ 'Greedy' 1)'ABC123 DEF456'
X
      ('[A-Z].*[0-9]' ⎕R 'X' ⍠ 'Greedy' 0)'ABC123 DEF456'
X23 X56

OM Option

Specifies whether matches may overlap.

1 | Searching continues for all patterns and then from the character following the start of the match, thus permitting overlapping matches.
0 | Searching continues from the character following the end of the match.

This option may only be used with ⎕S. With ⎕R searching always continues from the character following the end of the match (the characters following the start of the match will have been changed).

Examples:

      ('[0-9]+' ⎕S '\0' ⍠ 'OM' 0) 'A 1234 5678 B'
 1234  5678
      ('[0-9]+' ⎕S '\0' ⍠ 'OM' 1) 'A 1234 5678 B'
 1234  234  34  4  5678  678  78  8

InEnc Option

This option specifies the encoding of the input stream when it cannot be determined automatically. It is either:

  • a character vector that specifies the file-encoding as shown in the table below.
  • a 256-element numeric vector that maps each possible byte value (0-255) to a Unicode code point (1st element = Unicode code point corresponding to byte value 0, and so on). ¯1 indicates that the corresponding byte value is not mapped to any character. Apart from ¯1, no value may appear in the table more than once.

When the stream is read from its start, and the start of the stream contains a recognised Byte Order Mark (BOM), the encoding is taken as that specified by the BOM and this option is ignored. Otherwise, the encoding is assumed to be as specified by this option.

UTF-8 | The stream is processed as UTF-8 data. Note that ASCII is a subset of UTF-8, so this default is also suitable for ASCII data.
UTF-16 | The stream is processed as UTF16 little-endian data on little-ended systems, or as UTF16 big-endian data on big-endian systems.
UTF-16LE | The stream is processed as UTF16 little-endian data.
UTF-16BE | The stream is processed as UTF16 big-endian data.
UTF-32 | The stream is processed as UTF32 little-endian data on little-ended systems, or as UTF32 big-endian data on big-endian systems.
UTF-32LE | The stream is processed as UTF32 little-endian data.
UTF-32BE | The stream is processed as UTF32 big-endian data.
ASCII | The stream is processed as ASCII data. If the stream contains any characters outside of the ASCII range then an error is produced.
Windows-1252 | The stream is processed as Windows-1252 (ANSI) data.
ANSI | Same as Windows-1252

For compatibility with the OutEnc option, the above UTF formats may be qualified with -BOM (e.g. UTF-8-BOM) or -NOBOM. For input streams, the qualified and unqualified options are equivalent.

OutEnc Option

When the output is written to a stream, this option specifies how the data is to be encoded. It is either:

  • a character vector that specifies the file-encoding as shown in the table below.
  • a 256-element numeric vector that maps each possible byte value (0-255) to a Unicode code point (1st element = Unicode code point corresponding to byte value 0, and so on). ¯1 indicates that the corresponding byte value is not mapped to any character. Apart from ¯1, no value may appear in the table more than once.
Implied | If input came from a stream then the encoding format is the same as the input stream, otherwise UTF-8
UTF-8 | The data is written in UTF-8 format.
UTF-16 | The data is written in UTF16 little-endian format on little-ended systems, or in UTF16 big-endian format on big-endian systems.
UTF-16LE | The data is written in UTF-16 little-endian format.
UTF-16BE | The data is written in UTF-16 big-endian format.
UTF-32 | The data is written in UTF32 little-endian format on little-ended systems, or in UTF32 big-endian format on big-endian systems.
UTF-32LE | The data is written in UTF-32 little-endian format.
UTF-32BE | The data is written in UTF-32 big-endian format.
ASCII | The data is written in ASCII format.
Windows-1252 | The data is written in Windows-1252 (ANSI) format.
ANSI | Same as Windows-1252

The above UTF formats may be qualified with -BOM (e.g. UTF-8-BOM) to specify that a Byte Order Mark should be written at the start of the stream or, -NOBOM that it should not. For files, this is ignored if the file already contains any data. If the -BOM or -NOBOM suffix is omitted, UTF-8 defaults to UTF-8-NOBOM, while the other UTF formats default to -BOM.

Enc Option

This option sets both InEnc and OutEnc simultaneously, with the same given value. Any option value accepted by those options except Implied may be given.

ResultText Option

For ⎕R, this option determines the format of the result.

Implied | The output will either be a character vector or a vector of character vectors, dependent on the input document type
Simple | The output will be a character vector. Any and all line endings in the output will be represented by line ending characters within the character vector.
Nested | The output will be a vector of character vectors. Any and all line endings in the output document will be implied at the end of each character vector.

This option may only be used with ⎕R.

Examples:

      ⎕UCS ¨ ('A' ⎕R 'x') 'AB' 'CD'
  120 66  67 68
      ⎕UCS ('A' ⎕R 'x' ⍠ 'ResultText' 'Simple') 'AB' 'CD'
 120 66 13 10 67 68

UCP Option

This affects the way PCRE that processes \B, \b, \D, \d, \S, \s, \W, \w, and some of the POSIX character classes.

1 | Unicode properties are used to classify characters.
0 | Only ASCII characters are recognized.

Implementation Note: this option is implemented by setting or not setting the PCRE_UCP option when calling pcre_compile(). More information can be found in the PCRE documentation.

Examples

By default, the character ø (which is not an ASCII character) is considered to be a "non-word" character, so:

      ('\w'⎕S'\0')'Bjørn'  ⍝ identify "word" characters
 B  j  r  n
      ('\W'⎕S'\0')'Bjørn'  ⍝ non-word" characters
 ø

When UCP is set to 1, Unicode characters are matched as "word" characters (\w) too.

      ('\w'⎕S'\0' ⍠'UCP' 1)'Bjørn'
 B  j  ø  r  n

Line, document and mixed modes

The Mode setting determines how the input document is packaged as a block and passed to the search engine. In line mode each line is processed separately; in document mode and mixed mode the entire document is presented to the search engine. This affects both the semantics of the search expression, and memory usage.

Semantic differences

  • The ML option applies per block of data.
  • In line mode, search patterns cannot be constructed to span multiple lines. Specifically, patterns that include line ending characters (such as '\r') will never match because the line endings are never presented to the search engine.
  • By default the search pattern metacharacters '^' and '$' match the start and end of the block of data. In line mode this is always the start and end of each line. In document mode this is the start and end of the document. In mixed mode the behaviour of '^' and '$' are amended by setting the PCRE option 'MULTILINE' so that they match the start and end of each line within the document.

Memory usage differences

Blocks of data passed to the search engine are processed and stored in the workspace. Processing the input document in line mode limits the total memory requirements; in particular this means that large streams can be processed without holding all the data in the workspace at the same time.

Technical Considerations

⎕R and ⎕S utilise the open-source regular-expression search engine PCRE, which is built into the Dyalog software and distributed according to the PCRE licence which is published separately.

Before data is passed to PCRE it is converted to UTF-8 format. This converted data is buffered in the workspace; processing large documents may have significant memory requirements. In line mode, the data is broken into individual lines and each is processed separately, potentially reducing memory demands.

It is possible to save a workspace with an active ⎕R or ⎕S on the stack and execution can continue when the workspace is reloaded with the same interpreter version. Later versions of the interpreter may not remain compatible and may signal a DOMAIN ERROR with explanatory message in the status window if it is unable to continue execution.

PCRE has a buffer length limit of 231 bytes (2GB). UTF-8 encodes each character using between 1 and 6 bytes (typically 1 or 3). In the very worst case, where every character is encoded in 6 bytes, the maximum block length which can be searched would be 357,913,940 characters.

Further Examples

Several of the examples use the following vector as the input document:

      text
To be or not to be– that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles

Replace all upper and lower-case vowels by 'X':

       ('[aeiou]' ⎕R 'X' ⍠ 'IC' 1) text
TX bX Xr nXt tX bX– thXt Xs thX qXXstXXn:
WhXthXr 'tXs nXblXr Xn thX mXnd tX sXffXr
ThX slXngs Xnd XrrXws Xf XXtrXgXXXs fXrtXnX,
Xr tX tXkX Xrms XgXXnst X sXX Xf trXXblXs

Replace only the second vowel on each line by '\VOWEL\':

       ('[aeiou]' ⎕R '\\VOWEL\\'⍠('IC' 1)('ML' ¯2)) text
To b\VOWEL\ or not to be– that is the question:
Wheth\VOWEL\r 'tis nobler in the mind to suffer
The sl\VOWEL\ngs and arrows of outrageous fortune,
Or t\VOWEL\ take arms against a sea of troubles

Case fold each word:

      ('(?<first>\w)(?<remainder>\w*)' ⎕R '\u<first>\l<remainder>') text
To Be Or Not To Be– That Is The Question:
Whether 'Tis Nobler In The Mind To Suffer
The Slings And Arrows Of Outrageous Fortune,
Or To Take Arms Against A Sea Of Troubles

Extract only the lines with characters 'or' (in upper or lower case) on them:

      ↑('or' ⎕S '%' ⍠ ('IC' 1)('ML' 1)) text
To be or not to be– that is the question:
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles

Identify which lines contain the word 'or' (in upper or lower case) on them:

      ('\bor\b'⎕S 2⍠('IC' 1)('ML' 1))text
0 3

Note the difference between the characters 'or' (which appear in 'fortune') and the word 'or'.

Place every non-space sequence of characters in brackets:

      ('[^\s]+' ⎕R '(&)' ) 'To be or not to be, that is the question'
(To) (be) (or) (not) (to) (be,) (that) (is) (the) (question)

Replace all sequences of one or more spaces by newline. Note that the effect of this is dependent on the input format:

Character vector input results in a single character vector output with embedded newlines:

      ]display ('\s+' ⎕R '\r') 'To be or not to be, that is the question'
┌→───────┐
│To      │
│be      │
│or      │
│not     │
│to      │
│be,     │
│that    │
│is      │
│the     │
│question│
└────────┘

A vector of two character vectors as input results in a vector of 10 character vectors output:

      ]display ('\s+' ⎕R '\r') 'To be or not to be,' 'that is the question'
┌→─────────────────────────────────────────────────────────────┐
│ ┌→─┐ ┌→─┐ ┌→─┐ ┌→──┐ ┌→─┐ ┌→──┐ ┌→───┐ ┌→─┐ ┌→──┐ ┌→───────┐ │
│ │To│ │be│ │or│ │not│ │to│ │be,│ │that│ │is│ │the│ │question│ │
│ └──┘ └──┘ └──┘ └───┘ └──┘ └───┘ └────┘ └──┘ └───┘ └────────┘ │
└∊─────────────────────────────────────────────────────────────┘

Change numerals to their expanded names, using a function:

     ∇r←f a;n
[1]   n←'zero' 'one' 'two' 'three' 'four'
[2]   n,←'five' 'six' 'seven' 'eight' 'nine'
[3]   r←' ',⊃(⍎a.Match)↓n
     ∇
      verbose←('[0-9]' ⎕R f)
      verbose ⍕27×56×87
 one three one five four four

Swap 'red' and 'blue':

      ('red' 'blue' ⎕R 'blue' 'red') 'red hat blue coat'
blue hat red coat

Convert a comma separated values (CSV) file so that

  • dates in the first field are converted from European format to ISO, and
  • currency values are converted from Deutsche Marks (DEM) to Euros (DEM 1.95583 to €1).

The currency conversion requires the use of a function. Note the nested use of ⎕R.

Input file:

01/03/1980,Widgets,DEM 10.20
02/04/1980,Bolts,DEM 61.75
17/06/1980,Nuts; special rate DEM 17.00,DEM 17.00
18/07/1980,Hammer,DEM 1.25

Output file:

1980-03-01,Widgets,€ 5.21
1980-04-02,Bolts,€ 31.57
1980-06-17,Nuts; special rate DEM 17.00,€ 8.69
1980-07-18,Hammer,€ 0.63

     ∇ ret←f a;d;m;y;v
[1]    ⎕IO←0
[2]    :Select a.PatternNum
[3]    :Case 0
[4]        d m y←{a.Match[a.Offsets[⍵+1]+⍳a.Lengths[⍵+1]]}¨⍳3
[5]        ret←y,'-',m,'-',d,','
[6]    :Else
[7]        v←⍎a.Block[a.Offsets[1]+⍳a.Lengths[1]]
[8]        v÷←1.95583
[9]        ret←',€ ',('(\d+\.\d\d).*'⎕R'\1')⍕v
[10]   :EndSelect
     ∇
      in ← 'x.csv' ⎕NTIE 0
      out ← 'new.csv' ⎕NCREATE 0
      dateptn←'(\d{2})/(\d{2})/(\d{4}),'
      valptn←',DEM ([0-9.]+)'
      out (dateptn valptn ⎕R f) in
      ⎕nuntie¨in out

Create a simple profanity filter. For the list of objectionable words:

       profanity←'bleeding' 'heck'

first construct a pattern which will match the words:

      ptn←(('^' '$' '\r\n') ⎕R '\\b(' ')\\b' '|'
                           ⎕OPT 'Mode' 'D') profanity
      ptn
\b(bleeding|heck)\b

then a function that uses this pattern:

      sanitise←ptn ⎕R '****' ⎕opt 1
      sanitise '"Heck", I said'
"****", I said

Replace the characters 'or' with '\u0' without having to escape the backslash:

Escaping transformation strings can be a daunting task. To avoid doing so, one can simply enclose the string in braces. This is not a special feature, but just a consequence of how transformation functions are used.

      ('to' ⎕R {'\u0'})text
To be or not \u0 be– that is the question:
Whether 'tis nobler in the mind \u0 suffer
The slings and arrows of outrageous fortune,
Or \u0 take arms against a sea of troubles


Search

Search R←{X}(A ⎕S B) Y

See Replace.


Execute UNIX Command

Execute (UNIX) Command {R}←⎕SH Y

⎕SH executes a UNIX shell or a Windows Command Processor. ⎕SH is a synonym of ⎕CMD. Either function may be used in either environment (UNIX or Windows) with exactly the same effect. ⎕SH is probably more natural for the UNIX user. This section describes the behaviour of ⎕SH and ⎕CMD under UNIX. See Execute Windows Command for a discussion of the behaviour of these system functions under Windows.

The system commands )SH and )CMD provide similar facilities.

Y must be a simple character scalar or vector representing a UNIX shell command. R is a nested vector of character vectors.

Y may be any acceptable UNIX command. If the command does not produce any output, R is 0⍴⊂'' but the result is suppressed if not explicitly used or assigned. If the command has a non-zero exit code, then APL will signal a DOMAIN ERROR. If the command returns a result and has a zero exit code, then each element of R will be a line from the standard output (stdout) of the command. Output from standard error (stderr) is not captured unless redirected to stdout.

Examples

      ⎕SH'ls'
FILES WS temp

      ⎕SH 'rm WS/TEST'

      ⎕SH 'grep bin /etc/passwd ; exit 0'
bin:!:2:2::/bin:

      ⎕SH 'apl MYWS <inputfile >out1 2>out2 &'

Note:

This function is disabled and instead generates a DOMAIN ERROR if the RIDE_SPAWNED parameter is non-zero. This is designed to prevent it being invoked from a RIDE session which does not support this type of user interface. For further details, see the RIDE User Guide.


Start UNIX Auxiliary Processor

Start UNIX Auxiliary Processor X ⎕SH Y

Used dyadically, ⎕SH starts an Auxiliary Processor. The effect, as far as the APL user is concerned, is identical under both Windows and UNIX although there are differences in the method of implementation. ⎕SH is a synonym of ⎕CMD Either function may be used in either environment (UNIX or Windows) with exactly the same effect. ⎕SH is probably more natural for the UNIX user. This section describes the behaviour of ⎕SH and ⎕CMD under UNIX. See Start Windows Auxiliary Processor for a discussion of the behaviour of these system functions under Windows.

X must be a simple character vector. Y may be a simple character scalar or vector, or a nested character vector.

⎕SH loads the Auxiliary Processor from the file named by X using a search-path defined by the environment variable WSPATH.

The shy result R is the process id of the Auxiliary Processor task.

The effect of starting an AP is that one or more external functions are defined in the workspace. These appear as locked functions and may be used in exactly the same way as regular defined functions.

When an external function is used in an expression, the argument(s) (if any) are piped to the AP for processing. If the function returns a result, APL halts while the AP is processing and waits for the result. If not it continues processing in parallel.

The syntax of dyadic ⎕SH is similar to the UNIX execl(2) system call, where 'taskname' is the name of the auxiliary processor to be executed and arg0 through argn are the parameters of the calling line to be passed to the task, viz.

      'taskname' ⎕SH 'arg0' 'arg1' ... 'argn'

See Dyalog Programming Reference Guide for further information.

Examples

      'xutils' ⎕SH 'xutils' 'ss' 'dbr'
      '/bin/sh' ⎕SH 'sh' '-c' 'adb test'

Although it is possible for users to create their own APs, Dyalog recommends creating shared libraries/DLLs instead.


Unicode Convert

Unicode Convert R←{X} ⎕UCS Y

⎕UCS converts (Unicode) characters into integers and vice versa.

The optional left argument X is a character vector containing the name of a variable-length Unicode encoding scheme which must be one of:

  • 'UTF-8'
  • 'UTF-16'
  • 'UTF-32'

If not, a DOMAIN ERROR is issued.

If X is omitted, Y is a simple character or integer array, and the result R is a simple integer or character array with the same rank and shape as Y.

If X is specified, Y must be a simple character or integer vector, and the result R is a simple integer or character vector.

Monadic ⎕UCS

Used monadically, ⎕UCS simply converts characters to Unicode code points and vice-versa.

With a few exceptions, the first 256 Unicode code points correspond to the ANSI character set.

      ⎕UCS 'Hello World'
72 101 108 108 111 32 87 111 114 108 100

      ⎕UCS 2 11⍴72 101 108 108 111 32 87 111 114 108 100
Hello World
Hello World

The code points for the Greek alphabet are situated in the 900's:

      ⎕UCS 'καλημέρα'
954 945 955 951 956 941 961 945

Unicode also contains the APL character set. For example:

      ⎕UCS 123 40 43 47 9077 41 247 9076 9077 125
{(+/⍵)÷⍴⍵}

Dyadic ⎕UCS

Dyadic ⎕UCS is used to translate between Unicode characters and one of three standard variable-length Unicode encoding schemes, UTF-8, UTF-16 and UTF-32. These represent a Unicode character string as a vector of 1-byte (UTF-8), 2-byte (UTF-16) and 4-byte (UTF-32) signed integer values respectively.

      'UTF-8' ⎕UCS 'ABC'
65 66 67
      'UTF-8' ⎕UCS 'ABCÆØÅ'
65 66 67 195 134 195 152 195 133
      'UTF-8' ⎕UCS 195 134, 195 152, 195 133
ÆØÅ
      'UTF-8' ⎕UCS 'γεια σου'
206 179 206 181 206 185 206 177 32 207 131 206 191 207 133
      'UTF-16' ⎕UCS 'γεια σου'
947 949 953 945 32 963 959 965
      'UTF-32' ⎕UCS 'γεια σου'
947 949 953 945 32 963 959 965

Because integers are signed, numbers greater than 127 will be represented as 2-byte integers (type 163), and are thus not suitable for writing directly to a native file. To write the above data to file, the easiest solution is to use ⎕UCS to convert the data to 1-byte characters and append this data to the file:

      (⎕UCS 'UTF-8' ⎕UCS 'ABCÆØÅ') ⎕NAPPEND tn

Note regarding UTF-16: For most characters in the first plane of Unicode (0000-FFFF), UTF-16 and UCS-2 are identical. However, UTF-16 has the potential to encode all Unicode characters, by using more than 2 bytes for characters outside plane 1.

      'UTF-16' ⎕UCS 'ABCÆØÅ⍒⍋'
65 66 67 198 216 197 9042 9035
      ⎕←unihan←⎕UCS (2×2*16)+⍳3 ⍝ x20001-x20003

      'UTF-16' ⎕UCS unihan
55360 56321 55360 56322 55360 56323

Translation Error

⎕UCS will generate a DOMAIN ERROR if the argument cannot be converted. Additionally, in the Classic Edition, a TRANSLATION ERROR is generated if the result is not in ⎕AV or the numeric argument is not in ⎕AVU.


Using Microsoft .NET Search Path

Using (Microsoft .NET Search Path) ⎕USING

⎕USING specifies a list of Microsoft .NET Namespaces that are to be searched for a reference to a .NET class.

⎕USING is a vector of character vectors each element of which contains 1 or 2 comma-delimited strings. The first string specifies the name of a .NET namespace; the second specifies the pathname of an assembly file. This may be a full pathname or a relative one, but must include the file extension (.dll). If just the file name is specified, it is assumed to be located in the standard .NET Framework directory that was specified when the .NET Framework was installed (e.g. C:\windows\Microsoft.NET\Framework\v2.0.50727)

It is convenient to treat .NET namespaces and assemblies in pairs. For example:

⎕USING←'System,mscorlib.dll'
  ⎕USING,←⊂'System.Windows.Forms,System.Windows.Forms.dll'  ⎕USING,←⊂'System.Drawing,System.Drawing.dll'

Note that because Dyalog APL automatically loads mscorlib.dll (which contains the most commonly used classes in the System Namespace), it is not actually necessary to specify it explicitly in ⎕USING.

⎕USING has Namespace scope, i.e. each Dyalog APL Namespace, Class or Instance has its own value of ⎕USING that is initially inherited from its parent space but which may be separately modified. ⎕USING may also be localised in a function header, so that different functions can declare different search paths for .NET namespaces/assemblies.

If ⎕USING is empty (⎕USING←0⍴⊂''), APL will not search for .NET classes in order to resolve names which would otherwise give a VALUE ERROR.

Assigning a simple character vector to ⎕USING is equivalent to setting it to the enclose of that vector. The statement (⎕USING←'') does not empty ⎕USING, it sets it to a single empty element, which gives access to mscorlib.dll and the Bridge DLL without a namespace prefix.

Notes

  • The value of ⎕USING is only used when an object is instantiated. Changing the value of ⎕USING has no effect on objects that have already been instantiated in the active workspace.
  • When a workspace containing .Net objects is saved, .the names of the Net objects are saved with it but they are not automatically re-instantiated when the workspace is loaded or copied. A reference to such an orphaned object will report (NULL).

Examples:

  ⎕USING←'System'
  ]display ⎕USING
.→---------.
| .→-----. |
| |System| |
| '------' |
'∊---------'

⎕USING,←⊂'System.Windows.Forms,System.Windows.Forms.dll'
⎕USING,←⊂'System.Drawing,System.Drawing.dll'

An Assembly may contain top-level classes which are not packaged into .NET Namespaces. In this case, you omit the Namespace name. For example:

  ⎕USING←,⊂',.\LoanService.dll'


Verify Fix Input

Verify & Fix Input R←{X}⎕VFI Y

Y must be a simple character scalar or vector. X is optional. If present, X must be a simple character scalar or vector. R is a nested vector of length two whose first item is a simple logical vector and whose second item is a simple numeric vector of the same length as the first item of R.

Y is the character representation of a series of numeric constants. If X is omitted, adjacent numeric strings are separated by one or more blanks. Leading and trailing blanks and separating blanks in excess of one are redundant and ignored. If X is present, X specifies one or more alternative separating characters. Blanks in leading and trailing positions in Y and between numeric strings separated also by the character(s) in X are redundant and ignored. Leading, trailing and adjacent occurrences of the character(s) in X are not redundant. The character 0 is implied in Y before a leading character, after a trailing character, and between each adjacent pair of characters specified by X.

The length of the items of R is the same as the number of identifiable strings (or implied strings) in Y separated by blank or the value of X. An element of the first item of R is 1 where the corresponding string in Y is a valid numeric representation, or 0 otherwise. An element of the second item of R is the numeric value of the corresponding string in Y if it is a valid numeric representation, or 0 otherwise.

Examples

      ⎕VFI '2 -2 ¯2'
 1 0 1  2 0 ¯2

      ⎕VFI '12.1 1E1 1A1 ¯10'
 1 1 0 1  12.1 10 0 ¯10

      ⊃(//⎕VFI'12.1 1E1 1A1 ¯10')
12.1 10 ¯10

      ','⎕VFI'3.9,2.4,,76,'
 1 1 1 1 1  3.9 2.4 0 76 0

      '⋄'⎕VFI'1 ⋄ 2 3 ⋄ 4 '
 1 0 1  1 0 4
      (⍬ ⍬)≡⎕VFI''
1


Attributes

Attributes R←{X} ⎕AT Y

Y can be a simple character scalar, vector or matrix, or a vector of character vectors representing the names of 0 or more defined functions or operators. Used dyadically, this function closely emulates the APL2 implementation. Used monadically, it returns information that is more appropriate for Dyalog APL.

Y specifies one or more names. If Y specifies a single name as a character scalar, a character vector, or as a scalar enclosed character vector, the result R is a vector. If Y specifies one or more names as a character matrix or as a vector of character vectors R is a matrix with one row per name in Y.

Monadic Use

If X is omitted, R is a 4-element vector or a 4 column matrix with the same number of rows as names in Y containing the following attribute information:

R[1] or R[;1]: Each item is a 3-element integer vector representing the function header syntax:

1 | Function result | 0 if the function has no result 1 if the function has an explicit result ¯1 if the function has a shy result
2 | Function valence | 0 if the object is a niladic function or not a function 1 if the object is a monadic function 2 if the object is a dyadic function ¯2 if the object is an ambivalent function
3 | Operator valence | 0 if the object is not an operator 1 if the object is a monadic operator 2 if the object is a dyadic operator

The following values correspond to the syntax shown alongside:

        0  0  0     ∇ FOO
        1  0  0     ∇ Z←FOO
       ¯1  0  0     ∇ {Z}←FOO
        0 ¯2  0     ∇ {A} FOO B
       ¯1  1  2     ∇ {Z}←(F OP G)B

R[2] or R[;2]: Each item is the (⎕TS form) timestamp of the time the function was last fixed.

R[3] or R[;3]: Each item is an integer reporting the current ⎕LOCK state of the function:

0 | Not locked
1 | Cannot display function
2 | Cannot suspend function
3 | Cannot display or suspend

R[4] or R[;4]: Each item is a character vector - the network ID of the user who last fixed (edited) the function.

Example

    ∇ {z}←{l}(fn myop)r
[1]   ...

    ∇ z←foo
[1]   ...

    ∇ z←{larg}util rarg
[1]   ...

      ⎕LOCK'foo'

      util2←util

      ]display ⎕AT 'myop' 'foo' 'util' 'util2'
.→--------------------------------------------.
↓ .→------. .→-----------------.     .→---.   |
| |¯1 ¯2 1| |1996 8 2 2 13 56 0|   0 |john|   |
| '~------' '~-----------------'     '----'   |
| .→----.   .→------------.          .⊖.      |
| |1 0 0|   |0 0 0 0 0 0 0|        3 | |      |
| '~----'   '~------------'          '-'      |
| .→-----.  .→------------------.    .→---.   |
| |1 ¯2 0|  |1996 3 1 14 12 10 0|  0 |pete|   |
| '~-----'  '~------------------'    '----'   |
| .→-----.  .→-------------------.   .→-----. |
| |1 ¯2 0|  |1998 8 26 16 16 42 0| 0 |graeme| |
| '~-----'  '~-------------------'   '------' |
'∊--------------------------------------------'

Dyadic Use

The dyadic form of ⎕AT emulates APL2. It returns the same rank and shape result containing information that matches the APL2 implementation as closely as possible.

The number of elements or columns in R and their meaning depends upon the value of X which may be 1, 2, 3 or 4.

If X is 1, R specifies valences and contains 3 elements (or columns) whose meaning is as follows:

1 | Explicit result | 1 if the object has an explicit result or is a variable 0 otherwise
2 | Function valence | 0 if the object is a niladic function or not a function 1 if the object is a monadic function 2 if the object is an ambivalent function
3 | Operator valence | 0 if the object is not an operator 1 if the object is a monadic operator 2 if the object is a dyadic operator

If X is 2, R specifies fix times (the time the object was last updated) for functions and operators named in Y. The time is reported as 7 integer elements (or columns) whose meaning is as follows. The fix time reported for names in Y which are not defined functions or operators is 0.

1 | Year
2 | Month
3 | Day
4 | Hour
5 | Minute
6 | Second
7 | Milliseconds (this is always reported as 0)

If X is 3, R specifies execution properties and contains 4 elements (or columns) whose meaning is as follows:

1 | Displayable | 0 if the object is displayable 1 if the object is not displayable
2 | Suspendable | 0 if execution will suspend in the object 1 if execution will not suspend in the object
3 | Weak Interrupt behaviour | 0 if the object responds to interrupt 1 if the object ignores interrupt
4 |  | (always 0)

If X is 4, R specifies object size and contains 2 elements (or columns) which both report the ⎕SIZE of the object.


Canonical Representation

Canonical Representation R←⎕CR Y

Y must be a simple character scalar or vector which represents the name of a defined function or operator.

If Y is a name of a defined function or operator, R is a simple character matrix. The first row of R is the function or operator header. Subsequent rows are lines of the function or operator. R contains no unnecessary blanks, except for leading indentation of control structures, trailing blanks that pad each row, and the blanks in comments. If Y is the name of a variable, a locked function or operator, an external function, or is undefined, R is an empty matrix whose shape is 0 0.

Example

      ∇R←MEAN X    ⍝ Arithmetic mean
[1]  R←(+/X)÷⍴X
[2]  ∇
      +F←⎕CR'MEAN'
R←MEAN X    ⍝ Arithmetic mean
R←(+/X)÷⍴X

      ⍴F
2 30

The definition of ⎕CR has been extended to names assigned to functions by specification (←), and to local names of functions used as operands to defined operators.

If Y is a name assigned to a primitive function, R is a one-element vector containing the corresponding function symbol. If Y is a name assigned to a system function, R is a one element nested array containing the name of the system function.

Examples

      PLUS←+
      +F←⎕CR'PLUS'
+
      ⍴F
1
      C←⎕CR
      C'C'
 ⎕CR
      ⍴C'C'
1

      ∇R←CONDITION (FN1 ELSE FN2) X
[1]   →CONDITION/L1
[2]   R←FN2 X ⋄ →0
[3]  L1:R←FN1 X
[4]   ∇

      2 ⎕STOP 'ELSE'
      (X≥0) ⌊ ELSE ⌈ X←¯2.5

ELSE[2]
       X
¯2.5
       ⎕CR'FN2'
⌈
       →⎕LC
¯2

If Y is a name assigned to a derived function, R is a vector whose elements represent the arrays, functions, and operators from which Y was constructed. Constituent functions are represented by their own ⎕CRs, so in this respect the definition of ⎕CR is recursive. Primitive operators are treated like primitive functions, and are represented by their corresponding symbols. Arrays are represented by themselves.

Example

      BOX←2 2∘⍴
      +F←⎕CR'BOX'
 2 2 ∘⍴
      ⍴F
3
      ]display F
.→----------.
| .→--.     |
| |2 2| ∘ ⍴ |
| '~--' - - |
'∊----------'

If Y is a name assigned to a defined function, R is the ⎕CR of the defined function. In particular, the name that appears in the function header is the name of the original defined function, not the assigned name Y.

Example

      AVERAGE←MEAN
      ⎕CR'AVERAGE'
R←MEAN X    ⍝ Arithmetic mean
R←(+/X)÷⍴X


Edit Object

Edit Object {R}←{X}⎕ED Y

⎕ED invokes the Editor. Y is a simple character vector, a simple character matrix, or a vector of character vectors, containing the name(s) of objects to be edited. The optional left argument X is a character scalar or character vector which specifies the type(s) of the corresponding (new) object(s) named in Y, where:

∇ | function/operator
→ | simple character vector
∊ | vector of character vectors
- | character matrix
⍟ | Namespace script
○ | Class script
∘ | Interface

If an object named in Y already exists, the type specification in X is ignored for that name.

If ⎕ED is called from the Session, it opens Edit windows for the object(s) named in Y and returns a null result. The cursor is positioned in the first of the Edit windows opened by ⎕ED, but may be moved to the Session or to any other window which is currently open. The effect is almost identical to using )ED.

If ⎕ED is called from a defined function or operator, its behaviour is different. On asynchronous terminals, the Edit windows are automatically displayed in "full-screen" mode (ZOOMED). In all implementations, the user is restricted to those windows named in Y. The user may not skip to the Session even though the Session may be visible.

⎕ED terminates and returns a result ONLY when the user explicitly closes all the windows for the named objects. In this case the result contains the names of any objects which have been newly (re)fixed in the workspace as a result of the ⎕ED, and has the same structure as Y.

Objects named in Y that cannot be edited are silently ignored. Objects qualified with a namespace path are (e.g. a.b.c.foo) are silently ignored if the namespace does not exist.

Variants of Edit Object

The behaviour of ⎕ED may be modified using the variant operator ⍠ with the following options:

  • 'ReadOnly' - 0 or 1
  • 'EditName' - 'Default', 'Allow' or 'Disallow'.

If ReadOnly is set to 1, the edit window and all edit windows opened from it will be read-only. Note that setting ReadOnly to 0 will have no effect if the edit window is inherently read-only due to the nature of its content.

The 'EditName' option determines whether or not the user may open another edit window by clicking a name, and its values are interpreted as follows:

EditName | ⎕ED called from session | ⎕ED called from function
'Default' | Allow | Disallow
'Allow' | Allow | Allow
'Disallow' | Disallow | Disallow

There is no Principal Option.

Examples

      A←3 11⍴'Hello World'

In the first example, ⎕ED will display the contents of A as an editable character array which the user may change. The user can double-click on Hello to open an edit window on an object named Hello (which will be a new function if Hello is currently undefined). Furthermore, the user can enter any arbitrary name and double-click to edit it. This may be undesirable in an application.

      ⎕ED 'A'

In the second example, the Edit window will display the contents of A as a ReadOnly Character array. The user can still open a new edit by double-clicking Hello or World but nothing else.

      (⎕ED ⍠ 'ReadOnly' 1) 'A'

In the final example, the Edit window will display the contents of A as a ReadOnly Character array and the user cannot open a new edit window.

      (⎕ED ⍠('ReadOnly' 1)('EditName' 'Disallow'))'A'


Expunge Object

Expunge Object {R}←⎕EX Y

Y must be a simple character scalar, vector or matrix, or a vector of character vectors containing a list of names. R is a simple Boolean vector with one element per name in Y.

Each name in Y is disassociated from its value if the active referent for the name is a defined function, operator, variable or namespace.

The value of an element of R is 1 if the corresponding name in Y is now available for use. This does not necessarily mean that the existing value was erased for that name. A value of 0 is returned for an ill-formed name or for a distinguished name in Y. The result is suppressed if not used or assigned.

Examples

      ⎕EX'VAR'
      +⎕EX'FOO' '⎕IO' 'X' '123'
1 0 1 0

If a named object is being executed the existing value will continue to be used until its execution is completed. However, the name becomes available immediately for other use.

Examples

      )SI
#.FOO[1]*

      ⎕VR'FOO'
     ∇ R←FOO
[1]    R←10
     ∇
      +⎕EX'FOO'
1
      )SI
#.FOO[1]*

     ∇FOO[⎕]
defn error

      FOO←1 2 3
      →⎕LC
10
      FOO
1 2 3

If a named object is an external variable, the external array is disassociated from the name:

      ⎕XT'F'
FILES/COSTS
      ⎕EX'F' ⋄ ⎕XT'F'

If the named object is a GUI object, the object and all its children are deleted and removed from the screen. The expression ⎕EX'.' deletes all GUI objects owned by the current thread in the Root namespace but not those in sub-namespaces. In addition, if this expression is executed by thread 0, it resets all the properties of '.' to their default values. Furthermore, any unprocessed events in the event queue are discarded.

If the named object is a shared variable, the variable is retracted.

If the named object is the last remaining external function of an auxiliary process, the AP is terminated.

If the named object is the last reference into a dynamic link library, the DLL is freed.


Fix Definition

Fix Definition {R}←⎕FX Y

Y is the representation form of a function or operator which may be:

  • its canonical representation form similar to that produced by ⎕CR except that redundant blanks are permitted other than within names and constants, and the first and last rows may start with a del symbol (∇).
  • its nested representation form similar to that produced by ⎕NR except that redundant blanks are permitted other than within names and constants, and the first and last items may be del (∇) symbols.
  • its object representation form produced by ⎕OR.
  • its vector representation form similar to that produced by ⎕VR except that additional blanks are permitted other than within names and constants.

⎕FX attempts to create (fix) a function or operator in the workspace or current namespace from the definition given by Y. ⎕IO is an implicit argument of ⎕FX. Note that ⎕FX does not update the source of a scripted namespace, or of class or instance; the only two methods of updating the source of scripted objects is via the Editor, or by calling ⎕FIX.

If the function or operator is successfully fixed, R is a simple character vector containing its name and the result is shy. Otherwise R is an integer scalar containing the (⎕IO dependent) index of the row of the canonical representation form in which the first error preventing its definition is detected. In this case the result R is not shy.

Functions and operators which are pendent, that is, in the state indicator without a suspension mark (*), retain their original definition until they complete, or are cleared from the state indicator. All other occurrences of the function or operator assume the new definition. The function or operator will fail to fix if it has the same name as an existing variable, or a visible label.


Lock Definition

Lock Definition {R}←{X}⎕LOCK Y

Y must be a simple character scalar, or vector which is taken to be the name of a defined function or operator in the active workspace. ⎕LOCK does not apply to dfns or derived functions.

The active referent to the name in the workspace is locked. Stop, trace and monitor settings, established by the ⎕STOP, ⎕TRACE and ⎕MONITOR functions, are cancelled.

The optional left argument X specifies to what extent the function code is hidden. X may be 1, 2 or 3 (the default) with the following meaning:

  1. The object may not be displayed and you may not obtain its character form using ⎕CR, ⎕VR or ⎕NR.
  2. Execution cannot be suspended with the locked function or operator in the state indicator. On suspension of execution the state indicator is cut back to the statement containing the call to the locked function or operator.
  3. Both 1 and 2 apply. You can neither display the locked object nor suspend execution within it.

Locks are additive, so that

      1 ⎕LOCK'FOO' ⋄ 2 ⎕LOCK'FOO'

is equivalent to:

      3 ⎕LOCK'FOO'

The shy result R is the lock state (1,2 or 3) of Y.

A DOMAIN ERROR is reported if Y is ill-formed.

Examples

      ⎕FX'r←foo' 'r←10'
      ⎕NR'foo'
  r←foo r←10
      ⍴⎕NR'foo'
2
      ⎕LOCK'foo'
      ⍴⎕NR'foo'
0


Nested Representation

Nested Representation R←⎕NR Y

Y must be a simple character scalar or vector which represents the name of a function or a defined operator.

If Y is a name of a defined function or defined operator, R is a vector of text vectors. The first element of R contains the text of the function or operator header. Subsequent elements contain lines of the function or operator. Elements of R contain no unnecessary blanks, except for leading indentation of control structures and the blanks which precede comments.

If Y is the name of a variable, a locked function or operator, an external function or a namespace, or is undefined, R is an empty vector.

Example

      ∇R←MEAN X    ⍝ Average
[1]   R←(+/X)÷⍴X
      ∇

      +F←⎕NR'MEAN'
  R←MEAN X    ⍝Average   R←(+/X)÷⍴X

      ⍴F
2
      ]display F
.→----------------------------------------.
| .→---------------------.  .→----------. |
| | R←MEAN X    ⍝ Average|  | R←(+/X)÷⍴X| |
| '----------------------'  '-----------' |
'∊----------------------------------------'

The definition of ⎕NR has been extended to names assigned to functions by specification (←), and to local names of functions used as operands to defined operators. In these cases, the result of ⎕NR is identical to that of ⎕CR except that the representation of defined functions and operators is as described above.

Example

      AVG←MEAN∘,

      +F←⎕NR'AVG'
   R←MEAN X    ⍝ Average   R←(+/X)÷⍴X  ∘,

      ⍴F
3
      ]display F
.→------------------------------------------------.
| .→----------------------------------------.     |
| | .→---------------------.  .→----------. | ∘ , |
| | | R←MEAN X    ⍝ Average|  | R←(+/X)÷⍴X| | - - |
| | '----------------------'  '-----------' |     |
| '∊----------------------------------------'     |
'∊------------------------------------------------'


Profile Application

Profile Application {R}←{X}⎕PROFILE Y

⎕PROFILE facilitates the profiling of either CPU consumption or elapsed time for a workspace. It does so by retaining time measurements collected for APL functions/operators and function/operator lines. ⎕PROFILE is used to both control the state of profiling and retrieve the collected profiling data.

Y specifies the action to perform and any options for that action, if applicable. Y is case-insensitive. Note that the result R is in some cases shy.

Use | Description
{state}←⎕PROFILE 'start' {timer} | Turn profiling on using the specified timer or resume if profiling was stopped
{state}←⎕PROFILE 'stop' | Suspend the collection of profiling data
{state}←⎕PROFILE 'clear' | Turn profiling off, if active, and discard any collected profiling data
{state}←⎕PROFILE 'calibrate' | Calibrate the profiling timer
state←⎕PROFILE 'state' | Query profiling state
data←⎕PROFILE 'data' | Retrieve profiling data in flat form
data←⎕PROFILE 'tree' | Retrieve profiling data in tree form

⎕PROFILE has 2 states:

  • active – the profiler is running and profiling data is being collected.
  • inactive – the profiler is not running.

For most actions, the result of ⎕PROFILE is its current state and contains:

[1] | character vector indicating the ⎕PROFILE state having one of the values 'active' or 'inactive'
[2] | character vector indicating the timer being used having one of the values 'CPU' or 'elapsed'
[3] | call time bias in milliseconds. This is the amount of time, in milliseconds, that is consumed for the system to take a time measurement
[4] | timer granularity in milliseconds. This is the resolution of the timer being used

{state}←⎕PROFILE 'start' {timer}

Turn profiling on; timer is an optional case-independent character vector containing 'CPU' or 'elapsed' or 'none' or 'coverage'. If omitted, it defaults to 'CPU'. If timer is 'none', ⎕PROFILE records just the number of times each line of code is executed without incurring the timing overhead. If timer is 'coverage', ⎕PROFILE only identifies which lines of code are executed without incurring the timing or counting overhead.

The first time a particular timer is chosen, ⎕PROFILE will spend 1000 milliseconds (1 second) to approximate the call time bias and granularity for that timer.

      ⊢⎕PROFILE 'start' 'CPU'
 active  CPU  0.0001037499999 0.0001037499999

{state}←⎕PROFILE 'stop'

Suspends the collection of profiling data.

      ⊢⎕PROFILE 'stop'
 inactive  CPU  0.0001037499999 0.0001037499999

{state}←⎕PROFILE 'clear'

Clears any collected profiling data and, if profiling is active, places profiling in an inactive state.

      ⊢⎕PROFILE 'clear'
 inactive    0 0

{state}←⎕PROFILE 'calibrate'

Causes ⎕PROFILE to perform a 1000 millisecond calibration to approximate the call time bias and granularity for the current timer. Note, a timer must have been previously selected by using ⎕PROFILE 'start'.

⎕PROFILE will retain the lesser of the current timer values compared to the new values computed by the calibration. The rationale for this is to use the smallest possible values of which we can be certain.

      ⊢⎕PROFILE'calibrate'
 active  CPU  0.0001037499997 0.0001037499997

state←⎕PROFILE 'state'

Returns the current profiling state.

      )clear
clear ws
      ⎕PROFILE 'state'
 inactive    0 0

      ⎕PROFILE 'start' 'CPU'
 active  CPU  0.0001037499997 0.0001037499997
      ⎕PROFILE 'state'
 active  CPU  0.0001037499997 0.0001037499997

data←{X} ⎕PROFILE 'data'

Retrieves the collected profiling data. If the optional left argument X is omitted, the result is a matrix with the following columns:

[;1] | function name
[;2] | function line number or ⍬ for a whole function entry
[;3] | number of times the line or function was executed
[;4] | accumulated time (ms) for this entry exclusive of items called by this entry
[;5] | accumulated time (ms) for this entry inclusive of items called by this entry
[;6] | number of times the timer function was called for the exclusive time
[;7] | number of times the timer function was called for the inclusive time

Example: (numbers have been truncated for formatting)

      ⎕PROFILE 'data'
#.foo             1  1.04406  39347.64945   503 4080803
#.foo      1      1  0.12488     0.124887     1       1
#.foo      2    100  0.58851 39347.193900   200 4080500
#.foo      3    100  0.21340     0.213406   100     100
#.NS1.goo       100 99.44404   39346.6053 50300 4080300
#.NS1.goo  1    100  0.61679     0.616793   100     100
#.NS1.goo  2  10000 67.80292   39314.9642 20000 4050000
#.NS1.goo  3  10000 19.60274      19.6027 10000   10000

If X is specified it must be a simple vector of column indices. In this case, the result has the same shape as X and is a vector of the specified column vectors:

X ⎕PROFILE 'data' ←→ ↓[⎕IO](⎕PROFILE 'data')[;X]

If column 2 is included in the result, the value ¯1 is used instead of ⍬ to indicate a whole-function entry.

data←{X} ⎕PROFILE 'tree'

Retrieve the collected profiling data in tree format:

[;1] | depth level
[;2] | function name
[;3] | function line number or ⍬ for a whole function entry
[;4] | number of times the line or function was executed
[;5] | accumulated time (ms) for this entry exclusive of items called by this entry
[;6] | accumulated time (ms) for this entry inclusive of items called by this entry
[;7] | number of times the timer function was called for the exclusive time
[;8] | number of times the timer function was called for the inclusive time

The optional left argument is treated in exactly the same way as for X ⎕PROFILE 'data'.

Example:

      ⎕PROFILE 'tree'
0  #.foo               1     1.04406 39347.64945     503 4080803
1  #.foo      1        1     0.12488     0.12488       1       1
1  #.foo      2      100     0.58851 39347.19390     200 4080500
2  #.NS1.goo         100    99.44404 39346.60538   50300 4080300
3  #.NS1.goo  1      100     0.61679     0.61679     100     100
3  #.NS1.goo  2    10000    67.80292 39314.96426   20000 4050000
4  #.NS2.moo       10000 39247.16133 39247.16133 4030000 4030000
5  #.NS2.moo  1    10000    39.28315    39.28315   10000   10000
5  #.NS2.moo  2  1000000 36430.65236 36430.65236 1000000 1000000
5  #.NS2.moo  3  1000000  1645.36214  1645.36214 1000000 1000000
3  #.NS1.goo  3    10000    19.60274    19.60274   10000   10000
1  #.foo      3      100     0.21340     0.21340     100     100

Note that rows with an even depth level in column [;1] represent function summary entries and odd depth level rows are function line entries. Recursive functions will generate separate rows for each level of recursion.

Notes

Profile Data Entry Types

The results of ⎕PROFILE 'data' and ⎕PROFILE 'tree' have two types of entries; function summary entries and function line entries. Function summary entries contain ⍬ in the line number column, whereas function line entries contain the line number. Dfns line entries begin with 0 as they do not have a header line like traditional functions. The timer data and timer call counts in function summary entries represent the aggregate of the function line entries plus any time spent that cannot be directly attributed to a function line entry. This could include time spent during function initialisation, etc.

Example:

 #.foo         1  1.04406 39347.649450   503 4080803
 #.foo    1    1  0.12488     0.124887     1       1
 #.foo    2  100  0.58851 39347.193900   200 4080500
 #.foo    3  100  0.21340     0.213406   100     100

Timer Data Persistence

The profiling data collected is stored outside the workspace and will not impact workspace availability. The data is cleared upon workspace load, clear workspace, ⎕PROFILE 'clear', or interpreter sign off.

The PROFILE User Command

]PROFILE is a utility which implements a high-level interface to ⎕PROFILE and provides reporting and analysis tools that act upon the profiling data. For further information, see Tuning Applications using the Profile User Command.

Using ⎕PROFILE Directly

If you choose to use ⎕PROFILE directly, the following guidelines and information may be of use to you.

Note: Running your application with ⎕PROFILE turned on incurs a significant processing overhead and will slow your application down.

Decide which timer to use

⎕PROFILE supports profiling of either CPU or elapsed time. CPU time is generally of more interest in profiling application performance.

Simple Profiling

To get a quick handle on the top CPU time consumers in an application, use the following procedure:

  • Make sure the application runs long enough to collect enough data to overcome the timer granularity – a reasonable rule of thumb is to make sure the application runs for at least (4000×4⊃⎕PROFILE 'state') milliseconds.
  • Turn profiling on with ⎕PROFILE 'start' CPU
  • Run your application.
  • Pause the profiler with ⎕PROFILE 'stop'
  • Examine the profiling data from ⎕PROFILE 'data' or ⎕PROFILE 'tree' for entries that consume large amounts of resource.

This should identify any items that take more than 10% of the run time.

To find finer time consumers, or to focus on elapsed time rather than CPU time, take the following additional steps prior to running the profiler:

Turn off as much hardware as possible. This would include peripherals, network connections, etc.

  • Turn off as many other tasks and processes as possible. These include anti-virus software, firewalls, internet services, background tasks.
  • Raise the priority on the Dyalog APL task to higher than normal, but in general avoid giving it the highest priority.
  • Run the profiler as described above.

Doing this should help identify items that take more than 1% of the run time.

Advanced Profiling

The timing data collected by ⎕PROFILE is not adjusted for the timer's call time bias; in other words, the times reported by ⎕PROFILE include the time spent calling the timer function. One effect of this can be to make "cheap" lines that are called many times seem to consume more resource. If you desire more accurate profiling measurements, or if your application takes a short amount of time to run, you will probably want to adjust for the timer call time bias. To do so, subtract from the timing data the timer's' 'call time bias multiplied by the number of times the timer was called.

Example:

      CallTimeBias←3⊃⎕PROFILE 'state'
      RawTimes←⎕PROFILE 'data'
      Adjusted←RawTimes[;4 5]-RawTimes[;6 7]×CallTimeBias


Cross References

Cross References R←⎕REFS Y

Y must be a simple character scalar or vector, identifying the name of a function or operator, or the object representation form of a function or operator (see Object Representation ). R is a simple character matrix, with one name per row, of identified names in the function or operator in Y excluding distinguished names of system constants, variables or functions.

Example

      ⎕VR'OPTIONS'
     ∇ OPTIONS;OPTS;INP
[1]   ⍝ REQUESTS AND EXECUTES AN OPTION
[2]    OPTS ←'INPUT' 'REPORT' 'END'
[3]   IN:INP←ASK'OPTION:'
[4]    →EX⍴⍨(⊂INP)∊OPTS
[5]    'INVALID OPTION. SELECT FROM',OPTS ⋄ →IN
[6]   EX:→EX+OPTS⍳⊂INP
[7]    INPUT ⋄ →IN
[8]    REPORT ⋄ →IN
[9]   END:
     ∇

    ⎕REFS'OPTIONS'
ASK
END
EX
IN
INP
INPUT
OPTIONS
OPTS
REPORT

If Y is locked or is an External Function, R contains its name only. For example:

      ⎕LOCK 'OPTIONS' ⋄ ⎕REFS 'OPTIONS'
OPTIONS

If Y is the name of a primitive, external or derived function, R is an empty matrix with shape 0 0.


Set Stop

Set Stop {R}←X ⎕STOP Y

Y must be a simple character scalar or vector which is taken to be the name of a visible defined function or operator. X must be a simple non-negative integer scalar or vector. R is a simple integer vector of non-negative elements. X identifies the numbers of lines in the function or operator named by Y on which a stop control is to be placed. Numbers outside the range of line numbers in the function or operator (other than 0) are ignored. The number 0 indicates that a stop control is to be placed immediately prior to exit from the function or operator. If X is empty, all existing stop controls are cancelled. The value of X is independent of ⎕IO.

R is a vector of the line numbers on which a stop control has been placed in ascending order. The result is suppressed unless it is explicitly used or assigned.

Examples

      ⊢(0,⍳10) ⎕STOP 'FOO'
0 1

Existing stop controls in the function or operator named by Y are cancelled before new stop controls are set:

      ⊢1 ⎕STOP 'FOO'
1

All stop controls may be cancelled by giving X an empty vector:

      ⍴'' ⎕STOP 'FOO'
0

      ⍴⍬ ⎕STOP 'FOO'
0

Attempts to set stop controls in a locked function or operator are ignored.

      ⎕LOCK'FOO'

      ⊢0 1 ⎕STOP'FOO'

The effect of ⎕STOP when a function or operator is invoked is to suspend execution at the beginning of any line in the function or operator on which a stop control is placed immediately before that line is executed, and immediately before exiting from the function or operator if a stop control of 0 is set. Execution may be resumed by a branch expression. A stop control interrupt (1001) may also be trapped - see Trap Event .

Example

      ⎕FX'R←FOO' 'R←10'

      0 1 ⎕STOP'FOO'

      FOO
FOO[1]

      R
VALUE ERROR
      R
      ^

      →1
FOO[0]

      R
10

      →⎕LC
10


Query Stop

Query Stop R←⎕STOP Y

Y must be a simple character scalar or vector which is taken to be the name of a visible defined function or operator. R is a simple non-negative integer vector of the line numbers of the function or operator named by Y on which stop controls are set, shown in ascending order. The value 0 in R indicates that a stop control is set immediately prior to exit from the function or operator.

Example

      ⎕STOP'FOO'
0 1


Set Trace

Set Trace {R}←X ⎕TRACE Y

Y must be a simple character scalar or vector which is taken to be the name of a visible defined function or operator. X must be a simple non-negative integer scalar or vector.

X identifies the numbers of lines in the function or operator named by Y on which a trace control is to be placed. Numbers outside the range of line numbers in the function or operator (other than 0) are ignored. The number 0 indicates that a trace control is to be placed immediately prior to exit from the function or operator. The value of X is independent of ⎕IO.

R is a simple integer vector of non-negative elements indicating the lines in the function or operator on which a trace control has been placed.

Example

      +(0,⍳10) ⎕TRACE'FOO'
0 1

Existing trace controls in the function or operator named by Y are cancelled before new trace controls are set:

      + 1 ⎕TRACE'FOO'
1

All trace controls may be cancelled by giving X an empty vector:

      ⍴⍬ ⎕TRACE 'FOO'
0

Attempts to set trace controls in a locked function or operator are ignored.

      ⎕LOCK 'FOO'
      +1 ⎕TRACE 'FOO'

The effect of trace controls when a function or operator is invoked is to display the result of each complete expression for lines with trace controls as they are executed, and the result of the function if trace control 0 is set. If a line contains expressions separated by ⋄, the result of each complete expression is displayed for that line after execution.

The result of a complete expression is displayed even where the result would normally be suppressed. In particular:

  • the result of a branch statement is displayed;
  • the result (pass-through value) of assignment is displayed;
  • the result of a function whose result would normally be suppressed is displayed;

For each traced line, the output from ⎕TRACE is displayed as a two element vector, the first element of which contains the function or operator name and line number, and the second element of which takes one of two forms.

  • The result of the line, displayed as in standard output.
  • → followed by a line number.

Example

      ⎕VR 'DSL'
     ∇ R←DSL SKIP;A;B;C;D
[1]    A←2×3+4
[2]    B←(2 3⍴'ABCDEF')A
[3]    →NEXT×⍳SKIP
[4]    'SKIPPED LINE'
[5]   NEXT:C←'one' ⋄ D←'two'
[6]   END:R←C D
     ∇

      (0,⍳6) ⎕TRACE 'DSL'

      DSL 1
 DSL[1]  14
 DSL[2]   ABC   14
          DEF
 DSL[3]  →5
 DSL[5]  one
 DSL[5]  two
 DSL[6]   one   two
 DSL[0]   one   two
 one  two


Query Trace

Query Trace R←⎕TRACE Y

Y must be a simple character scalar or vector which is taken to be the name of a visible defined function or operator. R is a simple non-negative integer vector of the line numbers of the function or operator named by Y on which trace controls are set, shown in ascending order. The value 0 in R indicates that a trace control is set to display the result of the function or operator immediately prior to exit.

Example

      ⎕TRACE'DSL'
0 1 2 3 4 5 6


Vector Representation

Vector Representation R←⎕VR Y

Y must be a simple character scalar or vector which represents the name of a function or defined operator.

If Y is the name of a defined function or defined operator, R is a simple character vector containing a character representation of the function or operator with each line except the last terminated by the newline character (⎕UCS ⎕AVU[4]).

Its display form is as follows:

  1. the header line starts at column 8 with the ∇ symbol in column 6,
  2. the line number for each line of the function starts in column 1,
  3. the statement contained in each line starts at column 8 except for labelled lines or lines beginning with ⍝ which start at column 7,
  4. the header line and statements contain no redundant blanks beyond column 7 except that the ⋄ separator is surrounded by single blanks, control structure indentation is preserved and comments retain embedded blanks as originally defined,
  5. the last line shows only the ∇ character in column 6.

If Y is the name of a variable, a locked function or operator, an external function, or is undefined, R is an empty vector.

Example

      ⍴V←⎕VR'PLUS'
128

      V
     ∇ R←{A}PLUS B
[1]   ⍝ MONADIC OR DYADIC +
[2]    →DYADIC⍴⍨2=⎕NC'A' ⋄ R←B ⋄ →END
[3]   DYADIC:R←A+B ⋄ →END
[4]   END:
     ∇

The definition of ⎕VR has been extended to names assigned to functions by specification (←), and to local names of functions used as operands to defined operators. In these cases, the result of ⎕VR is identical to that of ⎕CR except that the representation of defined functions and operators is as described above.

Example

      AVG←MEAN∘,

      +F←⎕VR'AVG'
      ∇ R←MEAN X    ⍝ Arithmetic mean
[1]     R←(+/X)÷⍴X
     ∇ ∘,

      ⍴F
3

      ]display F
┌→───────────────────────────────────────────┐
│ ┌→───────────────────────────────────┐     │
│ │     ∇ R←MEAN X    ⍝ Arithmetic mean│ ∘ , │
│ │[1]    R←(+/X)÷⍴X                   │ - - │
│ │     ∇                              │     │
│ └────────────────────────────────────┘     │
└∊───────────────────────────────────────────┘


Base Class

Base Class R←⎕BASE.Y

⎕BASE is used to access the base class implementation of the name specified by Y.

Y must be the name of a Public member (Method, Field or Property) that is provided by the Base Class of the current Class or Instance.

⎕BASE is typically used to call a method in the Base Class which has been superseded by a Method in the current Class.

Note that ⎕BASE.Y is special syntax and any direct reference to ⎕BASE on its own or in any other context, is meaningless and causes SYNTAX ERROR.

In the following example, Class DomesticParrot derives from Class Parrot and supersedes its Speak method. DomesticParrot.Speak calls the Speak method in its Base Class Parrot, via ⎕BASE.

:Class Parrot: Bird
    ∇ R←Speak
      :Access Public
      R←'Squark!'
    ∇
:EndClass ⍝ Parrot

:Class DomesticParrot: Parrot
    ∇ R←Speak
      :Access Public
      R←⎕BASE.Speak,' Who''s a pretty boy, then!'
    ∇
:EndClass ⍝ DomesticParrot

      Maccaw←⎕NEW Parrot
      Maccaw.Speak
Squark!

      Polly←⎕NEW DomesticParrot
      Polly.Speak
Squark! Who's a pretty boy, then!


Class

Class R←{X}⎕CLASS Y

Monadic Case

Monadic ⎕CLASS returns a list of references to Classes and Interfaces that specifies the class hierarchy for the Class or Instance specified by Y.

Y must be a reference to a Class or to an Instance of a Class.

R is a vector of vectors whose items represent nodes in the Class hierarchy of Y. Each item of R is a vector whose first item is a Class reference and whose subsequent items (if any) are references to the Interfaces supported by that Class.

Example 1

This example illustrates a simple inheritance tree or Class hierarchy. There are 3 Classes, namely:

Animal

Bird (derived from Animal)

Parrot (derived from Bird)

:Class Animal
...
:EndClass ⍝ Animal

:Class Bird: Animal
...
:EndClass ⍝ Bird

:Class Parrot: Bird
...
:EndClass ⍝ Parrot
       ⎕CLASS Eeyore←⎕NEW Animal
  #.Animal
       ⎕CLASS Robin←⎕NEW Bird
  #.Bird    #.Animal
       ⎕CLASS Polly←⎕NEW Parrot
  #.Parrot    #.Bird    #.Animal

      ⎕CLASS¨ Parrot Animal
   #.Parrot    #.Bird    #.Animal      #.Animal

Example 2

The Penguin Class example (seePenguin Class Example) illustrates the use of Interfaces.

In this case, the Penguin Class derives from Animal (as above) but additionally supports the BirdBehaviour and FishBehaviour Interfaces, thereby inheriting members from both.

      Pingo←⎕NEW Penguin
      ⎕CLASS Pingo
  #.Penguin  #.FishBehaviour  #.BirdBehaviour    #.Animal

Dyadic Case

If X is specified, Y must be a reference to an Instance of a Class and X is a reference to an Interface that is supported by Instance Y or to a Class upon which Instance Y is based.

In this case, R is a reference to the implementation of Interface X by Instance Y, or to the implementation of (Base) Class X by Instance Y, and is used as a cast in order to access members of Y that correspond to members of Interface of (Base) Class X.

Example 1:

Once again, the Penguin Class example (seePenguin Class Example) is used to illustrate the use of Interfaces.

      Pingo←⎕NEW Penguin
      ⎕CLASS Pingo
  #.Penguin  #.FishBehaviour  #.BirdBehaviour    #.Animal

      (FishBehaviour ⎕CLASS Pingo).Swim
I can dive and swim like a fish
      (BirdBehaviour ⎕CLASS Pingo).Fly
Although I am a bird, I cannot fly
      (BirdBehaviour ⎕CLASS Pingo).Lay
I lay one egg every year
      (BirdBehaviour ⎕CLASS Pingo).Sing
Croak, Croak!

Example 2:

This example illustrates the use of dyadic ⎕CLASS to cast an Instance to a lower Class and thereby access a member in the lower Class that has been superseded by another Class higher in the tree.

      Polly←⎕NEW DomesticParrot
      Polly.Speak
Squark! Who's a pretty boy, then!

Note that the Speak method invoked above is the Speak method defined by Class DomesticParrot, which supersedes the Speak methods of sub-classes Parrot and Bird.

You may use a cast to access the (superseded) Speak method in the sub-classes Parrot and Bird.

      (Parrot ⎕CLASS Polly).Speak
Squark!
      (Bird ⎕CLASS Polly).Speak
Tweet, tweet!


Change Space

Change Space {R}←{X}⎕CS Y

Y must be namespace reference (ref) or a simple character scalar or vector identifying the name of a namespace.

If specified, X is a simple character scalar, vector, matrix or a nested vector of character vectors identifying zero or more workspace objects to be exported into the namespace Y.

The identifiers in X and Y may be simple names or compound names separated by '.' and including the names of the special namespaces '⎕SE', '#', and '##'.

The result R is the full name (starting #.) of the space in which the function or operator was executing prior to the ⎕CS.

⎕CS changes the space in which the current function or operator is running to the namespace Y and returns the original space, in which the function was previously running, as a shy result. After the ⎕CS, references to global names (with the exception of those specified in X) are taken to be references to global names in Y. References to local names (i.e. those local to the current function or operator) are, with the exception of those with name class 9, unaffected. Local names with name class 9 are however no longer visible.

When the function or operator terminates, the calling function resumes execution in its original space.

The names listed in X are temporarily exported to the namespace Y. If objects with the same name exist in Y, these objects are effectively shadowed and are inaccessible. Note that Dyadic ⎕CS may be used only if there is a traditional function in the state indicator (stack). Otherwise there would be no way to retract the export. In this case (for example in a clear workspace) DOMAIN ERROR is reported.

Note that calling ⎕CS with an empty argument Y obtains the namespace in which a function is currently executing.

Example

This simple example illustrates how ⎕CS may be used to avoid typing long pathnames when building a tree of GUI objects. Note that the objects NEW and OPEN are created as children of the FILE menu as a result of using ⎕CS to change into the F.MB.FILE namespace.

     ∇ MAKE_FORM;F;OLD
[1]    'F'⎕WC'Form'
[2]    'F.MB'⎕WC'MenuBar'
[3]    'F.MB.FILE'⎕WC'Menu' '&File'
[4]
[5]    OLD←⎕CS'F.MB.FILE'
[6]    'NEW'⎕WC'MenuItem' '&New'
[7]    'OPEN'⎕WC'MenuItem' '&Open'
[8]    ⎕CS OLD
[9]
[10]   'F.MB.EDIT'⎕WC'Menu' '&Edit'
[11]
[12]   OLD←⎕CS'F.MB.EDIT'
[13]   'UNDO'⎕WC'MenuItem' '&Undo'
[14]   'REDO'⎕WC'MenuItem' '&Redo'
[15]   ⎕CS OLD
[16]   ...
     ∇

Example

Suppose a form F1 contains buttons B1 and B2. Each button maintains a count of the number of times it has been pressed, and the form maintains a count of the total number of button presses. The single callback function PRESS and its subfunction FMT can reside in the form itself

      )CS F1
#.F1
      ⍝ Note that both instances reference
      ⍝ the same callback function
      'B1'⎕WS'Event' 'Select' 'PRESS'
      'B2'⎕WS'Event' 'Select' 'PRESS'

      ⍝ Initialise total and instance counts.
      TOTAL ← B1.COUNT ← B2.COUNT ← 0

    ∇ PRESS MSG
[1]   'FMT' 'TOTAL'⎕CS⊃MSG ⍝     Switch to instance space
[2]   (TOTAL COUNT)+←1   ⍝    Incr total & instance count
[3]   ⎕WS'Caption'(COUNT FMT TOTAL)⍝ Set instance caption
    ∇

    ∇ CAPT←INST FMT TOTL      ⍝ Format button caption.
[1]   CAPT←(⍕INST),'/',⍕TOTL  ⍝ E.g. 40/100.
    ∇

Example

This example uses ⎕CS to explore a namespace tree and display the structure. Note that it must export its own name (tree) each time it changes space, because the name tree is global.

      ∇ tabs tree space;subs     ⍝ Display namespace tree
[1]    tabs,space
[2]    'tree'⎕CS space
[3]    →(⍴subs←↓⎕NL 9)↓0
[4]    (tabs,'.   ')∘tree¨subs
     ∇

      )ns x.y
#.x.y
      )ns z
#.z
      ''tree '#'
#
.   x
.   .   y
.   z

Note

⎕CS is not permitted in a dfn or dop. If used therein it will cause a NONCE ERROR.


Display Form

Display Form {R}←⎕DF Y

⎕DF sets the Display Form of a namespace, a GUI object, a Class, or an Instance of a Class.

Y must be ⎕NULL or a simple character array that specifies the display form of a namespace. If defined, this array will be returned by the format functions and ⎕FMT instead of the default for the object in question. This also applies to the string that is displayed when the name is referenced but not assigned (the default display). If Y is ⎕NULL, ⎕DF resets the Display Form to the default.

The result R is the previous value of the Display Form which initially is ⎕NULL.

      'F'⎕WC'Form'
      ⍕F
#.F
      ⍴⍕F
3
      ⎕FMT F
#.F
      ⍴⎕FMT F
1 3
      F ⍝ default display uses ⍕
#.F

      F.⎕DF 'Pete''s Form'
      ⍕F
Pete's Form
      ⍴⍕F
11
      ⎕FMT F
Pete's Form
      ⍴⎕FMT F
1 11

Notice that ⎕DF will accept any character array, but ⎕FMT always returns a matrix.

      F.⎕DF 2 2 5⍴⎕A
      F
ABCDE
FGHIJ

KLMNO
PQRST
      ⍴⍕F
2 2 5

      ⍴⎕←⎕FMT F
ABCDE
FGHIJ

KLMNO
PQRST
5 5

Note that ⎕DF defines the Display Form statically, rather than dynamically.

      'F'⎕WC'Form' 'This is the Caption'
      F
#.F

      F.(⎕DF Caption)⍝ set display form to current caption
      F
This is the Caption

      F.Caption←'New Caption' ⍝ changing caption does not
                              ⍝ change the display form
      F
This is the Caption

You may use the Constructor function to assign the Display Form to an Instance of a Class. For example:

:Class MyClass
    ∇ Make arg
      :Access Public
      :Implements Constructor
      ⎕DF arg
    ∇
:EndClass ⍝ MyClass

      PD←⎕NEW MyClass 'Pete'
      PD
Pete

It is possible to set the Display Form for the Root and for ⎕SE

      )CLEAR
clear ws
      #
#
      ⎕DF ⎕WSID
      #
CLEAR WS

      ⎕SE
⎕SE
      ⎕SE.⎕DF 'Session'
      ⎕SE
Session

Note that ⎕DF applies directly to the object in question and is not automatically applied in a hierarchical fashion.

      'X'⎕NS ''
      X
#.X

      'Y'X.⎕NS ''
      X.Y
#.X.Y
      X.⎕DF 'This is X'
      X
This is X

      X.Y
#.X.Y


Fix Script

Fix Script {R}←{X}⎕FIX Y

⎕FIX establishes Namespaces, Classes, Interfaces and functions from the script specified by Y in the workspace.

In this section, the term namespace covers scripted Namespaces, Classes and Interfaces.

Y may be a simple character vector, or a vector of character vectors or character scalars. The value of X determines what Y may contain.

If Y is a simple character vector, it must start with "file://", followed by the name of a file which must exist. The contents of the file must follow the same rules that apply to Y when Y is a vector of character vectors or scalars. The file name can be relative or absolute; when considering cross-platform portability, using "/" as the directory delimiter is recommended, although "\" is also valid under Windows.

If specified, X must be a numeric scalar. It may currently take the value 0, 1 or 2. If not specified, the value is assumed to be 1.

If X is 0, Y must specify a single valid namespace which may or may not be named, or a file containing such a definition. If so, the shy result R contains a reference to the namespace. Even if the namespace is named, it is not established per se, although it will exist for as long as at least one reference to it exists.

If X is 1, Y must specify a single valid namespace which may or may not be named, or a file containing such a definition. If so, the shy result R contains a reference to the namespace. If Y contains the definition of a named namespace, the namespace is established in the workspace.

If X is 2, Y may specify a mixture of any number of valid, named namespaces or function definitions, or a file containing such a definition. A function definition must be either that of a dfn or a tradfn only and must be of the same form as when they are defined in namespace scripts. If so, the shy result R is a vector of character vectors, containing the names of all of the objects that have been established in the workspace; the order of the names in R is not defined. Currently 2 ⎕FIX is not certain to be an atomic operation, although this might change in future versions.

Example 1

In the first example, the Class specified by Y is named (MyClass) but the result of ⎕FIX is discarded. The end-result is that MyClass is established in the workspace as a Class.

      ⎕←⎕FIX ':Class MyClass' ':EndClass'
#.MyClass

Example 2

In the second example, the Class specified by Y is named (MyClass) and the result of ⎕FIX is assigned to a different name (MYREF). The end-result is that a Class named MyClass is established in the workspace, and MYREF is a reference to it.

      MYREF←⎕FIX ':Class MyClass' ':EndClass'
      )CLASSES
MyClass MYREF
      ⎕NC'MyClass' 'MYREF'
9.4 9.4
      MYREF
#.MyClass
      MYREF≡MyClass
1

Example 3

In the third example, the left-argument of 0 causes the named Class MyClass to be visible only via the reference to it (MYREF). It is there, but hidden.

      MYREF←0 ⎕FIX ':Class MyClass' ':EndClass'
      )CLASSES
MYREF
      MYREF
#.MyClass

Example 4

The fourth example illustrates the use of un-named Classes.

      src←':Class' '∇Make n'
      src,←'Access Public' 'Implements Constructor'
      src,←'⎕DF n' '∇' ':EndClass'
      MYREF←⎕FIX src
      )CLASSES
MYREF
      MYINST←⎕NEW MYREF'Pete'
      MYINST
Pete

Example 5

In the final example, the left argument of 2 allows a script containing multiple objects to be fixed:

      src←':Namespace andys' '∇foo' '2' '∇'
      src,←':EndNamespace' 'dfn←{⍺ ⍵}' '∇r←tfn'
      src,←'r←33' '∇' ':Class c1' '∇goo' '1'
      src,←'∇' ':EndClass'
      ≢⎕←2⎕fix src
 c1  tfn  dfn  andys
4

Restriction

⎕FIX is unable to fix a namespace from Y when Y specifies a multi-line dfn which is preceded by a ⋄ (diamond separator).

      ⎕FIX':Namespace iaK' 'foo' 'a←1 ⋄ adfn←{' '⍵' ' }'
DOMAIN ERROR: There were errors processing the script
      ⎕FIX':Namespace iaK' 'foo' 'a←1 ⋄ adfn←{' '⍵' ' }'
     ∧


Instances

Instances R←⎕INSTANCES Y

⎕INSTANCES returns a list all the current instances of the Class specified by Y.

Y must be a reference.

If Y is a reference to a Class, R is a vector of references to all existing Class Instances of Y. Otherwise, R is empty.

Examples

This example illustrates a simple inheritance tree or Class hierarchy. There are 3 Classes, namely:

Animal

Bird (derived from Animal)

Parrot (derived from Bird)

:Class Animal
...
:EndClass ⍝ Animal

:Class Bird: Animal
...
:EndClass ⍝ Bird

:Class Parrot: Bird
...
:EndClass ⍝ Parrot
      Eeyore←⎕NEW Animal
      Robin←⎕NEW Bird
      Polly←⎕NEW Parrot

      ⎕INSTANCES Parrot
 #.[Parrot]
      ⎕INSTANCES Bird
 #.[Bird]  #.[Parrot]
      ⎕INSTANCES Animal
 #.[Animal]  #.[Bird]  #.[Parrot]

      Eeyore.⎕DF 'eeyore'
      Robin.⎕DF 'robin'
      Polly.⎕DF 'polly'

      ⎕INSTANCES Parrot
 polly
      ⎕INSTANCES Bird
 robin  polly
      ⎕INSTANCES Animal
 eeyore  robin  polly


New Instance

New Instance R←⎕NEW Y

⎕NEW creates a new instance of the Class, Dyalog GUI object, or .NET Type specified by Y.

Y must be a 1- or 2-item scalar or vector. The first item is a reference to a Class or to a .NET Type, or a character vector containing the name of a Dyalog GUI object.

The second item, if specified, contains the argument to be supplied to the Class or Type Constructor or a list of property/value pairs for a Dyalog GUI object.

The result R is a reference to a new instance of Class, Dyalog GUI object, or Type Y.

For further information, see Interface Guide.

Class Example

:Class Animal
    ∇ Name nm
      :Access Public
      :Implements Constructor
      ⎕DF nm
    ∇
:EndClass ⍝ Animal

      Donkey←⎕NEW Animal 'Eeyore'
      Donkey
Eeyore

If ⎕NEW is called with just a Class reference (i.e. without parameters for the Constructor), the default constructor will be called. A default constructor is defined by a niladic function with the :Implements Constructor attribute. For example, the Animal Class may be redefined as:

:Class Animal
    ∇ NoName
      :Access Public
      :Implements Constructor
      ⎕DF 'Noname'
    ∇
    ∇ Name nm
      :Access Public
      :Implements Constructor
      ⎕DF nm
    ∇
:EndClass ⍝ Animal

      Horse←⎕NEW Animal
      Horse
Noname

.NET Examples

      ⎕USING←'System' 'System.Web.Mail,System.Web.dll'
      dt←⎕NEW DateTime (2006 1 1)
      msg←⎕NEW MailMessage
      ⎕NC 'dt' 'msg' 'DateTime' 'MailMessage'
9.2 9.2 9.6 9.6

Note that .NET Types are accessed as follows.

If the name specified by the first item of Y would otherwise generate a VALUE ERROR, and ⎕USING has been set, APL attempts to load the Type specified by Y from the .NET assemblies (DLLs) specified in ⎕USING. If successful, the name specified by Y is entered into the SYMBOL TABLE with a name-class of 9.6. Subsequent references to that symbol (in this case DateTime) are resolved directly and do not involve any assembly searching.

Dyalog GUI Examples

      F←⎕NEW ⊂'Form'
      F
#.[Form]

To specify the initial values of any properties, Y[2] must be a vector (or scalar) of items each of which is of the form (PropertyName PropertyValue); the free-form syntax implemented by ⎕WC and ⎕WS is not allowed.

      ⎕NEW'Form'(⊂'Caption' 'Hello')
#.[Form]

      F←⎕NEW'Form'(('Caption' 'Hello')('Posn' (10 10)))
      F
#.[Form]

Note that as ⎕NEW provides no facility to name a GUI object, the Event property should use the onEvent syntax so that a callback function (or the result of ⎕DQ) receives a ref to the object. Otherwise, without the onEvent syntax, the first element of the argument to a callback function will contain a character vector such as '[Form].[Button]' which merely describes the type of the object but does not identify the object itself.

      cap←'Caption' 'Push Me'
      ev← 'Event' ('onSelect' 'foo')
      F.(B←⎕NEW'Button'#.(pos cap ev))

Note that you may not create an instance of OCXClass using ⎕NEW.


Namespace

Namespace {R}←{X}⎕NS Y

If specified, X must be a simple character scalar or vector identifying the name of a namespace.

Y is either a character array which represents a list of names of objects to be copied into the namespace, or a ref to a namespace, or an array produced by the ⎕OR of a namespace.

Case 1

In the first case, Y must be a simple character scalar, vector, matrix or a nested vector of character vectors identifying zero or more workspace objects to be copied into the namespace X. The identifiers in X and Y may be simple names or compound names separated by '.' and including the names of the special namespaces '#', '##' and '⎕SE'.

The namespace X is created if it doesn't already exist. If the name is already in use for an object other than a namespace, APL issues a DOMAIN ERROR.

If X is omitted, an unnamed namespace is created.

The objects identified in the list Y are copied into the namespace X.

If X is specified, the result R is the full name (starting with #. or ⎕SE.) of the namespace X. If X is omitted, the result R is a namespace reference, or ref, to an unnamed namespace.

Examples

      +'X'⎕NS''               ⍝ Create namespace X.
#.X
      ⊢'X'⎕NS'VEC' 'UTIL.DISP'⍝ Copy VEC and DISP to X.
#.X
      )CS X                   ⍝ Change to namespace X.
#.X
      ⊢'Y'⎕NS'#.MAT' '##.VEC' ⍝ Create #.X.Y &copy in
#.X.Y
      ⊢'#.UTIL'⎕NS'Y.MAT'     ⍝ Copy MAT from Y to UTIL #.UTIL.
#.UTIL
      ⊢'#'⎕NS'Y'              ⍝ Copy namespace Y to root.
#

      ⊢''⎕NS'#.MAT'           ⍝ Copy MAT to current space.
#.X
      ⊢''⎕NS''                ⍝ Display current space.
#.X
      ⊢'Z'⎕NS ⎕OR'Y'          ⍝ Create nspace from ⎕OR.
#.X.Z
      NONAME←⎕NS ''           ⍝ Create unnamed nspace
      NONAME
#.[Namespace]
      DATA←⎕NS¨3⍴⊂''         ⍝ Create 3-element vector of
                             ⍝ distinct unnamed nspaces
      DATA
 #.[Namespace]  #.[Namespace]  #.[Namespace]

Case 2

The second case is where Y is a ref to a namespace or the ⎕OR of a namespace.

If Y is a ref to or a ⎕OR of a GUI object, #.X must be a valid parent for the GUI object represented by Y, or the operation will fail with a DOMAIN ERROR.

Otherwise, the result of the operation depends upon the existence of X.

  • If X does not currently exist (name class is 0), X is created as a complete copy (clone) of the original namespace represented by Y. If Y is a ref to or the ⎕OR of a GUI object or of a namespace containing GUI objects, the corresponding GUI components of Y will be instantiated in X.
  • If X is the name of an existing namespace (name class 9), the contents of Y, including any GUI components, are merged into X. Any items in X with corresponding names in Y (names with the same path in both Y and X) will be replaced by the names in Y, unless they have a conflicting name class in which case the existing items in X will remain unchanged. However, all GUI spaces in X will be stripped of their GUI components prior to the merge operation.


Source

Source R←⎕SRC Y

⎕SRC returns the script that defines the scripted object Y.

Y must be a reference to a scripted object. Scripted objects include Classes, Interfaces and scripted Namespaces.

R is a vector of character vectors containing the script that was used to define Y.

      )ed ○MyClass
:Class MyClass
∇ r←foo arg
:Access public shared
r←1+arg
∇
:EndClass

      z←⎕SRC MyClass
      ⍴z
6
      ⍴¨z
 14  15  27  13  5  9
      ⍪z
 :Class MyClass
     ∇ r←foo arg
       :Access public shared
       r←1+arg
     ∇
 :EndClass

Note: The only two ways to permanently alter the source of a scripted object are to change the object in the editor, or by refixing it using ⎕FIX. A useful technique to ensure that a scripted object is in sync with its source is to ⎕FIX ⎕SRC ref, where ref is an object reference..


This Space

This Space R←⎕THIS

⎕THIS returns a reference to the current namespace, i.e. to the space in which it is referenced.

If NC9 is a reference to any object whose name-class is 9, then:

      NC9≡NC9.⎕THIS
1

Examples

      ⎕THIS
#
      'X'⎕NS ''
      X.⎕THIS
#.X
     'F'⎕WC'Form'
     'F.B'⎕WC'Button'
      F.B.⎕THIS
#.F.B

      Polly←⎕NEW Parrot
      Polly.⎕THIS
#.[Parrot]

An Instance may use ⎕THIS to obtain a reference to its own Class:

    Polly.(⊃⊃⎕CLASS ⎕THIS)
#.Parrot

or a function (such as a Constructor or Destructor) may identify or enumerate all other Instances of the same Class:

      Polly.(⍴⎕INSTANCES⊃⊃⎕CLASS ⎕THIS)
1


Character Input/Output ⍞

⍞ is a variable which communicates between the user's terminal and APL. Its behaviour depends on whether it is being assigned or referenced.

When ⍞ is assigned with a vector or a scalar, the array is displayed without the normal ending new-line character. Successive assignments of vectors or scalars to ⍞ without any intervening input or output cause the arrays to be displayed on the same output line.

Example

      ⍞←'2+2' ⋄ ⍞←'=' ⋄ ⍞←4
2+2=4

Output through ⍞ is independent of the print width in ⎕PW. The way in which lines exceeding the print width of the terminal are treated is dependent on the characteristics of the terminal. Numeric output is formatted in the same manner as direct output (see Display of Arrays).

When ⍞ is assigned with a higher-rank array, the output is displayed in the same manner as for direct output except that the print width ⎕PW is ignored.

When ⍞ is referenced, terminal input is expected without any specific prompt, and the response is returned as a character vector.

If the ⍞ request was preceded by one or more assignments to ⍞ without any intervening input or output, the last (or only) line of the output characters are returned as part of the response.

Example

      mat←↑⌽⍞⍞⍞⍞⍞

Examples

      ⍞←'OPTION : ' ⋄ R←⍞
OPTION : INPUT

      R
OPTION : INPUT

      ⍴R
14

The output of simple arrays of rank greater than 1 through ⍞ includes a new-line character at the end of each line. Input through ⍞ includes the preceding output through ⍞ since the last new-line character. The result from ⍞, including the prior output, is limited to 256 characters.

A soft interrupt causes an INPUT INTERRUPT error if entered while ⍞ is awaiting input, and execution is then suspended (unless the interrupt is trapped):

      R←⍞

(Interrupt)

INPUT INTERRUPT

A time limit is imposed on input through ⍞ if ⎕RTL is set to a non-zero value:

      ⎕RTL←5 ⋄ ⍞←'PASSWORD ? ' ⋄ R←⍞
PASSWORD ?
TIMEOUT
      ⎕RTL←5 ⋄ ⍞←'PASSWORD : ' ⋄ R←⍞
                                   ^

The TIMEOUT interrupt is a trappable event.


Evaluated Input/Output ⎕

⎕ is a variable which communicates between the user's terminal and APL. Its behaviour depends on whether it is being assigned or referenced.

When ⎕ is assigned an array, the array is displayed at the terminal in exactly the same form as is direct output (see Display of Arrays).

Example

      ⎕←2+⍳5
3 4 5 6 7

      ⎕←2 4⍴'WINEMART'
WINE
MART

When ⎕ is referenced, a prompt (⎕:) is displayed at the terminal, and input is requested. The response is evaluated and an array is returned if the result is valid. If an error occurs in the evaluation, the error is reported as normal (unless trapped by a ⎕TRAP definition) and the prompt (⎕:) is again displayed for input. An EOF interrupt reports INPUT INTERRUPT and the prompt (⎕:) is again displayed for input. A soft interrupt is ignored and a hard interrupt reports INTERRUPT and the prompt (⎕:) is redisplayed for input.

Examples

      10×⎕+2
⎕:
      ⍳3
30 40 50

      2+⎕
⎕:
      X
VALUE ERROR
      X
     ^
⎕:
      2+⍳3
5 6 7

A system command may be entered. The system command is effected and the prompt is displayed again (unless the system command changes the environment):

      ⍴3,⎕
⎕:
      )WSID
WS/MYWORK
⎕:
      )SI
⎕
⎕:
      )CLEAR
CLEAR WS

If the response to a ⎕: prompt is an abort statement (→), the execution will be aborted:

      1 2 3 = ⎕
⎕:
      →

A trap definition on interrupt events set for the system variable ⎕TRAP in the range 1000-1008 has no effect whilst awaiting input in response to a ⎕: prompt.

Example

      ⎕TRAP←(11 'C' '''ERROR''')(1000 'C' '''STOP''')

      2+⎕
⎕:
      (Interrupt Signal)
INTERRUPT
⎕:
      'C'+2
ERROR

A time limit set in system variable ⎕RTL has no effect whilst awaiting input in response to a ⎕: prompt.


Dequeue Events

Dequeue Events {R}←⎕DQ Y

⎕DQ awaits and processes events. Y specifies the GUI objects(s) for which events are to be processed. Objects are identified by their names, as character scalars/vectors, or by namespace references. These may be objects of type Root, Form, Locator, FileBox, MsgBox, PropertySheet, TCPSocket, Timer, Clipboard and pop-up Menu. Sub-objects (children) of those named in Y are also included. However, any objects which exist, but are not named in Y, are effectively disabled (do not respond to the user).

If Y is #, '#', or '.', all objects currently owned and subsequently created by the current thread are included in the ⎕DQ. Note that because the Root object is owned by thread 0, events on Root are reported only to thread 0.

If Y is empty it specifies the object associated with the current namespace and is only valid if the current space is one of the objects listed above.

Otherwise, Y contains the name(s) of or reference(s) to the objects for which events are to be processed. Effectively, this is the list of objects with which the user may interact. A DOMAIN ERROR is reported if an element of Y refers to anything other than an existing "top-level" object.

Associated with every object is a set of events. For every event there is defined an "action" which specifies how that event is to be processed by ⎕DQ. The "action" may be a number with the value 0, 1 or ¯1, a character vector containing the name of a "callback function", or a character vector containing the name of a callback function coupled with an arbitrary array. Actions can be defined in a number of ways, but the following examples will illustrate the different cases.

      OBJ ⎕WS 'Event' 'Select' 0

      OBJ ⎕WS 'Event' 'Select' 1

      OBJ ⎕WS 'Event' 'Select' 'FOO'

      OBJ ⎕WS 'Event' 'Select' 'FOO' 10

      OBJ ⎕WS 'Event' 'Select' 'FOO&'

These are treated as follows:

Action = 0 (the default)

⎕DQ performs "standard" processing appropriate to the object and type of event. For example, the standard processing for a KeyPress event in an Edit object is to action the key press, i.e. to echo the character on the screen.

Action = ¯1

This disables the event. The "standard" processing appropriate to the object and type of event is not performed, or in some cases is reversed. For example, if the "action code" for a KeyPress event (22) is set to ¯1, ⎕DQ simply ignores all keystrokes for the object in question.

Action = 1

⎕DQ terminates and returns information pertaining to the event (the event message) in R as a nested vector whose first two elements are the name of the object (that generated the event) and the event code. R may contain additional elements depending upon the type of event that occurred.

Action = fn {larg}

fn is a character vector containing the name of a callback function. This function is automatically invoked by ⎕DQ whenever the event occurs, and prior to the standard processing for the event. The callback is supplied the event message (see above) as its right argument, and, if specified, the array larg as its left argument. If the callback function fails to return a result, or returns the scalar value 1, ⎕DQ then performs the standard processing appropriate to the object and type of event. If the callback function returns a scalar 0, the standard processing is not performed or in some cases is reversed.

If the callback function returns its event message with some of the parameters changed, these changes are incorporated into the standard processing. An example would be the processing of a keystroke message where the callback function substitutes upper case for lower case characters. The exact nature of this processing is described in the reference section on each event type.

Action = ⍎expr

If Action is set to a character vector whose first element is the execute symbol (⍎) the remaining string will be executed automatically whenever the event occurs. The default processing for the event is performed first and may not be changed or inhibited in any way.

Action = fn& {larg}

fn is a character vector containing the name of a callback function. The function is executed in a new thread. The default processing for the event is performed first and may not be changed or inhibited in any way.

The Result of ⎕DQ

⎕DQ terminates, returning the shy result R, in one of four instances.

Firstly, ⎕DQ terminates when an event occurs whose "action code" is 1. In this case, its result is a nested vector containing the event message associated with the event. The structure of an event message varies according to the event type (see Object Reference). However, an event message has at least two elements of which the first is a ref to the object or a character vector containing the name of the object, and the second is a character vector or numeric code which identifies the event type.

⎕DQ also terminates if all of the objects named in Y have been deleted. In this case, the result is an empty character vector. Objects are deleted either using ⎕EX, or on exit from a defined function or operator if the names are localised in the header, or on closing a form using the system menu.

Thirdly, ⎕DQ terminates if the object named in its right argument is a special modal object, such as a MsgBox, FileBox or Locator, and the user has finished interacting with the object (e.g. by pressing an "OK" button). The return value of ⎕DQ in this case depends on the action code of the event.

Finally, ⎕DQ terminates with a VALUE ERROR if it attempts to execute a callback function that is undefined.


Export Object

Export Object {R}←{X}⎕EXPORT Y

⎕EXPORT is used to set or query the export type of a defined function (or operator) referenced by the ⎕PATH mechanism.

Y is a character matrix or vector-of-vectors representing the names of functions and operators whose export type is to be set or queried.

X is an integer scalar or vector (one per name in the namelist) indicating the export type. X can currently be one of the values:

  • 0 - not exported.
  • 1 - exported (default).

A scalar or 1-element-vector type is replicated to conform with a multi-name list.

The result R is a vector that reports the export type of the functions and operators named in Y. When used dyadically to set export type, the result is shy.

When the path mechanism locates a referenced function (or operator) in the list of namespaces in the ⎕PATH system variable, it examines the function's export type:

0 | This instance of the function is ignored and the search is resumed at the next namespace in the ⎕PATH list. Type-0 is typically used for functions residing in a utility namespace which are not themselves utilities, for example the private sub-function of a utility function.
1 | This instance of the function is executed in the namespace in which it was found and the search terminated. The effect is exactly as if the function had been referenced by its full path name.

Warning: The left domain of ⎕EXPORT may be extended in future to include extra types 2, 3,... (for example, to change the behaviour of the function). This means that, while ⎕EXPORT returns a Boolean result in the first version, this may not be the case in the future. If you need a Boolean result, use 0≠ or an equivalent.

   (0≠⎕EXPORT ⎕nl 3 4)⌿⎕nl 3 4  ⍝ list of exported
                                ⍝ functions and ops.


Enqueue Event

Enqueue Event {R}←{X}⎕NQ Y

This system function generates an event or invokes a method.

While APL is executing, events occur "naturally" as a result of user action or of communication with other applications. These events are added to the event queue as and when they occur, and are subsequently removed and processed one by one by ⎕DQ. ⎕NQ provides an "artificial" means to generate an event and is analogous to ⎕SIGNAL.

If the left argument X is omitted or is 0, ⎕NQ adds the event specified by Y to the bottom of the event queue. The event will subsequently be processed by ⎕DQ when it reaches the top of the queue.

If X is 1, the event is actioned immediately by ⎕NQ itself and is processed in exactly the same way as it would be processed by ⎕DQ. For example, if the event has a callback function attached, ⎕NQ will invoke it directly. See Dequeue Events for further details. If the event generates any subsidiary events (for example, a KeyPress might generate a GotFocus), the subsidiary events are added to the event queue rather than being executed immediately.

Note that it is not possible for one thread to use 1 ⎕NQ to send an event to another thread.

If X is 2 and the name supplied is the name of an event, ⎕NQ performs the default processing for the event immediately, but does not invoke a callback function if there is one attached.

If X is 2 and the name supplied is the name of a (Dyalog APL) method, ⎕NQ invokes the method. Its (shy) result is the result produced by the method.

If X is 3, ⎕NQ invokes a method in an OLE Control. The (shy) result of ⎕NQ is the result produced by the method.

If X is 4, ⎕NQ signals an event from an ActiveXControl object to its host application. The (shy) result of ⎕NQ is the result returned by the host application and depends upon the syntax of the event. This case is only applicable to ActiveXControl objects.

Y is a nested vector containing an event message. The first two elements of Y are:

[1] | Object | ref or character vector
[2] | Event | numeric scalar or character vector which specifies an event or method

Y[1] must specify an existing object. If not, ⎕NQ terminates with a VALUE ERROR.

If Y[2] specifies a standard event type, subsequent elements must conform to the structure defined for that event type. If not, ⎕NQ terminates with a SYNTAX ERROR. If additional elements (beyond those defined for the event type) are supplied this will not cause an error, but is not recommended because Dyalog may extend the event message in the future.

If Y[2] specifies a non-standard event type, Y[3] onwards (if present) may contain arbitrary information. Although any event type not listed herein may be used, numbers in the range 0-1000 are reserved for future extensions.

If ⎕NQ is used monadically, or with a left argument of 0, its (shy) result is always an empty character vector. If a left argument of 1 is specified, ⎕NQ returns Y unchanged or a modified Y if the callback function returns its modified argument as a result.

If the left argument is 2, ⎕NQ returns either the value 1 or a value that is appropriate.

Examples

      ⍝ Send a keystroke ("A") to an Edit Field
      ⎕NQ TEST.ED 'KeyPress' 'A'

      ⍝ Iconify all top-level Forms
      {⎕NQ ⍵ 'StateChange' 1}¨'Form'⎕WN'.'

      ⍝ Set the focus to a particular field
      ⎕NQ TEST.ED3 40

      ⍝ Throw a new page on a printer
      1 ⎕NQ PR1 'NewPage'

      ⍝ Terminate ⎕DQ under program control

      'TEST'⎕WC 'Form' ... ('Event' 1001 1)
      ...
      ⎕DQ 'TEST'
      ...
      ⎕NQ TEST 1001  ⍝ From a callback

      ⍝ Call GetItemState method for a TreeView F.TV
      +2 ⎕NQ F.TV 'GetItemState' 6
96

      ⍝ Report where APL is installed
      +2 ⎕NQ'.' 'GetEnvironment' 'DYALOG'
C:\Program Files\Dyalog\Dyalog APL-64 15.0 Unicode


Windows Create Object

Window Create Object {R}←{X}⎕WC Y

This system function creates a GUI object. Y is either a vector which specifies properties that determine the new object's appearance and behaviour, or a ref to or the ⎕OR of a GUI object that exists or previously existed. X is a character vector which specifies the name of the new object, and its position in the object hierarchy.

If X is omitted, ⎕WC attaches a GUI component to the current namespace, retaining any functions, variables and other namespaces that it may contain. Monadic ⎕WC is discussed in detail at the end of this section.

If Y is a nested vector each element specifies a property. The Type property (which specifies the class of the object) must be specified. Most other properties take default values and need not be explicitly stated. Properties (including Type) may be declared either positionally or with a keyword followed by a value. Note that Type must always be the first property specified. Properties are specified positionally by placing their values in Y in the order prescribed for an object of that type.

If Y is a ref or the result of ⎕OR, the new object is a complete copy of the other, including any child objects, namespaces, functions and variables that it contained at that time.

The shy result R is the full name (starting #. or ⎕SE.) of the namespace X.

An object's name is specified by giving its full pathname in the object hierarchy. At the top of the hierarchy is the Root object whose name is ".". Below "." there may be one or more "top-level" objects. The names of these objects follow the standard rules for other APL objects as described in Chapter 1.

Names for sub-objects follow the same rules except that the character "." is used as a delimiter to indicate parent/child relationships.

The following are examples of legal and illegal names :

Legal | Illegal
FORM1 | FORM 1
form_23 | form#1
Form1.Gp | 11_Form
F1.g2.b34 | Form+1

If X refers to the name of an APL variable, label, function, or operator, a DOMAIN ERROR is reported. If X refers to the name of an existing GUI object or namespace, the existing one is replaced by the new one. The effect is the same as if it were deleted first.

If Y refers to a non-existent property, or to a property that is not defined for the type of object X, a DOMAIN ERROR is reported. A DOMAIN ERROR is also reported if a value is given that is inconsistent with the corresponding property. This can occur for example, if Y specifies values positionally and in the wrong order.

A "top-level" object created by ⎕WC whose name is localised in a function/operator header, is deleted on exit from the function/operator. All objects, including sub-objects, can be deleted using ⎕EX.

GUI objects are named relative to the current namespace, so the following examples are equivalent:

      'F1.B1' ⎕WC 'Button'

is equivalent to :

      )CS F1
#.F1
      'B1' ⎕WC 'Button'
      )CS
#

is equivalent to :

      'B1' F1.⎕WC 'Button'

Examples

⍝ Create a default Form called F1

      'F1' ⎕WC 'Form'

⍝ Create a Form with specified properties (by position)
⍝   Caption = "My Application"  (Title)
⍝   Posn    = 10 30  (10% down, 30% across)
⍝   Size    = 80 60  (80% high, 60% wide)

      'F1' ⎕WC 'Form' 'My Application' (10 30)(80 60)

⍝ Create a Form with specified properties (by keyword)
⍝   Caption = "My Application"  (Title)
⍝   Posn    = 10 30  (10% down, 30% across)
⍝   Size    = 80 60  (80% high, 60% wide)

      PROPS←⊂'Type' 'Form'
      PROPS,←⊂'Caption' 'My Application'
      PROPS,←⊂'Posn' 10 30
      PROPS,←⊂'Size' 80 60
      'F1' ⎕WC PROPS

⍝ Create a default Button (a pushbutton) in the Form F1

      'F1.BTN' ⎕WC 'Button'

⍝ Create a pushbutton labelled "Ôk"
⍝ 10% down and 10% across from the start of the FORM
⍝ with callback function FOO associated with EVENT 30
⍝ (this event occurs when the user presses the button)

      'F1.BTN'⎕WC'Button' '&Ok' (10 10)('Event' 30 'FOO')

Monadic ⎕WC is used to attach a GUI component to an existing object. The existing object must be a pure namespace or a GUI object. The operation may be performed by changing space to the object or by running ⎕WC inside the object using the dot syntax. For example, the following statements are equivalent.

      )CS F
#.F
      ⎕WC 'Form'  ⍝ Attach a Form to this namespace

      )CS
#
      F.⎕WC'Form' ⍝ Attach a Form to namespace F


Windows Get Property

Window Get Property R←{X}⎕WG Y

This system function returns property values for a GUI object.

X is a namespace reference or a character vector containing the name of the object. Y is a character vector or a vector of character vectors containing the name(s) of the properties whose values are required. The result R contains the current values of the specified properties. If Y specifies a single property name, a single property value is returned. If Y specifies more than one property, R is a vector with one element per name in Y.

If X refers to a non-existent GUI name, a VALUE ERROR is reported. If Y refers to a non-existent property, or to a property that is not defined for the type of object X, a DOMAIN ERROR is reported.

GUI objects are named relative to the current namespace. A null value of X (referring to the namespace in which the function is being evaluated) may be omitted. The following examples are equivalent:

      'F1.B1' ⎕WG 'Caption'
      'B1' F1.⎕WG 'Caption'
      '' F1.B1.⎕WG 'Caption'
      F1.B1.⎕WG 'Caption'

Examples

      'F1' ⎕WC 'Form' 'TEST'

      'F1' ⎕WG 'Caption'
TEST

      'F1' ⎕WG 'MaxButton'
1

      'F1' ⎕WG 'Size'
50 50

      ]display 'F1' ⎕WG 'Caption' 'MaxButton' 'Size'
┌→─────────────────┐
│ ┌→───┐   ┌→────┐ │
│ │TEST│ 1 │50 50│ │
│ └────┘   └~────┘ │
└∊─────────────────┘


Windows Child Names

Window Child Names R←{X}⎕WN Y

This system function reports the GUI objects whose parent is Y.

If Y is a name (i.e. is a character vector) then the result R is a vector of character vectors containing the names of the named direct GUI children of Y.

If Y is a reference then the result R is a vector of references to the direct GUI children of Y, named or otherwise.

The optional left argument X is a character vector which specifies the Type of GUI object to be reported; if X is not specified, no such filtering is performed.

Names of objects further down the tree are not returned, but can be obtained by recursive use of ⎕WN.

If Y refers to a namespace with no GUI element, a VALUE ERROR is reported.

Note that ⎕WN reports only those child objects visible from the current thread.

GUI objects are named relative to the current namespace. The following examples are equivalent:

      ⎕WN 'F1.B1'
      F1.⎕WN 'B1'
      F1.B1.⎕WN ''

Example

      f←⎕NEW⊂'Form'
      f.n←⎕ns''                  ⍝ A non-GUI object
      f.l←f.⎕NEW⊂'Label'         ⍝ A reference to a Label
      'f.b1'⎕wc'Button'          ⍝ A named Button
      f.(b2←⎕new ⊂'Button')      ⍝ A reference to a Button
      ⎕wn 'f'
 [Form].b1
      ⎕wn f
 #.[Form].[Label]  #.[Form].b1  #.[Form].[Button]
      'Button' ⎕wn f
 #.[Form].b1  #.[Form].[Button]


Windows Set Property

Window Set Property {R}←{X}⎕WS Y

This system function resets property values for a GUI object.

X is a namespace reference or a character vector containing the name of the object. Y defines the property or properties to be changed and the new value or values. If a single property is to be changed, Y is a vector whose first element Y[1] is a character vector containing the property name. If Y is of length 2, Y[2] contains the corresponding property value. However, if the property value is itself a numeric or nested vector, its elements may be specified in Y[2 3 4 ...] instead of as a single nested element in Y[2]. If Y specifies more than one property, they may be declared either positionally or with a keyword followed by a value. Properties are specified positionally by placing their values in Y in the order prescribed for an object of that type. Note that the first property in Y must always be specified with a keyword because the Type property (which is expected first) may not be changed using ⎕WS.

If X refers to a non-existent GUI name, a VALUE ERROR is reported. If Y refers to a non-existent property, or to a property that is not defined for the type of object X, or to a property whose value may not be changed by ⎕WS, a DOMAIN ERROR is reported.

The shy result R contains the previous values of the properties specified in Y.

GUI objects are named relative to the current namespace. A null value of X (referring to the namespace in which the function is being evaluated) may be omitted. The following examples are equivalent:

      'F1.B1' ⎕WS 'Caption' '&Ok'
      'B1' F1.⎕WS 'Caption' '&Ok'
      '' F1.B1.⎕WS 'Caption' '&Ok'
      F1.B1.⎕WS 'Caption' '&Ok'

Examples

      'F1' ⎕WC 'Form'  ⍝ A default Form

      'F1' ⎕WS 'Active' 0

      'F1' ⎕WS 'Caption' 'My Application'

      'F1' ⎕WS 'Posn' 0 0

      'F1' ⎕WS ('Active' 1)('Event' 'Configure' 'FOO')

      'F1' ⎕WS 'Junk' 10
DOMAIN ERROR

      'F1' ⎕WS 'MaxButton' 0
DOMAIN ERROR


File Append Component

File Append Component {R}←X ⎕FAPPEND Y

Access code 8

Y must be a simple integer scalar or a 1 or 2 element vector containing the file tie number followed by an optional passnumber. If the passnumber is omitted it is assumed to be zero. Subject to a few restrictions, X may be any array.

The shy result R is the number of the component to which X is written, and is 1 greater than the previously highest component number in the file, or 1 if the file is new.

Examples

      (1000?1000) ⎕FAPPEND 1

      ⎕←(2 3⍴⍳6) 'Geoff' (⎕OR'FOO') ⎕FAPPEND 1
12

      ⎕←A B C ⎕FAPPEND¨1
13 14 15

Dump←{
    tie←⍺ ⎕FCREATE 0              ⍝ create file.
    (⎕FUNTIE tie){}⍵ ⎕FAPPEND tie ⍝ append and untie.
}


File System Available

File System Available R←⎕FAVAIL

⎕FAVAIL returns the scalar value 1 unless the component file system is unavailable for some reason, in which case it returns scalar 0. If ⎕FAVAIL does return 0, most of the component file system functions will generate the error message FILE SYSTEM NOT AVAILABLE.


File Check and Repair

File Check and Repair R←{X} ⎕FCHK Y

⎕FCHK validates and repairs component files, and validates files associated with external variables, following an abnormal termination of the APL process or operating system.

Y must be a simple character scalar or vector which specifies the name of the file to be exclusively checked or repaired. For component files, the file must be named in accordance with the operating system's conventions, and may be a relative or absolute pathname. The file must exist and must not be tied. If no file extension is supplied, the set of extensions specified by the CFEXT parameter are tried one after another until the file is found or the set of extensions is exhausted. See CFEXT.

For files associated with external variables, any filename extension must be specified even if ⎕XT would not require it. The file must exist and must not currently be associated with an external variable.

Options for ⎕FCHK are specified using the Variant operator ⍠ or by the optional left argument X. The former is recommended but the older mechanism using the left argument is still supported.

In either case, the default behaviour is as follows:

  1. If the file appears to have been cleanly untied previously, return ⍬, i.e. report that the file is good.
  2. Otherwise, validate the file and return the appropriate result. If the file is corrupt, no attempt is made to repair it.

The result R is a vector of the numbers of missing or damaged components. R may include non-positive numbers of "pseudo components" that indicate damage to parts of the file other than in specific components:

0 | ACCESS MATRIX.
¯1 | Free-block tree.
¯2 | Component index tree.

Other negative numbers represent damage to the file metadata; this set may be extended in the future.

Specifying options using Variant

Using Variant, the options are as follows:

  • Task
  • Repair
  • Force

Rebuild causes the file indices to be discarded and rebuilt. Repair only takes place on files which have been checked and found to be damaged. It involves a rebuild, but that only takes place if it is needed. Note that Repair and Force only apply if Task is 'Scan'.

Task

Scan | causes the file to be checked and optionally repaired (see 'Repair' below)
Rebuild | causes the file to be unconditionally rebuilt

Repair (principle option)

0 | do not repair
1 | causes the file to be repaired if damage is found

Force

0 | do not validate the file if it appears to have been properly closed
1 | validate the file even if it appears to have been properly closed

Default values are highlighted thus in the above tables.

Examples

To check a file and attempt to fix it if damage is found:

      (⎕FCHK ⍠ 1)'suspect.dcf'

To forcibly check a file and attempt to fix it if damage is found:

      (⎕FCHK ⍠ ('Repair' 1)('Force'1))'suspect.dcf'

Specifying options using a left argument

Using the optional left-argument, X must be a vector of zero or more character vectors from among 'force', 'repair' and 'rebuild', which determine the detailed operation of the function. Note that these options are case-insensitive.

  • If X contains 'force', ⎕FCHK will validate the file even if it appears to have been cleanly untied.
  • If X contains 'repair', ⎕FCHK will repair the file, following validation, if it appears to be damaged. This option may be used in conjunction with 'force'.
  • If X contains 'rebuild', ⎕FCHK will repair the file unconditionally.

Following a check of the file, a non-null result indicates that the file is damaged.

Following a repair of the file, the result indicates those components that could not be recovered. Un-recovered components will give a FILE COMPONENT DAMAGED error if read but may be replaced without error.

Repair can recover only check-summed components from the file, i.e. only those components that were written with the checksum option enabled (see File Properties ).

Following an operating system crash, repair may result in one or more individual components being rolled back to a previous version or not recovered at all, unless Journaling levels 2 or 3 were also set when these components were written.


File Copy

File Copy R←X ⎕FCOPY Y

Access Code: 4609

Y must be a simple integer scalar or 1 or 2-element vector containing the file tie number and optional passnumber. The file need not be tied exclusively.

X is a character vector containing the name of a new file to be copied to. If no file extension is supplied, the first extension specified by the CFEXT parameter will be added. See CFEXT.

⎕FCOPY creates a copy of the tied file specified by Y, named X.

The new file X will have the same component level information, including the user number and update time as the original. The operating system file creation, modification and access times will be set to the time at which the copy occurred.

Unless otherwise specified (see File Properties below) the new file X will have the same file properties as the original, except that it will be a large-span file regardless of the span of the original.

The result R is the file tie number associated with the new file X.

Note that the Access Code is 4609, which is the sum of the Access Codes for ⎕FREAD (1), ⎕FRDCI (512) and ⎕FRDAC (4096).

Note also that although the file need not be tied exclusively, the ⎕FCOPY function will not yield the file to other APL processes while it is running, and it may take some considerable time to run in the case of a large component file.

Example

      told←'oldfile32'⎕FTIE 0
      'S' ⎕FPROPS told
32
      tnew←'newfile64' ⎕FCOPY told

      'S' ⎕FPROPS tnew
64

If X specifies the name of an existing file, the operation fails with a FILE NAME ERROR.

Note: This operation is atomic. If an error occurs during the copy operation (such as disk full) or if a strong interrupt is issued, the copy will be aborted and the new file X will not be created.

File Properties

⎕FCOPY allows you to specify properties for the new file via the variant operator ⍠ used with the following options:

  • 'J' - journaling level; a numeric value.
  • 'C' - checksum level; 0 or 1.
  • 'Z' - compression; 0 or 1.
  • 'U' - Unicode; 0 or 1
  • 'S' - File Size (span); 64

The Principal Option is as follows:

  • 0 - sets ('J' 0) ('C' 0)
  • 1 - sets ('J' 1) ('C' 1)
  • 2 - sets ('J' 2) ('C' 1)
  • 3 - sets ('J' 3) ('C' 1)

Examples

      newfid←'newfile' (⎕FCOPY ⍠3) 1

      'SEUJCZ' ⎕FPROPS newfid
64 0 1 3 1 0

Alternatively:

      JFCOPY←⎕FCOPY ⍠ 3

will name a variant of ⎕FCREATE which will create component file with level 3 journaling, and checksum enabled. Then:

      newfid←'newfile' JFCOPY 1

Note: Setting ('U' 0) (no Unicode support) is discouraged as it may cause the copy to fail with a TRANSLATION ERROR. Similarly using a Classic interpreter to ⎕FCOPY files may result in TRANSLATION ERRORs.


File Create

File Create {R}←X ⎕FCREATE Y

Y must be a simple integer scalar or a 1 or 2 element vector. The first element is the file tie number. The second element, if specified, must be 64This element sets the span of the file which in earlier Versions of Dyalog APL could be 32 or 64. Small-span (32-bit) component files may no longer be created and this element is retained only for backwards compatibility of code. 1.

The file tie number must not be the tie number associated with another tied file.

X must be either:

  1. a simple character scalar or vector which specifies the name of the file to be created. If no file extension is supplied, the first extension specified by the CFEXT parameter will be added. See CFEXT.
  2. a vector of length 1 or 2 whose items are:
  1. a simple character scalar or vector as above.
  2. an integer scalar specifying the file size limit in bytes.

The newly created file is tied for exclusive use.

The shy result of ⎕FCREATE is the tie number of the new file.

Automatic Tie Number Allocation

A tie number of 0 as argument to a create or tie operation, allocates, and returns as an explicit result, the first (closest to zero) available tie number. This allows you to simplify code. For example:

from:

      tie←1+⌈/0,⎕FNUM     ⍝ With next available number,
      file ⎕FCREATE tie   ⍝ ... create file.

to:

      tie←file ⎕FCREATE 0 ⍝ Create with first available..

Examples

      '..\BUDGET\SALES'    ⎕FCREATE 2    ⍝ Windows
      '../budget/SALES.85' ⎕FCREATE 2    ⍝ UNIX

      'COSTS' 200000 ⎕FCREATE 4         ⍝ max size 200000

File Properties

⎕FCREATE allows you to specify properties for the newly created file via the variant operator ⍠ used with the following options:

  • 'J' - journaling level; a numeric value
  • 'C' - checksum level; 0 or 1
  • 'Z' - compression; 0 or 1
  • 'U' - Unicode; 0 or 1
  • 'S' - File Size (span); 64

The Principal Option is as follows:

  • 0 - sets ('J' 0) ('C' 0)
  • 1 - sets ('J' 1) ('C' 1)
  • 2 - sets ('J' 2) ('C' 1)
  • 3 - sets ('J' 3) ('C' 1)

Examples

      'newfile' (⎕FCREATE⍠3) 0
1
      'SEUJCZ' ⎕FPROPS 1
64 0 1 3 1 0

Alternatively:

      JFCREATE←⎕FCREATE ⍠ 3

will name a variant of ⎕FCREATE which will create component file with level 3 journaling, and checksum enabled. Then:

      'newfile'JFCREATE 0
1


File Drop Component

File Drop Component {R}←⎕FDROP Y

Access code 32

Y must be a simple integer vector of length 2 or 3 whose elements are:

[1] | a file tie number
[2] | a number specifying the position and number of components to be dropped. A positive value indicates that components are to be removed from the beginning of the file; a negative value indicates that components are to be removed from the end of the file
[3] | an optional passnumber which if omitted is assumed to be zero

The shy result of a ⎕FDROP is a vector of the numbers of the dropped components. This is analogous to ⎕FAPPEND in that the result is potentially useful for updating some sort of dictionary:

      cnos,←vec ⎕FAPPEND¨tie ⍝ Append index to dictionary

      cnos~←⎕FDROP tie,-⍴vec ⍝ Remove index from dict.

Note that the result vector, though potentially large, is generated only on request.

Examples

      ⎕FSIZE 1
1 21 5436 4294967295

      ⎕FDROP 1 3 ⋄ ⎕FSIZE 1
4 21 5436 4294967295

      ⎕FDROP 1 ¯2 ⋄ ⎕FSIZE 1
4 19 5436 4294967295


File Erase

File Erase {R}←X ⎕FERASE Y

Access code 4

Y must be a simple integer scalar or 1 or 2 element vector containing the file tie number followed by an optional passnumber. If the passnumber is omitted it is assumed to be zero. X must be a character scalar or vector containing the name of the file associated with the tie number Y. This name must be identical with the name used to tie the file, and the file must be exclusively tied. The file named in X is erased and untied. See User Guide for file naming conventions under UNIX and Windows.

The shy result of ⎕FERASE is the tie number of the erased file.

Examples

      'SALES'⎕FERASE 'SALES' ⎕FTIE 0

      './temp' ⎕FCREATE 1
      'temp' ⎕FERASE 1
FILE NAME ERROR
      'temp'⎕FERASE 1
      ^


File History

File History R←⎕FHIST Y

Access code 16384

Y must be a simple integer vector of length 1 or 2 containing the file tie number and an optional passnumber. If the passnumber is omitted it is assumed to be zero.

The result is a numeric matrix with shape (5 2) whose rows represent the most recent occurrence of the following events.

  1. File creation (see note)
  2. (Undefined)
  3. Last update of the access matrix
  4. (Undefined)
  5. Last update performed by ⎕FAPPEND, ⎕FCREATE, ⎕FDROP or ⎕FREPLACE

For each event, the first column contain the user number and the second a timestamp. Like the timestamp reported by ⎕FRDCI this is measured in 60ths of a second since 1st January 1970 (UTC).

Currently, the second and fourth rows of the result (undefined) contain (0 0).

Note: ⎕FHIST collects information only if journaling and/or checksum is in operation. If neither is in use, the collection of data for ⎕FHIST is disabled and its result is entirely 0. If a file has both journaling and checksum disabled, and then either is enabled, the collection of data for ⎕FHIST is enabled too. In this case, the information in row 1 of ⎕FHIST relates to the most recent enabling ⎕FPROPS operation rather than the original ⎕FCREATE.

In the examples that follow, the FHist function is used below to format the result of ⎕FHIST.

     ∇ r←FHist tn;cols;rows;fhist;fmt;ToTS;I2D
[1]    rows←'Created' 'Undefined' 'Last ⎕FSTAC'
[2]    rows,←'Undefined' 'Last Updated'
[3]    cols←'User' 'TimeStamp'
[4]    fmt←'ZI4,2(⊂-⊃,ZI2),⊂ ⊃,ZI2,2(⊂:⊃,ZI2)'
[5]    I2D←{+2 ⎕NQ'.' 'IDNToDate'⍵}
[6]    ToTS←{d t←1 1 0 0 0⊂⍉⌊0 24 60 60 60⊤⍵
[7]        ↓fmt ⎕FMT(0 ¯1↓↑I2D¨25568+,d),0 ¯1↓t}
[8]    fhist←⎕FHIST tn
[9]    fhist[;2]←ToTS fhist[;2]
[10]   fhist[;1]←⍕¨fhist[;1]
[11]   r←((⊂''),rows),cols⍪fhist
     ∇

Examples

     'c:\temp'⎕FCREATE 1 ⋄ FHist 1
               User  TimeStamp
 Created       0     2012-01-14 12:29:53
 Undefined     0     1970-01-01 00:00:00
 Last ⎕FSTAC   0     2012-01-14 12:29:53
 Undefined     0     1970-01-01 00:00:00
 Last Updated  0     2012-01-14 12:29:53

      (⍳10)⎕FAPPEND 1  ⋄ FHist 1
               User  TimeStamp
 Created       0     2012-01-14 12:29:53
 Undefined     0     1970-01-01 00:00:00
 Last ⎕FSTAC   0     2012-01-14 12:29:53
 Undefined     0     1970-01-01 00:00:00
 Last Updated  0     2012-01-14 12:29:55

      ⎕FUNTIE 1

      'c:\temp'⎕FCREATE 1 ⋄ FHist 1
               User  TimeStamp
 Created       0     2012-01-14 12:29:53
 Undefined     0     1970-01-01 00:00:00
 Last ⎕FSTAC   0     2012-01-14 12:29:53
 Undefined     0     1970-01-01 00:00:00
 Last Updated  0     2012-01-14 12:29:55


File Hold

File Hold {R}←⎕FHOLD Y

Access code 2048

This function holds component file(s) and/or external variable(s). It is used to synchronise access to resources shared between multiple cooperating Dyalog processes. It is not intended to synchronise access between Dyalog threads; for this purpose you should use :Hold.

For a multi-threaded and multi-process application, a single ⎕FHOLD is used to synchronise inter-process access, while :Hold is used in multiple threads to synchronise access between threads in the same process. See also Hold Statement.

If applied to component files, then Y is an integer scalar, vector, or one-row matrix of file tie numbers, or a two-row matrix whose first row contains file tie numbers and whose second row contains passnumbers.

If applied to external variables, then Y is a simple scalar character, a character vector, a non-simple scalar character vector, or a vector of character vectors that specifies one or more names of external variable(s) (NOT the file names associated with those variables). Note that when Y is simple, each character in Y is interpreted as a variable name. If applied to component files and external variables, Y is a vector whose elements are either integer scalars representing tie numbers, or character scalars or vectors containing names of external variables.

The effect is as follows:

  1. All of the user's preceding holds (if any) are released, whether referenced in Y or not.
  2. Execution is suspended until the designated files are free of holds by any other task.
  3. When all the designated files are free, execution proceeds. Until the hold is released, other tasks using ⎕FHOLD on any of the designated files will wait.

If Y is empty, all of the user's preceding holds (if any) are released, and execution continues. A hold is released by any of the following:

  • Another ⎕FHOLD
  • Untying or retying all the designated files. If some but not all are untied or retied, they become free for another task but the hold persists for those that remain tied.
  • Termination of APL.
  • Any untrapped error or interrupt.
  • A return to immediate execution.

Note that a hold is not released by a request for input through ⎕ or ⍞.

⎕FHOLD is generally useful only when called from a defined function, as holds set in immediate execution (desk calculator) mode are released immediately.

If Y is a matrix, the shy result R is Y[1;]. Otherwise, the shy result R is Y.

Examples:

      ⎕FHOLD 1

      ⎕FHOLD ⍬

      ⎕FHOLD ⊂'XTVAR'

      ⎕FHOLD 1 2,[0.5]0 16385

      ⎕FHOLD 1 'XTVAR'


Component File Library

Component File Library R←⎕FLIB Y

Y must be a simple character scalar or vector which specifies the name of the directory whose APL component files are to be listed. If Y is empty, the current working directory is assumed.

The result R is a character matrix containing the names of the component files in the directory with one row per file. The number of columns is given by the longest file name. Each file name is prefixed by Y followed by a directory delimiter character. The ordering of the rows is not defined.

If there are no APL component files accessible to the user in the directory in question, the result is an empty character matrix with 0 rows and 0 columns.

Examples

      ⎕FLIB ''
SALESFILE
COSTS

      ⎕FLIB '.'
./SALESFILE
./COSTS
      ⎕FLIB '../budget'
../budget/SALES.85
../budget/COSTS.85


File Names

File Names R←⎕FNAMES

The result is a character matrix containing the names of all tied files, with one file name per row. The number of columns is that required by the longest file name.

A file name is returned precisely as it was specified when the file was tied. If no files are tied, the result is a character matrix with 0 rows and 0 columns. The rows of the result are in the order in which the files were tied.

Examples

      '/usr/pete/SALESFILE' ⎕FSTIE 16

      '../budget/COSTFILE' ⎕FSTIE 2

      'PROFIT' ⎕FCREATE 5

       ⎕FNAMES
/usr/pete/SALESFILE
../budget/COSTFILE
PROFIT

      ⍴⎕FNAMES
3 19
      ⎕FNUMS,⎕FNAMES
16 /usr/pete/SALESFILE
 2 ../budget/COSTFILE
 5 PROFIT


File Numbers

File Numbers R←⎕FNUMS

The result is an integer vector of the file tie number of all tied files. If no files are tied, the result is empty. The elements of the result are in the order in which the files were tied.

Examples

      '/home/pete/SALESFILE' ⎕FSTIE 16

      '../budget/COSTFILE' ⎕FSTIE 2

      'PROFIT' ⎕FCREATE 5

      ⎕FNUMS
16 2 5

      ⎕FNUMS,⎕FNAMES
16 /home/pete/SALESFILE
 2 ../budget/COSTFILE
 5 PROFIT

      ⎕FUNTIE ⎕FNUMS
      ⍴⎕FNUMS
0


File Properties

File Properties R←X ⎕FPROPS Y

Access Code 1 (to read) or 8192 (to change properties)

⎕FPROPS reports and sets the properties of a component file.

Y must be a simple integer scalar or 1 or 2-element vector containing the file tie number followed by an optional passnumber. If the passnumber is omitted, it is assumed to be 0.

X must be a simple character scalar or vector containing one or more valid Identifiers listed in the table below, or a 2-element nested vector which specifies an Identifier and a (new) value for that property. To set new values for more than one property, X must be is a vector of 2-element vectors, each of which contains an Identifier and a (new) value for that property.

If the left argument is a simple character array, the result R contains the current values for the properties identified by X. If the left argument is nested, the result R contains the previous values for the properties identified by X.

Identifier | Property | Description / Legal Values
S | File Size (read only) | 32 = Small-span Component Files (<4GB) 64 = Large-span Component Files
E | Endian-ness (read only) | 0 = Little-endian 1 = Big-endian
U | Unicode | 0 = Characters will be written as type 82 arrays 1 = Characters will be written as Unicode arrays
J | Journaling | 0 = Disable Journaling 1 = Enable APL crash proof Journaling 2 = Enable System crash proof Journaling; repair needed on recovery 3 = Enable full System crash proof Journaling
C | Checksum | 0 = Disable checksum 1 = Enable checksum
Z | Compression | 0 = Disable compression 1 = Enable compression

The default properties for a newly created file are as follows:

  • S = 64
  • U = 1 (in Unicode Edition) or 0 (in Classic Edition)
  • J = 1
  • C = 1
  • Z = 0
  • E depends upon the computer architecture.

Note that the defaults for C and J can be overridden by calling ⎕FCREATE via the Variant operator ⍠. For further information, see Automatic Tie Number Allocation.

Journaling Levels

Level 1 journaling (APL crash-proof) automatically protects a component file from damage in the event of abnormal termination of the APL process. The file state will be implicitly committed between updates and an incomplete update will automatically be rolled forward or back when the file is re-tied. In the event of an operating system crash the file may be more seriously damaged. If checksum was also enabled it may be repaired using ⎕FCHK but some components may be restored to a previous state or not restored at all.

Level 2 journaling (system crash-proof – repair needed on recovery) extends level 1 by ensuring that a component file is fully repairable using ⎕FCHK with no component loss in the event of an operating system failure. If an update was in progress when the system crashed the affected component will be rolled back to the previous state. Tying and modifying such a file without first running ⎕FCHK may however render it un-repairable.

Level 3 journaling (system crash-proof) extends level 2 by protecting a component file from damage in the event of abnormal termination of the APL process and also the operating system. Rollback of an incomplete update will be automatic and no explicit repair will be needed.

Enabling journaling on a component file will reduce performance of file updates; higher journaling levels have a greater impact.

Journaling levels 2 and 3 cannot be set unless the checksum option is also enabled.

The default level of journaling may be changed using the APL_FCREATE_PROPS_J parameter (see Dyalog for Microsoft Windows Installation and Configuration Guide: Configuration Parameters for more information).

Checksum Option

The checksum option is enabled by default. This enables a damaged file to be repaired using ⎕FCHK. It will however reduce the performance of file updates slightly and result in larger component files. The default may be changed using the APL_FCREATE_PROPS_C parameter (See User Guide).

Enabling the checksum option on an existing non-empty component file will result in all previously written components without a checksum being check-summed and converted. This operation which will take place when ⎕FPROPS is changed, may not therefore be instantaneous.

Journaling and checksum settings may be changed at any time a file is exclusively tied.

Example

      tn←'myfile64' ⎕FCREATE 0
      'SEUJ' ⎕FPROPS tn
64 0 1 0

The following expression disables Unicode and switches Journaling on. The function returns the previous settings:

      ('U' 0)('J' 1) ⎕FPROPS tn
1 0

Note that to set the value of just a single property, the following two statements are equivalent:

      'J' 1 ⎕FPROPS tn
      (,⊂'J' 1) ⎕FPROPS tn

Properties may be read by a task with ⎕FREAD permission (access code 1), and set by a task with ⎕FSTAC access (8192). To set the value of the Journaling property, the file must be exclusively tied.

Recommendation

It is recommended that all component files are protected by a minimum of Level 1 Journalling and have Checksum enabled.

Unprotected files should only be used:

  • for temporary work files where speed is paramount and integrity a secondary issue
  • or where compatibility with Versions of Dyalog prior to Version 12.0 is required

This recommendation is given for the following reasons:

  • Unprotected files are easily damaged by abnormal termination of the interpreter
  • They cannot be repaired using ⎕FCHK
  • They do not support ⎕FHIST
  • They are not well supported by the Dyalog File Server (DFS)
  • They do not support compression of components
  • Additional features added in future may not be supported

Compression Option

Components are compressed using the LZ4 compressor which delivers a medium level of compression, but is considered to be very fast compared to other algorithms.

Compression is intended to deliver a performance gain reading and writing large components on fast computers with slow (e.g. network) file access. Conversely, on a slow computer with fast file access compression may actually reduce read/write performance. For this reason it is optional at the component level.

The default for the 'Z' property is 0 which means no compression; 1 means compression. When written, components are compressed or not according to the current value of the 'Z' property. Changing this property does not change any components already in the file.

A component file may therefore contain a mixture of normal and compressed components. Note that only the data in file components are compressed, the file access matrix and other header information is not compressed.

When read, compressed components are decompressed regardless of the value of the 'Z' property.

An exclusive tie is not needed to change the file property.

Compression is not supported for files in which both Journalling and Checksum are disabled.


File Read Access

File Read Access R←⎕FRDAC Y

Access code 4096

Y must be a simple integer scalar or 1 or 2 element vector containing the file tie number followed by an optional passnumber. If the passnumber is omitted it is assumed to be zero. The result is the access matrix for the designated file.

For details see File Access Control.

Examples

      ⎕FRDAC 1
28 2105 16385
 0 2073 16385
31   ¯1     0


File Read Component Information

File Read Component Information R←⎕FRDCI Y

Access code 512

Y must be a simple integer vector of length 2 or 3 containing the file tie number, component number and an optional passnumber. If the passnumber is omitted it is assumed to be zero.

The result is a 3 element numeric vector containing the following information:

  1. the size of the component in bytes (i.e. how much disk space it occupies).
  2. the user number of the user who last updated the component.
  3. the time of the last update in 60ths of a second since 1st January 1970 (UTC).

Example

      ⎕FRDCI 1 13
2200 207 3.702094494E10


File Read Component

File Read Components R←⎕FREAD Y

Access code 1

Y is a 2 or 3 item vector containing the file tie number, the component number(s), and an optional passnumber. If the passnumber is omitted it is assumed to be zero. All elements of Y must be integers.

The second item in Y may be scalar which specifies a single component number or a vector of component numbers. If it is a scalar, the result is the value of the array that is stored in the specified component on the tied file. If it is a vector, the result is a vector of such arrays.

Note that any invocation of ⎕FREAD is an atomic operation. Thus if compnos is a vector, the statement:

      ⎕FREAD tie compnos passno

will return the same result as:

      {⎕FREAD tie ⍵ passno}¨compnos

However, the first statement will, in the case of a share-tied file, prevent any potential intervening file access from another user (without the need for a ⎕FHOLD). It will also perform slightly faster, especially when reading from a share-tied file.

Examples

      ⍴SALES←⎕FREAD 1 241
3 2 12

GetFile←{⎕io←0                ⍝ Extract contents.
    tie←⍵ ⎕fstie 0            ⍝ new tie number.
    fm to←2↑⎕fsize tie        ⍝ first and next component.
    cnos←fm+⍳to-fm            ⍝ vector of component nos.
    cvec←⎕fread tie cnos      ⍝ vector of components.
    cvec⊣⎕funtie tie        ⍝ ... untie and return.
}


File Rename

File Rename {R}←X ⎕FRENAME Y

Access code 128

Y must be a simple 1 or 2 element integer vector containing a file tie number and an optional passnumber. If the passnumber is omitted it is assumed to be zero.

X must be a simple character scalar or vector containing the new name of the file. This name must be in accordance with the operating system's conventions, and may be specified with a relative or absolute pathname. If no file extension is supplied, the first extension specified by the CFEXT parameter will be added. See CFEXT.

The file being renamed must be tied exclusively.

The shy result of ⎕FRENAME is the tie number of the file.

Examples

      'SALES' ⎕FTIE 1
      'PROFIT' ⎕FTIE 2

      ⎕FNAMES
SALES
PROFIT

      'SALES.85' ⎕FRENAME 1
      '../profits/PROFITS.85' ⎕FRENAME 2
      ⎕FNAMES
SALES.85
../profits/PROFITS.85

Rename←{
    fm to←⍵
    ⎕FUNTIE to ⎕FRENAME fm ⎕FTIE 0
}


File Replace Component

File Replace Component {R}←X ⎕FREPLACE Y

Access code 16

Y must be a simple 2 or 3 element integer vector containing the file tie number, the component number, and an optional passnumber. If the passnumber is omitted it is assumed to be zero. The component number specified must lie within the file's component number limits.

X is any array (including, for example, the ⎕OR of a namespace), and overwrites the value of the specified component. The component information (see File Read Component Information ) is also updated.

The shy result of ⎕FREPLACE is the file index (component number of replaced record).

Example

      SALES←⎕FREAD 1 241

      (SALES×1.1) ⎕FREPLACE 1 241

Define a function to replace (index, value) pairs in a component file JMS.DCF:

Frep←{
    tie←⍺ ⎕FTIE 0
    _←{⍵ ⎕FREPLACE tie ⍺}/¨⍵
    ⎕FUNTIE tie
}

      'jms'Frep(3 'abc')(29 'xxx')(7 'yyy')


File Resize

File Resize {R}←{X}⎕FRESIZE Y

Access code 1024

Y must be a simple integer scalar or 1 or 2 element vector containing the file tie number followed by an optional passnumber. If the passnumber is omitted it is assumed to be zero.

X is an integer that specifies the maximum permitted size of the file in bytes. The value 0 means the maximum possible size of file.

An attempt to update a component file that would cause it to exceed its maximum size will fail with a FILE FULL error (21). A side effect of ⎕FRESIZE is to cause the file to be compacted. This process removes any gaps in the file caused by replacing a component with a shorter array. Any interrupt entered at the keyboard during the compaction is ignored. Note that if the left argument is omitted, the file is simply compacted and the maximum file size remains unchanged.

During compaction, the file is restructured by reordering the components and by amalgamating the free areas at the end of the file. The file is then truncated and excess disk space is released back to the operating system. For a large file with many components, this process may take a significant time.

The shy result of ⎕FRESIZE is the tie number of the file.

Example

      'test'⎕FCREATE 1 ⋄ ⎕FSIZE 1
1 1 120 1.844674407E19
      (10 1000⍴1.1)⎕FAPPEND 1 ⋄ ⎕FSIZE 1
1 2 80288 1.844674407E19

      100000 ⎕FRESIZE 1 ⍝ Limit size to 100000 bytes

      (10 1000⍴1.1)⎕FAPPEND 1
FILE FULL
      (10 1000⍴1.1)⎕FAPPEND 1
     ∧

      ⎕FRESIZE 1      ⍝ Force file compaction.


File Size

File Size R←⎕FSIZE Y

Y must be a simple integer scalar or 1 or 2 element vector containing the file tie number followed by an optional passnumber. If the passnumber is omitted it is assumed to be zero. The result is a 4 element numeric vector containing the following:

Element | Description
1 | the number of first component
2 | 1 + the number of the last component, (i.e. the result of the next ⎕FAPPEND)
3 | the current size of the file in bytes
4 | the file size limit in bytes

Example

      ⎕FSIZE 1
1 21 65271 4294967295


File Set Access

File Set Access {R}←X ⎕FSTAC Y

Access code 8192

Y must be a simple integer scalar or 1 or 2 element vector containing the file tie number followed by an optional passnumber. If the passnumber is omitted it is assumed to be zero.

X must be a valid access matrix, i.e. a 3-column integer matrix with any number of rows. The function sets access control for the specified file operations (1st column), users (3rd column), with the specified passnumbers (2nd column). Note that a 0 in the 1st column specifies all file operations, a ¯1 in the 2nd column specifies that no passnumber is required, and a 0 in the 3rd column specifies all users. For further details, see File Access Control.

The shy result of ⎕FSTAC is the tie number of the file.

Examples

      'SALES' ⎕FCREATE 1
      (3 3⍴28 2105 16385 0 2073 16385 31 ¯1 0) ⎕FSTAC 1
      ((⎕FRDAC 1)⍪21 2105 16385) ⎕FSTAC 1

       (1 3⍴0 ¯1 0)⎕FSTAC 2 ⍝ Let everyone do anything


File Share Tie

File Share Tie {R}←X ⎕FSTIE Y

Y must be 0 or a simple 1 or 2 element integer vector containing an available file tie number to be associated with the file for further file operations, and an optional passnumber. If the passnumber is omitted it is assumed to be zero. The tie number must not already be associated with a tied file.

X must be a simple character scalar or vector which specifies the name of the file to be tied. The file must be named in accordance with the operating system's conventions, and may be specified with a relative or absolute pathname. If no file extension is supplied, the set of extensions specified by the CFEXT parameter are tried one after another until the file is found or the set of extensions is exhausted. See CFEXT.

The file must exist and be accessible by the user. If it is already tied by another task, it must not be tied exclusively.

The shy result of ⎕FSTIE is the tie number of the file.

Automatic Tie Number Allocation

A tie number of 0 as argument to a create, share tie or exclusive tie operation, allocates the first (closest to zero) available tie number and returns it as an explicit result. This allows you to simplify code. For example:

from:

      tie←1+⌈/0,⎕FNUMS  ⍝ With next available number,
      file ⎕FSTIE tie   ⍝ ... share tie file.

to:

      tie←file ⎕FSTIE 0 ⍝ Tie with 1st available number.

Example

      'SALES' ⎕FSTIE 1

      '../budget/COSTS' ⎕FSTIE 2


Exclusive File Tie

Exclusive File Tie {R}←X ⎕FTIE Y

Access code 2

Y must be 0 or a simple 1 or 2 element integer vector containing an available file tie number to be associated with the file for further file operations, and an optional passnumber. If the passnumber is omitted it is assumed to be zero. The tie number must not already be associated with a share tied or exclusively tied file.

X must be a simple character scalar or vector which specifies the name of the file to be exclusively tied. The file must be named in accordance with the operating system's conventions, and may be a relative or absolute pathname. If no file extension is supplied, the set of extensions specified by the CFEXT parameter are tried one after another until the file is found or the set of extensions is exhausted. See CFEXT.

The file must exist and the user must have write access to it. It may not already be tied by another user.

Automatic Tie Number Allocation

A tie number of 0 as argument to a create, share tie or exclusive tie operation, allocates the first (closest to zero) available tie number, and returns it as an explicit result. This allows you to simplify code. For example:

from:

      tie←1+⌈/0,⎕FNUMS ⍝ With next available number,
      file ⎕FTIE tie   ⍝ ... tie file.

to:

      tie←file ⎕FTIE 0 ⍝ Tie with first available number.

The shy result of ⎕FTIE is the tie number of the file.

Examples

      'SALES' ⎕FTIE 1

      '../budget/COSTS' ⎕FTIE  2

      '../budget/expenses' ⎕FTIE 0
3


File Untie

File Untie {R}←⎕FUNTIE Y

Y must be a simple integer scalar or vector (including Zilde). Files whose tie numbers occur in Y are untied. Other elements of Y have no effect.

If Y is empty, no files are untied, but all the interpreter's internal file buffers are flushed and the operating system is asked to flush all file updates to disk. This special facility allows the programmer to add extra security (at the expense of performance) for application data files.

The shy result of ⎕FUNTIE is a vector of tie numbers of the files actually untied.

Example

      ⎕FUNTIE ⎕FNUMS ⍝ Unties all tied files

      ⎕FUNTIE ⍬      ⍝ Flushes all buffers to disk


Native File Append

Native File Append {R}←X ⎕NAPPEND Y

This function appends the ravel of its left argument X to the end of the designated native file. X must be a simple homogeneous APL array. Y is a 1- or 2-element integer vector. Y[1] is a negative integer that specifies the tie number of a native file. The optional second element Y[2] specifies the data type to which the array X is to be converted before it is written to the file.

The shy file index result returned is the position within the file of the end of the record, which is also the start of the following one.

Unicode Edition

Unless you specify the data type in Y[2], a character array will by default be written using type 80.

If the data will not fit into the specified character width (bytes) ⎕NAPPEND will fail with a DOMAIN ERROR.

As a consequence of these two rules, you must specify the data type (either 160 or 320) in order to write Unicode characters whose code-point are in the range 256-65535 and >65535 respectively.

Example

      n←'test'⎕NCREATE 0
      'abc' ⎕nappend n

      'ταβέρνα'⎕nappend n
DOMAIN ERROR
      'ταβέρνα'⎕NAPPEND n
     ∧

      'ταβέρνα'⎕NAPPEND n 160

      ⎕NREAD n 80 3 0
abc
      ⎕NREAD n 160 7
ταβέρνα

To write 2 or more lines, you must insert appropriate end-of-line codes.

      ('hello',(⎕UCS 13 10),'world')⎕nappend ¯1 ⍝ Windows
      ('hello',(⎕UCS 10),'world')⎕nappend ¯1    ⍝ Other


Native File Erase

Native File Erase {R}←X ⎕NERASE Y

This function erases (deletes) a tied native file. Y is a negative integer tie number associated with a tied native file. X is a simple character vector or scalar containing the name of the same file and must be identical to the name used when it was opened by ⎕NCREATE or ⎕NTIE.

The shy result of ⎕NERASE is the tie number that the erased file had.

Example

      file ⎕nerase file ⎕ntie 0


Native File Lock

Native File Lock {R}←X ⎕NLOCK Y

This function assists the controlled update of shared native files by locking a range of bytes.

Locking enables controlled update of native files by co-operating users. A process requesting a lock on a region of a file will be blocked until that region becomes available. A write-lock is exclusive, whereas a read-lock is shared. In other words, any byte in a file may be in one of only three states:

  • Unlocked
  • Write-locked by exactly one process.
  • Read-locked by any number of processes.

Y must be a simple integer scalar or vector containing 1, 2 or 3 items namely:

  1. Tie number
  2. Offset (from 0) of first byte of region. Defaults to 0
  3. Number of bytes to lock. Defaults to maximum possible file size

X must be a simple integer scalar or vector containing 1 or 2 items, namely:

  1. Type: 0: Unlock, 1:Read lock, 2:Write lock.
  2. Timeout: Number of seconds to wait for lock before generating a TIMEOUT error. Defaults to indefinite wait.

The shy result R is Y. To unlock the file, this value should subsequently be supplied in the right argument to 0 ⎕NLOCK.

Examples:

    2 ⎕NLOCK ¯1        ⍝ write-lock whole file
    0 ⎕NLOCK ¯1        ⍝ unlock whole file.
    1 ⎕NLOCK ¯1        ⍝ read (share) lock whole file.
    2 ⎕NLOCK¨⎕NNUMS    ⍝ write-lock all files.
    0 ⎕NLOCK¨⎕NNUMS    ⍝ unlock all files.

    1 ⎕NLOCK ¯1 12 1   ⍝ read-lock byte 12.
    1 ⎕NLOCK ¯1 0 10   ⍝ read-lock first 10 bytes.
    2 ⎕NLOCK ¯1 20     ⍝ write-lock from byte 20 onwards.
    2 ⎕NLOCK ¯1 10 2   ⍝ write-lock 2 bytes from byte 10
    0 ⎕NLOCK ¯1 12 1   ⍝ remove lock from byte 12.

To lock the region immediately beyond the end of the file prior extending it:

   ⎕←region←2 ⎕NLOCK ¯1, ⎕NSIZE ¯1 ⍝ write-lock from EOF.
¯1 1000
   ... ⎕NAPPEND ¯1                 ⍝ append bytes to file
   ... ⎕NAPPEND ¯1                 ⍝ append bytes to file

   0 ⎕NLOCK region                 ⍝ release lock.

The left argument may have a second optional item that specifies a timeout value. If a lock has not been acquired within this number of seconds, the acquisition is abandoned and a TIMEOUT error reported.

    2 10 ⎕nlock ¯1      ⍝ wait up to 10 seconds for lock.

Notes:

There is no per-byte cost associated with region locking. It takes the same time to lock/unlock a region, irrespective of that region's size.

Different file servers implement locks in slightly different ways. For example on some systems, locks are advisory. This means that a write lock on a region precludes other locks intersecting that region, but doesn't stop reads or writes across the region. On the other hand, mandatory locks block both other locks and read/write operations. ⎕NLOCK will just pass the server's functionality along to the APL programmer without trying to standardise it across different systems.

All locks on a file will be removed by ⎕NUNTIE.

Blocked locking requests can be freed by a strong interrupt. Under Windows, this operation is performed from the Dyalog APL pop-up menu in the system tray.

Errors

In this release, an attempt to unlock a region that contains bytes that have not been locked results in a DOMAIN ERROR.

A LIMIT ERROR results if the operating system lock daemon has insufficient resources to honour the locking request.

Some systems support only write locks. In this case an attempt to set a read lock will generate a DOMAIN ERROR, and it may be appropriate for the APL programmer to trap the error and apply a write lock.

No attempt will be made to detect deadlock. Some servers do this and if such a condition is detected, a DEADLOCK error (1008) will be reported.


Native File Names

Native File Names R←⎕NNAMES

This niladic function reports the names of all currently open native files. R is a character matrix. Each row contains the name of a tied native file padded if necessary with blanks. The names are identical to those that were given when opening the files with ⎕NCREATE or ⎕NTIE. The rows of the result are in the order in which the files were tied.


Native File Numbers

Native File Numbers R←⎕NNUMS

This niladic function reports the tie numbers associated with all currently open native files. R is an integer vector of negative tie numbers. The elements of the result are in the order in which the files were tied.


Native File Read

Native File Read R←⎕NREAD Y

This monadic function reads data from a native file. Y is a 3- or 4-element integer vector whose elements are as follows:

[1] | negative tie number,
[2] | conversion code (see below),
[3] | count. If this value is ¯1, all of the elements defined by Y[2] are read from the position specified by Y[4] to the end of the file. This may result in the last few bytes in the file being ignored if they do not form a complete element.
[4] | start byte, counting from 0. If this value omitted or is ¯1, data is read starting from the current position in the file (initially 0).

Notes:

Y[2] specifies conversion to an APL internal form as follows. Note that the internal formats for character arrays differ between the Unicode and Classic Editions.

If both Y[3] and Y[4] have the value ¯1, then ⎕NREAD reads data from the current position in the file to the end of the file.

⎕NREAD can be used with any file. However, calling ⎕NREAD with at least one of Y[3 4] set to ¯1 is intended for regular files only; using on pipes, FIFOs or other special types of file is not recommended.

Table 25: Unicode Edition: Conversion Codes

Value | Number of bytes read | Result Type | Result shape
11 | count | 1 bit Boolean | 8 × count
80 | count | 8 bits character | count
82Conversion code 82 is permitted in the Unicode Edition for compatibility and causes 1-byte data on file to be translated (according to ⎕NXLATE) from ⎕AV indices into normal (Unicode) characters of type 80, 160 or 320. 1 | count | 8 bits character | count
83 | count | 8 bits integer | count
160 | 2 × count | 16-bits character | count
163 | 2 × count | 16 bits integer | count
320 | 4 × count | 32-bits character | count
323 | 4 × count | 32 bits integer | count
645 | 8 × count | 64 bits floating | count

Table 26: Classic Edition: Conversion Codes

Value | Number of bytes read | Result Type | Result shape
11 | count | 1 bit Boolean | 8 × count
82 | count | 8 bits character | count
83 | count | 8 bits integer | count
163 | 2 × count | 16 bits integer | count
323 | 4 × count | 32 bits integer | count
645 | 8 × count | 64 bits floating | count

Note that types 80, 160 and 320 and 83 and 163 are exclusive to Dyalog APL.

Example

      DATA←⎕NREAD ¯1 160 (0.5×⎕NSIZE ¯1) 0 ⍝ Unicode
      DATA←⎕NREAD ¯1 82 (⎕NSIZE ¯1) 0      ⍝ Classic
      DATA←⎕NREAD ¯1 82 ¯1 0       ⍝ Shorter version


Native File Rename

Native File Rename {R}←X ⎕NRENAME Y

⎕NRENAME is used to rename a native file.

Y is a negative integer tie number associated with a tied native file. X is a simple character vector or scalar containing a valid (and unused) file name.

The shy result of ⎕NRENAME is the tie number of the renamed file.


Native File Replace

Native File Replace {R}←X ⎕NREPLACE Y

⎕NREPLACE is used to write data to a native file, replacing data which is already there.

X must be a simple homogeneous APL array containing the data to be written.

Y is a 2- or 3-element integer vector whose elements are as follows:

[1] | negative tie number,
[2] | start byte, counting from 0, at which the data is to be written; the value ¯1 causes the data is read from the current position in the file (initially, 0).
[3] | conversion code (optional).

See Native File Read for a list of valid conversion codes.

The shy result is the position within the file of the end of the record, or, equivalently, the start of the following one. Used, for example, in:

      ⍝ Replace sequentially from indx.
      {⍺ ⎕NREPLACE tie ⍵}/vec,indx

Unicode Edition

Unless you specify the data type in Y[3], a character array will by default be written using type 80.

If the data will not fit into the specified character width (bytes) ⎕NREPLACE will fail with a DOMAIN ERROR.

As a consequence of these two rules, you must specify the data type (either 160 or 320) in order to write Unicode characters whose code-point is in the range 256-65535 and >65535 respectively.

Example

      n←'test'⎕NTIE 0 ⍝ See Example

      ⎕NREAD n 80 3 0
abc
      ⎕NREAD n 160 7
ταβέρνα

      ⎕←'εστιατόριο'⎕NREPLACE n 3
DOMAIN ERROR
      ⎕←'εστιατόριο'⎕NREPLACE n 3
     ∧

      ⎕←'εστιατόριο'⎕NREPLACE n 3 160
23
      ⎕NREAD n 80 3 0
abc
      ⎕NREAD n 160 10
εστιατόριο

For compatibility with old files, you may specify that the data be converted to type 82 on output. The conversion (to ⎕AV indices) will be determined by the local value of ⎕AVU.


Native File Resize

Native File Resize {R}←X ⎕NRESIZE Y

This function changes the size of a native file.

Y is a negative integer tie number associated with a tied native file.

X is a single integer value that specifies the new size of the file in bytes. If X is smaller than the current file size, the file is truncated. If X is larger than the current file size, the file is extended and the value of additional bytes is undefined.

The shy result of ⎕NRESIZE is the tie number of the resized file.


Native File Size

Native File Size R←⎕NSIZE Y

This reports the size of a native file.

Y is a negative integer tie number associated with a tied native file. The result R is the size of the file in bytes.


Native File Tie

Native File Tie {R}←X ⎕NTIE Y

⎕NTIE opens a native file.

X is a simple character vector or scalar containing a valid pathname for an existing native file.

Y is a 1- or 2-element vector.

Y[1] is a negative integer value that specifies an (unused) tie number by which the file may subsequently be referred.

Y[2] is optional and specifies the mode in which the file is to be opened. This is an integer value calculated as the sum of 2 codes. The first code refers to the type of access needed from users who have already tied the native file. The second code refers to the type of access you wish to grant to users who subsequently try to open the file while you have it open.

If Y[2] is omitted, the system tries to open the file with the default value of 66 (read and write access for this process and for any subsequent processes that attempt to access the file). If this fails, the system attempts to open the file with the value 64 (read access for this process, read and write for subsequent processes).

Needed from existing users |  | Granted to subsequent users
0 | read access | 0 | see noteThe original meaning of this value is no longer relevant. 0 now means the same as 16 (no access). 1
1 | write access | 16 | no access (exclusive)
2 | read and write access | 32 | read access
 |  | 48 | write access
 |  | 64 | read and write access

On UNIX systems, the second column has no meaning and only the first code (16|mode) is passed to the open(2) call as the access parameter. See include file fcntl.h for details. See also Native File Lock which is not platform dependent.

R is the tie number by which the file may subsequently be referred. If Y[1] is a negative integer, then R is a shy result; if Y[1] is 0, R is an explicit result.

Automatic Tie Number Allocation

A tie number of 0 as argument to a create or tie operation, allocates, and returns as an explicit result, the first (closest to zero) available tie number. This allows you to simplify code. For example:

from:

      tie←¯1+⌊/0,⎕NNUMS    ⍝ With next available number,
      file ⎕NTIE tie       ⍝ ... tie file.

to:

      tie←file ⎕NTIE 0     ⍝ Tie with first available no.

Example

ntie←{                  ⍝ tie file and return tie no.
    ⍺←2+64              ⍝ default all access.
    ⍵ ⎕ntie 0 ⍺         ⍝ return new tie no.
}

Note:

If the native file is already tied, executing ⎕NTIE with the same or a different tie number simply re-ties it with the same or the new tie number. Re-tying a file with a tie number of 0, allocates a new tie number. This feature may be used to re--tie the file using a different mode.


Native File Untie

Native File Untie {R}←⎕NUNTIE Y

This closes one or more native files. Y is a scalar or vector of negative integer tie numbers. The files associated with elements of Y are closed. Native file untie with a zero length argument (⎕NUNTIE ⍬) flushes all file buffers to disk - see File Untie for more explanation.

The shy result of ⎕NUNTIE is a vector of tie numbers of the files actually untied.


Native File Translate

Native File Translate {R}←{X}⎕NXLATE Y

This associates a character translation vector with a native file or, if Y is 0, with the use by ⎕DR.

A translate vector is a 256-element vector of integers from 0-255. Each element maps the corresponding ⎕AV position onto an ANSI character code.

For example, to map ⎕AV[17+⎕IO] onto ANSI 'a' (code 97), element 17 of the translate vector is set to 97.

⎕NXLATE is a non-Unicode (Classic Edition) feature and is retained in the Unicode Edition only for compatibility.

Y is either a negative integer tie number associated with a tied native file or 0. If Y is negative, monadic ⎕NXLATE returns the current translation vector associated with the corresponding native file. If specified, the left argument X is a 256-element vector of integers that specifies a new translate vector. In this case, the old translate vector is returned as a shy result. If Y is 0, it refers to the translate vector used by ⎕DR to convert to and from character data.

The system treats a translate vector with value (⍳256)-⎕IO as meaning no translation and thus provides raw input/output bypassing the whole translation process.

The default translation vector established at ⎕NTIE or ⎕NCREATE time is derived from the mapping defined in the current output translation table (normally WIN.DOT) and maps alphabetic, numeric and most other characters in ⎕AV to their corresponding ANSI positions. However, some characters are not resolved by this process and it is recommended that users define translate vectors to cover all cases.

Unicode Edition

⎕NXLATE is relevant in the Unicode Edition only to process Native Files that contain characters expressed as indices into ⎕AV, such as files written by the Classic Edition.

In the Unicode Edition, when reading data from a Native File using conversion code 82, incoming bytes are translated first to ⎕AV indices using the translation table specified by ⎕NXLATE, and then to type 80, 160 or 320 using ⎕AVU. When writing data to a Native File using conversion code 82, characters are converted using these two translation tables in reverse.


Thread Child Numbers

Thread Child Numbers R←⎕TCNUMS Y

Y must be a simple array of integers representing thread numbers.

The result R is a simple integer vector of the child threads of each thread of Y.

Examples

      ⎕TCNUMS 0
2 3

      ⎕TCNUMS 2 3
4 5 6 7 8 9


Current Thread Identity

Current Thread Identity R←⎕TID

R is a simple integer scalar whose value is the number of the current thread.

Examples

      ⎕TID     ⍝ Base thread number
0

      ⍎&'⎕TID' ⍝ Thread number of async ⍎.
1


Kill Thread

Kill Thread {R}←{X}⎕TKILL Y

Y must be a simple array of integers representing thread numbers to be terminated. X is a Boolean single, defaulting to 1, which indicates that all descendant threads should also be terminated.

The shy result R is a vector of the numbers of all threads that have been terminated.

The base thread 0 is always excluded from the cull.

Examples

      ⎕TKILL 0            ⍝ Kill background threads.

      ⎕TKILL ⎕TID         ⍝ Kill self and descendants.

      0 ⎕TKILL ⎕TID       ⍝ Kill self only.

      ⎕TKILL ⎕TCNUMS ⎕TID ⍝ Kill descendants.


Current Thread Name

Current Thread Name ⎕TNAME

The system variable ⎕TNAME reports and sets the name of the current APL thread. This name is used to identify the thread in the Tracer.

The default value of ⎕TNAME is an empty character vector.

You may set ⎕TNAME to any valid character vector, but it is recommended that control characters (such as ⎕AV[⎕IO] ) be avoided.

Example:

      ⎕TNAME←'Dylan'
      ⎕TNAME
Dylan


Thread Numbers

Thread Numbers R←⎕TNUMS

⎕TNUMS reports the numbers of all current threads.

R is a simple integer vector of the base thread and all its living descendants.

Example

      ⎕TNUMS
0 2 4 5 6 3 7 8 9


Wait for Threads to Terminate

Wait for Threads to Terminate R←⎕TSYNC Y

Y must be a simple array of thread numbers.

If Y is a simple scalar, R is an array, the result (if any) of the thread.

If Y is a simple non-scalar, R has the same shape as Y, and result is an array of enclosed thread results.

Examples

      dup←{⍵ ⍵}        ⍝ Duplicate

      ⎕←dup&88         ⍝ Show thread number
11
88 88

      ⎕TSYNC dup&88    ⍝ Wait for result
88 88

      ⎕TSYNC,dup&88
 88 88

      ⎕TSYNC dup&1 2 3
 1 2 3  1 2 3

      ⎕TSYNC dup&¨1 2 3
 1 1  2 2  3 3

Deadlock

The interpreter detects a potential deadlock if a number of threads wait for each other in a cyclic dependency. In this case, the thread that attempts to cause the deadlock issues error number 1008: DEADLOCK.

     ⎕TSYNC ⎕TID      ⍝ Wait for self
DEADLOCK
      ⎕TSYNC ⎕TID
      ^

      ⎕EN
1008

Potential Value Error

If any item of Y does not correspond to the thread number of an active thread, or if any subject thread terminates without returning a result, then ⎕TSYNC does not return a result. This means that, if the calling context of the ⎕TSYNC requires a result, for example: rslt←⎕TSYNC tnums, a VALUE ERROR will be generated. This situation can occur if threads have completed before ⎕TSYNC is called.

      ⎕←÷&4          ⍝ thread (3) runs and terminates.
3
0.25
      ⎕TSYNC 3       ⍝ no result required: no prob
      ⎕←⎕tsync 3     ⍝ context requires result
VALUE ERROR

      ⎕←⎕tsync {}&0  ⍝ non-result-returning fn: no result.
VALUE ERROR

Coding would normally avoid such an inconvenient VALUE ERROR either by arranging that the thread-spawning and ⎕TSYNC were on the same line:

      rslt ← ⎕TSYNC myfn&¨ argvec

or

      tnums←myfn&¨ argvec ⋄ rslt←⎕TSYNC tnums

or by error-trapping the VALUE ERROR.


Get Tokens

Get Tokens {R}←{X} ⎕TGET Y

Y must be a simple integer scalar or vector that specifies one or more tokens, each with a specific non-zero token type, that are to be retrieved from the pool.

X is an optional time-out value in seconds.

Shy result R is a scalar or vector containing the values of the tokens of type Y that have been retrieved from the token pool.

Note that types of the tokens in the pool may be positive or negative, and the elements of Y may also be positive or negative.

A request (⎕TGET) for a positive token will be satisfied by the presence of a token in the pool with the same positive or negative type. If the pool token has a positive type, it will be removed from the pool. If the pool token has a negative type, it will remain in the pool. Negatively typed tokens will therefore satisfy an infinite number of requests for their positive equivalents. Note that a request for a positive token will remove one if it is present, before resorting to its negative equivalent

A request for a negative token type will only be satisfied by the presence of a negative token type in the pool, and that token will be removed.

If, when a thread calls ⎕TGET, the token pool satisfies all of the tokens specified by Y, the function returns immediately with a (shy) result that contains the values associated with the pool tokens. Otherwise, the function will block (wait) until all of the requested tokens are present or until a timeout (as specified by X) occurs.

For example, if the pool contains only tokens of type 2:

    ⎕TGET 2 4        ⍝ blocks waiting for a 4-token ...

The ⎕TGET operation is atomic in the sense that no tokens are taken from the pool until all of the requested types are present. While this last example is waiting for a 4-token, other threads could take any of the remaining 2-tokens.

Note also, that repeated items in the right argument are distinct. The following will block until there are at least 3 × 2-tokens in the pool:

    ⎕TGET 3/2       ⍝ wait for 3 × 2-tokens ...

The pool is administered on a first-in-first-out basis. This is significant only if tokens of the same type are given distinct values. For example:

    ⎕TGET ⎕TPOOL             ⍝ empty pool.

    'ABCDE'⎕TPUT¨2 2 3 2 3  ⍝ pool some tokens.

    ⊢⎕TGET 2 3
AC

    ⊢⎕TGET 2 3
BE

Timeout is signalled by the return of an empty numeric vector ⍬ (zilde). By default, the value of a token is the same as its type. This means that, unless you have explicitly set the value of a token to ⍬, a ⎕TGET result of ⍬ unambiguously identifies a timeout.

Beware - the following statement will wait forever and can only be terminated by an interrupt.

    ⎕TGET 0       ⍝ wait forever ...

Note too that if a thread waiting to ⎕TGET tokens is ⎕TKILLed, the thread disappears without removing any tokens from the pool. Conversely, if a thread that has removed tokens from the pools is ⎕TKILLed, the tokens are not returned to the pool.


Token Pool

Token Pool R←⎕TPOOL

R is a simple scalar or vector containing the token types for each of the tokens that are currently in the token pool.

The following (⎕ML=0) function returns a 2-column snapshot of the contents of the pool. It does this by removing and replacing all of the tokens, restoring the state of the pool exactly as before. Coding it as a single expression guarantees that snap is atomic and cannot disturb running threads.

      snap←{(⎕TGET ⍵){(⍉↑⍵ ⍺) ⊣ ⍺ ⎕TPUT¨⍵}⍵}

      snap ⎕TPOOL
1       hello world
2                 2
3                 2
2  three-type token
2                 2


Put Tokens

Put Tokens {R}←{X} ⎕TPUT Y

Y must be a simple integer scalar or vector of non-zero token types.

X is an optional array of values to be stored in each of the tokens specified by Y.

Shy result R is a vector of thread numbers (if any) unblocked by the ⎕TPUT.

Examples

    ⎕TPUT 2 3 2     ⍝ put a 2-token, a 3-token and another
                      2-token into the pool.

    88 ⎕TPUT 2      ⍝ put another 2-token into the pool
                      this token has the value 88.

    'Hello'⎕TPUT ¯4 ⍝ put a ¯4-token into the pool with
                      the value 'Hello'.

If X is omitted, the value associated with each of the tokens added to the pool is the same as its type.

Note that you cannot put a 0-token into the pool; 0-s are removed from Y.


Token Requests

Token Requests R←⎕TREQ Y

Y is a simple scalar or vector of thread numbers.

R is a vector containing the concatenated token requests for all the threads specified in Y. This is effectively the result of catenating all of the right arguments together for all threads in Y that are currently executing ⎕TGET.

Example

    ⎕TREQ ⎕TNUMS    ⍝ tokens required by all threads.


Line Count

Line Count R←⎕LC

This is a simple vector of line numbers drawn from the state indicator (See The State Indicator). The most recently activated line is shown first. If a value corresponds to a defined function in the state indicator, it represents the current line number where the function is either suspended or pendent.

The value of ⎕LC changes immediately upon completion of the most recently activated line, or upon completion of execution within ⍎ or ⎕. If a ⎕STOP control is set, ⎕LC identifies the line on which the stop control is effected. In the case where a stop control is set on line 0 of a defined function, the first entry in ⎕LC is 0 when the control is effected.

The value of ⎕LC in a clear workspace is the null vector.

Examples

      )SI
#.TASK1[5]*
⍎
#.BEGIN[3]

      ⎕LC
5 3
      →⎕LC
      ⎕LC

      ⍴⎕LC
0


Latent Expression

Latent Expression ⎕LX

This may be a character vector or scalar representing an APL expression. The expression is executed automatically when the workspace is loaded. If APL is invoked using the -x flag, this execution is suppressed.

The value of ⎕LX in a clear workspace is ''.

Example

      ⎕LX←'''GOOD MORNING PETE'''

      )SAVE GREETING
GREETING saved Tue Sep 8 10:49:29 1998

      )LOAD GREETING
./GREETING saved Tue Sep 8 10:49:29 1998
GOOD MORNING PETE


Name Classification

Name Classification R←⎕NC Y

Y must be a simple character scalar, vector, matrix, or vector of vectors that specifies a list of names. R is a simple numeric vector containing one element per name in Y. Each element of R is the name class of the active referent to the object named in Y.

If Y is simple, a name class may be:

Name Class | Description
¯1 | invalid name
0 | unused name
1 | Label
2 | Variable
3 | Function
4 | Operator
8 | Event
9 | Object (GUI, namespace, COM, .NET)

If Y is nested a more precise analysis of name class is obtained whereby different types are identified by a decimal extension. For example, defined functions have name class 3.1, dfns have name class 3.2, and so forth. The complete set of name classification is as follows:

 | Array (2) | Function (3) | Operator (4) | Namespace (9)
n.1 | Variable | Traditional | Traditional | Created by ⎕NS,)NS or :Namespace
n.2 | Field | dfn | dop | Instance
n.3 | Property | Derived or Primitive | Derived or Primitive |
n.4 |  |  |  | Class
n.5 |  |  |  | Interface
n.6 | External Shared | External |  | External Class
n.7 |  |  |  | External Interface

In addition, values in R are negative to identify names of methods, properties and events that are inherited through the class hierarchy of the current class or instance.

Variable (Name-Class 2.1)

Conventional APL arrays have name-class 2.1.

      NUM←88
      CHAR←'Hello World'

      ⎕NC ↑'NUM' 'CHAR'
2 2

      ⎕NC 'NUM' 'CHAR'
2.1 2.1

      'MYSPACE'⎕NS ''
      MYSPACE.VAR←10
      MYSPACE.⎕NC'VAR'
2
      MYSPACE.⎕NC⊂'VAR'
2.1

Field (Name-Class 2.2)

Fields defined by APL Classes have name-class 2.2.

:Class nctest
    :Field Public pubFld
    :Field pvtFld

    ∇ r←NameClass x
      :Access Public
      r←⎕NC x
    ∇
...
:EndClass ⍝ nctest

      ncinst←⎕NEW nctest

The name-class of a Field, whether Public or Private, viewed from a Method that is executing within the Instance Space, is 2.2.

      ncinst.NameClass'pubFld' 'pvtFld'
2.2 2.2

Note that an internal Method sees both Public and Private Fields in the Class Instance. However, when viewed from outside the instance, only public fields are visible

      ⎕NC 'ncinst.pubFld' 'ncinst.pvtFld'
¯2.2 0

In this case, the name-class is negative to indicate that the name has been exposed by the class hierarchy, rather than existing in the associated namespace which APL has created to contain the instance. The same result is returned if ⎕NC is executed inside this space:

      ncinst.⎕NC'pubFld' 'pvtFld'
¯2.2 0

Note that the names of Fields are reported as being unused if the argument to ⎕NC is simple.

      ncinst.⎕NC 2 6⍴'pubFldpvtFld'
0 0

Property (Name-Class 2.3)

Properties defined by APL Classes have name-class 2.3.

:Class nctest
    :Field pvtFld←99

    :Property pubProp
    :Access Public
        ∇ r←get
          r←pvtFld
        ∇
    :EndProperty

    :Property pvtProp
        ∇ r←get
          r←pvtFld
        ∇
    :EndProperty

    ∇ r←NameClass x
      :Access Public
      r←⎕NC x
    ∇
...
:EndClass ⍝ nctest

      ncinst←⎕NEW nctest

The name-class of a Property, whether Public or Private, viewed from a Method that is executing within the Instance Space, is 2.3.

      ncinst.NameClass'pubProp' 'pvtProp'
2.3 2.3

Note that an internal Method sees both Public and Private Properties in the Class Instance. However, when viewed from outside the instance, only Public Properties are visible

      ⎕NC 'ncinst.pubProp' 'ncinst.pvtProp'
¯2.3 0

In this case, the name-class is negative to indicate that the name has been exposed by the class hierarchy, rather than existing in the associated namespace which APL has created to contain the instance. The same result is returned if ⎕NC is executed inside this space:

      ncinst.⎕NC 'pubProp' 'pvtProp'
¯2.3 0

Note that the names of Properties are reported as being unused if the argument to ⎕NC is simple.

      ncinst.⎕NC 2 6⍴'pubProppvtProp'
0 0

External Property (Name-Class 2.6)

Properties exposed by external objects (.NET and COM and the APL GUI) have name-class ¯2.6.

      ⎕USING←'System'
      dt←⎕NEW DateTime (2006 1 1)
      dt.⎕NC 'Day' 'Month' 'Year'
¯2.6 ¯2.6 ¯2.6

      'ex' ⎕WC 'OLEClient' 'Excel.Application'
      ex.⎕NC 'Caption' 'Version' 'Visible'
¯2.6 ¯2.6 ¯2.6

     'f'⎕WC'Form'
      f.⎕NC'Caption' 'Size'
¯2.6 ¯2.6

Note that the names of such Properties are reported as being unused if the argument to ⎕NC is simple.

      f.⎕NC 2 7⍴'CaptionSize   '
0 0

Defined Function (Name-Class 3.1)

Traditional APL defined functions have name-class 3.1.

     ∇ R←AVG X
[1]    R←(+/X)÷⍴X
     ∇
      AVG ⍳100
50.5

      ⎕NC'AVG'
3
      ⎕NC⊂'AVG'
3.1

      'MYSPACE'⎕NS 'AVG'
       MYSPACE.AVG ⍳100
50.5

      MYSPACE.⎕NC'AVG'
3
      ⎕NC⊂'MYSPACE.AVG'
3.1

Note that a function that is simply cloned from a defined function by assignment retains its name-class.

      MEAN←AVG
      ⎕NC'AVG' 'MEAN'
3.1 3.1

Whereas, the name of a function that amalgamates a defined function with any other functions has the name-class of a Derived Function, i.e. 3.3.

      VMEAN←AVG∘,
      ⎕NC'AVG' 'VMEAN'
3.1 3.3

Dfn (Name-Class 3.2)

Dfns have name-class 3.2

      Avg←{(+/⍵)÷⍴⍵}

      ⎕NC'Avg'
3
      ⎕NC⊂'Avg'
3.2

Derived Function (Name-Class 3.3)

Names that reference a primitive or derived function have a name-class of 3.3.

      PLUS←+
      SUM←+/
      CUM←PLUS\
      ⎕NC'PLUS' 'SUM' 'CUM'
3.3 3.3 3.3
      ⎕NC 3 4⍴'PLUSSUM CUM '
3 3 3

Note the difference between the name-class of a name referring to a defined function (3.1) and that of a name referring to a defined function bound with an operator to form a derived function (3.3). Trains, being derived functions, also have nameclass 3.3.

     ∇ R←AVG X
[1]    R←(+/X)÷⍴X
     ∇

      MEAN←AVG
      VMEAN←AVG∘,

      negrec←-,÷

      ⎕NC'AVG' 'MEAN' 'VMEAN' 'negrec'
3.1 3.1 3.3 3.3

External Function (Name-Class 3.6)

Methods exposed by the Dyalog APL GUI and COM and .NET objects have name-class ¯3.6. Methods exposed by External Functions created using ⎕NA and ⎕SH all have name-class 3.6.

      'F'⎕WC'Form'

      F.⎕NC'GetTextSize' 'GetFocus'
¯3.6 ¯3.6

      'EX'⎕WC'OLEClient' 'Excel.Application'
      EX.⎕NC 'Wait' 'Save' 'Quit'
¯3.6 ¯3.6 ¯3.6

      ⎕USING←'System'
      dt←⎕NEW DateTime (2006 1 1)
      dt.⎕NC 'AddDays' 'AddHours'
¯3.6 ¯3.6

      'beep'⎕NA'user32|MessageBeep i'

      ⎕NC'beep'
3
      ⎕NC⊂'beep'
3.6
      'xutils'⎕SH''
      )FNS
avx     box     dbr     getenv  hex     ltom    ltov    mtol    ss      vtol
      ⎕NC'hex' 'ss'
3.6 3.6

Note that the names of such Methods are reported as being unused if the argument to ⎕NC is simple.

      'F'⎕WC'Form'
      F.⎕NC↑'GetTextSize' 'GetFocus'
0 0

Operator (Name-Class 4.1)

Traditional Defined Operators have name-class 4.1.

      ∇FILTER∇
     ∇ VEC←(P FILTER)VEC  ⍝ Select from VEC those elts ..
[1]    VEC←(P¨VEC)/VEC    ⍝ for which BOOL fn P is true.
     ∇

      ⎕NC'FILTER'
4
      ⎕NC⊂'FILTER'
4.1

Dop (Name-Class 4.2)

Dops have name-class 4.2.

     pred←{⎕IO ⎕ML←1 3   ⍝ Partitioned reduction.
     ⊃⍺⍺/¨(⍺/⍳⍴⍺)⊂⍵
     }

      2 3 3 2 +pred ⍳10
3 12 21 19

      ⎕NC'pred'
4
      ⎕NC⊂'pred'
4.2

Derived Operator (Name-Class 4.3)

Derived operators include:

  • A name referring to a monadic operator.
  • A dyadic operator curried with its right-operand.

Example:

       each←¨
       each
¨
       ⎕NC ⊂'each'
4.3
       inv←⍣¯1
       inv
⍣ ¯1
       ⎕NC ⊂'inv'
4.3
       c2f←(32∘+)∘(×∘1.8) ⍝ Centigrade to Fahrenheit
       f2c 0 100
32 212
       f2c inv 32 212     ⍝ Fahrenheit to Centigrade
0 100

External Event (Name-Class 8.6)

Events exposed by Dyalog APL GUI objects, COM and .NET objects have name-class ¯8.6.

      f←⎕NEW'Form'('Caption' 'Dyalog GUI Form')
      f.⎕NC'Close' 'Configure' 'MouseDown'
¯8.6 ¯8.6 ¯8.6

      xl←⎕NEW'OLEClient'(⊂'ClassName' 'Excel.Application')
      xl.⎕NL -8
 NewWorkbook  SheetActivate  SheetBeforeDoubleClick ...

      xl.⎕NC 'SheetActivate' 'SheetCalculate'
¯8.6 ¯8.6

    ⎕USING←'System.Windows.Forms,system.windows.forms.dll'
    ⎕NC,⊂'Form'
9.6
    Form.⎕NL -8
 Activated  BackgroundImageChanged  BackColorChanged ...

Namespace (Name-Class 9.1)

Plain namespaces created using ⎕NS, or fixed from a :Namespace script, have name-class 9.1.

      'MYSPACE' ⎕NS ''
      ⎕NC'MYSPACE'
9
      ⎕NC⊂'MYSPACE'
9.1

Note however that a namespace created by cloning, where the right argument to ⎕NS is a ⎕OR of a namespace, retains the name-class of the original space.

      'CopyMYSPACE'⎕NS ⎕OR 'MYSPACE'
      'CopyF'⎕NS ⎕OR 'F'⎕WC'Form'

      ⎕NC'MYSPACE' 'F'
9.1 9.2
      ⎕NC'CopyMYSPACE' 'CopyF'
9.1 9.2

The Name-Class of .NET namespaces (visible through ⎕USING) is also 9.1

      ⎕USING←''
      ⎕NC 'System' 'System.IO'
9.1 9.1

Instance (Name-Class 9.2)

Instances of Classes created using ⎕NEW, and GUI objects created using ⎕WC all have name-class 9.2.

      MyInst←⎕NEW MyClass
      ⎕NC'MyInst'
9
      ⎕NC⊂'MyInst'
9.2
      UrInst←⎕NEW ⎕FIX ':Class'  ':EndClass'
      ⎕NC 'MyInst' 'UrInst'
9.2 9.2

      'F'⎕WC 'Form'
      'F.B' ⎕WC 'Button'
      ⎕NC 2 3⍴'F  F.B'
9 9
      ⎕NC'F' 'F.B'
9.2 9.2

      F.⎕NC'B'
9
      F.⎕NC⊂,'B'
9.2

Instances of COM Objects whether created using ⎕WC or ⎕NEW also have name-class 9.2.

      xl←⎕NEW'OLEClient'(⊂'ClassName' 'Excel.Application')
      'XL'⎕WC'OLEClient' 'Excel.Application'
      ⎕NC'xl' 'XL'
9.2 9.2

The same is true of Instances of .NET Classes (Types) whether created using ⎕NEW or .New.

      ⎕USING←'System'
      dt←⎕NEW DateTime (3↑⎕TS)
      DT←DateTime.New 3↑⎕TS
      ⎕NC 'dt' 'DT'
9.2 9.2

Note that if you remove the GUI component of a GUI object, using the Detach method, it reverts to a plain namespace.

      F.Detach
      ⎕NC⊂,'F'
9.1

Correspondingly, if you attach a GUI component to a plain namespace using the monadic form of ⎕WC, it morphs into a GUI object

      F.⎕WC 'PropertySheet'
      ⎕NC⊂,'F'
9.2

Class (Name-Class 9.4)

Classes created using the editor or ⎕FIX have name-class 9.4.

      )ED ○MyClass

:Class MyClass
    ∇ r←NameClass x
      :Access Public Shared
      r←⎕NC x
    ∇
:EndClass ⍝ MyClass

      ⎕NC 'MyClass'
9
      ⎕NC⊂'MyClass'
9.4

      ⎕FIX ':Class UrClass'  ':EndClass'
      ⎕NC 'MyClass' 'UrClass'
9.4 9.4

Note that the name of the Class is visible to a Public Method in that Class, or an Instance of that Class.

      MyClass.NameClass'MyClass'
9
      MyClass.NameClass⊂'MyClass'
9.4

Interface (Name-Class 9.5)

Interfaces, defined by :Interface ... :EndInterface clauses, have name-class 9.5.

:Interface IGolfClub
:Property Club
    ∇ r←get
    ∇
    ∇ set
    ∇
:EndProperty

∇ Shank←Swing Params
∇

:EndInterface ⍝ IGolfClub

      ⎕NC 'IGolfClub'
9
      ⎕NC ⊂'IGolfClub'
9.5

External Class (Name-Class 9.6)

External Classes (Types) exposed by .NET have name-class 9.6.

      ⎕USING←'System' 'System.IO'

      ⎕NC 'DateTime' 'File' 'DirectoryInfo'
9.6 9.6 9.6

Note that referencing a .NET class (type) with ⎕NC, fixes the name of that class in the workspace and obviates the need for APL to repeat the task of searching for and loading the class when the name is next used.

External Interface (Name-Class 9.7)

External Interfaces exposed by .NET have name-class 9.7.

      ⎕USING←'System.Web.UI,system.web.dll'

      ⎕NC 'IPostBackDataHandler' 'IPostBackEventHandler'
9.7 9.7

Note that referencing a .NET Interface with ⎕NC, fixes the name of that Interface in the workspace and obviates the need for APL to repeat the task of searching for and loading the Interface when the name is next used.


Name List

Name List R←{X}⎕NL Y

Y must be a simple numeric scalar or vector containing one or more of the values for name-class. See also Name Classification .

X is optional. If present, it must be a simple character scalar or vector. R is a list of the names of active objects whose name-class is included in Y in standard sorted order.

If any element of Y is negative, positive values in Y are treated as if they were negative, and R is a vector of character vectors. Otherwise, R is simple character matrix.

Furthermore, if ⎕NL is being evaluated inside the namespace associated with a Class or an Instance of a Class, and any element of Y is negative, R includes the Public names exposed by the Base Class (if any) and all other Classes in the Class hierarchy.

If X is supplied, R contains only those names which begin with any character of X. Standard sorted order is in Unicode point order for Unicode editions, and in the collation order of ⎕AV for Classic editions.

If an element of Y is an integer, the names of all of the corresponding sub-name-classes are included in R. For example, if Y contains the value 2, the names of all variables (name-class 2.1), fields (2.2), properties (2.3) and external or shared variables (2.6) are obtained. Otherwise, only the names of members of the corresponding sub-name-class are obtained.

Examples:

      ⎕NL 2 3
A
FAST
FIND
FOO
V

      'AV' ⎕NL 2 3
A
V

      ⎕NL ¯9
 Animal  Bird  BirdBehaviour  Coin  Cylinder  DomesticParrot  Eeyore  FishBehaviour  Nickel  Parrot  Penguin  Polly  Robin
      ⎕NL ¯9.3 ⍝ Instances
 Eeyore  Nickel  Polly  Robin
      ⎕NL ¯9.4 ⍝ Classes
 Animal  Bird  Coin  Cylinder  DomesticParrot  Parrot  Penguin
      ⎕NL ¯9.5 ⍝ Interfaces
 BirdBehaviour  FishBehaviour

⎕NL can also be used to explore Dyalog GUI Objects, .NET types and COM objects.

Dyalog GUI Objects

⎕NL may be used to obtain lists of the Methods, Properties and Events provided by Dyalog APL GUI Objects.

      'F' ⎕WC 'Form'
      F.⎕NL -2 ⍝ Properties
 Accelerator AcceptFiles  Active  AlphaBlend  AutoConf  Border  BCol  Caption ...

      F.⎕NL -3 ⍝ Methods
 Animate  ChooseFont  Detach  GetFocus  GetTextSize  ShowSIP  Wait

      F.⎕NL -8 ⍝ Events
Close  Create  DragDrop  Configure  ContextMenu  DropFiles  DropObjects  Expose  Help ...

.NET Classes (Types)

⎕NL can be used to explore .NET types.

When a reference is made to an undefined name, and ⎕USING is set, APL attempts to load the Type from the appropriate .NET Assemblies. If successful, the name is entered into the symbol table with name-class 9.6.

      ⎕USING←'System'
      DateTime
(System.DateTime)
      ⎕NL -9
 DateTime
      ⎕NC,⊂'DateTime'
9.6

The names of the Properties and Methods of a .NET Type may then be obtained using ⎕NL.

      DateTime.⎕NL -2 ⍝ Properties
 MaxValue  MinValue  Now  Today  UtcNow

      DateTime.⎕NL -3 ⍝ Methods
 get_Now  get_Today  get_UtcNow  op_Addition  op_Equality  ...

In fact it is not necessary to make a separate reference first, because the expression Type.⎕NL (where Type is a .NET Type) is itself a reference to Type. So, (with ⎕USING still set to 'System'):

      Array.⎕NL -3
 BinarySearch  Clear  Copy  CreateInstance  IndexOf  LastIndexOf  Reverse  Sort

      ⎕NL -9
 Array  DateTime

Another use for ⎕NL is to examine .NET enumerations. For example:

      ⎕USING←'System.Windows.Forms,system.windows.forms.dll'

      FormBorderStyle.⎕NL -2
Fixed3D  FixedDialog  FixedSingle  FixedToolWindow  None  Sizable  SizableToolWindow

      FormBorderStyle.FixedDialog.value__
3

      FormBorderStyle.({⍵,[1.5]⍎¨⍵,¨⊂'.value__'}⎕NL -2)
 Fixed3D            2
 FixedDialog        3
 FixedSingle        1
 FixedToolWindow    5
 None               0
 Sizable            4
 SizableToolWindow  6

COM Objects

Once a reference to a COM object has been obtained, ⎕NL may be used to obtain lists of its Methods, Properties and Events.

      xl←⎕NEW'OLEClient'(⊂'ClassName' 'Excel.Application')

      xl.⎕NL -2 ⍝ Properties
 _Default  ActiveCell  ActiveChart  ActiveDialog  ActiveMenuBar  ActivePrinter  ActiveSheet  ActiveWindow ...

      xl.⎕NL -3 ⍝ Methods
 _Evaluate  _FindFile  _Run2  _Wait  _WSFunction  ActivateMicrosoftApp  AddChartAutoFormat  AddCustomList  Browse  Calculate ...

      ⎕NL -9
 xl


Namespace Indicator

Namespace Indicator R←⎕NSI

R is a nested vector of character vectors containing the names of the spaces from which functions in the state indicator were called (⍴⎕NSI←→⍴⎕RSI←→⍴⎕SI).

⎕RSI and ⎕NSI are identical except that ⎕RSI returns refs to the spaces whereas ⎕NSI returns their names. Put another way: ⎕NSI←→⍕¨⎕RSI.

Note that ⎕NSI contains the names of spaces from which functions were called not those in which they are currently running.

Example

      )OBJECTS
xx      yy

      ⎕VR 'yy.foo'
     ∇ r←foo
[1]    r←⎕SE.goo
     ∇
      ⎕VR'⎕SE.goo'
     ∇ r←goo
[1]    r←⎕SI,[1.5]⎕NSI
     ∇

      )CS xx
#.xx
      calling←#.yy.foo
      ]display calling
┌→─────────────┐
↓ ┌→──┐ ┌→───┐ │
│ │goo│ │#.yy│ │
│ └───┘ └────┘ │
│ ┌→──┐ ┌→───┐ │
│ │foo│ │#.xx│ │
│ └───┘ └────┘ │
└∊─────────────┘


Space Indicator

Space Indicator R←⎕RSI

R is a vector of refs to the spaces from which functions in the state indicator were called (⍴⎕RSI←→⍴⎕NSI←→⍴⎕SI).

⎕RSI and ⎕NSI are identical except that ⎕RSI returns refs to the spaces whereas ⎕NSI returns their names. Put another way: ⎕NSI←→⍕¨⎕RSI.

Note that ⎕RSI returns refs to the spaces from which functions were called not those in which they are currently running.

Example

      )OBJECTS
xx      yy

      ⎕VR 'yy.foo'
     ∇ r←foo
[1]    r←⎕SE.goo
     ∇
      ⎕VR'⎕SE.goo'
     ∇ r←goo
[1]    r←⎕SI,[1.5]⎕RSI
     ∇

      )CS xx
#.xx
      calling←#.yy.foo
      ]display calling
┌→───────────┐
↓ ┌→──┐      │
│ │goo│ #.yy │
│ └───┘      │
│ ┌→──┐      │
│ │foo│ #.xx │
│ └───┘      │
└∊───────────┘


State Indicator

State Indicator R←⎕SI

R is a nested vector of vectors giving the names of the functions or operators in the execution stack.

Example

      )SI
#.PLUS[2]*
.
#.MATDIV[4]
#.FOO[1]*
⍎

      ⎕SI
 PLUS  MATDIV  FOO

      (⍴⎕LC)=⍴⎕SI
1

If execution stops in a callback function, ⎕DQ will appear on the stack, and may occur more than once

      )SI
#.ERRFN[7]*
⎕DQ
#.CALC
⎕DQ
#.MAIN

To edit the function on the top of the stack:

      ⎕ED ⊃⎕SI

The name of the function which called this one:

      ⊃1↓⎕SI

To check if the function ∆N is pendent:

     ((⊂∆N)∊1↓⎕SI)/'Warning : ',∆N,' is pendent'

See also Extended State Indicator .


Shadow Name

Shadow Name {R}←⎕SHADOW Y

Y must be a simple character scalar, vector or matrix or a vector of nested scalar of character vectors identifying one or more APL names. For a simple vector Y, names are separated by one or more blanks. For a matrix Y, each row is taken to be a single name.

Each valid name in Y is shadowed in the most recently invoked defined function or operator, as though it were included in the list of local names in the function or operator header. The class of the name becomes 0 (undefined). The name ceases to be shadowed when execution of the shadowing function or operator is completed. Shadow has no effect when the state indicator is empty.

The shy result R is a Boolean vector of 1s with the same length as the number of names in Y.

If a name is ill-formed, or if it is the name of a system constant or system function, DOMAIN ERROR is reported.

If the name of a top-level GUI object is shadowed, it is made inactive.

Example

      ⎕VR'RUN'
     ∇ NAME RUN FN
[1]   ⍝ Runs function named <NAME> defined
[2]   ⍝ from representation form <FN>
[3]    ⎕SHADOW NAME
[4]    ⍎⎕FX FN
     ∇

      0 ⎕STOP 'RUN' ⍝ stop prior RUN exiting

      'FOO' RUN 'R←FOO' 'R←10'
10

RUN[0]

      )SINL
#.RUN[0]*       FOO     FN      NAME

      →⎕LC

      FOO
VALUE ERROR
      FOO
      ^


Size of Object

Size of Object R←⎕SIZE Y

Y must be a simple character scalar, vector or matrix, or a vector of character vectors containing a list of names. R is a simple integer vector of non-negative elements with the same length as the number of names in Y.

If the name in Y identifies an object with an active referent, the workspace required in bytes by that object is returned in the corresponding element of R. Otherwise, 0 is returned in that element of R.

The result returned for an external variable is the space required to store the external array. The result for a system constant, variable or function is 0. The result returned for a GUI object gives the amount of workspace needed to store it, but excludes the space required for its children.

Note: Wherever possible, Dyalog APL shares the whole or part of a workspace object rather than generates a separate copy; however ⎕SIZE reports the size as though nothing is shared. ⎕SIZE also includes the space required for the interpreter's internal information about the object in question.

Examples

      ⎕VR 'FOO'
     ∇ R←FOO
[1]    R←10
     ∇

      A←⍳10

      'EXT/ARRAY' ⎕XT'E' ⋄ E←⍳20

      ⎕SIZE 'A' 'FOO' 'E' 'UND'
28 76 120 0


State Indicator Stack

State Indicator Stack R←⎕STACK

R is a two-column matrix, with one row per entry in the state indicator.

Column 1 :⎕OR form of user defined functions or operators on the state indicator. Space (⎕UCS 32) for entries that are not user defined functions or operators.

Column 2 :Indication of the type of the item on the stack.

space | user defined function or operator
⍎ | execute level
⎕ | evaluated input
* | desk calculator level
⎕DQ | in callback function
other | primitive operator

Example

      )SI
#.PLUS[2]*
.
#.MATDIV[4]
#.FOO[1]*
⍎

      ⎕STACK
         *
∇PLUS
         .
∇MATDIV
         *
∇FOO
         ⍎
         *

      ⍴⎕STACK
8 2

      (⍴⎕LC)=1↑⍴⎕STACK
0

Pendent defined functions and operators may be edited in Dyalog APL with no resulting SI damage. However, only the visible definition is changed; the pendent version on the stack is retained until its execution is complete. When the function or operator is displayed, only the visible version is seen. Hence ⎕STACK is a tool which allows the user to display the form of the actual function or operator being executed.

Example

To display the version of MATDIV currently pendent on the stack:

      ⊃⎕STACK[4;1]
     ∇ R←A MATDIV B
[1]   ⍝ Divide matrix A by matrix B
[2]    C←A⌹B
[3]   ⍝ Check accuracy
[4]    D←⌊0.5+A PLUS.TIMES B
     ∇


State of Object

State of Object R←⎕STATE Y

Y must be a simple character scalar or vector which is taken to be the name of an APL object or a system variable. The result returned is a nested vector of 4 elements as described below. ⎕STATE supplies information about shadowed or localised objects that is otherwise unobtainable.

1⊃R | Boolean vector, element set to 1 if and only if this level shadows Y. Note: (⍴1⊃R)=⍴⎕LC
2⊃R | Numeric vector giving the stack state of this name as it entered this level. Note: (⍴2⊃R)=⍴⎕LC 0=not on stack 1=suspended 2=pendent (may also be suspended) 3=active (may also be pendent or suspended)
3⊃R | Numeric vector giving the name classification of Y as it entered this level. Note: (⍴3⊃R)=+/1⊃R
4⊃R | Vector giving the contents of Y before it was shadowed at this level. Note: (⍴4⊃R)=+/0≠3⊃R

Example

      ⎕FMT∘⎕OR¨'FN1' 'FN2' 'FN3'
    ∇ FN1;A;B;C      ∇ FN2;A;C               ∇ FN3;A
[1]   A←1        [1]   A←'HELLO'         [1]   A←100
[2]   B←2        [2]   B←'EVERYONE'      [2]   ∘
[3]   C←3        [3]   C←'HOW ARE YOU?'      ∇
[4]   FN2        [4]  FN3
    ∇                ∇

      )SI
#.FN3[2]*
#.FN2[4]
#.FN1[4]

      ⎕STATE 'A'
 1 1 1  0 0 0  2 2 0   HELLO  1

       ⎕FMT∘⎕OR¨'foo' 'goo'
      ∇ foo;⎕IO       ∇ goo;⎕IO
 [1]    ⎕IO←0    [1]    ⎕IO←1
 [2]    goo      [2]    ⎕STATE'⎕IO'
      ∇               ∇

       foo
 1 1  0 0  ¯1 ¯1  0 1


Workspace Available

Workspace Available R←⎕WA

This is a simple integer scalar. It identifies the total available space in the active workspace area given as the number of bytes it could hold.

A side effect of using ⎕WA is an internal reorganisation of the workspace and process memory, as follows:

  1. Any un-referenced memory is discarded. This process, known as garbage collection, is required because whole cycles of refs can become un-referenced.
  2. Numeric arrays are demoted to their tightest form. For example, a simple numeric array that happens to contain only values 0 or 1, is demoted or squeezed to have a ⎕DR type of 11 (Boolean).
  3. All remaining used memory blocks are copied to the low-address end of the workspace, leaving a single free block at the high-address end. This process is known as compaction.
  4. All memory allocated is returned to the Operating System except the space required for the compacted workspace, plus a working overhead based on the configured maximum workspace size (MAXWS). If the compacted workspace occupies more than 1/16 of MAXWS then the overhead is 1/16 of MAXWS, otherwise it is 1/64 of MAXWS. On a Windows system, you can see the process size changing by using Task Manager.

Example

      ⎕WA
261412

See also: Specify Workspace Available


Workspace Identification

Workspace Identification ⎕WSID

This is a simple character vector. It contains the identification name of the active workspace. If a new name is assigned, that name becomes the identification name of the active workspace, provided that it is a correctly formed name.

See Workspaces for workspace naming conventions.

It is useful, though not essential, to associate workspaces with a specific directory in order to distinguish workspaces from other files.

The value of ⎕WSID in a clear workspace is 'CLEAR WS'.

Example

      ⎕WSID
CLEAR WS

      ⎕WSID←'ws/mywork       (UNIX)

      ⎕WSID←'B:\WS\MYWORK'   (Windows)


Extended State Indicator

Extended State Indicator R←⎕XSI

R is a nested vector of character vectors giving the full path names of the functions or operators in the execution stack. Note that if a function has changed space, its original (home) space is reported, rather than its current one.

Example

In the following, function foo in namespace x has called goo in namespace y. Function goo has then changed space (⎕CS) to namespace z where it has been suspended:

      )si
[z] y.goo[2]*
x.foo[1]

⎕XSI reports the full path name of each function:

      ⎕xsi
 #.y.goo  #.x.foo

This can be used for example, to edit all functions in the stack, irrespective of the current namespace by typing: ⎕ed ⎕xsi

See also State Indicator .


Extended Diagnostic Message

Extended Diagnostic Message R←⎕DMX

⎕DMX is a system object that provides information about the last reported APL error. ⎕DMX has thread scope, i.e. its value differs according to the thread from which it is referenced. In a multi-threaded application therefore, each thread has its own value of ⎕DMX.

⎕DMX contains the following Properties (name class 2.6). Note that this list is likely to change. Your code should not assume that this list will remain unchanged. You should also not assume that the display form of ⎕DMX will remain unchanged.

Category | character vector | The category of the error
DM | nested vector | Diagnostic message. This is the same as ⎕DM, but thread safe
EM | character vector | Event message; this is the same as ⎕EM ⎕EN
EN | integer | Error number. This is the same as ⎕EN, but thread safe
ENX | integer | Sub-error number
HelpURL | character vector | URL of a web page that will provide help for this error. APL identifies and has a handler for URLs starting with http:, https:, mailto: and www. This list may be extended in future
InternalLocation | nested vector | Identifies the line of interpreter source code (file name and line number) which raised the error. This information may be useful to Dyalog support when investigating an issue
Message | character vector | Further information about the error
OSError | see below | If applicable, identifies the error generated by the Operating System
Vendor | character vector | For system generated errors, Vendor will always contain the character vector 'Dyalog'. This value can be set using ⎕SIGNAL

OSError is a 3-element vector whose items are as follows:

1 integer This indicates how the operating system error was retrieved.
0 = by the C-library errno() function
1 = by the Windows GetLastError() function
2 | integer | Error code. The error number returned by the operating system using errno() or GetLastError() as above
3 | character vector | The description of the error returned by the operating system

Example

      1÷0
DOMAIN ERROR
      1÷0
     ∧
      ⎕DMX
 EM       DOMAIN ERROR
 Message  Divide by zero

      ⎕DMX.InternalLocation
 arith_su.c  554

Isolation of Handled Errors

⎕DMX cannot be explicitly localised in the header of a function. However, for all trapped errors, the interpreter creates an environment which effectively makes the current instance of ⎕DMX local to, and available only for the duration of, the trap-handling code.

With the exception of ⎕TRAP with Cutback, ⎕DMX is implicitly localised within:

  • Any function which explicitly localises ⎕TRAP
  • The :Case[List] or :Else clause of a :Trap control structure.
  • The right hand side of a D-function Error-Guard.

and is implicitly un-localised when:

  • A function which has explicitly localised ⎕TRAP terminates (even if the trap definition has been inherited from a function further up the stack).
  • The :EndTrap of the current :Trap control structure is reached.
  • A D-function Error-Guard exists.

During this time, if an error occurs then the localised ⎕DMX is updated to reflect the values generated by the error.

The same is true for ⎕TRAP with Cutback, with the exception that if the cutback trap event is triggered, the updated values for ⎕DMX are preserved until the function that set the cutback trap terminates.

The benefit of the localisation strategy is that code which uses error trapping as a standard operating procedure (such as a file utility which traps FILE NAME ERROR and creates missing files when required) will not pollute the environment with irrelevant error information.

Example

     ∇ tie←NewFile name
[1]    :Trap 22
[2]        tie←name ⎕FCREATE 0
[3]    :Else
[4]        ⎕DMX
[5]        tie←name ⎕FTIE 0
[6]        name ⎕FERASE tie
[7]        tie←name ⎕FCREATE 0
[8]    :EndTrap
[9]    ⎕FUNTIE tie
     ∇

⎕DMX is cleared by )RESET:

      )reset
      ⍴⎕FMT ⎕DMX
0 0

Note: ⎕SIGNAL can be used to reset the value of this system constant.

The first time we run NewFile 'pete', the file doesn't exist and the ⎕FCREATE in NewFile[2] succeeds.

      NewFile 'pete'
1

If we run the function again, the ⎕FCREATE in NewFile[2]generates an error which triggers the :Else clause of the :Trap. On entry to the :Else clause, the values in ⎕DMX reflect the error generated by ⎕FCREATE. The file is then tied, erased and recreated.

 EM       FILE NAME ERROR
 Message  File exists

After exiting the :Trap control structure, the shadowed value of ⎕DMX is discarded, revealing the original value that it shadowed.

      ⍴⎕FMT ⎕DMX
0 0

Example

The EraseFile function also uses a :Trap in order to ignore the situation when the file doesn't exist.

     ∇ EraseFile name;tie
[1]    :Trap 22
[2]        tie←name ⎕FTIE 0
[3]        name ⎕FERASE tie
[4]    :Else
[5]        ⎕DMX
[6]    :EndTrap
     ∇

The first time we run the function, it succeeds in tieing and then erasing the file.

      EraseFile 'pete'

The second time, the ⎕FTIE fails. On entry to the :Else clause, the values in ⎕DMX reflect this error.

      EraseFile 'pete'
 EM       FILE NAME ERROR
 Message  Unable to open file
 OSError  1 2  The system cannot find the file specified.

Once again, the local value of ⎕DMX is discarded on exit from the :Trap, revealing the shadowed value as before.

      ⍴⎕FMT ⎕DMX
0 0

Example

In this example only the error number (EN) property of ⎕DMX is displayed in order to simplify the output:

     ∇ foo n;⎕TRAP
[1]    'Start foo'⎕DMX.EN
[2]    ⎕TRAP←(2 'E' '→err')(11 'C' '→err')
[3]    goo n
[4]   err:'End foo:'⎕DMX.EN
     ∇

     ∇ goo n;⎕TRAP
[1]    ⎕TRAP←5 'E' '→err'
[2]    ⍎n⊃'÷0' '1 2+1 2 3' '∘'
[3]   err:'goo:'⎕DMX.EN
     ∇

In the first case a DOMAIN ERROR (11) is generated on goo[2]. This error is not included in the definition of ⎕TRAP in goo, but rather the Cutback ⎕TRAP definition in foo. The error causes the stack to be cut back to foo, and then execution branches to foo[4]. Thus ⎕DMX.EN in foo retains the value set when the error occurred in goo.

      foo 1
 Start foo  0
 End foo:  11

In the second case a LENGTH ERROR (5) is raised on goo[2]. This error is included in the definition of ⎕TRAP in goo so the value ⎕DMX.EN while in goo is 5, but when goo terminates and foo resumes execution the value of ⎕DMX.EN localised in goo is lost.

      foo 2
 Start foo  0
 goo:  5
 End foo:  0

In the third case a SYNTAX ERROR (2) is raised on goo[2]. Since the ⎕TRAP statement is handled within goo (although the applicable ⎕TRAP is defined in foo), the value ⎕DMX.EN while in goo is 2, but when goo terminates and foo resumes execution the value of ⎕DMX.EN localised in goo is lost.

      foo 3
 Start foo  0
 goo:  2
 End foo:  0


Event Message

Event Message R←⎕EM Y

Y must be a simple non-negative integer scalar or vector of event codes. If Y is a scalar, R is a simple character vector containing the associated event message. If Y is a vector, R is a vector of character vectors containing the corresponding event messages.

If Y refers to an undefined error code "n", the event message returned is "ERROR NUMBER n".

See APL Error Messages

Example

      ⎕EM 11
DOMAIN ERROR


Exception

Exception R←⎕EXCEPTION

This is a system object that identifies the most recent Exception thrown by a Microsoft .NET object.

⎕EXCEPTION derives from the Microsoft .NET class System.Exception. Among its properties are the following, all of which are strings:

Source | The name of the .NET namespace in which the exception was generated
StackTrace | The calling stack
Message | The error message
      ⎕USING←'System'
      DT←⎕NEW DateTime (100000 0 0)
EXCEPTION: Year, Month, and Day parameters describe an un-representable DateTime.
      DT←⎕NEW DateTime(100000 0 0)
     ∧
      ⎕EN
90
      ⎕EXCEPTION.Message
Year, Month, and Day parameters describe an un-representable DateTime.

      ⎕EXCEPTION.Source
mscorlib

      ⎕EXCEPTION.StackTrace
   at System.DateTime.DateToTicks(Int32 year,
                                  Int32 month, Int32 day)

   at System.DateTime..ctor(Int32 year,
                            Int32 month, Int32 day)

Similarly to GUI objects, ⎕EXCEPTION is not preserved across a save/load cycle if the workspace is loaded in a different interpreter.

Note: ⎕SIGNAL can be used to reset the value of this system constant.


Signal Event

Signal Event {R}←{X}⎕SIGNAL Y

Y must be a scalar or vector.

If Y is a an empty vector nothing is signalled.

If Y is a vector of more than one element, all but the first element are ignored.

R has the same value as Y.

Y=0 is a special form of ⎕SIGNAL, the side effect of which is to reset the values of certain system constants. It is described further down this section.

If the first element of Y is a simple integer in the range 1-999 it is taken to be an event number. X is an optional text message. If present, X must be a simple character scalar or vector, or an object reference. If X is omitted or is empty, the standard event message for the corresponding event number is assumed. See APL Error Messages. If there is no standard message, a message of the form ERROR NUMBER n is composed, where n is the event number in Y. Values outside the range 0 or 1-999 will result in a DOMAIN ERROR.

If the first element of Y is a 2 column matrix or a vector of 2 element vectors of name/values pairs, then it is considered to be a set of values to be used to override the default values in a new instance of ⎕DMX. Any other value for the first element of Y will result in a DOMAIN ERROR.

The names in the error specification must all appear in a system-generated ⎕DMX, otherwise a DOMAIN ERROR will be issued. For each name specified, the default value in the new instance of ⎕DMX is replaced with the value specified. EN must be one of the names in the error specification. Attempting to specify certain names, including InternalLocation and DM, will result in a DOMAIN ERROR. The value which is to be assigned to a name must be appropriate to the name in question.

Dyalog may enhance ⎕DMX in future, thus potentially altering the list of valid and/or assignable names.

If the first element of Y is an array of name/value pairs then specifying any value for X will result in a DOMAIN ERROR.

The effect of the system function is to interrupt execution. The state indicator is cut back to exit from the function or operator containing the line that invoked ⎕SIGNAL, or is cut back to exit the Execute (⍎) expression that invoked ⎕SIGNAL. If executed within a nested dfn, the state indicator is cut back to exit from the capsule containing the line that invoked ⎕SIGNAL. An error is then generated.

An error interrupt may be trapped if the system variable ⎕TRAP is set to intercept the event. Otherwise, the standard system action is taken (which may involve cutting back the state indicator further if there are locked functions or operators in the state indicator). The standard event message is replaced by the text given in X, if present.

Example

      ⎕VR'DIVIDE'
     ∇ R←A DIVIDE B;⎕TRAP
[1]    ⎕TRAP←11 'E' '→ERR'
[2]    R←A÷B ⋄ →0
[3]   ERR:'DIVISION ERROR' ⎕SIGNAL 11
     ∇

      2 4 6 DIVIDE 0
DIVISION ERROR
      2 4 6 DIVIDE 0
     ^

If you are using the Microsoft .NET Framework, you may use ⎕SIGNAL to throw an exception by specifying a value of 90 in Y. In this case, if you specify the optional left argument X, it must be a reference to a .NET object that is or derives from the Microsoft .NET class System.Exception. The following example illustrates a constructor function CTOR that expects to be called with a value for ⎕IO (0 or 1)

     ∇ CTOR IO;EX
[1]    :If IO∊0 1
[2]        ⎕IO←IO
[3]    :Else
[4]        EX←ArgumentException.New'IO must be 0 or 1'
[5]        EX ⎕SIGNAL 90
[6]    :EndIf
     ∇

⎕SIGNAL 0: Reset error-related system constants

If Y is a simple integer with the value 0, ⎕SIGNAL does not interrupt execution, but merely returns the value 0. The side effect of calling ⎕SIGNAL 0 is to reset the values of ⎕DM, ⎕DMX, ⎕EN and ⎕EXCEPTION to their default values. ⎕SIGNAL 0 is the only form of ⎕SIGNAL which can be used to reset the aforementioned system constants; including a left argument or using a name/value pair right argument of ⎕SIGNAL will result in a DOMAIN ERROR.

Example:

      ÷0
DOMAIN ERROR: Divide by zero
      ÷0
     ∧
      ⎕DM ⎕EN ⎕DMX
┌──────────────────────────────┬──┬─────────────────────────┐
│┌────────────┬────────┬──────┐│11│ EM       DOMAIN ERROR   │
││DOMAIN ERROR│      ÷0│     ∧││  │ Message  Divide by zero │
│└────────────┴────────┴──────┘│  │                         │
└──────────────────────────────┴──┴─────────────────────────┘
      ⊢⎕SIGNAL 0
0
      ⎕DM ⎕EN ⎕DMX
┌┬─┬┐
││0││
└┴─┴┘

Further examples

Example 1

      'Hello'⎕SIGNAL 200
Hello
      'Hello'⎕SIGNAL 200
     ∧
      ⎕DMX
 EM       Hello
 Message

      ⎕DM
 Hello        'Hello'⎕SIGNAL 200       ∧

      ⎕SIGNAL⊂⊂('EN' 200)
ERROR 200
      ⎕SIGNAL⊂⊂('EN' 200)
     ∧

      ⎕DMX
 EM       ERROR 200
 Message

      ⎕DM
 ERROR 200        ⎕SIGNAL⊂⊂('EN' 200)       ∧

Example 2

      ⎕SIGNAL⊂('EN' 200)('Vendor' 'Andy')('Message' 'My error')
ERROR 200: My error
      ⎕SIGNAL⊂('EN' 200)('Vendor' 'Andy')('Message' 'My error')
     ∧

      ⎕DMX
 EM       ERROR 200
 Message  My error
      ⍪⎕DMX.(EN EM Vendor)
       200
 ERROR 200
      Andy

Be aware of the following case, in which the argument has not been sufficiently nested:

      ⎕SIGNAL⊂('EN' 200)
DOMAIN ERROR: Unexpected name in signalled ⎕DMX specification
      ⎕SIGNAL⊂('EN' 200)
     ∧


Trap Event

Trap Event ⎕TRAP

This is a non-simple vector. An item of ⎕TRAP specifies an action to be taken when one of a set of events occurs. An item of ⎕TRAP is a 2 or 3 element vector whose items are simple scalars or vectors in the following order:

  1. an integer vector whose value is one or more event codes selected from the list in the Figure on the following two pages.
  2. a character scalar whose value is an action code selected from the letters C, E, N or S.
  3. if element 2 is the letter C or E, this item is a character vector forming a valid APL expression or series of expressions separated by ⋄. Otherwise, this element is omitted.

An EVENT may be an APL execution error, an interrupt by the user or the system, a control interrupt caused by the ⎕STOP system function, or an event generated by the ⎕SIGNAL system function.

When an event occurs, the system searches for a trap definition for that event. The most local ⎕TRAP value is searched first, followed by successive shadowed values of ⎕TRAP, and finally the global ⎕TRAP value. Separate actions defined in a single ⎕TRAP value are searched from left to right. If a trap definition for the event is found, the defined action is taken. Otherwise, the normal system action is followed.

The ACTION code identifies the nature of the action to be taken when an associated event occurs. Permitted codes are interpreted as follows:

C | Cutback | The state indicator is 'cut back' to the environment in which the ⎕TRAP is locally defined (or to immediate execution level). The APL expression in element 3 of the same ⎕TRAP item is then executed.
E | Execute | The APL expression in element 3 of the same ⎕TRAP item is executed in the environment in which the event occurred.
N | Next | The event is excluded from the current ⎕TRAP definition. The search will continue through further localised definitions of ⎕TRAP.
S | Stop | Stops the search and causes the normal APL action to be taken in the environment in which the event occurred.

Table 27: Trappable Event Codes

Code | Event
0 | Any event in range 1-999
1 | WS FULL
2 | SYNTAX ERROR
3 | INDEX ERROR
4 | RANK ERROR
5 | LENGTH ERROR
6 | VALUE ERROR
7 | FORMAT ERROR
10 | LIMIT ERROR
11 | DOMAIN ERROR
12 | HOLD ERROR
16 | NONCE ERROR
18 | FILE TIE ERROR
19 | FILE ACCESS ERROR
20 | FILE INDEX ERROR
21 | FILE FULL
22 | FILE NAME ERROR
23 | FILE DAMAGED
24 | FILE TIED
25 | FILE TIED REMOTELY
26 | FILE SYSTEM ERROR
28 | FILE SYSTEM NOT AVAILABLE
30 | FILE SYSTEM TIES USED UP
31 | FILE TIE QUOTA USED UP
32 | FILE NAME QUOTA USED UP
34 | FILE SYSTEM NO SPACE
35 | FILE ACCESS ERROR - CONVERTING FILE
38 | FILE COMPONENT DAMAGED
52 | FIELD CONTENTS RANK ERROR
53 | FIELD CONTENTS TOO MANY COLUMNS
54 | FIELD POSITION ERROR
55 | FIELD SIZE ERROR
56 | FIELD CONTENTS/TYPE MISMATCH
57 | FIELD TYPE/BEHAVIOUR UNRECOGNISED
58 | FIELD ATTRIBUTES RANK ERROR
59 | FIELD ATTRIBUTES LENGTH ERROR
60 | FULL-SCREEN ERROR
61 | KEY CODE UNRECOGNISED
62 | KEY CODE RANK ERROR
63 | KEY CODE TYPE ERROR
70 | FORMAT FILE ACCESS ERROR
71 | FORMAT FILE ERROR
72 | NO PIPES
76 | PROCESSOR TABLE FULL
84 | TRAP ERROR
90 | EXCEPTION
92 | TRANSLATION ERROR
200-499 | Reserved for distributed auxiliary processors
500-999 | User-defined events
1000 | Any event in range 1001-1008
1001 | Stop vector
1002 | Weak interrupt
1003 | INTERRUPT
1005 | EOF INTERRUPT
1006 | TIMEOUT
1007 | RESIZE (Dyalog APL/X, Dyalog APL/W)
1008 | DEADLOCK

See Trap Statement for an alternative 'control structured' error trapping mechanism.

Examples

      ⎕TRAP←⊂(3 4 5) 'E' 'ERROR' ⋄ ⍴⎕TRAP
1

      ⎕TRAP
  3 4 5 E ERROR

Items may be specified as scalars. If there is only a single trap definition, it need not be enclosed. However, the value of ⎕TRAP will be rigorously correct:

      ⎕TRAP←11 'E' '→LAB'

      ⎕TRAP
  11 E →ERR

      ⍴⎕TRAP
1

The value of ⎕TRAP in a clear workspace is an empty vector whose prototype is

0⍴(⍬ '' ''). A convenient way of cancelling a ⎕TRAP definition is:

      ⎕TRAP←0⍴⎕TRAP

Event codes 0 and 1000 allow all events in the respective ranges 1-999 and 1000-1006 to be trapped. Specific event codes may be excluded by the N action (which must precede the general event action):

      ⎕TRAP←(1 'N')(0 'E' '→GENERR')

The 'stop' action is a useful mechanism for cancelling trap definitions during development of applications.

The 'cut-back' action is useful for returning control to a known point in the application system when errors occur. The following example shows a function that selects and executes an option with a general trap to return control to the function when an untrapped event occurs:

     ∇ SELECT;OPT;⎕TRAP
[1]   ⍝ Option selection and execution
[2]   ⍝ A general cut-back trap
[3]    ⎕TRAP←(0 1000)'C' '→ERR'
[4]   INP:⍞←'OPTION : ' ⋄ OPT←(OPT≠' ')/OPT←9↓⍞
[5]    →EX⍴⍨(⊂OPT)∊Options ⋄ 'INVALID OPTION' ⋄ →INP
[6]   EX:⍎OPT ⋄ →INP
[7]   ERR:ERROR∆ACTION ⋄ →INP
[8]   END:
     ∇

User-defined events may be signalled through the ⎕SIGNAL system function. A user-defined event (in the range 500-999) may be trapped explicitly or implicitly by the event code 0.

Example

      ⎕TRAP←500 'E' '''USER EVENT 500 - TRAPPED'''

      ⎕SIGNAL 500
USER EVENT 500 - TRAPPED


Query Access Control

Query Access Control R←⎕SVC Y

This system function queries the access control on one or more shared variables.

Y is a character scalar, vector, or matrix containing names of shared variables. Each name may optionally be paired with its surrogate. If so, the surrogate must be separated from the name by at least one space.

If Y specifies a single name, the result R is a Boolean vector containing the current effective access control vector. If Y is a matrix of names, R is a Boolean matrix whose rows contain the current effective access control vectors for the corresponding row in Y.

For further information, see the preceding section on setting the access control vector.

Example

      ⎕SVC 'X'
0 0 0 0


Set Access Control

Set Access Control R←X ⎕SVC Y

This system function sets access control on one or more shared variables.

Y is a character scalar, vector, or matrix containing names of shared variables. Each name may optionally be paired with its surrogate. If so, the surrogate must be separated from the name by at least one space.

X may be a 4-element Boolean vector which specifies the access control to be applied to all of the shared variables named in Y. Alternatively, X may be a 4-column Boolean matrix whose rows specify the access control for the corresponding name in Y. X may also be a scalar or a 1-element vector. If so, it treated as if it were a 4-element vector with the same value in each element.

Each shared variable has a current access control vector which is a 4-element Boolean vector. A 1 in each of the four positions has the following impact :

[1] | You cannot set a new value for the shared variable until after an intervening use or set by your partner.
[2] | Your partner cannot set a new value for the shared variable until after an intervening use or set by you.
[3] | You cannot use the value of the shared variable until after an intervening set by your partner.
[4] | Your partner cannot use the value of the shared variable until after an intervening set by you.

The effect of ⎕SVC is to reset the access control vectors for each of the shared variables named in Y by OR-ing the values most recently specified by your partner with the values in X. This means that you cannot reset elements of the control vector which your partner has set to 1.

Note that the initial value of your partner's access control vector is normally 0 0 0 0. However, if it is a non-APL client application that has established a hot DDE link, its access control vector is defined to be 1 0 0 1. This inhibits either partner from setting the value of the shared variable twice, without an intervening use (or set) by the other. This prevents loss of data which is deemed to be desirable from the nature of the link. (An application that requests a hot link is assumed to require every value of the shared variable, and not to miss any). Note that APL's way of inhibiting another application from setting the value twice (without an intervening use) is to delay the acknowledgement of the DDE message containing the second value until the variable has been used by the APL workspace. An application that waits for an acknowledgement will therefore hang until this happens. An application that does not wait will carry on obliviously.

The result R is a Boolean vector or matrix, corresponding to the structure of X, which contains the new access control settings. If Y refers to a name which is not a shared variable, or if the surrogate name is mis-spelt, the corresponding value in R is 4⍴0.

Examples

      1 0 0 1 ⎕SVC 'X'
1 0 0 1

      1 ⎕SVC 'X EXTNAME'
1 1 1 1

      (2 4⍴1 0 0 1 0 1 1 0) ⎕SVC ↑'ONE' 'TWO'
1 1 1 1
0 1 1 0


Shared Variable Offer

Shared Variable Offer ⎕SVO

Dyadic ⎕SVO means

Shared Variable Offer

      DATA←⍳9
     'DDE:' ⎕SVO 'DATA'
1

Monadic ⎕SVO means

Query Degree of Coupling

      ⎕SVO 'DATA'
1

Language Elements


Shared Variable Offer

Shared Variable Offer R←X ⎕SVO Y

This system function offers to share one or more variables with another APL workspace or with another application. Shared variables are implemented using Dynamic Data Exchange (DDE) and may be used to communicate with any other application that supports this protocol. See Interface Guide for further details.

Y is a character scalar, vector or matrix. If it is a vector it contains a name and optionally an external name or surrogate. The first name is the name used internally in the current workspace. The external name is the name used to make the connection with the partner and, if specified, must be separated from the internal name by one or more blanks. If the partner is another application, the external name corresponds to the DDE item specified by that application. If the external name is omitted, the internal name is used instead. The internal name must be a valid APL name and be either undefined or be the name of a variable. There are no such restrictions on the content of the external name.

Instead of an external name, Y may contain the special symbol '⍎' separated from the (internal) name by a blank. This is used to implement a mechanism for sending DDE_EXECUTE messages, and is described at the end of this section.

If Y is a scalar, it specifies a single 1-character name. If Y is a matrix, each row of Y specifies a name and an optional external name as for the vector case.

The left argument X is a character vector or matrix. If it is a vector, it contains a string that defines the protocol, the application to which the shared variable is to be connected, and the topic of the conversation. These three components are separated by the characters ':' and '|' respectively. The protocol is currently always 'DDE', but future implementations of Dyalog APL may support additional communications protocols if applicable. If Y specifies more than one name, X may be a vector or a matrix with one row per row in Y.

If the shared variable offer is a general one (server), X, or the corresponding row of X, should just contain 'DDE:'. In this case, Dyalog automatically defines the application name and topic to be dyalog and ⎕WSID respectively.

The result R is a numeric scalar or vector with one element for each name in Y and indicates the "degree of coupling". A value of 2 indicates that the variable is fully coupled (via a warm or hot DDE link) with a shared variable in another APL workspace, or with a DDE item in another application. A value of 1 indicates that there is no connection, or that the second application rejected a warm link. In this case, a transfer of data may have taken place (via a cold link) but the connection is no longer open. Effectively, APL treats an application that insists on a cold link as if it immediately retracts the sharing after setting or using the value, whichever is appropriate.

Examples

      'DDE:' ⎕SVO 'X'
1

      'DDE:' ⎕SVO 'X SALES_92'
1

      'DDE:' ⎕SVO ↑'X SALES_92' 'COSTS_92'
1 1

      'DDE:DYALOG|SERV_WS' ⎕SVO 'X'
2

      'DDE:EXCEL|SHEET1' ⎕SVO 'DATA R1C1:R10C12'
2

A special syntax is used to provide a mechanism for sending DDE_EXECUTE messages to another application. This case is identified by specifying the '⍎' symbol in place of the external name. The subsequent assignment of a character vector to a variable shared with the external name of '⍎' causes the value of the variable to be transmitted in the form of a DDE_EXECUTE message. The value of the variable is then reset to 1 or 0 corresponding to a positive or negative acknowledgement from the partner. In most (if not all) applications, commands transmitted in DDE_EXECUTE messages must be enclosed in square brackets []. For details, see the relevant documentation for the external application.

Examples:

      'DDE:EXCEL|SYSTEM' ⎕SVO 'X ⍎'
2

      X←'[OPEN("c:\mydir\mysheet.xls")]'
      X
1

      X←'[SELECT("R1C1:R5C10")]'
      X
1


Query Degree of Coupling

Query Degree of Coupling R←⎕SVO Y

This system function returns the current degree of coupling for one or more shared variables.

Y is a character scalar, vector or matrix. If it is a vector it contains a shared variable name and optionally its external name or surrogate separated from it by one of more blanks.

If Y is a scalar, it specifies a single 1-character name. If Y is a matrix, each row of Y specifies a name and an optional external name as for the vector case.

If Y specifies a single name, the result R is a 1-element vector whose value 0, 1 or 2 indicates its current degree of coupling. If Y specifies more than one name, R is a vector whose elements indicate the current degree of coupling of the variable specified by the corresponding row in Y. A value of 2 indicates that the variable is fully coupled (via a warm or hot DDE link) with a shared variable in another APL workspace, or with a DDE item in another application. A value of 1 indicates that you have offered the variable but there is no such connection, or that the second application rejected a warm link. In this case, a transfer of data may have taken place (via a cold link) but the connection is no longer open. A value of 0 indicates that the name is not a shared variable.

Examples

      ⎕SVO 'X'
2
      ⎕SVO ↑'X SALES' 'Y' 'JUNK'
2 1 0


Shared Variable Query

Shared Variable Query R←⎕SVQ Y

This system function is implemented for compatibility with other versions of APL but currently performs no useful function. Its purpose is to obtain a list of outstanding shared variable offers made to you, to which you have not yet responded.

Using DDE as the communication protocol, it is not possible to implement ⎕SVQ effectively.


Shared Variable Retract Offer

Shared Variable Retract Offer R←⎕SVR Y

This system function terminates communication via one or more shared variables, or aborts shared variable offers that have not yet been accepted.

Y is a character scalar, vector or matrix. If it is a vector it contains a shared variable name and optionally its external name or surrogate separated from it by one of more blanks. If Y is a scalar, it specifies a single 1-character name. If Y is a matrix, each row of Y specifies a name and an optional external name as for the vector case.

The result R is vector whose length corresponds to the number of names specified by Y, indicating the level of sharing of each variable after retraction.

See Shared Variable State for further information on the possible states of a shared variable.


Shared Variable State

Shared Variable State R←⎕SVS Y

This system function returns the current state of one or more shared variables.

Y is a character scalar, vector or matrix. If it is a vector it contains a shared variable name and optionally its external name or surrogate separated from it by one of more blanks. If Y is a scalar, it specifies a single 1-character name. If Y is a matrix, each row of Y specifies a name and an optional external name as for the vector case.

If Y specifies a single name, the result R is a 4-element vector indicating its current state. If Y specifies more than one name, R is a matrix whose rows indicate the current state of the variable specified by the corresponding row in Y.

There are four possible shared variable states:

0 0 1 1 | means that you and your partner are both aware of the current value, and neither has since reset it. This is also the initial value of the state when the link is first established.
1 0 1 0 | means that you have reset the shared variable and your partner has not yet used it. This state can only occur if both partners are APL workspaces.
0 1 0 1 | means that your partner has reset the shared variable but that you have not yet used it.
0 0 0 0 | the name is not that of a shared variable

Examples

      ⎕SVS 'X'
0 1 0 1

      ⎕SVS ↑'X SALES' 'Y' 'JUNK'
0 0 1 1
1 0 1 0
0 0 0 0


Underscored Alphabetic Characters

Underscored Alphabetic Characters R←⎕Ⓐ

⎕Ⓐ is a deprecated feature. Dyalog strongly recommends that you move away from the use of ⎕Ⓐ and of the underscored alphabet itself, as these symbols now constitute the sole remaining non-standard use of characters in Dyalog applications.

In Versions of Dyalog APL prior to Version 11.0, ⎕Ⓐ was a simple character vector, composed of the letters of the alphabet with underscores. If the Dyalog Alt font was in use, these symbols displayed as additional National Language characters.

Version 10.1 and Earlier

      ⎕Ⓐ
ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ

For compatibility with previous versions of Dyalog APL, functions that contain references to ⎕Ⓐ will continue to return characters with the same index in ⎕AV as before. However, the display of ⎕Ⓐ is now ⎕Á, and the old underscored symbols appear as they did in previous Versions when the Dyalog Alt font was in use.

Current Version

      ⎕Á
ÁÂÃÇÈÊËÌÍÎÏÐÒÓÔÕÙÚÛÝþãìðòõ


Arbitrary Input

Arbitrary Input R←X ⎕ARBIN Y

This transmits a stream of 8-bit codes in Y to an output device specified by X prior to reading from an input device specified by X.

Y may be a scalar or a simple vector of integer numbers in the range 0-255.

X may take several forms:

terminate (input output) | ⎕ARBIN | codes
terminate input | ⎕ARBIN | codes

terminate

This is a numeric scalar or vector that specifies how the read operation should be terminated.

  • If it is a numeric scalar, it defines the number of bytes to be read.
  • If it is a numeric vector, it defines a set of terminating bytes.
  • If it is the null vector, the read terminates on Newline (10).

input

This is a simple numeric scalar that specifies the input device.

  • If it is positive or zero, it represents a file descriptor that must have been associated by the command that started Dyalog APL.
  • If it is negative, it represents the tie number of a file opened by ⎕NTIE or ⎕NCREATE.

output

If specified, this is a simple numeric integer that identifies the output device.

  • If it is positive or zero, it represents a file descriptor that must have been associated by the command that started Dyalog APL.
  • If it is negative, it represents the tie number of a file opened by ⎕NTIE or ⎕NCREATE.

The result R is a simple numeric vector. Each item of R is the numeric representation of an 8-bit code in the range 0 to 255 received from the input device. The meaning of the code is dependent on the characteristics of the input device. If a set of delimiters was defined by terminate, the last code returned will belong to that set.

⎕RTL (Response Time Limit) is an implicit argument of ⎕ARBIN. This allows a time limit to be imposed on input. If the time limit is reached, ⎕ARBIN returns with the codes read up to that point. This does not apply under Windows.

The operation will fail with a DOMAIN ERROR if Y contains anything other than numbers in the range 0-255, or if the current process does not have permission to read from or write to the specified device(s).

Examples (UNIX)

      )sh mkfifo ./fifo

      in←'./fifo'⎕NTIE 0
      out←'./fifo'⎕NTIE 0

      (10 (in out))⎕ARBIN ⎕UCS ⎕D
48 49 50 51 52 53 54 55 56 57

      (⍬ (in out))⎕ARBIN 10
10

⍝ cope with parity on line ending 10
      ((10+0 128) (in out))⎕ARBIN 10
10


Arbitrary Output

Arbitrary Output {R}←X ⎕ARBOUT Y

This transmits a stream of 8-bit codes in Y to an output device specified by X.

Y may be a scalar or a simple vector of integer numbers in the range 0-255.

X is a simple numeric integer that specifies the output device.

  • If X is positive or zero, it represents a file descriptor that must have been associated by the command that started Dyalog APL.
  • If X is negative, it represents the tie number of a file opened by ⎕NTIE or ⎕NCREATE.

If Y is an empty vector, no codes are sent to the output device.

The shy result R is ⍬.

The operation will fail with a DOMAIN ERROR if Y contains anything other than numbers in the range 0-255, or if the current process does not have permission to write to the specified device.

Examples

Write ASCII digits '123' to stream 9:

      9 ⎕ARBOUT 49 50 51

Write ASCII characters 'ABC' to MYFILE:

     'MYFILE' ⎕NCREATE ¯1
      ¯1 ⎕ARBOUT 65 66 67

Append the string 'Κάλο Πάσχα' to the same file, and close it:

      ¯1 ⎕ARBOUT 'UTF-8' ⎕UCS'Κάλο Πάσχα'
      ⎕NUNTIE ¯1


Atomic Vector

Atomic Vector R←⎕AV

⎕AV is a deprecated feature and is replaced by ⎕UCS.

This is a simple character vector of all 256 characters in the Classic Dyalog APL character.

In the Classic Edition the contents of ⎕AV are defined by the Output Translate Table.

In the Unicode Edition, the contents of ⎕AV are defined by the system variable ⎕AVU.

Examples

      ⎕AV[48+⍳10]
0123456789

      5 52⍴12↓⎕av
%'⍺⍵_abcdefghijklmnopqrstuvwxyz__¯.⍬0123456789_¤¥$£¢
∆ABCDEFGHIJKLMNOPQRSTUVWXYZ__ý·⍙ÁÂÃÇÈÊËÌÍÎÏÐÒÓÔÕÙÚÛ
ÝÞãìðòõ{€}⊣⌷¨ÀÄÅÆ⍨ÉÑÖØÜßàáâäåæçèéêëíîïñ[/⌿\⍀<≤=≥>≠∨^
-+÷×?∊⍴~↑↓⍳○*⌈⌊∇∘(⊂⊃∩∪⊥⊤|;,⍱⍲⍒⍋⍉⌽⊖⍟⌹!⍕⍎⍫⍪≡≢óôöø"#_&'
___________@ùúû^ü`⌷¶:⍷¿¡⋄←→⍝)]§⎕⍞⍣%'⍺⍵_abcdefghijk


Atomic Vector Unicode

Atomic Vector - Unicode ⎕AVU

⎕AVU specifies the contents of the atomic vector, ⎕AV, and is used to translate data between Unicode and non-Unicode character formats when required, for example when:

  • Unicode Edition loads or copies a Classic Edition workspace or a workspace saved by a Version prior to Version 12.0.
  • Unicode Edition reads character data from a non-Unicode component file, or receives data type 82 from a TCP socket.
  • Unicode Edition writes data to a non-Unicode component file
  • Unicode Edition reads or writes data from or to a Native File using conversion code 82.
  • Classic Edition loads or copies a Unicode Edition workspace
  • Classic Edition reads character data from a Unicode component file, or receives data type 80, 160, or 320 from a TCP socket.
  • Classic Edition writes data to a Unicode component file.

⎕AVU is an integer vector with 256 elements, containing the Unicode code points which define the characters in ⎕AV.

Note

In Versions of Dyalog prior to Version 12.0 and in the Classic Edition, a character is stored internally as an index into the atomic vector, ⎕AV. When a character is displayed or printed, the index in ⎕AV is translated to a number in the range 0-255 which represents the index of the character in an Extended ASCII font. This mapping is done by the Output Translate Table which is user-configurable. Note that although ASCII fonts typically all contain the same symbols in the range 0-127, there are a number of different Extended ASCII font layouts, including proprietary APL fonts, which provide different symbols in positions 128-255. The actual symbol that appears on the screen or on the printed page is therefore a function of the Output Translate Table and the font in use. Classic Edition provides two different fonts (and thus two different ⎕AV layouts) for use with the Development Environment, named Dyalog Std (with APL underscores) and Dyalog Alt (without APL underscores).

The default value of ⎕AVU corresponds to the use of the Dyalog Alt Output Translate Table and font in the Classic Edition or in earlier versions of Dyalog APL.

      2 13⍴⎕AVU[97+⍳26]
193 194 195 199 200 202 203 204 205 206 207 208 210
211 212 213 217 218 219 221 254 227 236 240 242 245
      ⎕UCS 2 13⍴⎕AVU[97+⍳26]
ÁÂÃÇÈÊËÌÍÎÏÐÒ
ÓÔÕÙÚÛÝþãìðòõ

⎕AVU can be localised, in order to make it straightforward to write access functions which receive or read data from systems with varying atomic vectors. If you have been using Dyalog Alt for most things but have some older code which uses underscores, you can bring this code together in the same workspace and have it all look "as it should" by using the Alt and Std definitions for ⎕AVU as you copy each part of the code into the same Unicode Edition workspace.

      )COPY avu.dws Std.⎕AVU
C:\Program Files\Dyalog\Dyalog APL 12.0 Unicode\ws\avu saved Thu Dec 06 11:24:32 2007

      2 13⍴⎕AVU[97+⍳26]
9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410
9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423
       ⎕UCS 2 13⍴⎕AVU[97+⍳26]
ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂ
ⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ

Rules for Conversion on Import

When the Unicode Edition imports APL objects from a non-Unicode source, function comments and character data of type 82 are converted to Unicode. When the Classic Edition imports APL objects from a Unicode source, this translation is performed in reverse.

If the objects are imported from a Version 12.0 (or later) workspace (i.e. from a workspace that contains its own value of ⎕AVU) the value of #.⎕AVU (the value of ⎕AVU in the root) in the source workspace is used. Otherwise, such as when APL objects are imported from a pre-Version 12 workspace, from a component file, or from a TCP socket, the local value of ⎕AVU in the target workspace is used.

Rules for Conversion on Export

When the Unicode Edition exports APL objects to a non-Unicode destination, such as a non-Unicode Component File or non-Unicode TCPSocket Object, function comments (in ⎕ORs) and character data of type 82 are converted to ⎕AV indices using the local value of ⎕AVU.

When the Classic Edition exports APL objects to a Unicode destination, such as a Unicode Component File or Unicode TCPSocket Object, function comments (in ⎕ORs) and character data of type 82 are converted to Unicode using the local value of ⎕AVU.

In all cases, if a character to be translated is not defined in ⎕AVU, a TRANSLATION ERROR (event number 92) will be signalled.


Diagnostic Message

Diagnostic Message R←⎕DM

This niladic function returns the last reported APL error as a three-element vector, giving error message, line in error and position of caret pointer.

Example

      2÷0
DOMAIN ERROR
      2÷0
     ^

      ⎕DM
 DOMAIN ERROR        2÷0       ^

Note: ⎕SIGNAL can be used to reset the value of this system constant.


Event Number

Event Number R←⎕EN

This simple integer scalar reports the identification number for the most recent event which occurred, caused by an APL action or by an interrupt or by the ⎕SIGNAL system function. Its value in a clear workspace is 0.

Example

      ÷0
DOMAIN ERROR: Divide by zero
      ÷0
     ∧
      ⎕EN
11

See APL Error Messages

Note: ⎕SIGNAL can be used to reset the value of this system constant.


Key Label

Key Label R←⎕KL Y

Classic Edition only.

Y is a simple character vector or a vector of character vectors containing Input Codes for Keyboard Shortcuts. In the Classic Edition, keystrokes are associated with Keyboard Shortcuts by the Input Translate Table.

R is a simple character vector or a vector of character vectors containing the labels associated with the codes. If Y specifies codes that are not defined, the corresponding elements of R are the codes in Y.

⎕KL provides the information required to build device-independent help messages into applications, particularly full-screen applications using ⎕SM and ⎕SR.

Examples:

      ⎕KL 'RC'
Right

      ⎕KL 'ER' 'EP' 'QT' 'F1' 'F13'
  Enter  Esc  Shift+Esc  F1  Shift+F1


Program Function Key

Program Function Key R←{X}⎕PFKEY Y

⎕PFKEY is a system function that sets or queries the programmable function keys. ⎕PFKEY associates a sequence of keystrokes with a function key. When the user subsequently presses the key, it is as if he had typed the associated keystrokes one by one.

Note that RIDE does not currently support the use of ⎕PFKEY; it is possible however to associate simple strings to function keys - see the RIDE User Guide for more information.

Y is an integer scalar in the range 0-255 specifying a programmable function key. If X is omitted the result R is the current setting of the key. If the key has not been defined previously, the result is an empty character vector.

If X is specified it is a simple or nested character vector defining the new setting of the key. The value of X is returned in the result R.

The elements of X are either character scalars or 2-element character vectors which specify keycodes. See Keyboard Shortcuts.

Programmable function keys are recognised in any of the three types of window (SESSION, EDIT and TRACE) provided by the Dyalog APL development environment. ⎕SR operates with the 'raw' function keys and ignores programmed settings.

Note that key definitions can reference other function keys, such as "F1" or "F123".

The size of the buffer associated with ⎕PFKEY is specified by the pfkey_size parameter.

Examples

       (')FNS',⊂'ER')⎕PFKEY 1
┌─┬─┬─┬─┬──┐
│)│F│N│S│ER│
└─┴─┴─┴─┴──┘
       (')VARS',⊂'ER')⎕PFKEY 2
┌─┬─┬─┬─┬─┬──┐
│)│V│A│R│S│ER│
└─┴─┴─┴─┴─┴──┘
      'F1' 'F2' ⎕PFKEY 3 ⍝ Does )FNS and )VARS
┌──┬──┐
│F1│F2│
└──┴──┘

The following expression defines the action for F12 to be "move the text to the right of the cursor to the left of the cursor".

      'Rl' 'CT' 'LL' 'PT'⎕PFKEY 12
┌──┬──┬──┬──┐
│Rl│CT│LL│PT│
└──┴──┴──┴──┘


Screen Dimensions

Screen Dimensions R←⎕SD

⎕SD is a 2-element integer vector containing the number of rows and columns on the screen, or in the USER window.

For asynchronous terminals under UNIX, the screen size is taken from the terminal database terminfo or termcap.

In window implementations of Dyalog APL, ⎕SD reports the current size (in characters) of the USER window or the current size of the SM object, whichever is appropriate.


Screen Map

Screen Map ⎕SM

⎕SM is a system variable that defines a character-based user interface (as opposed to a graphical user interface). In versions of Dyalog APL that support asynchronous terminals, ⎕SM defines a form that is displayed on the USER SCREEN. The implementation of ⎕SM in "window" environments is compatible with these versions. In Dyalog APL/X, ⎕SM occupies its own separate window on the display, but is otherwise equivalent. In versions of Dyalog APL with GUI support, ⎕SM either occupies its own separate window (as in Dyalog APL/X) or, if it exists, uses the window assigned to the SM object. This allows ⎕SM to be used in a GUI application in conjunction with other GUI components.

In general ⎕SM is a nested matrix containing between 3 and 13 columns. Each row of ⎕SM represents a field; each column a field attribute.

The columns have the following meanings:

Column | Description | Default
1 | Field Contents | N/A
2 | Field Position - Top Row | N/A
3 | Field Position - Left Column | N/A
4 | Window Size - Rows | 0
5 | Window Size - Columns | 0
6 | Field Type | 0
7 | Behaviour | 0
8 | Video Attributes | 0
9 | Active Video Attributes | ¯1
10 | Home Element - Row | 1
11 | Home Element - Column | 1
12 | Scrolling Group - Vertical | 0
13 | Scrolling Group - Horizontal | 0

With the exception of columns 1 and 8, all elements in ⎕SM are integer scalar values.

Elements in column 1 (Field Contents) may be:

  • A numeric scalar
  • A numeric vector
  • A 1-column numeric matrix
  • A character scalar
  • A character vector
  • A character matrix (rank 2)
  • A nested matrix defining a sub-form whose structure and contents must conform to that defined for ⎕SM as a whole. This definition is recursive. Note however that a sub-form must be a matrix - a vector is not allowed.

Elements in column 8 (Video Attributes) may be:

  • An integer scalar that specifies the appearance of the entire field.
  • An integer array of the same shape as the field contents. Each element specifies the appearance of the corresponding element in the field contents.

Screen Management (Async Terminals)

Dyalog APL for UNIX systems on tty devices (async terminals or on terminal emulators) manages two screens; the SESSION screen and the USER screen. If the SESSION screen is current, an assignment to ⎕SM causes the display to switch to the USER screen and show the form defined by ⎕SM.

Note that the RIDE does not directly support ⎕SM, although it is possible to display ⎕SM in the tty session to which a RIDE client is connected.

If the USER screen is current, any change in the value of ⎕SM is immediately reflected by a corresponding change in the appearance of the display. However, an assignment to ⎕SM that leaves its value unchanged has no effect.

Dyalog APL automatically switches to the SESSION screen for default output, if it enters immediate input mode (6-space prompt), or through use of ⎕ or ⍞. This means that typing

      ⎕SM ← expression

in the APL session will cause the screen to switch first to the USER screen, display the form defined by ⎕SM, and then switch back to the SESSION screen to issue the 6-space prompt. This normally happens so quickly that all the user sees is a flash on the screen.

To retain the USER screen in view it is necessary to issue a call to ⎕SR or for APL to continue processing. e.g.

      ⎕SM ← expression  ⋄  ⎕SR 1

or

      ⎕SM ← expression  ⋄  ⎕DL 5

Screen Management (Window Versions)

In Dyalog APL/X, and optionally in Dyalog APL/W, ⎕SM is displayed in a separate USER WINDOW on the screen. In an end-user application this may be the only Dyalog APL window. However, during development, there will be a SESSION window, and perhaps EDIT and TRACE windows too.

The USER Window will only accept input during execution of ⎕SR. It is otherwise "output-only". Furthermore, during the execution of ⎕SR it is the only active window, and the SESSION, EDIT and TRACE Windows will not respond to user input.

Screen Management (GUI Versions)

In versions of Dyalog APL that provide GUI support, there is a special SM object that defines the position and size of the window to be associated with ⎕SM. This allows character-mode applications developed for previous versions of Dyalog APL to be migrated to and integrated with GUI environments without the need for a total re-write.

Effect of Localisation

Like all system variables (with the exception of ⎕TRAP) ⎕SM is subject to "pass-through localisation". This means that a localised ⎕SM assumes its value from the calling environment. The localisation of ⎕SM does not, of itself therefore, affect the appearance of the display. However, reassignment of a localised ⎕SM causes the new form to overlay rather than replace whatever forms are defined further down the stack. The localisation of ⎕SM thus provides a simple method of defining pop-up forms, help messages, etc.

The user may edit the form defined by ⎕SM using the system function ⎕SR. Under the control of ⎕SR the user may change the following elements in ⎕SM which may afterwards be referenced to obtain the new values.

Column 1 | Field Contents
Column 10 | Home Element - Row (by scrolling vertically)
Column 11 | Home Element - Column (by scrolling horizontally)


Screen Read

Screen Read R←{X}⎕SR Y

⎕SR is a system function that allows the user to edit or otherwise interact with the form defined by ⎕SM.

In versions of Dyalog APL that support asynchronous terminals, if the current screen is the SESSION screen, ⎕SR immediately switches to the USER SCREEN and displays the form defined by ⎕SM.

In Dyalog APL/X, ⎕SR causes the input cursor to be positioned in the USER window. During execution of ⎕SR, only the USER Window defined by ⎕SM will accept input and respond to the keyboard or mouse. The SESSION and any EDIT and TRACE Windows that may appear on the display are dormant.

In versions of Dyalog APL with GUI support, a single SM object may be defined. This object defines the size and position of the ⎕SM window, and allows ⎕SM to be used in conjunctions with other GUI components. In these versions, ⎕SR acts as a superset of ⎕DQ (see Dequeue Events ) but additionally controls the character-based user interface defined by ⎕SM.

Y is an integer vector that specifies the fields which the user may visit. In versions with GUI support, Y may additionally contain the names of GUI objects with which the user may also interact.

If specified, X may be an enclosed vector of character vectors defining EXIT_KEYS or a 2-element nested vector defining EXIT_KEYS and the INITIAL_CONTEXT.

The result R is the EXIT_CONTEXT.

Thus the 3 uses of ⎕SR are:

     EXIT_CONTEXT←⎕SR FIELDS

     EXIT_CONTEXT←(⊂EXIT_KEYS)⎕SR FIELDS

     EXIT_CONTEXT←(EXIT_KEYS)(INITIAL_CONTEXT)⎕SR FIELDS

FIELDS

If an element of Y is an integer scalar, it specifies a field as the index of a row in ⎕SM (if ⎕SM is a vector it is regarded as having 1 row).

If an element of Y is an integer vector, it specifies a sub-field. The first element in Y specifies the top-level field as above. The next element is used to index a row in the form defined by ⊃⎕SM[Y[1];1] and so forth.

If an element of Y is a character scalar or vector, it specifies the name of a top-level GUI object with which the user may also interact. Such an object must be a "top-level" object, i.e. the Root object ('.') or a Form or pop-up Menu. This feature is implemented ONLY in versions of Dyalog APL with GUI support.

EXIT_KEYS

Each element of EXIT_KEYS is a 2-character code from the Input Translate Table for the keyboard. If the user presses one of these keys, ⎕SR will terminate and return a result.

If EXIT_KEYS is not specified, it defaults to:

      'ER' 'EP' 'QT'

which (normally) specifies <Enter>, <Esc> and <Shift+Esc>.

INITIAL_CONTEXT

This is a vector of between 3 and 6 elements with the following meanings and defaults:

Element | Description | Default
1 | Initial Field | N/A
2 | Initial Cursor Position - Row | N/A
3 | Initial Cursor Position - Col | N/A
4 | Initial Keystroke | ''
5 | (ignored) | N/A
6 | Changed Field Flags | 0

Structure of INITIAL_CONTEXT

INITIAL_CONTEXT[1] specifies the field in which the cursor is to be placed. It is an integer scalar or vector, and must be a member of Y. It must not specify a field which has BUTTON behaviour (64), as the cursor is not allowed to enter such a field.

INITIAL_CONTEXT[2 3] are integer scalars which specify the initial cursor position within the field in terms of row and column numbers.

INITIAL_CONTEXT[4] is either empty, or a 2-element character vector specifying the initial keystroke as a code from the Input Translate Table for the keyboard.

INITIAL_CONTEXT[5] is ignored. It is included so that the EXIT_CONTEXT result of one call to ⎕SR can be used as the INITIAL_CONTEXT to a subsequent call.

INITIAL_CONTEXT[6] is a Boolean scalar or vector the same length as Y. It specifies which of the fields in Y has been modified by the user.

EXIT_CONTEXT

The result EXIT_CONTEXT is a 6 or 9-element vector whose first 6 elements have the same structure as the INITIAL_CONTEXT. Elements 7-9 only apply to those versions of Dyalog APL that provide mouse support.

Element | Description
1 | Final Field
2 | Final Cursor Position - Row
3 | Final Cursor Position - Col
4 | Terminating Keystroke
5 | Event Code
6 | Changed Field Flags
7 | Pointer Field
8 | Pointer Position - Row
9 | Pointer Position - Col

Structure of the Result of ⎕SR

EXIT_CONTEXT[1] contains the field in which the cursor was when ⎕SR terminated due to the user pressing an exit key or due to an event occurring. It is an integer scalar or vector, and a member of Y.

EXIT_CONTEXT[2 3] are integer scalars which specify the row and column position of the cursor within the field EXIT_CONTEXT[1] when ⎕SR terminated.

EXIT_CONTEXT[4] is a 2-element character vector specifying the last keystroke pressed by the user before ⎕SR terminated. Unless ⎕SR terminated due to an event, EXIT_CONTEXT[4] will contain one of the exit keys defined by X. The keystroke is defined in terms of an Input Translate Table code.

EXIT_CONTEXT[5] contains the sum of the event codes that caused ⎕SR to terminate. For example, if the user pressed a mouse button on a BUTTON field (event code 64) and the current field has MODIFIED behaviour (event code 2) EXIT_CONTEXT[5] will have the value 66.

EXIT_CONTEXT[6] is a Boolean scalar or vector the same length as Y. It specifies which of the fields in Y has been modified by the user during this ⎕SR, ORed with INITIAL_CONTEXT[6]. Thus if the EXIT_CONTEXT of one call to ⎕SR is fed back as the INITIAL_CONTEXT of the next, EXIT_CONTEXT[6] records the fields changed since the start of the process.

EXIT_CONTEXT (Window Versions)

⎕SR returns a 9-element result ONLY if it is terminated by the user pressing a mouse button. In this case:

EXIT_CONTEXT[7] contains the field over which the mouse pointer was positioned when the user pressed a button. It is an integer scalar or vector, and a member of Y.

EXIT_CONTEXT[8 9] are integer scalars which specify the row and column position of the mouse pointer within the field EXIT_CONTEXT[7] when ⎕SR terminated.

Note:

This function is disabled and instead generates a DOMAIN ERROR if the RIDE_SPAWNED parameter is non-zero. This is designed to prevent it being invoked from a RIDE session which does not support this type of user interface. For further details, see the RIDE User Guide.


Set Monitor

Set Monitor {R}←X ⎕MONITOR Y

Y must be a simple character scalar or vector which is taken to be the name of a visible defined function or operator.

Note that ⎕MONITOR does not apply to dfns or dops.

X must be a simple non-negative integer scalar or vector. R is a simple integer vector of non-negative elements.

X identifies the numbers of lines in the function or operator named by Y on which a monitor is to be placed. Numbers outside the range of line numbers in the function or operator (other than 0) are ignored. The number 0 indicates that a monitor is to be placed on the function or operator as a whole. The value of X is independent of ⎕IO.

R is a vector of numbers on which a monitor has been placed in ascending order. The result is suppressed unless it is explicitly used or assigned. R will be empty for dfns and dops.

The effect of ⎕MONITOR is to accumulate timing statistics for the lines for which the monitor has been set. See Query Monitor for details.

Examples

      +(0,⍳10) ⎕MONITOR 'FOO'
0 1 2 3 4 5

Existing monitors are cancelled before new ones are set:

      +1 ⎕MONITOR 'FOO'
1

All monitors may be cancelled by supplying an empty vector:

      ⍬ ⎕MONITOR 'FOO'

Monitors may be set on a locked function or operator, but no information will be reported. Monitors are saved with the workspace.


Query Monitor

Query Monitor R←⎕MONITOR Y

Y must be a simple character scalar or vector which is taken to be the name of a visible defined function or operator.

Note that ⎕MONITOR does not apply to dfns or dops.

R is a simple non-negative integer matrix of 5 columns with one row for each line in the function or operator Y which has the monitor set, giving:

Column 1 | Line number
Column 2 | Number of times the line was executed
Column 3 | CPU time in milliseconds
Column 4 | Elapsed time in milliseconds
Column 5 | Reserved

The value of 0 in column one indicates that the monitor is set on the function or operator as a whole. R will be empty for dfns and dops.

Example

      ∇ FOO
[1]   A←?25 25⍴100
[2]   B←⌹A
[3]   C←⌹B
[4]   R1←⌊0.5+A+.×B
[5]   R2←A=C
      ∇

      (0,⍳5) ⎕MONITOR 'FOO' ⍝ Set monitor

      FOO                   ⍝ Run function

      ⎕MONITOR 'FOO'        ⍝ Monitor query
0 1 1418 1000 0
1 1   83    0 0
2 1  400    0 0
3 1  397    0 0
4 1  467 1000 0
5 1  100    0 0


Variant

Variant {R}←{X}(f ⎕OPT B)Y

⎕OPT is synonymous with the Variant Operator ⍠ and can be used in both Classic and Unicode Editions - unlike ⍠ which is valid in Unicode Editions only, and ⎕U2360 which is valid in Classic Editions only.

See Variant.


Object Representation

Object Representation R←⎕OR Y

⎕OR converts a defined function, defined operator or namespace to a special form, described as its object representation, that may be assigned to a variable and/or stored on a component file⎕OR and GUI objects stored in workspaces or in component files are not portable between 32-bit and 64-bit versions of Dyalog nor between different implementations (platforms) and are not backwards compatible 1. Classes and Instances are however outside the domain of ⎕OR.

Taking the ⎕OR of a defined function or operator is an extremely fast operation as it simply changes the type information in the object's header, leaving its internal structure unaltered. Converting the object representation back to an executable function or operator using ⎕FX is also very fast.

However, the saved results of ⎕OR which were produced on a different hardware platform or using an older version of Dyalog APL may require a significant amount of processing when re-constituted using ⎕FX. For optimum performance, it is strongly recommended that you save ⎕ORs using the same version of Dyalog APL and on the same hardware platform that you will use to ⎕FX them.

⎕OR may also be used to convert a namespace (either a plain namespace or a named GUI object created by ⎕WC) into a form that can be stored in a variable or on a component file. The namespace may be reconstructed using ⎕NS or ⎕WC with its original name or with a new one. ⎕OR may therefore be used to clone a namespace or GUI object.

Y must be a simple character scalar or vector which contains the name of an APL object.

If Y is the name of a variable, the result R is its value. In this case, R←⎕OR Y is identical to R←⍎Y.

Otherwise, R is a special form of the name Y, re-classified as a variable. The rank of R is 0 (R is scalar), and the depth of R is 1. These unique characteristics distinguish the result of ⎕OR from any other object. The Type of R (∊R) is itself. Note that although R is scalar, it may not be index assigned to an element of an array unless it is enclosed.

If Y is the name of a function or operator, R is in the domain of the monadic functions Same (⊣ and ⊢), Depth (≡), Disclose (⊃), Enclose (⊂), Rotate (⌽), Transpose (⍉), Index (⌷), Indexing ([]), Format (⍕), Identity (+), Shape (⍴), Type (∊) and Unique (∪), of the dyadic functions Left (⊣), Right (⊢), Without (~), Index Of (⍳), Intersection (∩), Match (≡), Membership (∊), Not Match (≠) and Union (∪), and of the monadic system functions Canonical Representation (⎕CR), Cross-Reference (⎕REFS), Fix (⎕FX), Format (⎕FMT), Nested Representation (⎕NR) and Vector Representation (⎕VR).

Note that a ⎕OR object can be transmitted through an 'APL-style' TCP socket. This technique may be used to transfer objects including namespaces between APL sessions.

The object representation forms of namespaces produced by ⎕OR may not be used as arguments to any primitive functions. The only operations permitted for such objects (or arrays containing such objects) are ⎕EX, ⎕FAPPEND, ⎕FREPLACE, ⎕NS, and ⎕WC.

Example

      F←⎕OR ⎕FX'R←FOO' 'R←10'

      ⍴F

      ⍴⍴F
0
      ≡F
1
      F≡∊F
1

The display of the ⎕OR form of a function or operator is a listing of the function or operator. If the ⎕OR form of a function or operator has been enclosed, then the result will display as the name preceded by the symbol ∇. It is permitted to apply ⎕OR to a locked function or operator. In this instance the result will display as for the enclosed form.

Examples

       F
      ∇ R←FOO
[1]     R←10
      ∇

      ⊂F
 ∇FOO

      ⎕LOCK'FOO'

      ⎕OR'FOO'
∇FOO
      A←⍳5

      A[3]←⊂F

      A
1 2  ∇FOO  4 5

For the ⎕OR forms of two functions or operators to be considered identical, their unlocked display forms must be the same, they must either both be locked or unlocked, and any monitors, trace and stop vectors must be the same.

Example

      F←⎕OR ⎕FX 'R←A PLUS B' 'R←A+B'

      F≡⎕OR 'PLUS'
1

      1 ⎕STOP 'PLUS'

      F≡⎕OR 'PLUS'
0

Namespace Examples

The following example sets up a namespace called UTILS, copies into it the contents of the UTIL workspace, then writes it to a component file:

      )CLEAR
clear ws
      )NS UTILS
#.UTILS
      )CS UTILS
#.UTILS
      )COPY UTIL
C:\WDYALOG\WS\UTIL saved Fri Mar 17 12:48:06 1995
      )CS
#
      'ORTEST' ⎕FCREATE 1
      (⎕OR'UTILS')⎕FAPPEND 1

The namespace can be restored with ⎕NS, using either the original name or a new one:

      )CLEAR
clear ws
      'UTILS' ⎕NS ⎕FREAD 1 1
#.UTILS
      )CLEAR
clear ws
      'NEWUTILS' ⎕NS ⎕FREAD 1 1
#.NEWUTILS

This example illustrates how ⎕OR can be used to clone a GUI object; in this case a Group containing some Button objects. Note that ⎕WC will accept only a ⎕OR object as its argument (or preceded by the "Type" keyword). You may not specify any other properties in the same ⎕WC statement, but you must instead use ⎕WS to reset them afterwards.

    'F'⎕WC'Form'
    'F.G1' ⎕WC 'Group' '&One' (10 10)(80 30)
    'F.G1.B2'⎕WC'Button' '&Blue' (40 10)('Style' 'Radio')
    'F.G1.B3'⎕WC'Button' '&Green' (60 10)('Style' 'Radio')
    'F.G1.B1'⎕WC'Button' '&Red' (20 10)('Style' 'Radio')
    'F.G2' ⎕WC ⎕OR 'F.G1'
    'F.G2' ⎕WS ('Caption' 'Two')('Posn' 10 60)

Note too that ⎕WC and ⎕NS may be used interchangeably to rebuild pure namespaces or GUI namespaces from a ⎕OR object. You may therefore use ⎕NS to rebuild a Form or use ⎕WC to rebuild a pure namespace that has no GUI components.


Response Time Limit

Response Time Limit ⎕RTL

A non-zero value in ⎕RTL places a time limit, in seconds, for input requested via ⍞, ⎕ARBIN, and ⎕SR. ⎕RTL may be assigned any integer in the range 0 to 32767. The value in a clear workspace is 0.

Example

      ⎕RTL←5 ⋄ ⍞←'FUEL QUANTITY?' ⋄ R←⍞
FUEL QUANTITY?
TIMEOUT
      ⎕RTL←5 ⋄ ⍞←'FUEL QUANTITY?' ⋄ R←⍞


Terminal Control

Terminal Control (⎕ML) R←⎕TC

⎕TC is a deprecated feature and is replaced by ⎕UCS (see note).

⎕TC is a simple three element vector. If ⎕ML < 3 this is ordered as follows:

⎕TC[1] | Backspace
⎕TC[2] | Linefeed
⎕TC[3] | Newline

Note that ⎕TC≡⎕AV[⎕IO+⍳3] for ⎕ML< 3 .

If ⎕ML ≥ 3 the order of the elements of ⎕TC is instead compatible with IBM's APL2:

⎕TC[1] | Backspace
⎕TC[2] | Newline
⎕TC[3] | Linefeed

Elements of ⎕TC beyond 3 are not defined but are reserved.

Note

With the introduction of ⎕UCS in Version 12.0, the use of ⎕TC is discouraged and it is strongly recommended that you generate control characters using ⎕UCS instead. This recommendation holds true even if you continue to use the Classic Edition.

Control Character | Old | New
Backspace | ⎕TC[1] | ⎕UCS 8
Linefeed | ⎕TC[2] (⎕ML<3) ⎕TC[3] (⎕ML≥3) | ⎕UCS 10
Newline | ⎕TC[3] (⎕ML<3) ⎕TC[2] (⎕ML≥3) | ⎕UCS 13


Set External Variable

Set External Variable {R}←X ⎕XT Y

Y must be a simple character scalar or vector which is taken to be a variable name. X must be a simple character scalar or vector which is taken to be a file reference. The name given by Y is identified as an EXTERNAL VARIABLE associated with an EXTERNAL ARRAY whose value may be stored in file identified by X. See User Guide for file naming conventions under Windows and UNIX. The shy result R has the same value as X.

If Y is the name of a defined function or operator, a label or a namespace in the active workspace, a DOMAIN ERROR is reported.

Attempts to assign namespace references or the ⎕OR of namespaces to an external array will result in a DOMAIN ERROR.

Example

      'EXT\ARRAY' ⎕XT 'V'

If the file reference does not exist, the external variable has no value until a value is assigned:

      V
VALUE ERROR
      V
      ^

A value assigned to an external variable is stored in file space, not within the workspace:

      ⎕WA
2261186

      V←⍳100000

      ⎕WA
2261186

There are no specific restrictions placed on the use of external variables. They must conform to the normal requirements when used as arguments of functions or as operands of operators. The essential difference between a variable and an external variable is that an external variable requires only temporary workspace for an operation to accommodate (usually) a part of its value.

Examples

      V←⍳5
      +/V
15

      V[3]←⊂'ABC'

      V
1 2  ABC  4 5

      ⍴¨V
     3

Assignment allows the structure or the value of an external variable to be changed without fully defining the external array in the workspace.

Examples

      V,←⊂2 4⍴⍳8

      ⍴V
6

      V[6]
1 2 3 4
5 6 7 8

      V[1 2 4 5 6]×←10

      V
10 20  ABC  40 50  10 20 30 40
                   50 60 70 80

An external array is (usually) preserved in file space when the name of the external variable is disassociated from the file. It may be re-associated with any valid variable name.

Example

      ⎕EX'V'

      'EXT\ARRAY'⎕XT'F'

      F
10 20  ABC  40 50  10 20 30 40
                   50 60 70 80

In UNIX versions, if X is an empty vector, the external array is associated with a temporary file which is erased when the array is disassociated.

Example

      ''⎕XT'TEMP'

      TEMP←⍳10

      +/TEMP×TEMP
385

      ⎕EX'TEMP'

An external array may be erased using the native file function: ⎕NERASE.

In a multi-user environment (UNIX or a Windows LAN) a new file associated with an external array is created with access permission for owner read/write. An existing file is opened for exclusive use (by the owner) if the permissions remain at this level. If the access permissions allow any other users to read and write to the file, the file is opened for shared use. In UNIX versions, access permissions may be modified using the appropriate Operating System command, or in Windows using the supplied function XVAR from the UTIL workspace.


Query External Variable

Query External Variable R←⎕XT Y

Y must be a simple character scalar or vector which is taken to be a variable name. R is a simple character vector containing the file reference of the external array associated with the variable named by Y, or the null vector if there is no associated external array.

Example

      ⎕XT'V'
EXT\ARRAY

      ⍴⎕XT'G'
0


Window Expose

Window Expose ⎕WX

⎕WX is a system variable with the value 0, 1 ,2 or 3. Considered as a sum of bit flags, the first bit in ⎕WX specifies (a); the second (b) as follows:

  1. whether or not the names of properties, methods and events provided by a Dyalog APL GUI object are exposed
  2. certain aspects of behaviour of .NET and COM objects

If ⎕WX is 1 (1st bit is set), the names of properties, methods and events are exposed as reserved names in GUI namespaces and can be accessed directly by name. This means that the same names may not be used for global variables in GUI namespaces.

If ⎕WX is 0, these names are hidden and may only be accessed indirectly using ⎕WG and ⎕WS.

If ⎕WX is 3 (2nd bit is also set) COM and .NET objects adopt the behaviour introduced in Version 11, as opposed to the behaviour in previous versions of Dyalog APL.

Note that it is the value of ⎕WX in the object itself, rather than the value of ⎕WX in the calling environment, that determines its behaviour.

When you create an object, its ⎕WX (like any other system variable) is initially inherited from its parent.

If the value of ⎕WX of a GUI object is initially 0, it will not expose its members. If you subsequently change it from 0 to 1, it will expose them. If you change its ⎕WX back to 0, it will not expose any yet-unexposed members, although already-exposed members will continue to be exposed.

The value of ⎕WX in a clear workspace is defined by the default_wx parameter (see default_wx) which itself defaults to 3.

⎕WX has namespace scope and may be localised in a function header. This allows you to create a utility namespace or utility function in which the exposure of objects is known and determined, regardless of its global value in the workspace.

Notes:

  • The visibility of the properties and methods of the Root object are not controlled by ⎕WX but by the PropertyExposeRoot parameter. For further information, see PropertyExposeRoot.
  • ⎕WX is retained for backwards compatibility and should be considered as deprecated. Dyalog recommends ⎕WX be set to 3 and never changed.


Print Width

Print Width ⎕PW

⎕PW is the maximum number of output characters per line before folding the display.

⎕PW may be assigned any integer value in the range 42 to 32767. Note that in versions of Dyalog APL prior to 13.0 ⎕PW had a minimum value of 30; this was increased to support 128-bit decimal values.

If an attempt is made to display a line wider than ⎕PW, then the display will be folded at or before the ⎕PW width and the folded portions indented 6 spaces. The display of a simple numeric array may be folded at a width less than ⎕PW so that individual numbers are not split.

⎕PW only affects output, either direct or through ⎕ output. It does not affect the result of the function Format (⍕), of the system function ⎕FMT, or output through the system functions ⎕ARBOUT and ⎕ARBIN, or output through ⍞.

Note that if the auto_pw parameter (Options/Configure/Session/Auto PW) is set to 1, ⎕PW is automatically adjusted whenever the Session window is resized. In these circumstances, a value assigned to ⎕PW will only apply until the Session window is next resized.

Examples

      ⎕PW←42

      ⎕←3⍴÷3
0.3333333333 0.3333333333 0.3333333333
      0.3333333333


Session Namespace

Session Namespace ⎕SE

⎕SE is a system namespace. Its GUI components (MenuBar, ToolBar, and so forth) define the appearance and behaviour of the APL Session window and may be customised to suit individual requirements.

⎕SE is maintained separately from the active workspace and is not affected by )LOAD or )CLEAR. It is therefore useful for containing utility functions. The contents of ⎕SE may be saved in and loaded from a .DSE file.

See Dyalog for Microsoft Windows UI Guide for further details.


Introduction

System commands are not executable APL expressions. They provide services or information associated with the workspace and the external environment.

Command Presentation

System commands may be entered from immediate execution mode or in response to the prompt ⎕: within evaluated input. All system commands begin with the symbol ), known as a right parenthesis. All system commands may be entered in upper or lower case.

Table 28: System Commands

Command | Description
)CLASSES | List classes
)CLEAR | Clear the workspace
)CMD Y | Execute a Windows Command
)CONTINUE | Save a Continue workspace and terminate APL
)COPY {Y} | Copy objects from another workspace
)CS {Y} | Change current namespace
)DROP {Y} | Drop named workspace
)ED Y | Edit object(s)
)ERASE Y | Erase object(s)
)EVENTS | List events of GUI namespace or object
)FNS {Y} | List user defined Functions
)HOLDS | Display Held tokens
)LIB {Y} | List workspaces in a directory
)LOAD {Y} | Load a workspace
)METHODS | List methods in GUI namespace or object
)NS {Y} | Create a global Namespace
)OBJECTS {Y} | List global namespaces
)OBS {Y} | List global namespaces (alternative form)
)OFF | Terminate the APL session
)OPS {Y} | List user defined Operators
)PCOPY {Y} | Perform Protected Copy of objects
)PROPS | List properties of GUI namespace or object
)RESET | Reset the state indicator
)SAVE {Y} | Save the workspace
)SH {Y} | Execute a (UNIX) Shell command
)SI | State Indicator
)SIC | Clear State Indicator
)SINL | State Indicator with local Name Lists
)TID {Y} | Switch current Thread Identity
)VARS {Y} | List user defined global Variables
)WSID {Y} | Workspace Identification
)XLOAD Y | Load a workspace; do not execute ⎕LX
{ } indicates that the parameter(s) denoted by Y are optional.


List Classes

List Classes )CLASSES

This command lists the names of APL Classes in the active workspace.

Example:

      )CLEAR
clear ws
      )ED ○MyClass

:Class MyClass
    ∇ Make Name
      :Implements Constructor
      ⎕DF Name
    ∇
:EndClass ⍝ MyClass

      )CLASSES
MyClass
      )COPY OO YourClass
.\OO saved Sun Jan 29 18:32:03 2006
      )CLASSES
MyClass YourClass
      ⎕NC 'MyClass' 'YourClass'
9.4 9.4


Clear Workspace

Clear Workspace )CLEAR

This command clears the active workspace and gives the report "clear ws". The active workspace is lost. The name of a clear workspace is CLEAR WS. System variables are initialised with their default values as described in System Variables.

In GUI implementations of Dyalog APL, )CLEAR expunges all GUI objects, discards any unprocessed events in the event queue and resets the properties of the Root object '.' to their default values.

Example

      )CLEAR
clear ws


Windows Command Processor

Windows Command Processor )CMD cmd

This command allows Windows Command Processor or UNIX shell commands to be given from APL. )CMD is a synonym of )SH. Either command may be given in either environment (Windows or UNIX) with exactly the same effect. )CMD is probably more natural for the Windows user. This section describes the behaviour of )CMD and )SH under Windows. See Execute (UNIX) Command for a discussion of the behaviour of these commands under UNIX.

The system functions ⎕SH and ⎕CMD provide similar facilities but may be executed from within APL code.

Note that under Windows, you may not execute )CMD without a command. If you wish to, you can easily open a new Command Prompt window outside APL.

Example

     )cmd dir
 Volume in drive C is OS
 Volume Serial Number is B438-9B76

 Directory of C:\Users\Pete\Documents\Dyalog APL-64 17.0 Unicode Files

23/06/2018  15:59    <DIR>          .
23/06/2018  15:59    <DIR>          ..
23/06/2018  14:53           181,488 default.dlf
13/06/2018  20:13         1,262,296 def_uk.dse
14/06/2018  14:36           108,976 UserCommand20.cache
               3 File(s)      1,552,760 bytes
               2 Dir(s)  101,371,437,056 bytes free

If cmd issues prompts and expects user input, it is ESSENTIAL to explicitly redirect input and output to the console. If this is done, APL detects the presence of a ">" in the command line and runs the command processor in a visible window and does not direct output to the pipe. If you fail to do this your system will appear to hang because there is no mechanism for you to receive or respond to the prompt.

Example

      )CMD DATE <CON >CON

(Command Prompt window appears)

Current date is Wed 19-07-1995
Enter new date (dd-mm-yy): 20-07-95

(Command Prompt window disappears)

Implementation Notes

The argument of )CMD is simply passed to the appropriate command processor for execution and its output is received using an unnamed pipe.

By default, )CMD will execute the string ('cmd.exe /c',Y) where Y is the argument given to )CMD. However, the implementation permits the use of alternative command processors as follows:

Before execution, the argument is prefixed and postfixed with strings defined by the APL parameters CMD_PREFIX and CMD_POSTFIX. The former specifies the name of your command processor and any parameters that it requires. The latter specifies a string which may be required. If CMD_PREFIX is not defined, it defaults to the name defined by the environment variable COMSPEC followed by "\c". If COMSPEC is not defined, it defaults to COMMAND.COM or CMD.EXE as appropriate. If CMD_POSTFIX is not defined, it defaults to an empty vector.

Note:

This function is disabled and instead generates a DOMAIN ERROR if the RIDE_SPAWNED parameter is non-zero. This is designed to prevent it being invoked from a RIDE session which does not support this type of user interface. For further details, see the RIDE User Guide.


Save Continuation

Save Continuation )CONTINUE

This command saves the active workspace in the current working directory and ends the Dyalog APL session. The name of the workspace file is CONTINUE in upper-case with the extension defined by the WSEXT parameter.

Note that the values of all system variables (including ⎕SM) and GUI objects are also saved in CONTINUE.

When a CONTINUE workspace is loaded, the latent expression (if any) is NOT executed.


Copy Workspace

Copy Workspace )COPY {ws {nms}}

This command brings all or selected global objects nms from a stored workspace (or session file) with the given name. A stored workspace is one which has previously been saved with the system command )SAVE or the system function ⎕SAVE.

See Workspaces for the rules for specifying a workspace name.

If the list of names is excluded, all defined objects (including namespaces) are copied.

If the workspace name identifies a valid, readable workspace, the system reports the workspace name, "saved" and the date and time when the workspace was last saved.

Examples

      )COPY WS/UTILITY
WS/UTILITY saved Mon Nov  1 13:11:19 1992

      )COPY TEMP ⎕LX FOO X A.B.C
./TEMP saved Mon Nov  1 14:20:47 1992
not found X

Copied objects are defined at the global level in the active workspace. Existing global objects in the active workspace with the same name as a copied object are replaced. If the copied object replaces either a function in the state indicator, or an object that is an operand of an operator in the state indicator, or a function whose left argument is being executed, the original object remains defined until its execution is completed or it is no longer referenced by an operator in the state indicator. If the workspace name is not valid or does not exist or if access to the workspace is not authorised, the system reports ws not found.

You may copy an object from a namespace by specifying its full pathname. The object will be copied to the current namespace in the active workspace, losing its original parent and gaining a new one in the process. You may only copy a GUI object into a namespace that is a suitable parent for that object. For example, you could only copy a Group object from a saved workspace if the current namespace in the active workspace is itself a Form, SubForm or Group.

If the workspace name identifies a file that is not a workspace, the system reports bad ws.

If the source workspace is too large to be loaded, the system reports ws too large.

When copying data between Classic and Unicode Editions, )COPY will fail with TRANSLATION ERROR if any object in the source workspace fails conversion between Unicode and ⎕AV indices, whether or not that object is specified by nms. See Note for further details.

If "ws" is omitted, the file open dialog box is displayed and all objects copied from the selected workspace.

If the list of names is included, the names of system variables may also be included and copied into the active workspace. The global referents will be copied.

If an object is not found in the stored workspace, the system reports not found followed by the name of the object.

Dependant Objects

If the list of names includes the name of:

  • an Instance of a Class but not the Class itself
  • a Class but not a Class upon which it depends
  • an array or a namespace that contains a ref to another namespace, but not the namespace to which it refers

the dependant object(s) will also be copied but will be unnamed and hidden. In such as case, the system will issue a warning message.

For example, if a saved workspace named CFWS contains a Class named #.CompFile and an Instance (of CompFile) named icf,

      )COPY CFWS icf
.\CFWS saved Fri Mar 03 10:21:36 2006
copied object created an unnamed copy of class #.CompFile

The existence of a hidden copy can be confusing, especially if it is a hidden copy of an object which had a name which is in use in the current workspace. In the above example, if there is a class called CompFile in the workspace into which icf is copied, the copied instance may appear to be an instance of the visible CompFile, but it will actually be an instance of the hidden CompFile - which may have very different (or perhaps worse: very slightly different) characteristics to the named version.

If you copy a Class without copying its Base Class, the Class can be used (it will use the invisible copy of the Base Class), but if you edit the Class, you will either be unable to save it because the editor cannot find the Base Class, or - if there is a visible Class of that name in the workspace - it will be used as the Base Class.

In the latter case, the invisible copy which was brought in by )COPY will now disappear, since there are no longer any references to it - and if these two Base Classes were different, the behaviour of the derived Class will change (and any changes made to the invisible Base Class since it was copied will be lost).

Referenced Objects

If you copy a Class or a namespace that is referenced by a Class as its Base Class or via a :Include statement, the referring Class will continue to refer to the original definition of the copied name which will be retained for that purpose. The Class can be made to refer to the copied definition of that name by refixing it.

Example

The current workspace has a class named pete whose Base class is called base.

:Class pete: base
:EndClass

:Class base
    ∇ r←foo n
      :Access Public
      r←'Original'n
    ∇
:EndClass

A second workspace named copy.dws contains a different version of the base class:

:Class base
    ∇ r←foo n
      :Access Public
      r←'Copied'n
    ∇
:EndClass

      )copy copy.dws base
copy.dws saved Thu Nov 22 16:24:27 2018
      inst←⎕NEW pete
      inst.foo 1
Original  1

      ⎕FIX ⎕SRC pete
      inst←⎕NEW pete
      inst.foo 1
Copied  1

Copying Objects from Session Files

You may also copy objects from session (.dse) files, although with certain restrictions.

Example:

        )copy C:\Users\Pete\Desktop\pete.dse ⎕SE.UCMD
C:\Users\Pete\Desktop\pete.dse saved Wed Oct 14 ...
  • You can copy a function or variable from any namespace under a saved ⎕SE, no matter what your current namespace is.
  • You can copy any namespace without GUI from a saved ⎕SE, no matter what you current namespace is.
  • You can copy any namespace with GUI from a saved ⎕SE as long as your current namespace is the same as the parent namespace of the namespace you are trying to copy

Examples:

In the following example, the not copied cases occur because the current namespace is not an appropriate parent for the object in question.

      )CS #
#
      )copy C:\Users\...\pete.dse ⎕SE.Dyalog.Callbacks
C:\Users\...\pete.dse saved Wed Oct 14 15:31:14 2015

       )copy C:\Users\...\pete.dse ⎕SE.cbbot
C:\Users\...\pete.dse saved Wed Oct 14 15:31:14 2015
not copied cbbot

       )CS ⎕SE
⎕SE
      )copy C:\Users\...\pete.dse ⎕SE.cbbot
C:\Users\...\pete.dse saved Wed Oct 14 15:31:14 2015

      )copy C:\Users\...\pete.dse ⎕SE.cbbot.bandsb1
C:\Users\...\pete.dse saved Wed Oct 14 15:31:14 2015
not copied bandsb1


Change Space

Change Space )CS {nm}

)CS changes the current space to the global namespace nm.

If no nm is given, the system changes to the top level (Root) namespace. If nm is not the name of a global namespace, the system reports the error message Namespace does not exist.

name may be either a simple name or a compound name separated by '.', including one of the special names '#' (Root) or '##' (Parent).

Examples

      )CS
#
      )CS X
#.X
      )CS Y.Z
#.X.Y.Z
      )CS ##
#.X.Y
      )CS #.UTIL
#.UTIL


Drop Workspace

Drop Workspace )DROP {ws}

This command removes the specified workspace from disk storage.

See Workspaces for the rules for specifying a workspace name.

If ws is omitted, a file open dialog box is displayed to elicit the workspace name.

Example

      )DROP WS/TEMP
Thu Sep 17 10:32:18 1998


Edit Object

Edit Object )ED nms

)ED invokes the Dyalog APL editor and opens an Edit window for each of the objects specified in nms.

If a name includes the slash character ("\" or "/") it is taken to be the name of a file. See Editing Scripts and Text Files.

If a name specifies a new symbol it is taken to be a function or operator. However, if a name is localised in a suspended function or operator but is otherwise undefined, it is assumed to be a vector of character vectors.

The type of a new object may be specified explicitly by preceding its name with an appropriate symbol as follows:

∇ | function or operator
→ | simple character vector
∊ | vector of character vectors
- | character matrix
⍟ | Namespace script
○ | Class script
∘ | Interface

The first object named becomes the top window on the stack. See the Dyalog for Microsoft Windows UI Guide or the Dyalog for UNIX UI Guide for details.

Examples

      )ED MYFUNCTION

      )ED ∇FOO -MAT ∊VECVEC

Objects specified in nms that cannot be edited are silently ignored. Objects qualified with a namespace path are (e.g. a.b.c.foo) are silently ignored if the namespace does not exist.


Erase Object

Erase Object )ERASE nms

This command erases named global defined objects (functions, operators, variables, namespaces and GUI objects) from the active workspace or current namespace.

If a named object is a function or operator in the state indicator, or the object is an operand of an operator in the state indicator, or the object is a function whose left argument is being executed, the object remains defined until its execution is completed or it is no longer referenced by an operator in the state indicator. However, the name is available immediately for other uses.

If a named object is a GUI object, the object and all its children are deleted and removed from the screen.

If an object is not erased for any reason, the system reports not found followed by the name of the object.

Erasing objects such as external functions may have other implications: see Expunge Object for details.

Example

      )ERASE FOO A ⎕IO
not found ⎕IO


List Events

List Events )EVENTS

The )EVENTS system command lists the Events that may be generated by the object associated with the current space.

For example:

      ⎕CS 'BB' ⎕WC 'BrowseBox'

      )EVENTS
Close   Create  FileBoxCancel   FileBoxOK

)EVENTS produces no output when executed in a pure (non-GUI) namespace, for example:

      ⎕CS 'X' ⎕NS ''
      )EVENTS


List Global Defined Functions

List Global Defined Functions )FNS {nm}

This command displays the names of global defined functions in the active workspace or current namespace. Names are displayed in ⎕AV collation order. If a name is included after the command, only those names starting at or after the given name in collation order are displayed.

Examples

      )FNS
ASK DISPLAY GET PUT ZILCH
      )FNS G
GET PUT ZILCH


Display Held Tokens

Display Held Tokens )HOLDS

System command )HOLDS displays a list of tokens which have been acquired or requested by the :Hold control structure.

Each line of the display is of the form:

token:  acq  req  req ...

Where acq is the number of the thread that has acquired the token, and req is the number of a thread which is requesting it. For a token to appear in the display, a thread (and only one thread) must have acquired it, whereas any number of threads can be requesting it.

Example

Thread 300’s attempt to acquire token 'blue' results in a deadlock:

300:DEADLOCK
Sema4[1] :Hold 'blue'
        ^

      )HOLDS
blue:   100
green:  200     100
red:    300     200     100

  • Blue has been acquired by thread 100.
  • Green has been acquired by 200 and requested by 100.
  • Red has been acquired by 300 and requested by 200 and 100.

The following cycle of dependencies has caused the deadlock:

Thread 300 attempts to acquire blue,      300 → blue
which is owned by 100,                     ↑      ↓
which is waiting for red,                 red ←  100
which is owned by 300.


List Workspace Library

List Workspace Library )LIB {dir}

This command lists the names of Dyalog APL workspaces contained in the given directory.

Example

      )LIB WS
MYWORK TEMP

If a directory is not given, the workspaces on the user's APL workspace path (WSPATH) are listed. In this case, the listing is divided into sections identifying the directories concerned. The current directory is identified as ".".

Example

      )LIB
.
        PDTEMP  WORK   GRAPHICS
c:\Dyalog\ws
        display groups


Load Workspace

Load Workspace )LOAD {ws}

This command causes the named stored workspace to be loaded. The current active workspace is lost.

See Workspaces for the rules for specifying a workspace name.

If ws is a full or relative pathname, only the specified directory is examined. If not, the APL workspace path (WSPATH) is traversed in search of the named workspace. A stored workspace is one which has previously been saved with the system command )SAVE or the system function ⎕SAVE. Under Windows, if ws is omitted, the File Open dialog box is displayed.

If the workspace name is not valid or does not exist or if access to the workspace is not authorised, the system reports ws not found. If the workspace name identifies a file or directory that is not a workspace, the system reports workspace name is not a ws. If successfully loaded, the system reports workspace name saved, followed by the date and time when the workspace was last saved. If the workspace is too large to be loaded into the APL session, the system reports ws too large. After loading the workspace, the current namespace is set to # and the latent expression (⎕LX) is executed unless APL was invoked with the -x option. If the workspace was saved with a suspension, typing the expression →1+⎕lc will resume execution and switch back into the namespace associated with the suspended function.

If the workspace contains any GUI objects whose Visible property is 1, these objects will be displayed. If the workspace contains a non-empty ⎕SM but does not contain an SM GUI object, the form defined by ⎕SM will be displayed in a window on the screen.

Holding the Ctrl key down while entering a )LOAD command or selecting a workspace from the session file menu now causes the incoming latent expression to be traced.

Holding the Shift key down while selecting a workspace from the session file menu will prevent execution of the latent expression.

Example

      )load dfns
C:\Program Files\Dyalog\Dyalog APL-64 15.0 Unicode\ws\dfns.dws saved Thu Jul 28 17:25:28 2016

An assortment of D Functions and Operators.

      tree #                ⍝ Workspace map.
      ↑¯10↑↓attrib ⎕nl 3 4  ⍝ What's new?
      notes find 'Word'     ⍝ Apropos "Word".


List Methods

List Methods )METHODS

The )METHODS system command lists the Methods that apply to the object associated with the current space.

For example:

      ⎕CS 'F' ⎕WC 'Form'
      )METHODS
Animate ChooseFont   Detach  GetFocus    GetTextSize Wait

)METHODS produces no output when executed in a pure (non-GUI) namespace, for example:

      ⎕CS 'X' ⎕NS ''
      )METHODS


Create Namespace

Create Namespace )NS {nm}

)NS creates a global namespace and displays its full name, nm.

nm may be either a simple name or a compound name separated by '.', including one of the special names '#' (Root) or '##' (Parent).

If name does not start with the special Root space identifier '#', the new namespace is created relative to the current one.

If name is already in use for a workspace object other than a namespace, the command fails and displays the error message Name already exists.

If name is an existing namespace, no change occurs.

)NS with no nm specification displays the current namespace.

Examples

      )NS
#

      )NS W.X
#.W.X

      )CS W.X
#.W.X

      )NS Y.Z
#.W.X.Y.Z

      )NS
#.W.X


List Global Namespaces

List Global Namespaces )OBJECTS {nm}

This command displays the names of global namespaces in the active workspace. Names are displayed in the ⎕AV collating order. If a name is included after the command, only those names starting at or after the given name in collating order are displayed. Namespaces are objects created using ⎕NS, )NS or ⎕WC and have name class 9.

Note: )OBS can be used as an alternative to )OBJECTS

Examples

      )OBJECTS
FORM1   UTIL    WSDOC   XREF

      )OBS W
WSDOC   XREF


List Global Namespaces Short

List Global Namespaces )OBS {nm}

This command is the same as the )OBJECTS command. See List Global Namespaces


Sign Off APL

Sign Off APL )OFF

This command terminates the APL session, returning to the Operating System command processor or shell.


List Global Defined Operators

List Global Defined Operators )OPS {nm}

This command displays the names of global defined operators in the active workspace or current namespace. Names are displayed in ⎕AV collation order. If a name is included after the command, only those names starting at or after the given name in collation order are displayed.

Examples

      )OPS
AND DOIF DUAL ELSE POWER

      )OPS E
ELSE POWER


Protected Copy

Protected Copy )PCOPY {ws {nms}}

This command brings all or selected global objects from a stored workspace with the given name provided that there is no existing global usage of the name in the active workspace. A stored workspace is one which has previously been saved with the system command )SAVE or the system function ⎕SAVE.

)PCOPY does not copy ⎕SM. This restriction may be removed in a later release.

If the workspace name is not valid or does not exist or if access to the workspace is not authorised, the system reports "ws not found". If the workspace name identifies a file that is not a workspace, or is a workspace with an invalid version number (one that is greater than the version of the current APL) the system reports "bad ws".

See Workspaces for the rules for specifying a workspace name.

If the workspace name is the name of a valid, readable workspace, the system reports the workspace name, "saved", and the date and time that the workspace was last saved.

If the list of names is excluded, all global defined objects (functions and variables) are copied. If an object is not found in the stored workspace, the system reports "not found" followed by the name of the object. If an object cannot be copied into the active workspace because there is an existing referent, the system reports "not copied" followed by the name of the object.

For further information, see Example.

Examples

      )PCOPY WS/UTILITY
WS/UTILITY saved Mon Nov  1 13:11:19 1993
not copied COPIED IF
not copied COPIED JOIN

      )PCOPY TEMP FOO X
./TEMP saved Mon Nov  1 14:20:47 1993
not found X

Warning

If a workspace full condition occurs during the execution of )PCOPY the state of the active workspace is unpredictable.


List Properties

List Properties )PROPS

The )PROPS system command lists the Properties of the object associated with the current space.

For example:

      ⎕CS 'BB' ⎕WC 'BrowseBox'

      )PROPS
BrowseFor       Caption ChildList       Data    Event
EventList       HasEdit KeepOnClose     MethodList
PropList        StartIn Target  Translate       Type

)PROPS produces no output when executed in a pure (non GUI) namespace, for example:

      ⎕CS 'X' ⎕NS ''
      )PROPS


Reset State Indicator

Reset State Indicator )RESET {n}

This command cancels all suspensions recorded in the state indicator and discards any unprocessed events in the event queue.

The optional parameter n specifies that only the top n suspensions are to be cleared.

)RESET also performs an internal re-organisation of the workspace and process memory. See Workspace Available for details.

Example

      )SI
#.FOO[1]*
⍎
#.FOO[1]*

      )RESET

      )SI


Save Workspace

Save Workspace )SAVE {-force} {ws}

This command compacts (see Workspace Available for details) and saves the active workspace.

If specified, ws is a full or relative path name to the file in which the workspace will be written. If ws is omitted, it defaults to ⎕WSID. Unless the path specified by ws or ⎕WSID is a full pathname, it is taken to be relative to the current working directory which may be obtained by the expression: ⊃1 ⎕NPARTS ''.

If ws specifies a file name other than that implied by ⎕WSID, the specified file must not already exist unless the force parameter is specified.. If ws is omitted or resolves to the same file as ⎕WSID, an existing stored workspace with the same name will be replaced.

See Workspaces for the rules for specifying a workspace name.

If an extension is not specified, an extension is added according to the WSEXT parameter..

A workspace may not be saved if any threads (other than the root thread 0) are running or if there are any Edit or Trace windows open. Otherwise, the workspace is saved with its state of execution intact, however certain operations may be performed before it is saved. For further information, see Set Workspace Save Options.

)SAVE may fail with one of the following error messages:

unacceptable char | The given workspace name was ill-formed
not saved this ws is WSID | An attempt was made to change the name of the workspace for the save, and the renamed workspace already existed. This error can be overridden by specifying -force.
not saved this ws is CLEAR WS | The active workspace was CLEAR WS and no attempt was made to change the name.
Can't save - file could not be created. | The workspace name supplied did not represent a valid file name for the current Operating System.
cannot create | The user does not have access to create the file OR the workspace name conflicts with an existing non-workspace file.
cannot save with windows open | A workspace may not be saved if trace or edit windows are open.

After a successful save, the system reports the workspace name, followed by the word "saved" and the current time and date; and if ws specified a new name, ⎕WSID is assigned that name.

Example

      )SAVE MYWORK
./MYWORK saved Thu Sep 17 10:32:20 1998

Note that any time prior to executing )SAVE, the active workspace may be renamed by the system command )WSID or by assigning a name to the system variable ⎕WSID.

A stored workspace may subsequently be loaded with the system command )LOAD or the system function ⎕LOAD, and objects may be copied from a stored workspace with the system commands )COPY or )PCOPY or the system function ⎕CY.


Execute UNIX Command

Execute (UNIX) Command )SH {cmd}

This command allows WINDOWS or UNIX shell commands to be given from APL. )SH is a synonym of )CMD. Either command may be given in either environment (Windows or UNIX) with exactly the same effect. )SH is probably more natural for the UNIX user. This section describes the behaviour of )SH and )CMD under UNIX. See Windows Command Processor for a discussion of their behaviour under Windows.

The system functions ⎕SH and ⎕CMD provide similar facilities but may be executed from within APL code.

)SH allows UNIX shell commands to be given from APL. The argument must be entered in the appropriate case (usually lower-case). The result of the command, if any, is displayed.

)SH causes Dyalog APL to invoke the system() library call. The shell which is used to run the command is therefore the shell which system() is defined to call. For example, under AIX this would be /usr/bin/sh.

When the shell is closed, control returns to APL. See Dyalog for UNIX UI Guide for further information.

The parameters CMD_PREFIX and CMD_POSTFIX may be used to execute a different shell under the shell associated with system().

Example

      )sh ps -u andys | grep -v ps
   UID      PID    TTY  TIME CMD
  6179  9437326  pts/0  0:00 ksh
  6179 10223736  pts/0  0:00 dyalog
  6179 10354810  pts/0  0:00 sh
  6179 10879188  pts/0  0:00 ksh
  6179 11665660      -  0:00 sshd

Note:

This function is disabled and instead generates a DOMAIN ERROR if the RIDE_SPAWNED parameter is non-zero. This is designed to prevent it being invoked from a RIDE session which does not support this type of user interface. For further details, see the RIDE User Guide.


State Indicator

State Indicator )SI {n} {-tid=tn}

This command displays the contents of the state indicator in the active workspace. The state indicator identifies those operations which are suspended or pendent for each suspension.

The optional parameter n specifies that only the first n or last ¯n lines of the output should be displayed.

The optional parameter -tid=tn specifies that the state indicator is to be displayed only for thread number tn.

The list consists of a line for each suspended or pendent operation beginning with the most recently suspended function or operator. Each line may be:

  • The name of a defined function or operator, followed by the line number at which the operation is halted, and followed by the * symbol if the operation is suspended. The name of the function or operator is its full pathname relative to the root namespace #. For example, #.UTIL.PRINT. In addition, the display of a function or operator which has dynamically changed space away from its origin is prefixed with its current space. For example, [⎕SE] TRAV.
  • A primitive operator symbol.
  • The Execute function symbol (⍎).
  • The Evaluated Input symbol (⎕).
  • The System Function ⎕DQ or ⎕SR (occurs when executing a callback function).

Examples

      )SI
#.PLUS[2]*
.
#.MATDIV[4]
#.FOO[1]*
⍎

This example indicates that at some point function FOO was executed and suspended on line 1. Subsequently, function MATDIV was invoked, with a function derived from the Inner Product or Outer Product operator (.) having defined function PLUS as an operand.

In the following, function foo in namespace x has called goo in namespace y. Function goo has then changed space (⎕CS) to namespace z where it has been suspended:

      )SI
[z] y.goo[2]*
x.foo[1]

Threads

In a multi-threading application, where parent threads spawn child threads, the state indicator assumes the structure of a branching tree. Branches of the tree are represented by indenting lines belonging to child threads. For example:

      )SI
·   #.Calc[1]
&5
·   ·   #.DivSub[1]
·   &7
·   ·   #.DivSub[1]
·   &6
·   #.Div[2]*
&4
#.Sub[3]
#.Main[4]

Here, Main has called Sub, which has spawned threads 4 and 5 with functions: Div and Calc. Function Div, after spawning DivSub in each of threads 6 and 7, has been suspended at line [2].

The state indicator for a particular thread tn may be displayed by specifying the parameter -tid=tn.

       ⎕←foo&¨10 10 10 10
┌→─────────┐
│9 10 11 12│
└~─────────┘
       )si
·   #.foo[1]
&9
·   #.foo[1]
&10
·   #.foo[1]
&11
·   #.foo[1]
&12
      )si -tid=11
#.foo[1]


Clear State Indicator

Clear State Indicator )SIC

This command is a synonym for )RESET. See Reset State Indicator


State Indicator Name List

State Indicator & Name List )SINL

This command displays the contents of the state indicator together with local names. The display is the same as for )SI (see above) except that a list of local names is appended to each defined function or operator line.

Example

      )SINL
#.PLUS[2]*        B       A       R       DYADIC  END
.
#.MATDIV[4]       R       END     I       J       ⎕TRAP
#.FOO[1]* R
⍎


Thread Identity

Thread Identity )TID {tid}

)TID associates the Session window with the specified thread so that expressions that you subsequently execute in the Session are executed in the context of that thread.

If you attempt to )TID to a thread that is paused or running, that thread will, if possible, be interrupted by a strong interrupt. If the thread is in a state which it would be inappropriate to interrupt (for example, if the thread is executing an external function), the system reports:

      Can't switch, this thread is n

If no thread number is given, )TID reports the number of the current thread.

Examples

      ⍝ State indicator
      )si
·   #.print[1]
&3
·   ·   #.sub_calc[2]*
·   &2
·   #.calc[1]
&1

      ⍝ Current thread
      )tid
is 2

      ⍝ Switch suspension to thread 3
      )tid 3
was 2

      ⍝ State indicator
      )si
·   #.print[1]*
&3
·   ·   #.sub_calc[2]
·   &2
·   calc[1]
&1

      ⍝ Attempt to switch to pendent thread 1
      )tid 1
Can't switch, this thread is 3


List Global Defined Variables

List Global Defined Variables )VARS {nm}

This command displays the names of global defined variables in the active workspace or current namespace. Names are displayed in ⎕AV collation order. If a name is included after the command, only those names starting at or after the given name in collation order are displayed.

Examples

      )VARS
A  B  F  TEMP VAR

      )VARS F
F TEMP VAR


Workspace Identification

Workspace Identification )WSID {ws}

This command displays or sets the name of the active workspace.

If a workspace name is not specified, )WSID reports the name of the current active workspace. The name reported is the full path name, including directory references.

If a workspace name is given, the current active workspace is renamed accordingly. The previous name of the active workspace (excluding directory references) is reported. See Workspaces for the rules for specifying a workspace name.

Examples

      )LOAD WS/TEMP
WS/TEMP saved Thu Sep 17 10:32:19 1998

      )WSID
is WS/TEMP

      )WSID WS/KEEP
was WS/TEMP

      )WSID
WS/KEEP


Load without Latent Expression

Load without Latent Expression )XLOAD {ws}

This command causes the named stored workspace to be loaded. The current active workspace is lost.

)XLOAD is identical in effect to )LOAD except that )XLOAD does not cause the expression defined by the latent expression ⎕LX in the saved workspace to be executed.


PCRE Overview

PCRE (Perl Compatible Regular Expressions) is an open source library used by the ⎕R and ⎕S system operators. The regular expression syntax which the library supports is not unique to APL nor is it an integral part of the language.

There are two named sections: pcrepattern, which describes the full syntax and semantics); and prcresyntax, a quick reference summary.


PCRE Regular Expression Syntax Summary

The following is a summary of search pattern syntax.

PCRESYNTAX(3)              Library Functions Manual              PCRESYNTAX(3)

NAME
       PCRE - Perl-compatible regular expressions

PCRE REGULAR EXPRESSION SYNTAX SUMMARY

       The  full syntax and semantics of the regular expressions that are sup-
       ported by PCRE are described in  the  pcrepattern  documentation.  This
       document contains a quick-reference summary of the syntax.

QUOTING

         \x         where x is non-alphanumeric is a literal x
         \Q...\E    treat enclosed characters as literal

CHARACTERS

         \a         alarm, that is, the BEL character (hex 07)
         \cx        "control-x", where x is any ASCII character
         \e         escape (hex 1B)
         \f         form feed (hex 0C)
         \n         newline (hex 0A)
         \r         carriage return (hex 0D)
         \t         tab (hex 09)
         \0dd       character with octal code 0dd
         \ddd       character with octal code ddd, or backreference
         \o{ddd..}  character with octal code ddd..
         \xhh       character with hex code hh
         \x{hhh..}  character with hex code hhh..

       Note that \0dd is always an octal code, and that \8 and \9 are the lit-
       eral characters "8" and "9".

CHARACTER TYPES

         .          any character except newline;
                      in dotall mode, any character whatsoever
         \C         one data unit, even in UTF mode (best avoided)
         \d         a decimal digit
         \D         a character that is not a decimal digit
         \h         a horizontal white space character
         \H         a character that is not a horizontal white space character
         \N         a character that is not a newline
         \p{xx}     a character with the xx property
         \P{xx}     a character without the xx property
         \R         a newline sequence
         \s         a white space character
         \S         a character that is not a white space character
         \v         a vertical white space character
         \V         a character that is not a vertical white space character
         \w         a "word" character
         \W         a "non-word" character
         \X         a Unicode extended grapheme cluster

       By default, \d, \s, and \w match only ASCII characters, even  in  UTF-8
       mode  or  in  the 16- bit and 32-bit libraries. However, if locale-spe-
       cific matching is happening, \s and \w may also match  characters  with
       code  points  in  the range 128-255. If the PCRE_UCP option is set, the
       behaviour of these escape sequences is changed to use  Unicode  proper-
       ties and they match many more characters.

GENERAL CATEGORY PROPERTIES FOR \p and \P

         C          Other
         Cc         Control
         Cf         Format
         Cn         Unassigned
         Co         Private use
         Cs         Surrogate

         L          Letter
         Ll         Lower case letter
         Lm         Modifier letter
         Lo         Other letter
         Lt         Title case letter
         Lu         Upper case letter
         L&         Ll, Lu, or Lt

         M          Mark
         Mc         Spacing mark
         Me         Enclosing mark
         Mn         Non-spacing mark

         N          Number
         Nd         Decimal number
         Nl         Letter number
         No         Other number

         P          Punctuation
         Pc         Connector punctuation
         Pd         Dash punctuation
         Pe         Close punctuation
         Pf         Final punctuation
         Pi         Initial punctuation
         Po         Other punctuation
         Ps         Open punctuation

         S          Symbol
         Sc         Currency symbol
         Sk         Modifier symbol
         Sm         Mathematical symbol
         So         Other symbol

         Z          Separator
         Zl         Line separator
         Zp         Paragraph separator
         Zs         Space separator

PCRE SPECIAL CATEGORY PROPERTIES FOR \p and \P

         Xan        Alphanumeric: union of properties L and N
         Xps        POSIX space: property Z or tab, NL, VT, FF, CR
         Xsp        Perl space: property Z or tab, NL, VT, FF, CR
         Xuc        Univerally-named character: one that can be
                      represented by a Universal Character Name
         Xwd        Perl word: property Xan or underscore

       Perl and POSIX space are now the same. Perl added VT to its space char-
       acter set at release 5.18 and PCRE changed at release 8.34.

SCRIPT NAMES FOR \p AND \P

       Arabic, Armenian, Avestan, Balinese, Bamum, Bassa_Vah, Batak,  Bengali,
       Bopomofo,  Brahmi,  Braille, Buginese, Buhid, Canadian_Aboriginal, Car-
       ian, Caucasian_Albanian, Chakma, Cham, Cherokee, Common, Coptic, Cunei-
       form, Cypriot, Cyrillic, Deseret, Devanagari, Duployan, Egyptian_Hiero-
       glyphs,  Elbasan,  Ethiopic,  Georgian,  Glagolitic,  Gothic,  Grantha,
       Greek,  Gujarati,  Gurmukhi,  Han,  Hangul,  Hanunoo, Hebrew, Hiragana,
       Imperial_Aramaic,    Inherited,     Inscriptional_Pahlavi,     Inscrip-
       tional_Parthian,   Javanese,   Kaithi,   Kannada,  Katakana,  Kayah_Li,
       Kharoshthi, Khmer, Khojki, Khudawadi, Lao, Latin, Lepcha,  Limbu,  Lin-
       ear_A,  Linear_B,  Lisu,  Lycian, Lydian, Mahajani, Malayalam, Mandaic,
       Manichaean,     Meetei_Mayek,     Mende_Kikakui,      Meroitic_Cursive,
       Meroitic_Hieroglyphs,  Miao,  Modi, Mongolian, Mro, Myanmar, Nabataean,
       New_Tai_Lue,  Nko,  Ogham,  Ol_Chiki,  Old_Italic,   Old_North_Arabian,
       Old_Permic, Old_Persian, Old_South_Arabian, Old_Turkic, Oriya, Osmanya,
       Pahawh_Hmong,    Palmyrene,    Pau_Cin_Hau,    Phags_Pa,    Phoenician,
       Psalter_Pahlavi,  Rejang,  Runic,  Samaritan, Saurashtra, Sharada, Sha-
       vian, Siddham, Sinhala, Sora_Sompeng, Sundanese, Syloti_Nagri,  Syriac,
       Tagalog,  Tagbanwa,  Tai_Le,  Tai_Tham, Tai_Viet, Takri, Tamil, Telugu,
       Thaana, Thai, Tibetan, Tifinagh, Tirhuta, Ugaritic,  Vai,  Warang_Citi,
       Yi.

CHARACTER CLASSES

         [...]       positive character class
         [^...]      negative character class
         [x-y]       range (can be used for hex characters)
         [[:xxx:]]   positive POSIX named set
         [[:^xxx:]]  negative POSIX named set

         alnum       alphanumeric
         alpha       alphabetic
         ascii       0-127
         blank       space or tab
         cntrl       control character
         digit       decimal digit
         graph       printing, excluding space
         lower       lower case letter
         print       printing, including space
         punct       printing, excluding alphanumeric
         space       white space
         upper       upper case letter
         word        same as \w
         xdigit      hexadecimal digit

       In  PCRE,  POSIX character set names recognize only ASCII characters by
       default, but some of them use Unicode properties if  PCRE_UCP  is  set.
       You can use \Q...\E inside a character class.

QUANTIFIERS

         ?           0 or 1, greedy
         ?+          0 or 1, possessive
         ??          0 or 1, lazy
         *           0 or more, greedy
         *+          0 or more, possessive
         *?          0 or more, lazy
         +           1 or more, greedy
         ++          1 or more, possessive
         +?          1 or more, lazy
         {n}         exactly n
         {n,m}       at least n, no more than m, greedy
         {n,m}+      at least n, no more than m, possessive
         {n,m}?      at least n, no more than m, lazy
         {n,}        n or more, greedy
         {n,}+       n or more, possessive
         {n,}?       n or more, lazy

ANCHORS AND SIMPLE ASSERTIONS

         \b          word boundary
         \B          not a word boundary
         ^           start of subject
                      also after internal newline in multiline mode
         \A          start of subject
         $           end of subject
                      also before newline at end of subject
                      also before internal newline in multiline mode
         \Z          end of subject
                      also before newline at end of subject
         \z          end of subject
         \G          first matching position in subject

MATCH POINT RESET

         \K          reset start of match

       \K is honoured in positive assertions, but ignored in negative ones.

ALTERNATION

         expr|expr|expr...

CAPTURING

         (...)           capturing group
         (?<name>...)    named capturing group (Perl)
         (?'name'...)    named capturing group (Perl)
         (?P<name>...)   named capturing group (Python)
         (?:...)         non-capturing group
         (?|...)         non-capturing group; reset group numbers for
                          capturing groups in each alternative

ATOMIC GROUPS

         (?>...)         atomic, non-capturing group

COMMENT

         (?#....)        comment (not nestable)

OPTION SETTING

         (?i)            caseless
         (?J)            allow duplicate names
         (?m)            multiline
         (?s)            single line (dotall)
         (?U)            default ungreedy (lazy)
         (?x)            extended (ignore white space)
         (?-...)         unset option(s)

       The  following  are  recognized  only at the very start of a pattern or
       after one of the newline or \R options with similar syntax.  More  than
       one of them may appear.

         (*LIMIT_MATCH=d) set the match limit to d (decimal number)
         (*LIMIT_RECURSION=d) set the recursion limit to d (decimal number)
         (*NO_AUTO_POSSESS) no auto-possessification (PCRE_NO_AUTO_POSSESS)
         (*NO_START_OPT) no start-match optimization (PCRE_NO_START_OPTIMIZE)
         (*UTF8)         set UTF-8 mode: 8-bit library (PCRE_UTF8)
         (*UTF16)        set UTF-16 mode: 16-bit library (PCRE_UTF16)
         (*UTF32)        set UTF-32 mode: 32-bit library (PCRE_UTF32)
         (*UTF)          set appropriate UTF mode for the library in use
         (*UCP)          set PCRE_UCP (use Unicode properties for \d etc)

       Note  that LIMIT_MATCH and LIMIT_RECURSION can only reduce the value of
       the limits set by the caller of pcre_exec(), not increase them.

NEWLINE CONVENTION

       These are recognized only at the very start of  the  pattern  or  after
       option settings with a similar syntax.

         (*CR)           carriage return only
         (*LF)           linefeed only
         (*CRLF)         carriage return followed by linefeed
         (*ANYCRLF)      all three of the above
         (*ANY)          any Unicode newline sequence

WHAT \R MATCHES

       These  are  recognized  only  at the very start of the pattern or after
       option setting with a similar syntax.

         (*BSR_ANYCRLF)  CR, LF, or CRLF
         (*BSR_UNICODE)  any Unicode newline sequence

LOOKAHEAD AND LOOKBEHIND ASSERTIONS

         (?=...)         positive look ahead
         (?!...)         negative look ahead
         (?<=...)        positive look behind
         (?<!...)        negative look behind

       Each top-level branch of a look behind must be of a fixed length.

BACKREFERENCES

         \n              reference by number (can be ambiguous)
         \gn             reference by number
         \g{n}           reference by number
         \g{-n}          relative reference by number
         \k<name>        reference by name (Perl)
         \k'name'        reference by name (Perl)
         \g{name}        reference by name (Perl)
         \k{name}        reference by name (.NET)
         (?P=name)       reference by name (Python)

SUBROUTINE REFERENCES (POSSIBLY RECURSIVE)

         (?R)            recurse whole pattern
         (?n)            call subpattern by absolute number
         (?+n)           call subpattern by relative number
         (?-n)           call subpattern by relative number
         (?&name)        call subpattern by name (Perl)
         (?P>name)       call subpattern by name (Python)
         \g<name>        call subpattern by name (Oniguruma)
         \g'name'        call subpattern by name (Oniguruma)
         \g<n>           call subpattern by absolute number (Oniguruma)
         \g'n'           call subpattern by absolute number (Oniguruma)
         \g<+n>          call subpattern by relative number (PCRE extension)
         \g'+n'          call subpattern by relative number (PCRE extension)
         \g<-n>          call subpattern by relative number (PCRE extension)
         \g'-n'          call subpattern by relative number (PCRE extension)

CONDITIONAL PATTERNS

         (?(condition)yes-pattern)
         (?(condition)yes-pattern|no-pattern)

         (?(n)...        absolute reference condition
         (?(+n)...       relative reference condition
         (?(-n)...       relative reference condition
         (?(<name>)...   named reference condition (Perl)
         (?('name')...   named reference condition (Perl)
         (?(name)...     named reference condition (PCRE)
         (?(R)...        overall recursion condition
         (?(Rn)...       specific group recursion condition
         (?(R&name)...   specific recursion condition
         (?(DEFINE)...   define subpattern for reference
         (?(assert)...   assertion condition

BACKTRACKING CONTROL

       The following act immediately they are reached:

         (*ACCEPT)       force successful match
         (*FAIL)         force backtrack; synonym (*F)
         (*MARK:NAME)    set name to be passed back; synonym (*:NAME)

       The following act only when a subsequent match failure causes  a  back-
       track to reach them. They all force a match failure, but they differ in
       what happens afterwards. Those that advance the start-of-match point do
       so only if the pattern is not anchored.

         (*COMMIT)       overall failure, no advance of starting point
         (*PRUNE)        advance to next starting character
         (*PRUNE:NAME)   equivalent to (*MARK:NAME)(*PRUNE)
         (*SKIP)         advance to current matching position
         (*SKIP:NAME)    advance to position corresponding to an earlier
                         (*MARK:NAME); if not found, the (*SKIP) is ignored
         (*THEN)         local failure, backtrack to next alternation
         (*THEN:NAME)    equivalent to (*MARK:NAME)(*THEN)

CALLOUTS

         (?C)      callout
         (?Cn)     callout with data n

SEE ALSO

       pcrepattern(3), pcreapi(3), pcrecallout(3), pcrematching(3), pcre(3).

AUTHOR

       Philip Hazel
       University Computing Service
       Cambridge CB2 3QH, England.

REVISION

       Last updated: 08 January 2014
       Copyright (c) 1997-2014 University of Cambridge.


PCRE Regular Expression Details

PCREPATTERN(3)             Library Functions Manual             PCREPATTERN(3)

NAME
       PCRE - Perl-compatible regular expressions

PCRE REGULAR EXPRESSION DETAILS

       The  syntax and semantics of the regular expressions that are supported
       by PCRE are described in detail below. There is a quick-reference  syn-
       tax summary in the pcresyntax page. PCRE tries to match Perl syntax and
       semantics as closely as it can. PCRE  also  supports  some  alternative
       regular  expression  syntax (which does not conflict with the Perl syn-
       tax) in order to provide some compatibility with regular expressions in
       Python, .NET, and Oniguruma.

       Perl's  regular expressions are described in its own documentation, and
       regular expressions in general are covered in a number of  books,  some
       of  which  have  copious  examples. Jeffrey Friedl's "Mastering Regular
       Expressions", published by  O'Reilly,  covers  regular  expressions  in
       great  detail.  This  description  of  PCRE's  regular  expressions  is
       intended as reference material.

       This document discusses the patterns that are supported  by  PCRE  when
       one    its    main   matching   functions,   pcre_exec()   (8-bit)   or
       pcre[16|32]_exec() (16- or 32-bit), is used. PCRE also has  alternative
       matching  functions,  pcre_dfa_exec()  and pcre[16|32_dfa_exec(), which
       match using a different algorithm that is not Perl-compatible. Some  of
       the  features  discussed  below  are not available when DFA matching is
       used. The advantages and disadvantages of  the  alternative  functions,
       and  how  they  differ  from the normal functions, are discussed in the
       pcrematching page.

SPECIAL START-OF-PATTERN ITEMS

       A number of options that can be passed to pcre_compile()  can  also  be
       set by special items at the start of a pattern. These are not Perl-com-
       patible, but are provided to make these options accessible  to  pattern
       writers  who are not able to change the program that processes the pat-
       tern. Any number of these items  may  appear,  but  they  must  all  be
       together right at the start of the pattern string, and the letters must
       be in upper case.

   UTF support

       The original operation of PCRE was on strings of  one-byte  characters.
       However,  there  is  now also support for UTF-8 strings in the original
       library, an extra library that supports  16-bit  and  UTF-16  character
       strings,  and a third library that supports 32-bit and UTF-32 character
       strings. To use these features, PCRE must be built to include appropri-
       ate  support. When using UTF strings you must either call the compiling
       function with the PCRE_UTF8, PCRE_UTF16, or PCRE_UTF32 option,  or  the
       pattern must start with one of these special sequences:

         (*UTF8)
         (*UTF16)
         (*UTF32)
         (*UTF)

       (*UTF)  is  a  generic  sequence  that  can  be  used  with  any of the
       libraries.  Starting a pattern with such a sequence  is  equivalent  to
       setting  the  relevant  option.  How setting a UTF mode affects pattern
       matching is mentioned in several places below. There is also a  summary
       of features in the pcreunicode page.

       Some applications that allow their users to supply patterns may wish to
       restrict  them  to  non-UTF  data  for   security   reasons.   If   the
       PCRE_NEVER_UTF  option  is  set  at  compile  time, (*UTF) etc. are not
       allowed, and their appearance causes an error.

   Unicode property support

       Another special sequence that may appear at the start of a  pattern  is
       (*UCP).   This  has  the same effect as setting the PCRE_UCP option: it
       causes sequences such as \d and \w to use Unicode properties to  deter-
       mine character types, instead of recognizing only characters with codes
       less than 128 via a lookup table.

   Disabling auto-possessification

       If a pattern starts with (*NO_AUTO_POSSESS), it has the same effect  as
       setting  the  PCRE_NO_AUTO_POSSESS  option  at compile time. This stops
       PCRE from making quantifiers possessive when what follows cannot  match
       the  repeated item. For example, by default a+b is treated as a++b. For
       more details, see the pcreapi documentation.

   Disabling start-up optimizations

       If a pattern starts with (*NO_START_OPT), it has  the  same  effect  as
       setting the PCRE_NO_START_OPTIMIZE option either at compile or matching
       time. This disables several  optimizations  for  quickly  reaching  "no
       match" results. For more details, see the pcreapi documentation.

   Newline conventions

       PCRE  supports five different conventions for indicating line breaks in
       strings: a single CR (carriage return) character, a  single  LF  (line-
       feed) character, the two-character sequence CRLF, any of the three pre-
       ceding, or any Unicode newline sequence. The pcreapi page  has  further
       discussion  about newlines, and shows how to set the newline convention
       in the options arguments for the compiling and matching functions.

       It is also possible to specify a newline convention by starting a  pat-
       tern string with one of the following five sequences:

         (*CR)        carriage return
         (*LF)        linefeed
         (*CRLF)      carriage return, followed by linefeed
         (*ANYCRLF)   any of the three above
         (*ANY)       all Unicode newline sequences

       These override the default and the options given to the compiling func-
       tion. For example, on a Unix system where LF  is  the  default  newline
       sequence, the pattern

         (*CR)a.b

       changes the convention to CR. That pattern matches "a\nb" because LF is
       no longer a newline. If more than one of these settings is present, the
       last one is used.

       The  newline  convention affects where the circumflex and dollar asser-
       tions are true. It also affects the interpretation of the dot metachar-
       acter when PCRE_DOTALL is not set, and the behaviour of \N. However, it
       does not affect what the \R escape sequence matches. By  default,  this
       is  any Unicode newline sequence, for Perl compatibility. However, this
       can be changed; see the description of \R in the section entitled "New-
       line  sequences"  below.  A change of \R setting can be combined with a
       change of newline convention.

   Setting match and recursion limits

       The caller of pcre_exec() can set a limit on the number  of  times  the
       internal  match() function is called and on the maximum depth of recur-
       sive calls. These facilities are provided to catch runaway matches that
       are provoked by patterns with huge matching trees (a typical example is
       a pattern with nested unlimited repeats) and to avoid  running  out  of
       system  stack  by  too  much  recursion.  When  one  of these limits is
       reached, pcre_exec() gives an error return. The limits can also be  set
       by items at the start of the pattern of the form

         (*LIMIT_MATCH=d)
         (*LIMIT_RECURSION=d)

       where d is any number of decimal digits. However, the value of the set-
       ting must be less than the value set (or defaulted) by  the  caller  of
       pcre_exec()  for  it  to  have  any effect. In other words, the pattern
       writer can lower the limits set by the programmer, but not raise  them.
       If  there  is  more  than one setting of one of these limits, the lower
       value is used.

EBCDIC CHARACTER CODES

       PCRE can be compiled to run in an environment that uses EBCDIC  as  its
       character code rather than ASCII or Unicode (typically a mainframe sys-
       tem). In the sections below, character code values are  ASCII  or  Uni-
       code; in an EBCDIC environment these characters may have different code
       values, and there are no code points greater than 255.

CHARACTERS AND METACHARACTERS

       A regular expression is a pattern that is  matched  against  a  subject
       string  from  left  to right. Most characters stand for themselves in a
       pattern, and match the corresponding characters in the  subject.  As  a
       trivial example, the pattern

         The quick brown fox

       matches a portion of a subject string that is identical to itself. When
       caseless matching is specified (the PCRE_CASELESS option), letters  are
       matched  independently  of case. In a UTF mode, PCRE always understands
       the concept of case for characters whose values are less than  128,  so
       caseless  matching  is always possible. For characters with higher val-
       ues, the concept of case is supported if PCRE is compiled with  Unicode
       property  support,  but  not  otherwise.   If  you want to use caseless
       matching for characters 128 and above, you must  ensure  that  PCRE  is
       compiled with Unicode property support as well as with UTF support.

       The  power  of  regular  expressions  comes from the ability to include
       alternatives and repetitions in the pattern. These are encoded  in  the
       pattern by the use of metacharacters, which do not stand for themselves
       but instead are interpreted in some special way.

       There are two different sets of metacharacters: those that  are  recog-
       nized  anywhere in the pattern except within square brackets, and those
       that are recognized within square brackets.  Outside  square  brackets,
       the metacharacters are as follows:

         \      general escape character with several uses
         ^      assert start of string (or line, in multiline mode)
         $      assert end of string (or line, in multiline mode)
         .      match any character except newline (by default)
         [      start character class definition
         |      start of alternative branch
         (      start subpattern
         )      end subpattern
         ?      extends the meaning of (
                also 0 or 1 quantifier
                also quantifier minimizer
         *      0 or more quantifier
         +      1 or more quantifier
                also "possessive quantifier"
         {      start min/max quantifier

       Part  of  a  pattern  that is in square brackets is called a "character
       class". In a character class the only metacharacters are:

         \      general escape character
         ^      negate the class, but only if the first character
         -      indicates character range
         [      POSIX character class (only if followed by POSIX
                  syntax)
         ]      terminates the character class

       The following sections describe the use of each of the metacharacters.

BACKSLASH

       The backslash character has several uses. Firstly, if it is followed by
       a character that is not a number or a letter, it takes away any special
       meaning that character may have. This use of  backslash  as  an  escape
       character applies both inside and outside character classes.

       For  example,  if  you want to match a * character, you write \* in the
       pattern.  This escaping action applies whether  or  not  the  following
       character  would  otherwise be interpreted as a metacharacter, so it is
       always safe to precede a non-alphanumeric  with  backslash  to  specify
       that  it stands for itself. In particular, if you want to match a back-
       slash, you write \\.

       In a UTF mode, only ASCII numbers and letters have any special  meaning
       after  a  backslash.  All  other characters (in particular, those whose
       codepoints are greater than 127) are treated as literals.

       If a pattern is compiled with  the  PCRE_EXTENDED  option,  most  white
       space  in the pattern (other than in a character class), and characters
       between a # outside a character class and the next newline,  inclusive,
       are ignored. An escaping backslash can be used to include a white space
       or # character as part of the pattern.

       If you want to remove the special meaning from a  sequence  of  charac-
       ters,  you can do so by putting them between \Q and \E. This is differ-
       ent from Perl in that $ and  @  are  handled  as  literals  in  \Q...\E
       sequences  in  PCRE, whereas in Perl, $ and @ cause variable interpola-
       tion. Note the following examples:

         Pattern            PCRE matches   Perl matches

         \Qabc$xyz\E        abc$xyz        abc followed by the
                                             contents of $xyz
         \Qabc\$xyz\E       abc\$xyz       abc\$xyz
         \Qabc\E\$\Qxyz\E   abc$xyz        abc$xyz

       The \Q...\E sequence is recognized both inside  and  outside  character
       classes.   An  isolated \E that is not preceded by \Q is ignored. If \Q
       is not followed by \E later in the pattern, the literal  interpretation
       continues  to  the  end  of  the pattern (that is, \E is assumed at the
       end). If the isolated \Q is inside a character class,  this  causes  an
       error, because the character class is not terminated.

   Non-printing characters

       A second use of backslash provides a way of encoding non-printing char-
       acters in patterns in a visible manner. There is no restriction on  the
       appearance  of non-printing characters, apart from the binary zero that
       terminates a pattern, but when a pattern  is  being  prepared  by  text
       editing,  it  is  often  easier  to  use  one  of  the following escape
       sequences than the binary character it represents:

         \a        alarm, that is, the BEL character (hex 07)
         \cx       "control-x", where x is any ASCII character
         \e        escape (hex 1B)
         \f        form feed (hex 0C)
         \n        linefeed (hex 0A)
         \r        carriage return (hex 0D)
         \t        tab (hex 09)
         \0dd      character with octal code 0dd
         \ddd      character with octal code ddd, or back reference
         \o{ddd..} character with octal code ddd..
         \xhh      character with hex code hh
         \x{hhh..} character with hex code hhh.. (non-JavaScript mode)
         \uhhhh    character with hex code hhhh (JavaScript mode only)

       The precise effect of \cx on ASCII characters is as follows: if x is  a
       lower  case  letter,  it  is converted to upper case. Then bit 6 of the
       character (hex 40) is inverted. Thus \cA to \cZ become hex 01 to hex 1A
       (A  is  41, Z is 5A), but \c{ becomes hex 3B ({ is 7B), and \c; becomes
       hex 7B (; is 3B). If the data item (byte or 16-bit value) following  \c
       has  a  value greater than 127, a compile-time error occurs. This locks
       out non-ASCII characters in all modes.

       The \c facility was designed for use with ASCII  characters,  but  with
       the  extension  to  Unicode it is even less useful than it once was. It
       is, however, recognized when PCRE is compiled  in  EBCDIC  mode,  where
       data  items  are always bytes. In this mode, all values are valid after
       \c. If the next character is a lower case letter, it  is  converted  to
       upper  case.  Then  the  0xc0  bits  of the byte are inverted. Thus \cA
       becomes hex 01, as in ASCII (A is C1), but because the  EBCDIC  letters
       are  disjoint,  \cZ becomes hex 29 (Z is E9), and other characters also
       generate different values.

       After \0 up to two further octal digits are read. If  there  are  fewer
       than  two  digits,  just  those  that  are  present  are used. Thus the
       sequence \0\x\07 specifies two binary zeros followed by a BEL character
       (code  value 7). Make sure you supply two digits after the initial zero
       if the pattern character that follows is itself an octal digit.

       The escape \o must be followed by a sequence of octal digits,  enclosed
       in  braces.  An  error occurs if this is not the case. This escape is a
       recent addition to Perl; it provides way of specifying  character  code
       points  as  octal  numbers  greater than 0777, and it also allows octal
       numbers and back references to be unambiguously specified.

       For greater clarity and unambiguity, it is best to avoid following \ by
       a digit greater than zero. Instead, use \o{} or \x{} to specify charac-
       ter numbers, and \g{} to specify back references. The  following  para-
       graphs describe the old, ambiguous syntax.

       The handling of a backslash followed by a digit other than 0 is compli-
       cated, and Perl has changed in recent releases, causing  PCRE  also  to
       change. Outside a character class, PCRE reads the digit and any follow-
       ing digits as a decimal number. If the number is less  than  8,  or  if
       there  have been at least that many previous capturing left parentheses
       in the expression, the entire sequence is taken as a back reference.  A
       description  of how this works is given later, following the discussion
       of parenthesized subpatterns.

       Inside a character class, or if  the  decimal  number  following  \  is
       greater than 7 and there have not been that many capturing subpatterns,
       PCRE handles \8 and \9 as the literal characters "8" and "9", and  oth-
       erwise re-reads up to three octal digits following the backslash, using
       them to generate a data character.  Any  subsequent  digits  stand  for
       themselves. For example:

         \040   is another way of writing an ASCII space
         \40    is the same, provided there are fewer than 40
                   previous capturing subpatterns
         \7     is always a back reference
         \11    might be a back reference, or another way of
                   writing a tab
         \011   is always a tab
         \0113  is a tab followed by the character "3"
         \113   might be a back reference, otherwise the
                   character with octal code 113
         \377   might be a back reference, otherwise
                   the value 255 (decimal)
         \81    is either a back reference, or the two
                   characters "8" and "1"

       Note  that octal values of 100 or greater that are specified using this
       syntax must not be introduced by a leading zero, because no  more  than
       three octal digits are ever read.

       By  default, after \x that is not followed by {, from zero to two hexa-
       decimal digits are read (letters can be in upper or  lower  case).  Any
       number of hexadecimal digits may appear between \x{ and }. If a charac-
       ter other than a hexadecimal digit appears between \x{  and  },  or  if
       there is no terminating }, an error occurs.

       If  the  PCRE_JAVASCRIPT_COMPAT option is set, the interpretation of \x
       is as just described only when it is followed by two  hexadecimal  dig-
       its.   Otherwise,  it  matches  a  literal "x" character. In JavaScript
       mode, support for code points greater than 256 is provided by \u, which
       must  be  followed  by  four hexadecimal digits; otherwise it matches a
       literal "u" character.

       Characters whose value is less than 256 can be defined by either of the
       two  syntaxes for \x (or by \u in JavaScript mode). There is no differ-
       ence in the way they are handled. For example, \xdc is exactly the same
       as \x{dc} (or \u00dc in JavaScript mode).

   Constraints on character values

       Characters  that  are  specified using octal or hexadecimal numbers are
       limited to certain values, as follows:

         8-bit non-UTF mode    less than 0x100
         8-bit UTF-8 mode      less than 0x10ffff and a valid codepoint
         16-bit non-UTF mode   less than 0x10000
         16-bit UTF-16 mode    less than 0x10ffff and a valid codepoint
         32-bit non-UTF mode   less than 0x100000000
         32-bit UTF-32 mode    less than 0x10ffff and a valid codepoint

       Invalid Unicode codepoints are the range  0xd800  to  0xdfff  (the  so-
       called "surrogate" codepoints), and 0xffef.

   Escape sequences in character classes

       All the sequences that define a single character value can be used both
       inside and outside character classes. In addition, inside  a  character
       class, \b is interpreted as the backspace character (hex 08).

       \N  is not allowed in a character class. \B, \R, and \X are not special
       inside a character class. Like  other  unrecognized  escape  sequences,
       they  are  treated  as  the  literal  characters  "B",  "R", and "X" by
       default, but cause an error if the PCRE_EXTRA option is set. Outside  a
       character class, these sequences have different meanings.

   Unsupported escape sequences

       In  Perl, the sequences \l, \L, \u, and \U are recognized by its string
       handler and used  to  modify  the  case  of  following  characters.  By
       default,  PCRE does not support these escape sequences. However, if the
       PCRE_JAVASCRIPT_COMPAT option is set, \U matches a "U"  character,  and
       \u can be used to define a character by code point, as described in the
       previous section.

   Absolute and relative back references

       The sequence \g followed by an unsigned or a negative  number,  option-
       ally  enclosed  in braces, is an absolute or relative back reference. A
       named back reference can be coded as \g{name}. Back references are dis-
       cussed later, following the discussion of parenthesized subpatterns.

   Absolute and relative subroutine calls

       For  compatibility with Oniguruma, the non-Perl syntax \g followed by a
       name or a number enclosed either in angle brackets or single quotes, is
       an  alternative  syntax for referencing a subpattern as a "subroutine".
       Details are discussed later.   Note  that  \g{...}  (Perl  syntax)  and
       \g<...>  (Oniguruma  syntax)  are  not synonymous. The former is a back
       reference; the latter is a subroutine call.

   Generic character types

       Another use of backslash is for specifying generic character types:

         \d     any decimal digit
         \D     any character that is not a decimal digit
         \h     any horizontal white space character
         \H     any character that is not a horizontal white space character
         \s     any white space character
         \S     any character that is not a white space character
         \v     any vertical white space character
         \V     any character that is not a vertical white space character
         \w     any "word" character
         \W     any "non-word" character

       There is also the single sequence \N, which matches a non-newline char-
       acter.   This  is the same as the "." metacharacter when PCRE_DOTALL is
       not set. Perl also uses \N to match characters by name; PCRE  does  not
       support this.

       Each  pair of lower and upper case escape sequences partitions the com-
       plete set of characters into two disjoint  sets.  Any  given  character
       matches  one, and only one, of each pair. The sequences can appear both
       inside and outside character classes. They each match one character  of
       the  appropriate  type.  If the current matching point is at the end of
       the subject string, all of them fail, because there is no character  to
       match.

       For  compatibility with Perl, \s did not used to match the VT character
       (code 11), which made it different from the the  POSIX  "space"  class.
       However,  Perl  added  VT  at  release  5.18, and PCRE followed suit at
       release 8.34. The default \s characters are now HT  (9),  LF  (10),  VT
       (11),  FF  (12),  CR  (13),  and space (32), which are defined as white
       space in the "C" locale. This list may vary if locale-specific matching
       is  taking place. For example, in some locales the "non-breaking space"
       character (\xA0) is recognized as white space, and  in  others  the  VT
       character is not.

       A  "word"  character is an underscore or any character that is a letter
       or digit.  By default, the definition of letters  and  digits  is  con-
       trolled  by PCRE's low-valued character tables, and may vary if locale-
       specific matching is taking place (see "Locale support" in the  pcreapi
       page).  For  example,  in  a French locale such as "fr_FR" in Unix-like
       systems, or "french" in Windows, some character codes greater than  127
       are  used  for  accented letters, and these are then matched by \w. The
       use of locales with Unicode is discouraged.

       By default, characters whose code points are  greater  than  127  never
       match \d, \s, or \w, and always match \D, \S, and \W, although this may
       vary for characters in the range 128-255 when locale-specific  matching
       is  happening.   These  escape sequences retain their original meanings
       from before Unicode support was available, mainly for  efficiency  rea-
       sons.  If  PCRE  is  compiled  with  Unicode  property support, and the
       PCRE_UCP option is set, the behaviour is changed so that Unicode  prop-
       erties are used to determine character types, as follows:

         \d  any character that matches \p{Nd} (decimal digit)
         \s  any character that matches \p{Z} or \h or \v
         \w  any character that matches \p{L} or \p{N}, plus underscore

       The  upper case escapes match the inverse sets of characters. Note that
       \d matches only decimal digits, whereas \w matches any  Unicode  digit,
       as  well as any Unicode letter, and underscore. Note also that PCRE_UCP
       affects \b, and \B because they are defined in  terms  of  \w  and  \W.
       Matching these sequences is noticeably slower when PCRE_UCP is set.

       The  sequences  \h, \H, \v, and \V are features that were added to Perl
       at release 5.10. In contrast to the other sequences, which  match  only
       ASCII  characters  by  default,  these always match certain high-valued
       code points, whether or not PCRE_UCP is set. The horizontal space char-
       acters are:

         U+0009     Horizontal tab (HT)
         U+0020     Space
         U+00A0     Non-break space
         U+1680     Ogham space mark
         U+180E     Mongolian vowel separator
         U+2000     En quad
         U+2001     Em quad
         U+2002     En space
         U+2003     Em space
         U+2004     Three-per-em space
         U+2005     Four-per-em space
         U+2006     Six-per-em space
         U+2007     Figure space
         U+2008     Punctuation space
         U+2009     Thin space
         U+200A     Hair space
         U+202F     Narrow no-break space
         U+205F     Medium mathematical space
         U+3000     Ideographic space

       The vertical space characters are:

         U+000A     Linefeed (LF)
         U+000B     Vertical tab (VT)
         U+000C     Form feed (FF)
         U+000D     Carriage return (CR)
         U+0085     Next line (NEL)
         U+2028     Line separator
         U+2029     Paragraph separator

       In 8-bit, non-UTF-8 mode, only the characters with codepoints less than
       256 are relevant.

   Newline sequences

       Outside a character class, by default, the escape sequence  \R  matches
       any  Unicode newline sequence. In 8-bit non-UTF-8 mode \R is equivalent
       to the following:

         (?>\r\n|\n|\x0b|\f|\r|\x85)

       This is an example of an "atomic group", details  of  which  are  given
       below.  This particular group matches either the two-character sequence
       CR followed by LF, or  one  of  the  single  characters  LF  (linefeed,
       U+000A),  VT  (vertical  tab, U+000B), FF (form feed, U+000C), CR (car-
       riage return, U+000D), or NEL (next line,  U+0085).  The  two-character
       sequence is treated as a single unit that cannot be split.

       In  other modes, two additional characters whose codepoints are greater
       than 255 are added: LS (line separator, U+2028) and PS (paragraph sepa-
       rator,  U+2029).   Unicode character property support is not needed for
       these characters to be recognized.

       It is possible to restrict \R to match only CR, LF, or CRLF (instead of
       the  complete  set  of  Unicode  line  endings)  by  setting the option
       PCRE_BSR_ANYCRLF either at compile time or when the pattern is matched.
       (BSR is an abbrevation for "backslash R".) This can be made the default
       when PCRE is built; if this is the case, the  other  behaviour  can  be
       requested  via  the  PCRE_BSR_UNICODE  option.   It is also possible to
       specify these settings by starting a pattern string  with  one  of  the
       following sequences:

         (*BSR_ANYCRLF)   CR, LF, or CRLF only
         (*BSR_UNICODE)   any Unicode newline sequence

       These override the default and the options given to the compiling func-
       tion, but they can themselves be  overridden  by  options  given  to  a
       matching  function.  Note  that  these  special settings, which are not
       Perl-compatible, are recognized only at the very start  of  a  pattern,
       and  that  they  must  be  in  upper  case. If more than one of them is
       present, the last one is used. They can be combined with  a  change  of
       newline convention; for example, a pattern can start with:

         (*ANY)(*BSR_ANYCRLF)

       They  can also be combined with the (*UTF8), (*UTF16), (*UTF32), (*UTF)
       or (*UCP) special sequences. Inside a character class, \R is treated as
       an  unrecognized  escape  sequence,  and  so  matches the letter "R" by
       default, but causes an error if PCRE_EXTRA is set.

   Unicode character properties

       When PCRE is built with Unicode character property support, three addi-
       tional  escape sequences that match characters with specific properties
       are available.  When in 8-bit non-UTF-8 mode, these  sequences  are  of
       course  limited  to  testing  characters whose codepoints are less than
       256, but they do work in this mode.  The extra escape sequences are:

         \p{xx}   a character with the xx property
         \P{xx}   a character without the xx property
         \X       a Unicode extended grapheme cluster

       The property names represented by xx above are limited to  the  Unicode
       script names, the general category properties, "Any", which matches any
       character  (including  newline),  and  some  special  PCRE   properties
       (described  in the next section).  Other Perl properties such as "InMu-
       sicalSymbols" are not currently supported by PCRE.  Note  that  \P{Any}
       does not match any characters, so always causes a match failure.

       Sets of Unicode characters are defined as belonging to certain scripts.
       A character from one of these sets can be matched using a script  name.
       For example:

         \p{Greek}
         \P{Han}

       Those  that are not part of an identified script are lumped together as
       "Common". The current list of scripts is:

       Arabic, Armenian, Avestan, Balinese, Bamum, Bassa_Vah, Batak,  Bengali,
       Bopomofo,  Brahmi,  Braille, Buginese, Buhid, Canadian_Aboriginal, Car-
       ian, Caucasian_Albanian, Chakma, Cham, Cherokee, Common, Coptic, Cunei-
       form, Cypriot, Cyrillic, Deseret, Devanagari, Duployan, Egyptian_Hiero-
       glyphs,  Elbasan,  Ethiopic,  Georgian,  Glagolitic,  Gothic,  Grantha,
       Greek,  Gujarati,  Gurmukhi,  Han,  Hangul,  Hanunoo, Hebrew, Hiragana,
       Imperial_Aramaic,    Inherited,     Inscriptional_Pahlavi,     Inscrip-
       tional_Parthian,   Javanese,   Kaithi,   Kannada,  Katakana,  Kayah_Li,
       Kharoshthi, Khmer, Khojki, Khudawadi, Lao, Latin, Lepcha,  Limbu,  Lin-
       ear_A,  Linear_B,  Lisu,  Lycian, Lydian, Mahajani, Malayalam, Mandaic,
       Manichaean,     Meetei_Mayek,     Mende_Kikakui,      Meroitic_Cursive,
       Meroitic_Hieroglyphs,  Miao,  Modi, Mongolian, Mro, Myanmar, Nabataean,
       New_Tai_Lue,  Nko,  Ogham,  Ol_Chiki,  Old_Italic,   Old_North_Arabian,
       Old_Permic, Old_Persian, Old_South_Arabian, Old_Turkic, Oriya, Osmanya,
       Pahawh_Hmong,    Palmyrene,    Pau_Cin_Hau,    Phags_Pa,    Phoenician,
       Psalter_Pahlavi,  Rejang,  Runic,  Samaritan, Saurashtra, Sharada, Sha-
       vian, Siddham, Sinhala, Sora_Sompeng, Sundanese, Syloti_Nagri,  Syriac,
       Tagalog,  Tagbanwa,  Tai_Le,  Tai_Tham, Tai_Viet, Takri, Tamil, Telugu,
       Thaana, Thai, Tibetan, Tifinagh, Tirhuta, Ugaritic,  Vai,  Warang_Citi,
       Yi.

       Each character has exactly one Unicode general category property, spec-
       ified by a two-letter abbreviation. For compatibility with Perl,  nega-
       tion  can  be  specified  by including a circumflex between the opening
       brace and the property name.  For  example,  \p{^Lu}  is  the  same  as
       \P{Lu}.

       If only one letter is specified with \p or \P, it includes all the gen-
       eral category properties that start with that letter. In this case,  in
       the  absence of negation, the curly brackets in the escape sequence are
       optional; these two examples have the same effect:

         \p{L}
         \pL

       The following general category property codes are supported:

         C     Other
         Cc    Control
         Cf    Format
         Cn    Unassigned
         Co    Private use
         Cs    Surrogate

         L     Letter
         Ll    Lower case letter
         Lm    Modifier letter
         Lo    Other letter
         Lt    Title case letter
         Lu    Upper case letter

         M     Mark
         Mc    Spacing mark
         Me    Enclosing mark
         Mn    Non-spacing mark

         N     Number
         Nd    Decimal number
         Nl    Letter number
         No    Other number

         P     Punctuation
         Pc    Connector punctuation
         Pd    Dash punctuation
         Pe    Close punctuation
         Pf    Final punctuation
         Pi    Initial punctuation
         Po    Other punctuation
         Ps    Open punctuation

         S     Symbol
         Sc    Currency symbol
         Sk    Modifier symbol
         Sm    Mathematical symbol
         So    Other symbol

         Z     Separator
         Zl    Line separator
         Zp    Paragraph separator
         Zs    Space separator

       The special property L& is also supported: it matches a character  that
       has  the  Lu,  Ll, or Lt property, in other words, a letter that is not
       classified as a modifier or "other".

       The Cs (Surrogate) property applies only to  characters  in  the  range
       U+D800  to U+DFFF. Such characters are not valid in Unicode strings and
       so cannot be tested by PCRE, unless  UTF  validity  checking  has  been
       turned    off    (see    the    discussion    of    PCRE_NO_UTF8_CHECK,
       PCRE_NO_UTF16_CHECK and PCRE_NO_UTF32_CHECK in the pcreapi page).  Perl
       does not support the Cs property.

       The  long  synonyms  for  property  names  that  Perl supports (such as
       \p{Letter}) are not supported by PCRE, nor is it  permitted  to  prefix
       any of these properties with "Is".

       No character that is in the Unicode table has the Cn (unassigned) prop-
       erty.  Instead, this property is assumed for any code point that is not
       in the Unicode table.

       Specifying  caseless  matching  does not affect these escape sequences.
       For example, \p{Lu} always matches only upper  case  letters.  This  is
       different from the behaviour of current versions of Perl.

       Matching  characters  by Unicode property is not fast, because PCRE has
       to do a multistage table lookup in order to find  a  character's  prop-
       erty. That is why the traditional escape sequences such as \d and \w do
       not use Unicode properties in PCRE by default, though you can make them
       do  so  by  setting the PCRE_UCP option or by starting the pattern with
       (*UCP).

   Extended grapheme clusters

       The \X escape matches any number of Unicode  characters  that  form  an
       "extended grapheme cluster", and treats the sequence as an atomic group
       (see below).  Up to and including release 8.31, PCRE  matched  an  ear-
       lier, simpler definition that was equivalent to

         (?>\PM\pM*)

       That  is,  it matched a character without the "mark" property, followed
       by zero or more characters with the "mark"  property.  Characters  with
       the  "mark"  property are typically non-spacing accents that affect the
       preceding character.

       This simple definition was extended in Unicode to include more  compli-
       cated  kinds of composite character by giving each character a grapheme
       breaking property, and creating rules  that  use  these  properties  to
       define  the  boundaries  of  extended grapheme clusters. In releases of
       PCRE later than 8.31, \X matches one of these clusters.

       \X always matches at least one character. Then it  decides  whether  to
       add additional characters according to the following rules for ending a
       cluster:

       1. End at the end of the subject string.

       2. Do not end between CR and LF; otherwise end after any control  char-
       acter.

       3.  Do  not  break  Hangul (a Korean script) syllable sequences. Hangul
       characters are of five types: L, V, T, LV, and LVT. An L character  may
       be  followed by an L, V, LV, or LVT character; an LV or V character may
       be followed by a V or T character; an LVT or T character may be follwed
       only by a T character.

       4.  Do not end before extending characters or spacing marks. Characters
       with the "mark" property always have  the  "extend"  grapheme  breaking
       property.

       5. Do not end after prepend characters.

       6. Otherwise, end the cluster.

   PCRE's additional properties

       As  well  as the standard Unicode properties described above, PCRE sup-
       ports four more that make it possible  to  convert  traditional  escape
       sequences  such as \w and \s to use Unicode properties. PCRE uses these
       non-standard, non-Perl properties internally when PCRE_UCP is set. How-
       ever, they may also be used explicitly. These properties are:

         Xan   Any alphanumeric character
         Xps   Any POSIX space character
         Xsp   Any Perl space character
         Xwd   Any Perl "word" character

       Xan  matches  characters that have either the L (letter) or the N (num-
       ber) property. Xps matches the characters tab, linefeed, vertical  tab,
       form  feed,  or carriage return, and any other character that has the Z
       (separator) property.  Xsp is the same as Xps; it used to exclude  ver-
       tical  tab,  for Perl compatibility, but Perl changed, and so PCRE fol-
       lowed at release 8.34. Xwd matches the same  characters  as  Xan,  plus
       underscore.

       There  is another non-standard property, Xuc, which matches any charac-
       ter that can be represented by a Universal Character Name  in  C++  and
       other  programming  languages.  These are the characters $, @, ` (grave
       accent), and all characters with Unicode code points  greater  than  or
       equal  to U+00A0, except for the surrogates U+D800 to U+DFFF. Note that
       most base (ASCII) characters are excluded. (Universal  Character  Names
       are  of  the  form \uHHHH or \UHHHHHHHH where H is a hexadecimal digit.
       Note that the Xuc property does not match these sequences but the char-
       acters that they represent.)

   Resetting the match start

       The  escape sequence \K causes any previously matched characters not to
       be included in the final matched sequence. For example, the pattern:

         foo\Kbar

       matches "foobar", but reports that it has matched "bar".  This  feature
       is  similar  to  a lookbehind assertion (described below).  However, in
       this case, the part of the subject before the real match does not  have
       to  be of fixed length, as lookbehind assertions do. The use of \K does
       not interfere with the setting of captured  substrings.   For  example,
       when the pattern

         (foo)\Kbar

       matches "foobar", the first substring is still set to "foo".

       Perl  documents  that  the  use  of  \K  within assertions is "not well
       defined". In PCRE, \K is acted upon  when  it  occurs  inside  positive
       assertions,  but  is  ignored  in negative assertions. Note that when a
       pattern such as (?=ab\K) matches, the reported start of the  match  can
       be greater than the end of the match.

   Simple assertions

       The  final use of backslash is for certain simple assertions. An asser-
       tion specifies a condition that has to be met at a particular point  in
       a  match, without consuming any characters from the subject string. The
       use of subpatterns for more complicated assertions is described  below.
       The backslashed assertions are:

         \b     matches at a word boundary
         \B     matches when not at a word boundary
         \A     matches at the start of the subject
         \Z     matches at the end of the subject
                 also matches before a newline at the end of the subject
         \z     matches only at the end of the subject
         \G     matches at the first matching position in the subject

       Inside  a  character  class, \b has a different meaning; it matches the
       backspace character. If any other of  these  assertions  appears  in  a
       character  class, by default it matches the corresponding literal char-
       acter  (for  example,  \B  matches  the  letter  B).  However,  if  the
       PCRE_EXTRA  option is set, an "invalid escape sequence" error is gener-
       ated instead.

       A word boundary is a position in the subject string where  the  current
       character  and  the previous character do not both match \w or \W (i.e.
       one matches \w and the other matches \W), or the start or  end  of  the
       string  if  the  first or last character matches \w, respectively. In a
       UTF mode, the meanings of \w and \W  can  be  changed  by  setting  the
       PCRE_UCP  option. When this is done, it also affects \b and \B. Neither
       PCRE nor Perl has a separate "start of word" or "end of  word"  metase-
       quence.  However,  whatever follows \b normally determines which it is.
       For example, the fragment \ba matches "a" at the start of a word.

       The \A, \Z, and \z assertions differ from  the  traditional  circumflex
       and dollar (described in the next section) in that they only ever match
       at the very start and end of the subject string, whatever  options  are
       set.  Thus,  they are independent of multiline mode. These three asser-
       tions are not affected by the PCRE_NOTBOL or PCRE_NOTEOL options, which
       affect  only the behaviour of the circumflex and dollar metacharacters.
       However, if the startoffset argument of pcre_exec() is non-zero,  indi-
       cating that matching is to start at a point other than the beginning of
       the subject, \A can never match. The difference between \Z  and  \z  is
       that \Z matches before a newline at the end of the string as well as at
       the very end, whereas \z matches only at the end.

       The \G assertion is true only when the current matching position is  at
       the  start point of the match, as specified by the startoffset argument
       of pcre_exec(). It differs from \A when the  value  of  startoffset  is
       non-zero.  By calling pcre_exec() multiple times with appropriate argu-
       ments, you can mimic Perl's /g option, and it is in this kind of imple-
       mentation where \G can be useful.

       Note,  however,  that  PCRE's interpretation of \G, as the start of the
       current match, is subtly different from Perl's, which defines it as the
       end  of  the  previous  match. In Perl, these can be different when the
       previously matched string was empty. Because PCRE does just  one  match
       at a time, it cannot reproduce this behaviour.

       If  all  the alternatives of a pattern begin with \G, the expression is
       anchored to the starting match position, and the "anchored" flag is set
       in the compiled regular expression.

CIRCUMFLEX AND DOLLAR

       The  circumflex  and  dollar  metacharacters are zero-width assertions.
       That is, they test for a particular condition being true  without  con-
       suming any characters from the subject string.

       Outside a character class, in the default matching mode, the circumflex
       character is an assertion that is true only  if  the  current  matching
       point  is  at the start of the subject string. If the startoffset argu-
       ment of pcre_exec() is non-zero, circumflex  can  never  match  if  the
       PCRE_MULTILINE  option  is  unset. Inside a character class, circumflex
       has an entirely different meaning (see below).

       Circumflex need not be the first character of the pattern if  a  number
       of  alternatives are involved, but it should be the first thing in each
       alternative in which it appears if the pattern is ever  to  match  that
       branch.  If all possible alternatives start with a circumflex, that is,
       if the pattern is constrained to match only at the start  of  the  sub-
       ject,  it  is  said  to be an "anchored" pattern. (There are also other
       constructs that can cause a pattern to be anchored.)

       The dollar character is an assertion that is true only if  the  current
       matching  point  is  at  the  end of the subject string, or immediately
       before a newline at the end of the string (by default). Note,  however,
       that  it  does  not  actually match the newline. Dollar need not be the
       last character of the pattern if a number of alternatives are involved,
       but  it should be the last item in any branch in which it appears. Dol-
       lar has no special meaning in a character class.

       The meaning of dollar can be changed so that it  matches  only  at  the
       very  end  of  the string, by setting the PCRE_DOLLAR_ENDONLY option at
       compile time. This does not affect the \Z assertion.

       The meanings of the circumflex and dollar characters are changed if the
       PCRE_MULTILINE  option  is  set.  When  this  is the case, a circumflex
       matches immediately after internal newlines as well as at the start  of
       the  subject  string.  It  does not match after a newline that ends the
       string. A dollar matches before any newlines in the string, as well  as
       at  the very end, when PCRE_MULTILINE is set. When newline is specified
       as the two-character sequence CRLF, isolated CR and  LF  characters  do
       not indicate newlines.

       For  example, the pattern /^abc$/ matches the subject string "def\nabc"
       (where \n represents a newline) in multiline mode, but  not  otherwise.
       Consequently,  patterns  that  are anchored in single line mode because
       all branches start with ^ are not anchored in  multiline  mode,  and  a
       match  for  circumflex  is  possible  when  the startoffset argument of
       pcre_exec() is non-zero. The PCRE_DOLLAR_ENDONLY option is  ignored  if
       PCRE_MULTILINE is set.

       Note  that  the sequences \A, \Z, and \z can be used to match the start
       and end of the subject in both modes, and if all branches of a  pattern
       start  with  \A it is always anchored, whether or not PCRE_MULTILINE is
       set.

FULL STOP (PERIOD, DOT) AND \N

       Outside a character class, a dot in the pattern matches any one charac-
       ter  in  the subject string except (by default) a character that signi-
       fies the end of a line.

       When a line ending is defined as a single character, dot never  matches
       that  character; when the two-character sequence CRLF is used, dot does
       not match CR if it is immediately followed  by  LF,  but  otherwise  it
       matches  all characters (including isolated CRs and LFs). When any Uni-
       code line endings are being recognized, dot does not match CR or LF  or
       any of the other line ending characters.

       The  behaviour  of  dot  with regard to newlines can be changed. If the
       PCRE_DOTALL option is set, a dot matches  any  one  character,  without
       exception. If the two-character sequence CRLF is present in the subject
       string, it takes two dots to match it.

       The handling of dot is entirely independent of the handling of  circum-
       flex  and  dollar,  the  only relationship being that they both involve
       newlines. Dot has no special meaning in a character class.

       The escape sequence \N behaves like  a  dot,  except  that  it  is  not
       affected  by  the  PCRE_DOTALL  option.  In other words, it matches any
       character except one that signifies the end of a line. Perl  also  uses
       \N to match characters by name; PCRE does not support this.

MATCHING A SINGLE DATA UNIT

       Outside  a character class, the escape sequence \C matches any one data
       unit, whether or not a UTF mode is set. In the 8-bit library, one  data
       unit  is  one  byte;  in the 16-bit library it is a 16-bit unit; in the
       32-bit library it is a 32-bit unit. Unlike a  dot,  \C  always  matches
       line-ending  characters.  The  feature  is provided in Perl in order to
       match individual bytes in UTF-8 mode, but it is unclear how it can use-
       fully  be  used.  Because  \C breaks up characters into individual data
       units, matching one unit with \C in a UTF mode means that the  rest  of
       the string may start with a malformed UTF character. This has undefined
       results, because PCRE assumes that it is dealing with valid UTF strings
       (and  by  default  it checks this at the start of processing unless the
       PCRE_NO_UTF8_CHECK, PCRE_NO_UTF16_CHECK or  PCRE_NO_UTF32_CHECK  option
       is used).

       PCRE  does  not  allow \C to appear in lookbehind assertions (described
       below) in a UTF mode, because this would make it impossible  to  calcu-
       late the length of the lookbehind.

       In general, the \C escape sequence is best avoided. However, one way of
       using it that avoids the problem of malformed UTF characters is to  use
       a  lookahead to check the length of the next character, as in this pat-
       tern, which could be used with a UTF-8 string (ignore white  space  and
       line breaks):

         (?| (?=[\x00-\x7f])(\C) |
             (?=[\x80-\x{7ff}])(\C)(\C) |
             (?=[\x{800}-\x{ffff}])(\C)(\C)(\C) |
             (?=[\x{10000}-\x{1fffff}])(\C)(\C)(\C)(\C))

       A  group  that starts with (?| resets the capturing parentheses numbers
       in each alternative (see "Duplicate  Subpattern  Numbers"  below).  The
       assertions  at  the start of each branch check the next UTF-8 character
       for values whose encoding uses 1, 2, 3, or 4 bytes,  respectively.  The
       character's  individual bytes are then captured by the appropriate num-
       ber of groups.

SQUARE BRACKETS AND CHARACTER CLASSES

       An opening square bracket introduces a character class, terminated by a
       closing square bracket. A closing square bracket on its own is not spe-
       cial by default.  However, if the PCRE_JAVASCRIPT_COMPAT option is set,
       a lone closing square bracket causes a compile-time error. If a closing
       square bracket is required as a member of the class, it should  be  the
       first  data  character  in  the  class (after an initial circumflex, if
       present) or escaped with a backslash.

       A character class matches a single character in the subject. In  a  UTF
       mode,  the  character  may  be  more than one data unit long. A matched
       character must be in the set of characters defined by the class, unless
       the  first  character in the class definition is a circumflex, in which
       case the subject character must not be in the set defined by the class.
       If  a  circumflex is actually required as a member of the class, ensure
       it is not the first character, or escape it with a backslash.

       For example, the character class [aeiou] matches any lower case  vowel,
       while  [^aeiou]  matches  any character that is not a lower case vowel.
       Note that a circumflex is just a convenient notation for specifying the
       characters  that  are in the class by enumerating those that are not. A
       class that starts with a circumflex is not an assertion; it still  con-
       sumes  a  character  from the subject string, and therefore it fails if
       the current pointer is at the end of the string.

       In UTF-8 (UTF-16, UTF-32) mode, characters with values greater than 255
       (0xffff)  can be included in a class as a literal string of data units,
       or by using the \x{ escaping mechanism.

       When caseless matching is set, any letters in a  class  represent  both
       their  upper  case  and lower case versions, so for example, a caseless
       [aeiou] matches "A" as well as "a", and a caseless  [^aeiou]  does  not
       match  "A", whereas a caseful version would. In a UTF mode, PCRE always
       understands the concept of case for characters whose  values  are  less
       than  128, so caseless matching is always possible. For characters with
       higher values, the concept of case is supported  if  PCRE  is  compiled
       with  Unicode  property support, but not otherwise.  If you want to use
       caseless matching in a UTF mode for characters 128 and above, you  must
       ensure  that  PCRE is compiled with Unicode property support as well as
       with UTF support.

       Characters that might indicate line breaks are  never  treated  in  any
       special  way  when  matching  character  classes,  whatever line-ending
       sequence is in  use,  and  whatever  setting  of  the  PCRE_DOTALL  and
       PCRE_MULTILINE options is used. A class such as [^a] always matches one
       of these characters.

       The minus (hyphen) character can be used to specify a range of  charac-
       ters  in  a  character  class.  For  example,  [d-m] matches any letter
       between d and m, inclusive. If a  minus  character  is  required  in  a
       class,  it  must  be  escaped  with a backslash or appear in a position
       where it cannot be interpreted as indicating a range, typically as  the
       first or last character in the class, or immediately after a range. For
       example, [b-d-z] matches letters in the range b to d, a hyphen  charac-
       ter, or z.

       It is not possible to have the literal character "]" as the end charac-
       ter of a range. A pattern such as [W-]46] is interpreted as a class  of
       two  characters ("W" and "-") followed by a literal string "46]", so it
       would match "W46]" or "-46]". However, if the "]"  is  escaped  with  a
       backslash  it is interpreted as the end of range, so [W-\]46] is inter-
       preted as a class containing a range followed by two other  characters.
       The  octal or hexadecimal representation of "]" can also be used to end
       a range.

       An error is generated if a POSIX character  class  (see  below)  or  an
       escape  sequence other than one that defines a single character appears
       at a point where a range ending character  is  expected.  For  example,
       [z-\xff] is valid, but [A-\d] and [A-[:digit:]] are not.

       Ranges  operate in the collating sequence of character values. They can
       also  be  used  for  characters  specified  numerically,  for   example
       [\000-\037].  Ranges  can include any characters that are valid for the
       current mode.

       If a range that includes letters is used when caseless matching is set,
       it matches the letters in either case. For example, [W-c] is equivalent
       to [][\\^_`wxyzabc], matched caselessly, and  in  a  non-UTF  mode,  if
       character  tables  for  a French locale are in use, [\xc8-\xcb] matches
       accented E characters in both cases. In UTF modes,  PCRE  supports  the
       concept  of  case for characters with values greater than 128 only when
       it is compiled with Unicode property support.

       The character escape sequences \d, \D, \h, \H, \p, \P, \s, \S, \v,  \V,
       \w, and \W may appear in a character class, and add the characters that
       they match to the class. For example, [\dABCDEF] matches any  hexadeci-
       mal  digit.  In  UTF modes, the PCRE_UCP option affects the meanings of
       \d, \s, \w and their upper case partners, just as  it  does  when  they
       appear  outside a character class, as described in the section entitled
       "Generic character types" above. The escape sequence \b has a different
       meaning  inside  a character class; it matches the backspace character.
       The sequences \B, \N, \R, and \X are not  special  inside  a  character
       class.  Like  any other unrecognized escape sequences, they are treated
       as the literal characters "B", "N", "R", and "X" by default, but  cause
       an error if the PCRE_EXTRA option is set.

       A  circumflex  can  conveniently  be used with the upper case character
       types to specify a more restricted set of characters than the  matching
       lower  case  type.  For example, the class [^\W_] matches any letter or
       digit, but not underscore, whereas [\w] includes underscore. A positive
       character class should be read as "something OR something OR ..." and a
       negative class as "NOT something AND NOT something AND NOT ...".

       The only metacharacters that are recognized in  character  classes  are
       backslash,  hyphen  (only  where  it can be interpreted as specifying a
       range), circumflex (only at the start), opening  square  bracket  (only
       when  it can be interpreted as introducing a POSIX class name, or for a
       special compatibility feature - see the next  two  sections),  and  the
       terminating  closing  square  bracket.  However,  escaping  other  non-
       alphanumeric characters does no harm.

POSIX CHARACTER CLASSES

       Perl supports the POSIX notation for character classes. This uses names
       enclosed  by  [: and :] within the enclosing square brackets. PCRE also
       supports this notation. For example,

         [01[:alpha:]%]

       matches "0", "1", any alphabetic character, or "%". The supported class
       names are:

         alnum    letters and digits
         alpha    letters
         ascii    character codes 0 - 127
         blank    space or tab only
         cntrl    control characters
         digit    decimal digits (same as \d)
         graph    printing characters, excluding space
         lower    lower case letters
         print    printing characters, including space
         punct    printing characters, excluding letters and digits and space
         space    white space (the same as \s from PCRE 8.34)
         upper    upper case letters
         word     "word" characters (same as \w)
         xdigit   hexadecimal digits

       The  default  "space" characters are HT (9), LF (10), VT (11), FF (12),
       CR (13), and space (32). If locale-specific matching is  taking  place,
       the  list  of  space characters may be different; there may be fewer or
       more of them. "Space" used to be different to \s, which did not include
       VT, for Perl compatibility.  However, Perl changed at release 5.18, and
       PCRE followed at release 8.34.  "Space" and \s now match the  same  set
       of characters.

       The  name  "word"  is  a Perl extension, and "blank" is a GNU extension
       from Perl 5.8. Another Perl extension is negation, which  is  indicated
       by a ^ character after the colon. For example,

         [12[:^digit:]]

       matches  "1", "2", or any non-digit. PCRE (and Perl) also recognize the
       POSIX syntax [.ch.] and [=ch=] where "ch" is a "collating element", but
       these are not supported, and an error is given if they are encountered.

       By default, characters with values greater than 128 do not match any of
       the POSIX character classes. However, if the PCRE_UCP option is  passed
       to  pcre_compile(),  some  of  the  classes are changed so that Unicode
       character properties are used. This is achieved  by  replacing  certain
       POSIX classes by other sequences, as follows:

         [:alnum:]  becomes  \p{Xan}
         [:alpha:]  becomes  \p{L}
         [:blank:]  becomes  \h
         [:digit:]  becomes  \p{Nd}
         [:lower:]  becomes  \p{Ll}
         [:space:]  becomes  \p{Xps}
         [:upper:]  becomes  \p{Lu}
         [:word:]   becomes  \p{Xwd}

       Negated  versions, such as [:^alpha:] use \P instead of \p. Three other
       POSIX classes are handled specially in UCP mode:

       [:graph:] This matches characters that have glyphs that mark  the  page
                 when printed. In Unicode property terms, it matches all char-
                 acters with the L, M, N, P, S, or Cf properties, except for:

                   U+061C           Arabic Letter Mark
                   U+180E           Mongolian Vowel Separator
                   U+2066 - U+2069  Various "isolate"s

       [:print:] This matches the same  characters  as  [:graph:]  plus  space
                 characters  that  are  not controls, that is, characters with
                 the Zs property.

       [:punct:] This matches all characters that have the Unicode P (punctua-
                 tion)  property,  plus those characters whose code points are
                 less than 128 that have the S (Symbol) property.

       The other POSIX classes are unchanged, and match only  characters  with
       code points less than 128.

COMPATIBILITY FEATURE FOR WORD BOUNDARIES

       In  the POSIX.2 compliant library that was included in 4.4BSD Unix, the
       ugly syntax [[:<:]] and [[:>:]] is used for matching  "start  of  word"
       and "end of word". PCRE treats these items as follows:

         [[:<:]]  is converted to  \b(?=\w)
         [[:>:]]  is converted to  \b(?<=\w)

       Only these exact character sequences are recognized. A sequence such as
       [a[:<:]b] provokes error for an unrecognized  POSIX  class  name.  This
       support  is not compatible with Perl. It is provided to help migrations
       from other environments, and is best not used in any new patterns. Note
       that  \b matches at the start and the end of a word (see "Simple asser-
       tions" above), and in a Perl-style pattern the preceding  or  following
       character  normally  shows  which  is  wanted, without the need for the
       assertions that are used above in order to give exactly the  POSIX  be-
       haviour.

VERTICAL BAR

       Vertical  bar characters are used to separate alternative patterns. For
       example, the pattern

         gilbert|sullivan

       matches either "gilbert" or "sullivan". Any number of alternatives  may
       appear,  and  an  empty  alternative  is  permitted (matching the empty
       string). The matching process tries each alternative in turn, from left
       to  right, and the first one that succeeds is used. If the alternatives
       are within a subpattern (defined below), "succeeds" means matching  the
       rest of the main pattern as well as the alternative in the subpattern.

INTERNAL OPTION SETTING

       The  settings  of  the  PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and
       PCRE_EXTENDED options (which are Perl-compatible) can be  changed  from
       within  the  pattern  by  a  sequence  of  Perl option letters enclosed
       between "(?" and ")".  The option letters are

         i  for PCRE_CASELESS
         m  for PCRE_MULTILINE
         s  for PCRE_DOTALL
         x  for PCRE_EXTENDED

       For example, (?im) sets caseless, multiline matching. It is also possi-
       ble to unset these options by preceding the letter with a hyphen, and a
       combined setting and unsetting such as (?im-sx), which sets  PCRE_CASE-
       LESS  and PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED,
       is also permitted. If a  letter  appears  both  before  and  after  the
       hyphen, the option is unset.

       The  PCRE-specific options PCRE_DUPNAMES, PCRE_UNGREEDY, and PCRE_EXTRA
       can be changed in the same way as the Perl-compatible options by  using
       the characters J, U and X respectively.

       When  one  of  these  option  changes occurs at top level (that is, not
       inside subpattern parentheses), the change applies to the remainder  of
       the pattern that follows. If the change is placed right at the start of
       a pattern, PCRE extracts it into the global options (and it will there-
       fore show up in data extracted by the pcre_fullinfo() function).

       An  option  change  within a subpattern (see below for a description of
       subpatterns) affects only that part of the subpattern that follows  it,
       so

         (a(?i)b)c

       matches abc and aBc and no other strings (assuming PCRE_CASELESS is not
       used).  By this means, options can be made to have  different  settings
       in  different parts of the pattern. Any changes made in one alternative
       do carry on into subsequent branches within the  same  subpattern.  For
       example,

         (a(?i)b|c)

       matches  "ab",  "aB",  "c",  and "C", even though when matching "C" the
       first branch is abandoned before the option setting.  This  is  because
       the  effects  of option settings happen at compile time. There would be
       some very weird behaviour otherwise.

       Note: There are other PCRE-specific options that  can  be  set  by  the
       application  when  the  compiling  or matching functions are called. In
       some cases the pattern can contain special leading  sequences  such  as
       (*CRLF)  to  override  what  the  application  has set or what has been
       defaulted.  Details  are  given  in  the  section   entitled   "Newline
       sequences"  above.  There  are also the (*UTF8), (*UTF16),(*UTF32), and
       (*UCP) leading sequences that can be used to set UTF and Unicode  prop-
       erty  modes;  they are equivalent to setting the PCRE_UTF8, PCRE_UTF16,
       PCRE_UTF32 and the PCRE_UCP options, respectively. The (*UTF)  sequence
       is  a  generic version that can be used with any of the libraries. How-
       ever, the application can set the PCRE_NEVER_UTF  option,  which  locks
       out the use of the (*UTF) sequences.

SUBPATTERNS

       Subpatterns are delimited by parentheses (round brackets), which can be
       nested.  Turning part of a pattern into a subpattern does two things:

       1. It localizes a set of alternatives. For example, the pattern

         cat(aract|erpillar|)

       matches "cataract", "caterpillar", or "cat". Without  the  parentheses,
       it would match "cataract", "erpillar" or an empty string.

       2.  It  sets  up  the  subpattern as a capturing subpattern. This means
       that, when the whole pattern  matches,  that  portion  of  the  subject
       string that matched the subpattern is passed back to the caller via the
       ovector argument of the matching function. (This applies  only  to  the
       traditional  matching functions; the DFA matching functions do not sup-
       port capturing.)

       Opening parentheses are counted from left to right (starting from 1) to
       obtain  numbers  for  the  capturing  subpatterns.  For example, if the
       string "the red king" is matched against the pattern

         the ((red|white) (king|queen))

       the captured substrings are "red king", "red", and "king", and are num-
       bered 1, 2, and 3, respectively.

       The  fact  that  plain  parentheses  fulfil two functions is not always
       helpful.  There are often times when a grouping subpattern is  required
       without  a capturing requirement. If an opening parenthesis is followed
       by a question mark and a colon, the subpattern does not do any  captur-
       ing,  and  is  not  counted when computing the number of any subsequent
       capturing subpatterns. For example, if the string "the white queen"  is
       matched against the pattern

         the ((?:red|white) (king|queen))

       the captured substrings are "white queen" and "queen", and are numbered
       1 and 2. The maximum number of capturing subpatterns is 65535.

       As a convenient shorthand, if any option settings are required  at  the
       start  of  a  non-capturing  subpattern,  the option letters may appear
       between the "?" and the ":". Thus the two patterns

         (?i:saturday|sunday)
         (?:(?i)saturday|sunday)

       match exactly the same set of strings. Because alternative branches are
       tried  from  left  to right, and options are not reset until the end of
       the subpattern is reached, an option setting in one branch does  affect
       subsequent  branches,  so  the above patterns match "SUNDAY" as well as
       "Saturday".

DUPLICATE SUBPATTERN NUMBERS

       Perl 5.10 introduced a feature whereby each alternative in a subpattern
       uses  the same numbers for its capturing parentheses. Such a subpattern
       starts with (?| and is itself a non-capturing subpattern. For  example,
       consider this pattern:

         (?|(Sat)ur|(Sun))day

       Because  the two alternatives are inside a (?| group, both sets of cap-
       turing parentheses are numbered one. Thus, when  the  pattern  matches,
       you  can  look  at captured substring number one, whichever alternative
       matched. This construct is useful when you want to  capture  part,  but
       not all, of one of a number of alternatives. Inside a (?| group, paren-
       theses are numbered as usual, but the number is reset at the  start  of
       each  branch.  The numbers of any capturing parentheses that follow the
       subpattern start after the highest number used in any branch. The  fol-
       lowing example is taken from the Perl documentation. The numbers under-
       neath show in which buffer the captured content will be stored.

         # before  ---------------branch-reset----------- after
         / ( a )  (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x
         # 1            2         2  3        2     3     4

       A back reference to a numbered subpattern uses the  most  recent  value
       that  is  set  for that number by any subpattern. The following pattern
       matches "abcabc" or "defdef":

         /(?|(abc)|(def))\1/

       In contrast, a subroutine call to a numbered subpattern  always  refers
       to  the  first  one in the pattern with the given number. The following
       pattern matches "abcabc" or "defabc":

         /(?|(abc)|(def))(?1)/

       If a condition test for a subpattern's having matched refers to a  non-
       unique  number, the test is true if any of the subpatterns of that num-
       ber have matched.

       An alternative approach to using this "branch reset" feature is to  use
       duplicate named subpatterns, as described in the next section.

NAMED SUBPATTERNS

       Identifying  capturing  parentheses  by number is simple, but it can be
       very hard to keep track of the numbers in complicated  regular  expres-
       sions.  Furthermore,  if  an  expression  is  modified, the numbers may
       change. To help with this difficulty, PCRE supports the naming of  sub-
       patterns. This feature was not added to Perl until release 5.10. Python
       had the feature earlier, and PCRE introduced it at release  4.0,  using
       the  Python syntax. PCRE now supports both the Perl and the Python syn-
       tax. Perl allows identically numbered  subpatterns  to  have  different
       names, but PCRE does not.

       In  PCRE,  a subpattern can be named in one of three ways: (?<name>...)
       or (?'name'...) as in Perl, or (?P<name>...) as in  Python.  References
       to  capturing parentheses from other parts of the pattern, such as back
       references, recursion, and conditions, can be made by name as  well  as
       by number.

       Names  consist of up to 32 alphanumeric characters and underscores, but
       must start with a non-digit.  Named  capturing  parentheses  are  still
       allocated  numbers  as  well as names, exactly as if the names were not
       present. The PCRE API provides function calls for extracting the  name-
       to-number  translation  table  from a compiled pattern. There is also a
       convenience function for extracting a captured substring by name.

       By default, a name must be unique within a pattern, but it is  possible
       to relax this constraint by setting the PCRE_DUPNAMES option at compile
       time. (Duplicate names are also always permitted for  subpatterns  with
       the  same  number, set up as described in the previous section.) Dupli-
       cate names can be useful for patterns where only one  instance  of  the
       named  parentheses  can  match. Suppose you want to match the name of a
       weekday, either as a 3-letter abbreviation or as the full name, and  in
       both cases you want to extract the abbreviation. This pattern (ignoring
       the line breaks) does the job:

         (?<DN>Mon|Fri|Sun)(?:day)?|
         (?<DN>Tue)(?:sday)?|
         (?<DN>Wed)(?:nesday)?|
         (?<DN>Thu)(?:rsday)?|
         (?<DN>Sat)(?:urday)?

       There are five capturing substrings, but only one is ever set  after  a
       match.  (An alternative way of solving this problem is to use a "branch
       reset" subpattern, as described in the previous section.)

       The convenience function for extracting the data by  name  returns  the
       substring  for  the first (and in this example, the only) subpattern of
       that name that matched. This saves searching  to  find  which  numbered
       subpattern it was.

       If  you  make  a  back  reference to a non-unique named subpattern from
       elsewhere in the pattern, the subpatterns to which the name refers  are
       checked  in  the order in which they appear in the overall pattern. The
       first one that is set is used for the reference. For example, this pat-
       tern matches both "foofoo" and "barbar" but not "foobar" or "barfoo":

         (?:(?<n>foo)|(?<n>bar))\k<n>

       If you make a subroutine call to a non-unique named subpattern, the one
       that corresponds to the first occurrence of the name is  used.  In  the
       absence of duplicate numbers (see the previous section) this is the one
       with the lowest number.

       If you use a named reference in a condition test (see the section about
       conditions below), either to check whether a subpattern has matched, or
       to check for recursion, all subpatterns with the same name are  tested.
       If  the condition is true for any one of them, the overall condition is
       true. This is the same behaviour as  testing  by  number.  For  further
       details  of  the  interfaces  for  handling  named subpatterns, see the
       pcreapi documentation.

       Warning: You cannot use different names to distinguish between two sub-
       patterns  with  the same number because PCRE uses only the numbers when
       matching. For this reason, an error is given at compile time if differ-
       ent  names  are given to subpatterns with the same number. However, you
       can always give the same name to subpatterns with the same number, even
       when PCRE_DUPNAMES is not set.

REPETITION

       Repetition  is  specified  by  quantifiers, which can follow any of the
       following items:

         a literal data character
         the dot metacharacter
         the \C escape sequence
         the \X escape sequence
         the \R escape sequence
         an escape such as \d or \pL that matches a single character
         a character class
         a back reference (see next section)
         a parenthesized subpattern (including assertions)
         a subroutine call to a subpattern (recursive or otherwise)

       The general repetition quantifier specifies a minimum and maximum  num-
       ber  of  permitted matches, by giving the two numbers in curly brackets
       (braces), separated by a comma. The numbers must be  less  than  65536,
       and the first must be less than or equal to the second. For example:

         z{2,4}

       matches  "zz",  "zzz",  or  "zzzz". A closing brace on its own is not a
       special character. If the second number is omitted, but  the  comma  is
       present,  there  is  no upper limit; if the second number and the comma
       are both omitted, the quantifier specifies an exact number of  required
       matches. Thus

         [aeiou]{3,}

       matches at least 3 successive vowels, but may match many more, while

         \d{8}

       matches  exactly  8  digits. An opening curly bracket that appears in a
       position where a quantifier is not allowed, or one that does not  match
       the  syntax of a quantifier, is taken as a literal character. For exam-
       ple, {,6} is not a quantifier, but a literal string of four characters.

       In UTF modes, quantifiers apply to characters rather than to individual
       data  units. Thus, for example, \x{100}{2} matches two characters, each
       of which is represented by a two-byte sequence in a UTF-8 string. Simi-
       larly,  \X{3} matches three Unicode extended grapheme clusters, each of
       which may be several data units long (and  they  may  be  of  different
       lengths).

       The quantifier {0} is permitted, causing the expression to behave as if
       the previous item and the quantifier were not present. This may be use-
       ful  for  subpatterns that are referenced as subroutines from elsewhere
       in the pattern (but see also the section entitled "Defining subpatterns
       for  use  by  reference only" below). Items other than subpatterns that
       have a {0} quantifier are omitted from the compiled pattern.

       For convenience, the three most common quantifiers have  single-charac-
       ter abbreviations:

         *    is equivalent to {0,}
         +    is equivalent to {1,}
         ?    is equivalent to {0,1}

       It  is  possible  to construct infinite loops by following a subpattern
       that can match no characters with a quantifier that has no upper limit,
       for example:

         (a?)*

       Earlier versions of Perl and PCRE used to give an error at compile time
       for such patterns. However, because there are cases where this  can  be
       useful,  such  patterns  are now accepted, but if any repetition of the
       subpattern does in fact match no characters, the loop is forcibly  bro-
       ken.

       By  default,  the quantifiers are "greedy", that is, they match as much
       as possible (up to the maximum  number  of  permitted  times),  without
       causing  the  rest of the pattern to fail. The classic example of where
       this gives problems is in trying to match comments in C programs. These
       appear  between  /*  and  */ and within the comment, individual * and /
       characters may appear. An attempt to match C comments by  applying  the
       pattern

         /\*.*\*/

       to the string

         /* first comment */  not comment  /* second comment */

       fails,  because it matches the entire string owing to the greediness of
       the .*  item.

       However, if a quantifier is followed by a question mark, it  ceases  to
       be greedy, and instead matches the minimum number of times possible, so
       the pattern

         /\*.*?\*/

       does the right thing with the C comments. The meaning  of  the  various
       quantifiers  is  not  otherwise  changed,  just the preferred number of
       matches.  Do not confuse this use of question mark with its  use  as  a
       quantifier  in its own right. Because it has two uses, it can sometimes
       appear doubled, as in

         \d??\d

       which matches one digit by preference, but can match two if that is the
       only way the rest of the pattern matches.

       If  the PCRE_UNGREEDY option is set (an option that is not available in
       Perl), the quantifiers are not greedy by default, but  individual  ones
       can  be  made  greedy  by following them with a question mark. In other
       words, it inverts the default behaviour.

       When a parenthesized subpattern is quantified  with  a  minimum  repeat
       count  that is greater than 1 or with a limited maximum, more memory is
       required for the compiled pattern, in proportion to  the  size  of  the
       minimum or maximum.

       If a pattern starts with .* or .{0,} and the PCRE_DOTALL option (equiv-
       alent to Perl's /s) is set, thus allowing the dot  to  match  newlines,
       the  pattern  is  implicitly anchored, because whatever follows will be
       tried against every character position in the subject string, so  there
       is  no  point  in  retrying the overall match at any position after the
       first. PCRE normally treats such a pattern as though it  were  preceded
       by \A.

       In  cases  where  it  is known that the subject string contains no new-
       lines, it is worth setting PCRE_DOTALL in order to  obtain  this  opti-
       mization, or alternatively using ^ to indicate anchoring explicitly.

       However,  there  are  some cases where the optimization cannot be used.
       When .*  is inside capturing parentheses that are the subject of a back
       reference elsewhere in the pattern, a match at the start may fail where
       a later one succeeds. Consider, for example:

         (.*)abc\1

       If the subject is "xyz123abc123" the match point is the fourth  charac-
       ter. For this reason, such a pattern is not implicitly anchored.

       Another  case where implicit anchoring is not applied is when the lead-
       ing .* is inside an atomic group. Once again, a match at the start  may
       fail where a later one succeeds. Consider this pattern:

         (?>.*?a)b

       It  matches "ab" in the subject "aab". The use of the backtracking con-
       trol verbs (*PRUNE) and (*SKIP) also disable this optimization.

       When a capturing subpattern is repeated, the value captured is the sub-
       string that matched the final iteration. For example, after

         (tweedle[dume]{3}\s*)+

       has matched "tweedledum tweedledee" the value of the captured substring
       is "tweedledee". However, if there are  nested  capturing  subpatterns,
       the  corresponding captured values may have been set in previous itera-
       tions. For example, after

         /(a|(b))+/

       matches "aba" the value of the second captured substring is "b".

ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS

       With both maximizing ("greedy") and minimizing ("ungreedy"  or  "lazy")
       repetition,  failure  of what follows normally causes the repeated item
       to be re-evaluated to see if a different number of repeats  allows  the
       rest  of  the pattern to match. Sometimes it is useful to prevent this,
       either to change the nature of the match, or to cause it  fail  earlier
       than  it otherwise might, when the author of the pattern knows there is
       no point in carrying on.

       Consider, for example, the pattern \d+foo when applied to  the  subject
       line

         123456bar

       After matching all 6 digits and then failing to match "foo", the normal
       action of the matcher is to try again with only 5 digits  matching  the
       \d+  item,  and  then  with  4,  and  so on, before ultimately failing.
       "Atomic grouping" (a term taken from Jeffrey  Friedl's  book)  provides
       the  means for specifying that once a subpattern has matched, it is not
       to be re-evaluated in this way.

       If we use atomic grouping for the previous example, the  matcher  gives
       up  immediately  on failing to match "foo" the first time. The notation
       is a kind of special parenthesis, starting with (?> as in this example:

         (?>\d+)foo

       This kind of parenthesis "locks up" the  part of the  pattern  it  con-
       tains  once  it  has matched, and a failure further into the pattern is
       prevented from backtracking into it. Backtracking past it  to  previous
       items, however, works as normal.

       An  alternative  description  is that a subpattern of this type matches
       the string of characters that an  identical  standalone  pattern  would
       match, if anchored at the current point in the subject string.

       Atomic grouping subpatterns are not capturing subpatterns. Simple cases
       such as the above example can be thought of as a maximizing repeat that
       must  swallow  everything  it can. So, while both \d+ and \d+? are pre-
       pared to adjust the number of digits they match in order  to  make  the
       rest of the pattern match, (?>\d+) can only match an entire sequence of
       digits.

       Atomic groups in general can of course contain arbitrarily  complicated
       subpatterns,  and  can  be  nested. However, when the subpattern for an
       atomic group is just a single repeated item, as in the example above, a
       simpler  notation,  called  a "possessive quantifier" can be used. This
       consists of an additional + character  following  a  quantifier.  Using
       this notation, the previous example can be rewritten as

         \d++foo

       Note that a possessive quantifier can be used with an entire group, for
       example:

         (abc|xyz){2,3}+

       Possessive  quantifiers  are  always  greedy;  the   setting   of   the
       PCRE_UNGREEDY option is ignored. They are a convenient notation for the
       simpler forms of atomic group. However, there is no difference  in  the
       meaning  of  a  possessive  quantifier and the equivalent atomic group,
       though there may be a performance  difference;  possessive  quantifiers
       should be slightly faster.

       The  possessive  quantifier syntax is an extension to the Perl 5.8 syn-
       tax.  Jeffrey Friedl originated the idea (and the name)  in  the  first
       edition of his book. Mike McCloskey liked it, so implemented it when he
       built Sun's Java package, and PCRE copied it from there. It  ultimately
       found its way into Perl at release 5.10.

       PCRE has an optimization that automatically "possessifies" certain sim-
       ple pattern constructs. For example, the sequence  A+B  is  treated  as
       A++B  because  there is no point in backtracking into a sequence of A's
       when B must follow.

       When a pattern contains an unlimited repeat inside  a  subpattern  that
       can  itself  be  repeated  an  unlimited number of times, the use of an
       atomic group is the only way to avoid some  failing  matches  taking  a
       very long time indeed. The pattern

         (\D+|<\d+>)*[!?]

       matches  an  unlimited number of substrings that either consist of non-
       digits, or digits enclosed in <>, followed by either ! or  ?.  When  it
       matches, it runs quickly. However, if it is applied to

         aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

       it  takes  a  long  time  before reporting failure. This is because the
       string can be divided between the internal \D+ repeat and the  external
       *  repeat  in  a  large  number of ways, and all have to be tried. (The
       example uses [!?] rather than a single character at  the  end,  because
       both  PCRE  and  Perl have an optimization that allows for fast failure
       when a single character is used. They remember the last single  charac-
       ter  that  is required for a match, and fail early if it is not present
       in the string.) If the pattern is changed so that  it  uses  an  atomic
       group, like this:

         ((?>\D+)|<\d+>)*[!?]

       sequences of non-digits cannot be broken, and failure happens quickly.

BACK REFERENCES

       Outside a character class, a backslash followed by a digit greater than
       0 (and possibly further digits) is a back reference to a capturing sub-
       pattern  earlier  (that is, to its left) in the pattern, provided there
       have been that many previous capturing left parentheses.

       However, if the decimal number following the backslash is less than 10,
       it  is  always  taken  as a back reference, and causes an error only if
       there are not that many capturing left parentheses in the  entire  pat-
       tern.  In  other words, the parentheses that are referenced need not be
       to the left of the reference for numbers less than 10. A "forward  back
       reference"  of  this  type can make sense when a repetition is involved
       and the subpattern to the right has participated in an  earlier  itera-
       tion.

       It  is  not  possible to have a numerical "forward back reference" to a
       subpattern whose number is 10 or  more  using  this  syntax  because  a
       sequence  such  as  \50 is interpreted as a character defined in octal.
       See the subsection entitled "Non-printing characters" above for further
       details  of  the  handling of digits following a backslash. There is no
       such problem when named parentheses are used. A back reference  to  any
       subpattern is possible using named parentheses (see below).

       Another  way  of  avoiding  the ambiguity inherent in the use of digits
       following a backslash is to use the \g  escape  sequence.  This  escape
       must be followed by an unsigned number or a negative number, optionally
       enclosed in braces. These examples are all identical:

         (ring), \1
         (ring), \g1
         (ring), \g{1}

       An unsigned number specifies an absolute reference without the  ambigu-
       ity that is present in the older syntax. It is also useful when literal
       digits follow the reference. A negative number is a relative reference.
       Consider this example:

         (abc(def)ghi)\g{-1}

       The sequence \g{-1} is a reference to the most recently started captur-
       ing subpattern before \g, that is, is it equivalent to \2 in this exam-
       ple.   Similarly, \g{-2} would be equivalent to \1. The use of relative
       references can be helpful in long patterns, and also in  patterns  that
       are  created  by  joining  together  fragments  that contain references
       within themselves.

       A back reference matches whatever actually matched the  capturing  sub-
       pattern  in  the  current subject string, rather than anything matching
       the subpattern itself (see "Subpatterns as subroutines" below for a way
       of doing that). So the pattern

         (sens|respons)e and \1ibility

       matches  "sense and sensibility" and "response and responsibility", but
       not "sense and responsibility". If caseful matching is in force at  the
       time  of the back reference, the case of letters is relevant. For exam-
       ple,

         ((?i)rah)\s+\1

       matches "rah rah" and "RAH RAH", but not "RAH  rah",  even  though  the
       original capturing subpattern is matched caselessly.

       There  are  several  different ways of writing back references to named
       subpatterns. The .NET syntax \k{name} and the Perl syntax  \k<name>  or
       \k'name'  are supported, as is the Python syntax (?P=name). Perl 5.10's
       unified back reference syntax, in which \g can be used for both numeric
       and  named  references,  is  also supported. We could rewrite the above
       example in any of the following ways:

         (?<p1>(?i)rah)\s+\k<p1>
         (?'p1'(?i)rah)\s+\k{p1}
         (?P<p1>(?i)rah)\s+(?P=p1)
         (?<p1>(?i)rah)\s+\g{p1}

       A subpattern that is referenced by  name  may  appear  in  the  pattern
       before or after the reference.

       There  may be more than one back reference to the same subpattern. If a
       subpattern has not actually been used in a particular match,  any  back
       references to it always fail by default. For example, the pattern

         (a|(bc))\2

       always  fails  if  it starts to match "a" rather than "bc". However, if
       the PCRE_JAVASCRIPT_COMPAT option is set at compile time, a back refer-
       ence to an unset value matches an empty string.

       Because  there may be many capturing parentheses in a pattern, all dig-
       its following a backslash are taken as part of a potential back  refer-
       ence  number.   If  the  pattern continues with a digit character, some
       delimiter must  be  used  to  terminate  the  back  reference.  If  the
       PCRE_EXTENDED  option  is  set, this can be white space. Otherwise, the
       \g{ syntax or an empty comment (see "Comments" below) can be used.

   Recursive back references

       A back reference that occurs inside the parentheses to which it  refers
       fails  when  the subpattern is first used, so, for example, (a\1) never
       matches.  However, such references can be useful inside  repeated  sub-
       patterns. For example, the pattern

         (a|b\1)+

       matches any number of "a"s and also "aba", "ababbaa" etc. At each iter-
       ation of the subpattern,  the  back  reference  matches  the  character
       string  corresponding  to  the previous iteration. In order for this to
       work, the pattern must be such that the first iteration does  not  need
       to  match the back reference. This can be done using alternation, as in
       the example above, or by a quantifier with a minimum of zero.

       Back references of this type cause the group that they reference to  be
       treated  as  an atomic group.  Once the whole group has been matched, a
       subsequent matching failure cannot cause backtracking into  the  middle
       of the group.

ASSERTIONS

       An  assertion  is  a  test on the characters following or preceding the
       current matching point that does not actually consume  any  characters.
       The  simple  assertions  coded  as  \b, \B, \A, \G, \Z, \z, ^ and $ are
       described above.

       More complicated assertions are coded as  subpatterns.  There  are  two
       kinds:  those  that  look  ahead of the current position in the subject
       string, and those that look  behind  it.  An  assertion  subpattern  is
       matched  in  the  normal way, except that it does not cause the current
       matching position to be changed.

       Assertion subpatterns are not capturing subpatterns. If such an  asser-
       tion  contains  capturing  subpatterns within it, these are counted for
       the purposes of numbering the capturing subpatterns in the  whole  pat-
       tern.  However,  substring  capturing  is carried out only for positive
       assertions. (Perl sometimes, but not always, does do capturing in nega-
       tive assertions.)

       For  compatibility  with  Perl,  assertion subpatterns may be repeated;
       though it makes no sense to assert the same thing  several  times,  the
       side  effect  of  capturing  parentheses may occasionally be useful. In
       practice, there only three cases:

       (1) If the quantifier is {0}, the  assertion  is  never  obeyed  during
       matching.   However,  it  may  contain internal capturing parenthesized
       groups that are called from elsewhere via the subroutine mechanism.

       (2) If quantifier is {0,n} where n is greater than zero, it is  treated
       as  if  it  were  {0,1}.  At run time, the rest of the pattern match is
       tried with and without the assertion, the order depending on the greed-
       iness of the quantifier.

       (3)  If  the minimum repetition is greater than zero, the quantifier is
       ignored.  The assertion is obeyed just  once  when  encountered  during
       matching.

   Lookahead assertions

       Lookahead assertions start with (?= for positive assertions and (?! for
       negative assertions. For example,

         \w+(?=;)

       matches a word followed by a semicolon, but does not include the  semi-
       colon in the match, and

         foo(?!bar)

       matches  any  occurrence  of  "foo" that is not followed by "bar". Note
       that the apparently similar pattern

         (?!foo)bar

       does not find an occurrence of "bar"  that  is  preceded  by  something
       other  than "foo"; it finds any occurrence of "bar" whatsoever, because
       the assertion (?!foo) is always true when the next three characters are
       "bar". A lookbehind assertion is needed to achieve the other effect.

       If you want to force a matching failure at some point in a pattern, the
       most convenient way to do it is  with  (?!)  because  an  empty  string
       always  matches, so an assertion that requires there not to be an empty
       string must always fail.  The backtracking control verb (*FAIL) or (*F)
       is a synonym for (?!).

   Lookbehind assertions

       Lookbehind  assertions start with (?<= for positive assertions and (?<!
       for negative assertions. For example,

         (?<!foo)bar

       does find an occurrence of "bar" that is not  preceded  by  "foo".  The
       contents  of  a  lookbehind  assertion are restricted such that all the
       strings it matches must have a fixed length. However, if there are sev-
       eral  top-level  alternatives,  they  do  not all have to have the same
       fixed length. Thus

         (?<=bullock|donkey)

       is permitted, but

         (?<!dogs?|cats?)

       causes an error at compile time. Branches that match  different  length
       strings  are permitted only at the top level of a lookbehind assertion.
       This is an extension compared with Perl, which requires all branches to
       match the same length of string. An assertion such as

         (?<=ab(c|de))

       is  not  permitted,  because  its single top-level branch can match two
       different lengths, but it is acceptable to PCRE if rewritten to use two
       top-level branches:

         (?<=abc|abde)

       In  some  cases, the escape sequence \K (see above) can be used instead
       of a lookbehind assertion to get round the fixed-length restriction.

       The implementation of lookbehind assertions is, for  each  alternative,
       to  temporarily  move the current position back by the fixed length and
       then try to match. If there are insufficient characters before the cur-
       rent position, the assertion fails.

       In  a UTF mode, PCRE does not allow the \C escape (which matches a sin-
       gle data unit even in a UTF mode) to appear in  lookbehind  assertions,
       because  it  makes it impossible to calculate the length of the lookbe-
       hind. The \X and \R escapes, which can match different numbers of  data
       units, are also not permitted.

       "Subroutine"  calls  (see below) such as (?2) or (?&X) are permitted in
       lookbehinds, as long as the subpattern matches a  fixed-length  string.
       Recursion, however, is not supported.

       Possessive  quantifiers  can  be  used  in  conjunction with lookbehind
       assertions to specify efficient matching of fixed-length strings at the
       end of subject strings. Consider a simple pattern such as

         abcd$

       when  applied  to  a  long string that does not match. Because matching
       proceeds from left to right, PCRE will look for each "a" in the subject
       and  then  see  if what follows matches the rest of the pattern. If the
       pattern is specified as

         ^.*abcd$

       the initial .* matches the entire string at first, but when this  fails
       (because there is no following "a"), it backtracks to match all but the
       last character, then all but the last two characters, and so  on.  Once
       again  the search for "a" covers the entire string, from right to left,
       so we are no better off. However, if the pattern is written as

         ^.*+(?<=abcd)

       there can be no backtracking for the .*+ item; it can  match  only  the
       entire  string.  The subsequent lookbehind assertion does a single test
       on the last four characters. If it fails, the match fails  immediately.
       For  long  strings, this approach makes a significant difference to the
       processing time.

   Using multiple assertions

       Several assertions (of any sort) may occur in succession. For example,

         (?<=\d{3})(?<!999)foo

       matches "foo" preceded by three digits that are not "999". Notice  that
       each  of  the  assertions is applied independently at the same point in
       the subject string. First there is a  check  that  the  previous  three
       characters  are  all  digits,  and  then there is a check that the same
       three characters are not "999".  This pattern does not match "foo" pre-
       ceded  by  six  characters,  the first of which are digits and the last
       three of which are not "999". For example, it  doesn't  match  "123abc-
       foo". A pattern to do that is

         (?<=\d{3}...)(?<!999)foo

       This  time  the  first assertion looks at the preceding six characters,
       checking that the first three are digits, and then the second assertion
       checks that the preceding three characters are not "999".

       Assertions can be nested in any combination. For example,

         (?<=(?<!foo)bar)baz

       matches  an occurrence of "baz" that is preceded by "bar" which in turn
       is not preceded by "foo", while

         (?<=\d{3}(?!999)...)foo

       is another pattern that matches "foo" preceded by three digits and  any
       three characters that are not "999".

CONDITIONAL SUBPATTERNS

       It  is possible to cause the matching process to obey a subpattern con-
       ditionally or to choose between two alternative subpatterns,  depending
       on  the result of an assertion, or whether a specific capturing subpat-
       tern has already been matched. The two possible  forms  of  conditional
       subpattern are:

         (?(condition)yes-pattern)
         (?(condition)yes-pattern|no-pattern)

       If  the  condition is satisfied, the yes-pattern is used; otherwise the
       no-pattern (if present) is used. If there are more  than  two  alterna-
       tives  in  the subpattern, a compile-time error occurs. Each of the two
       alternatives may itself contain nested subpatterns of any form, includ-
       ing  conditional  subpatterns;  the  restriction  to  two  alternatives
       applies only at the level of the condition. This pattern fragment is an
       example where the alternatives are complex:

         (?(1) (A|B|C) | (D | (?(2)E|F) | E) )

       There  are  four  kinds of condition: references to subpatterns, refer-
       ences to recursion, a pseudo-condition called DEFINE, and assertions.

   Checking for a used subpattern by number

       If the text between the parentheses consists of a sequence  of  digits,
       the condition is true if a capturing subpattern of that number has pre-
       viously matched. If there is more than one  capturing  subpattern  with
       the  same  number  (see  the earlier section about duplicate subpattern
       numbers), the condition is true if any of them have matched. An  alter-
       native  notation is to precede the digits with a plus or minus sign. In
       this case, the subpattern number is relative rather than absolute.  The
       most  recently opened parentheses can be referenced by (?(-1), the next
       most recent by (?(-2), and so on. Inside loops it can also  make  sense
       to refer to subsequent groups. The next parentheses to be opened can be
       referenced as (?(+1), and so on. (The value zero in any of these  forms
       is not used; it provokes a compile-time error.)

       Consider  the  following  pattern, which contains non-significant white
       space to make it more readable (assume the PCRE_EXTENDED option) and to
       divide it into three parts for ease of discussion:

         ( \( )?    [^()]+    (?(1) \) )

       The  first  part  matches  an optional opening parenthesis, and if that
       character is present, sets it as the first captured substring. The sec-
       ond  part  matches one or more characters that are not parentheses. The
       third part is a conditional subpattern that tests whether  or  not  the
       first  set  of  parentheses  matched.  If they did, that is, if subject
       started with an opening parenthesis, the condition is true, and so  the
       yes-pattern  is  executed and a closing parenthesis is required. Other-
       wise, since no-pattern is not present, the subpattern matches  nothing.
       In  other  words,  this  pattern matches a sequence of non-parentheses,
       optionally enclosed in parentheses.

       If you were embedding this pattern in a larger one,  you  could  use  a
       relative reference:

         ...other stuff... ( \( )?    [^()]+    (?(-1) \) ) ...

       This  makes  the  fragment independent of the parentheses in the larger
       pattern.

   Checking for a used subpattern by name

       Perl uses the syntax (?(<name>)...) or (?('name')...)  to  test  for  a
       used  subpattern  by  name.  For compatibility with earlier versions of
       PCRE, which had this facility before Perl, the syntax  (?(name)...)  is
       also recognized.

       Rewriting the above example to use a named subpattern gives this:

         (?<OPEN> \( )?    [^()]+    (?(<OPEN>) \) )

       If  the  name used in a condition of this kind is a duplicate, the test
       is applied to all subpatterns of the same name, and is true if any  one
       of them has matched.

   Checking for pattern recursion

       If the condition is the string (R), and there is no subpattern with the
       name R, the condition is true if a recursive call to the whole  pattern
       or any subpattern has been made. If digits or a name preceded by amper-
       sand follow the letter R, for example:

         (?(R3)...) or (?(R&name)...)

       the condition is true if the most recent recursion is into a subpattern
       whose number or name is given. This condition does not check the entire
       recursion stack. If the name used in a condition  of  this  kind  is  a
       duplicate, the test is applied to all subpatterns of the same name, and
       is true if any one of them is the most recent recursion.

       At "top level", all these recursion test  conditions  are  false.   The
       syntax for recursive patterns is described below.

   Defining subpatterns for use by reference only

       If  the  condition  is  the string (DEFINE), and there is no subpattern
       with the name DEFINE, the condition is  always  false.  In  this  case,
       there  may  be  only  one  alternative  in the subpattern. It is always
       skipped if control reaches this point  in  the  pattern;  the  idea  of
       DEFINE  is that it can be used to define subroutines that can be refer-
       enced from elsewhere. (The use of subroutines is described below.)  For
       example,  a  pattern  to match an IPv4 address such as "192.168.23.245"
       could be written like this (ignore white space and line breaks):

         (?(DEFINE) (?<byte> 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) )
         \b (?&byte) (\.(?&byte)){3} \b

       The first part of the pattern is a DEFINE group inside which a  another
       group  named "byte" is defined. This matches an individual component of
       an IPv4 address (a number less than 256). When  matching  takes  place,
       this  part  of  the pattern is skipped because DEFINE acts like a false
       condition. The rest of the pattern uses references to the  named  group
       to  match the four dot-separated components of an IPv4 address, insist-
       ing on a word boundary at each end.

   Assertion conditions

       If the condition is not in any of the above  formats,  it  must  be  an
       assertion.   This may be a positive or negative lookahead or lookbehind
       assertion. Consider  this  pattern,  again  containing  non-significant
       white space, and with the two alternatives on the second line:

         (?(?=[^a-z]*[a-z])
         \d{2}-[a-z]{3}-\d{2}  |  \d{2}-\d{2}-\d{2} )

       The  condition  is  a  positive  lookahead  assertion  that  matches an
       optional sequence of non-letters followed by a letter. In other  words,
       it  tests  for the presence of at least one letter in the subject. If a
       letter is found, the subject is matched against the first  alternative;
       otherwise  it  is  matched  against  the  second.  This pattern matches
       strings in one of the two forms dd-aaa-dd or dd-dd-dd,  where  aaa  are
       letters and dd are digits.

COMMENTS

       There are two ways of including comments in patterns that are processed
       by PCRE. In both cases, the start of the comment must not be in a char-
       acter class, nor in the middle of any other sequence of related charac-
       ters such as (?: or a subpattern name or number.  The  characters  that
       make up a comment play no part in the pattern matching.

       The  sequence (?# marks the start of a comment that continues up to the
       next closing parenthesis. Nested parentheses are not permitted. If  the
       PCRE_EXTENDED option is set, an unescaped # character also introduces a
       comment, which in this case continues to  immediately  after  the  next
       newline  character  or character sequence in the pattern. Which charac-
       ters are interpreted as newlines is controlled by the options passed to
       a  compiling function or by a special sequence at the start of the pat-
       tern, as described in the section entitled "Newline conventions" above.
       Note that the end of this type of comment is a literal newline sequence
       in the pattern; escape sequences that happen to represent a newline  do
       not  count.  For  example,  consider this pattern when PCRE_EXTENDED is
       set, and the default newline convention is in force:

         abc #comment \n still comment

       On encountering the # character, pcre_compile()  skips  along,  looking
       for  a newline in the pattern. The sequence \n is still literal at this
       stage, so it does not terminate the comment. Only an  actual  character
       with the code value 0x0a (the default newline) does so.

RECURSIVE PATTERNS

       Consider  the problem of matching a string in parentheses, allowing for
       unlimited nested parentheses. Without the use of  recursion,  the  best
       that  can  be  done  is  to use a pattern that matches up to some fixed
       depth of nesting. It is not possible to  handle  an  arbitrary  nesting
       depth.

       For some time, Perl has provided a facility that allows regular expres-
       sions to recurse (amongst other things). It does this by  interpolating
       Perl  code in the expression at run time, and the code can refer to the
       expression itself. A Perl pattern using code interpolation to solve the
       parentheses problem can be created like this:

         $re = qr{\( (?: (?>[^()]+) | (?p{$re}) )* \)}x;

       The (?p{...}) item interpolates Perl code at run time, and in this case
       refers recursively to the pattern in which it appears.

       Obviously, PCRE cannot support the interpolation of Perl code. Instead,
       it  supports  special  syntax  for recursion of the entire pattern, and
       also for individual subpattern recursion.  After  its  introduction  in
       PCRE  and  Python,  this  kind of recursion was subsequently introduced
       into Perl at release 5.10.

       A special item that consists of (? followed by a  number  greater  than
       zero  and  a  closing parenthesis is a recursive subroutine call of the
       subpattern of the given number, provided that  it  occurs  inside  that
       subpattern.  (If  not,  it is a non-recursive subroutine call, which is
       described in the next section.) The special item  (?R)  or  (?0)  is  a
       recursive call of the entire regular expression.

       This  PCRE  pattern  solves  the nested parentheses problem (assume the
       PCRE_EXTENDED option is set so that white space is ignored):

         \( ( [^()]++ | (?R) )* \)

       First it matches an opening parenthesis. Then it matches any number  of
       substrings  which  can  either  be  a sequence of non-parentheses, or a
       recursive match of the pattern itself (that is, a  correctly  parenthe-
       sized substring).  Finally there is a closing parenthesis. Note the use
       of a possessive quantifier to avoid backtracking into sequences of non-
       parentheses.

       If  this  were  part of a larger pattern, you would not want to recurse
       the entire pattern, so instead you could use this:

         ( \( ( [^()]++ | (?1) )* \) )

       We have put the pattern into parentheses, and caused the  recursion  to
       refer to them instead of the whole pattern.

       In  a  larger  pattern,  keeping  track  of  parenthesis numbers can be
       tricky. This is made easier by the use of relative references.  Instead
       of (?1) in the pattern above you can write (?-2) to refer to the second
       most recently opened parentheses  preceding  the  recursion.  In  other
       words,  a  negative  number counts capturing parentheses leftwards from
       the point at which it is encountered.

       It is also possible to refer to  subsequently  opened  parentheses,  by
       writing  references  such  as (?+2). However, these cannot be recursive
       because the reference is not inside the  parentheses  that  are  refer-
       enced.  They are always non-recursive subroutine calls, as described in
       the next section.

       An alternative approach is to use named parentheses instead.  The  Perl
       syntax  for  this  is (?&name); PCRE's earlier syntax (?P>name) is also
       supported. We could rewrite the above example as follows:

         (?<pn> \( ( [^()]++ | (?&pn) )* \) )

       If there is more than one subpattern with the same name,  the  earliest
       one is used.

       This  particular  example pattern that we have been looking at contains
       nested unlimited repeats, and so the use of a possessive quantifier for
       matching strings of non-parentheses is important when applying the pat-
       tern to strings that do not match. For example, when  this  pattern  is
       applied to

         (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()

       it  yields  "no  match" quickly. However, if a possessive quantifier is
       not used, the match runs for a very long time indeed because there  are
       so  many  different  ways the + and * repeats can carve up the subject,
       and all have to be tested before failure can be reported.

       At the end of a match, the values of capturing  parentheses  are  those
       from  the outermost level. If you want to obtain intermediate values, a
       callout function can be used (see below and the pcrecallout  documenta-
       tion). If the pattern above is matched against

         (ab(cd)ef)

       the  value  for  the  inner capturing parentheses (numbered 2) is "ef",
       which is the last value taken on at the top level. If a capturing  sub-
       pattern  is  not  matched at the top level, its final captured value is
       unset, even if it was (temporarily) set at a deeper  level  during  the
       matching process.

       If  there are more than 15 capturing parentheses in a pattern, PCRE has
       to obtain extra memory to store data during a recursion, which it  does
       by using pcre_malloc, freeing it via pcre_free afterwards. If no memory
       can be obtained, the match fails with the PCRE_ERROR_NOMEMORY error.

       Do not confuse the (?R) item with the condition (R),  which  tests  for
       recursion.   Consider  this pattern, which matches text in angle brack-
       ets, allowing for arbitrary nesting. Only digits are allowed in  nested
       brackets  (that is, when recursing), whereas any characters are permit-
       ted at the outer level.

         < (?: (?(R) \d++  | [^<>]*+) | (?R)) * >

       In this pattern, (?(R) is the start of a conditional  subpattern,  with
       two  different  alternatives for the recursive and non-recursive cases.
       The (?R) item is the actual recursive call.

   Differences in recursion processing between PCRE and Perl

       Recursion processing in PCRE differs from Perl in two  important  ways.
       In  PCRE (like Python, but unlike Perl), a recursive subpattern call is
       always treated as an atomic group. That is, once it has matched some of
       the subject string, it is never re-entered, even if it contains untried
       alternatives and there is a subsequent matching failure.  This  can  be
       illustrated  by the following pattern, which purports to match a palin-
       dromic string that contains an odd number of characters  (for  example,
       "a", "aba", "abcba", "abcdcba"):

         ^(.|(.)(?1)\2)$

       The idea is that it either matches a single character, or two identical
       characters surrounding a sub-palindrome. In Perl, this  pattern  works;
       in  PCRE  it  does  not if the pattern is longer than three characters.
       Consider the subject string "abcba":

       At the top level, the first character is matched, but as it is  not  at
       the end of the string, the first alternative fails; the second alterna-
       tive is taken and the recursion kicks in. The recursive call to subpat-
       tern  1  successfully  matches the next character ("b"). (Note that the
       beginning and end of line tests are not part of the recursion).

       Back at the top level, the next character ("c") is compared  with  what
       subpattern  2 matched, which was "a". This fails. Because the recursion
       is treated as an atomic group, there are now  no  backtracking  points,
       and  so  the  entire  match fails. (Perl is able, at this point, to re-
       enter the recursion and try the second alternative.)  However,  if  the
       pattern is written with the alternatives in the other order, things are
       different:

         ^((.)(?1)\2|.)$

       This time, the recursing alternative is tried first, and  continues  to
       recurse  until  it runs out of characters, at which point the recursion
       fails. But this time we do have  another  alternative  to  try  at  the
       higher  level.  That  is  the  big difference: in the previous case the
       remaining alternative is at a deeper recursion level, which PCRE cannot
       use.

       To  change  the pattern so that it matches all palindromic strings, not
       just those with an odd number of characters, it is tempting  to  change
       the pattern to this:

         ^((.)(?1)\2|.?)$

       Again,  this  works  in Perl, but not in PCRE, and for the same reason.
       When a deeper recursion has matched a single character,  it  cannot  be
       entered  again  in  order  to match an empty string. The solution is to
       separate the two cases, and write out the odd and even cases as  alter-
       natives at the higher level:

         ^(?:((.)(?1)\2|)|((.)(?3)\4|.))

       If  you  want  to match typical palindromic phrases, the pattern has to
       ignore all non-word characters, which can be done like this:

         ^\W*+(?:((.)\W*+(?1)\W*+\2|)|((.)\W*+(?3)\W*+\4|\W*+.\W*+))\W*+$

       If run with the PCRE_CASELESS option, this pattern matches phrases such
       as "A man, a plan, a canal: Panama!" and it works well in both PCRE and
       Perl. Note the use of the possessive quantifier *+ to avoid  backtrack-
       ing  into  sequences of non-word characters. Without this, PCRE takes a
       great deal longer (ten times or more) to  match  typical  phrases,  and
       Perl takes so long that you think it has gone into a loop.

       WARNING:  The  palindrome-matching patterns above work only if the sub-
       ject string does not start with a palindrome that is shorter  than  the
       entire  string.  For example, although "abcba" is correctly matched, if
       the subject is "ababa", PCRE finds the palindrome "aba" at  the  start,
       then  fails at top level because the end of the string does not follow.
       Once again, it cannot jump back into the recursion to try other  alter-
       natives, so the entire match fails.

       The  second  way  in which PCRE and Perl differ in their recursion pro-
       cessing is in the handling of captured values. In Perl, when a  subpat-
       tern  is  called recursively or as a subpattern (see the next section),
       it has no access to any values that were captured  outside  the  recur-
       sion,  whereas  in  PCRE  these values can be referenced. Consider this
       pattern:

         ^(.)(\1|a(?2))

       In PCRE, this pattern matches "bab". The  first  capturing  parentheses
       match  "b",  then in the second group, when the back reference \1 fails
       to match "b", the second alternative matches "a" and then recurses.  In
       the  recursion,  \1 does now match "b" and so the whole match succeeds.
       In Perl, the pattern fails to match because inside the  recursive  call
       \1 cannot access the externally set value.

SUBPATTERNS AS SUBROUTINES

       If  the  syntax for a recursive subpattern call (either by number or by
       name) is used outside the parentheses to which it refers,  it  operates
       like  a subroutine in a programming language. The called subpattern may
       be defined before or after the reference. A numbered reference  can  be
       absolute or relative, as in these examples:

         (...(absolute)...)...(?2)...
         (...(relative)...)...(?-1)...
         (...(?+1)...(relative)...

       An earlier example pointed out that the pattern

         (sens|respons)e and \1ibility

       matches  "sense and sensibility" and "response and responsibility", but
       not "sense and responsibility". If instead the pattern

         (sens|respons)e and (?1)ibility

       is used, it does match "sense and responsibility" as well as the  other
       two  strings.  Another  example  is  given  in the discussion of DEFINE
       above.

       All subroutine calls, whether recursive or not, are always  treated  as
       atomic  groups. That is, once a subroutine has matched some of the sub-
       ject string, it is never re-entered, even if it contains untried alter-
       natives  and  there  is  a  subsequent  matching failure. Any capturing
       parentheses that are set during the subroutine  call  revert  to  their
       previous values afterwards.

       Processing  options  such as case-independence are fixed when a subpat-
       tern is defined, so if it is used as a subroutine, such options  cannot
       be changed for different calls. For example, consider this pattern:

         (abc)(?i:(?-1))

       It  matches  "abcabc". It does not match "abcABC" because the change of
       processing option does not affect the called subpattern.

ONIGURUMA SUBROUTINE SYNTAX

       For compatibility with Oniguruma, the non-Perl syntax \g followed by  a
       name or a number enclosed either in angle brackets or single quotes, is
       an alternative syntax for referencing a  subpattern  as  a  subroutine,
       possibly  recursively. Here are two of the examples used above, rewrit-
       ten using this syntax:

         (?<pn> \( ( (?>[^()]+) | \g<pn> )* \) )
         (sens|respons)e and \g'1'ibility

       PCRE supports an extension to Oniguruma: if a number is preceded  by  a
       plus or a minus sign it is taken as a relative reference. For example:

         (abc)(?i:\g<-1>)

       Note  that \g{...} (Perl syntax) and \g<...> (Oniguruma syntax) are not
       synonymous. The former is a back reference; the latter is a  subroutine
       call.

CALLOUTS

       Perl has a feature whereby using the sequence (?{...}) causes arbitrary
       Perl code to be obeyed in the middle of matching a regular  expression.
       This makes it possible, amongst other things, to extract different sub-
       strings that match the same pair of parentheses when there is a repeti-
       tion.

       PCRE provides a similar feature, but of course it cannot obey arbitrary
       Perl code. The feature is called "callout". The caller of PCRE provides
       an  external function by putting its entry point in the global variable
       pcre_callout (8-bit library) or pcre[16|32]_callout (16-bit  or  32-bit
       library).   By default, this variable contains NULL, which disables all
       calling out.

       Within a regular expression, (?C) indicates the  points  at  which  the
       external  function  is  to be called. If you want to identify different
       callout points, you can put a number less than 256 after the letter  C.
       The  default  value is zero.  For example, this pattern has two callout
       points:

         (?C1)abc(?C2)def

       If the PCRE_AUTO_CALLOUT flag is passed to a compiling function,  call-
       outs  are automatically installed before each item in the pattern. They
       are all numbered 255. If there is a conditional group  in  the  pattern
       whose condition is an assertion, an additional callout is inserted just
       before the condition. An explicit callout may also be set at this posi-
       tion, as in this example:

         (?(?C9)(?=a)abc|def)

       Note that this applies only to assertion conditions, not to other types
       of condition.

       During matching, when PCRE reaches a callout point, the external  func-
       tion  is  called.  It  is  provided with the number of the callout, the
       position in the pattern, and, optionally, one item of  data  originally
       supplied  by  the caller of the matching function. The callout function
       may cause matching to proceed, to backtrack, or to fail altogether.

       By default, PCRE implements a number of optimizations at  compile  time
       and  matching  time, and one side-effect is that sometimes callouts are
       skipped. If you need all possible callouts to happen, you need  to  set
       options  that  disable  the relevant optimizations. More details, and a
       complete description of the interface  to  the  callout  function,  are
       given in the pcrecallout documentation.

BACKTRACKING CONTROL

       Perl  5.10 introduced a number of "Special Backtracking Control Verbs",
       which are still described in the Perl  documentation  as  "experimental
       and  subject to change or removal in a future version of Perl". It goes
       on to say: "Their usage in production code should  be  noted  to  avoid
       problems  during upgrades." The same remarks apply to the PCRE features
       described in this section.

       The new verbs make use of what was previously invalid syntax: an  open-
       ing parenthesis followed by an asterisk. They are generally of the form
       (*VERB) or (*VERB:NAME). Some may take either form,  possibly  behaving
       differently  depending  on  whether or not a name is present. A name is
       any sequence of characters that does not include a closing parenthesis.
       The maximum length of name is 255 in the 8-bit library and 65535 in the
       16-bit and 32-bit libraries. If the name is  empty,  that  is,  if  the
       closing  parenthesis immediately follows the colon, the effect is as if
       the colon were not there.  Any number of these verbs  may  occur  in  a
       pattern.

       Since  these  verbs  are  specifically related to backtracking, most of
       them can be used only when the pattern is to be matched  using  one  of
       the  traditional  matching  functions, because these use a backtracking
       algorithm. With the exception of (*FAIL), which behaves like a  failing
       negative  assertion,  the  backtracking control verbs cause an error if
       encountered by a DFA matching function.

       The behaviour of these verbs in repeated  groups,  assertions,  and  in
       subpatterns called as subroutines (whether or not recursively) is docu-
       mented below.

   Optimizations that affect backtracking verbs

       PCRE contains some optimizations that are used to speed up matching  by
       running some checks at the start of each match attempt. For example, it
       may know the minimum length of matching subject, or that  a  particular
       character must be present. When one of these optimizations bypasses the
       running of a match,  any  included  backtracking  verbs  will  not,  of
       course, be processed. You can suppress the start-of-match optimizations
       by setting the PCRE_NO_START_OPTIMIZE  option  when  calling  pcre_com-
       pile() or pcre_exec(), or by starting the pattern with (*NO_START_OPT).
       There is more discussion of this option in the section entitled "Option
       bits for pcre_exec()" in the pcreapi documentation.

       Experiments  with  Perl  suggest that it too has similar optimizations,
       sometimes leading to anomalous results.

   Verbs that act immediately

       The following verbs act as soon as they are encountered. They  may  not
       be followed by a name.

          (*ACCEPT)

       This  verb causes the match to end successfully, skipping the remainder
       of the pattern. However, when it is inside a subpattern that is  called
       as  a  subroutine, only that subpattern is ended successfully. Matching
       then continues at the outer level. If (*ACCEPT) in triggered in a posi-
       tive  assertion,  the  assertion succeeds; in a negative assertion, the
       assertion fails.

       If (*ACCEPT) is inside capturing parentheses, the data so far  is  cap-
       tured. For example:

         A((?:A|B(*ACCEPT)|C)D)

       This  matches  "AB", "AAD", or "ACD"; when it matches "AB", "B" is cap-
       tured by the outer parentheses.

         (*FAIL) or (*F)

       This verb causes a matching failure, forcing backtracking to occur.  It
       is  equivalent to (?!) but easier to read. The Perl documentation notes
       that it is probably useful only when combined  with  (?{})  or  (??{}).
       Those  are,  of course, Perl features that are not present in PCRE. The
       nearest equivalent is the callout feature, as for example in this  pat-
       tern:

         a+(?C)(*FAIL)

       A  match  with the string "aaaa" always fails, but the callout is taken
       before each backtrack happens (in this example, 10 times).

   Recording which path was taken

       There is one verb whose main purpose  is  to  track  how  a  match  was
       arrived  at,  though  it  also  has a secondary use in conjunction with
       advancing the match starting point (see (*SKIP) below).

         (*MARK:NAME) or (*:NAME)

       A name is always  required  with  this  verb.  There  may  be  as  many
       instances  of  (*MARK) as you like in a pattern, and their names do not
       have to be unique.

       When a match succeeds, the name of the  last-encountered  (*MARK:NAME),
       (*PRUNE:NAME),  or  (*THEN:NAME) on the matching path is passed back to
       the caller as  described  in  the  section  entitled  "Extra  data  for
       pcre_exec()"  in  the  pcreapi  documentation.  Here  is  an example of
       pcretest output, where the /K modifier requests the retrieval and  out-
       putting of (*MARK) data:

           re> /X(*MARK:A)Y|X(*MARK:B)Z/K
         data> XY
          0: XY
         MK: A
         XZ
          0: XZ
         MK: B

       The (*MARK) name is tagged with "MK:" in this output, and in this exam-
       ple it indicates which of the two alternatives matched. This is a  more
       efficient  way of obtaining this information than putting each alterna-
       tive in its own capturing parentheses.

       If a verb with a name is encountered in a positive  assertion  that  is
       true,  the  name  is recorded and passed back if it is the last-encoun-
       tered. This does not happen for negative assertions or failing positive
       assertions.

       After  a  partial match or a failed match, the last encountered name in
       the entire match process is returned. For example:

           re> /X(*MARK:A)Y|X(*MARK:B)Z/K
         data> XP
         No match, mark = B

       Note that in this unanchored example the  mark  is  retained  from  the
       match attempt that started at the letter "X" in the subject. Subsequent
       match attempts starting at "P" and then with an empty string do not get
       as far as the (*MARK) item, but nevertheless do not reset it.

       If  you  are  interested  in  (*MARK)  values after failed matches, you
       should probably set the PCRE_NO_START_OPTIMIZE option  (see  above)  to
       ensure that the match is always attempted.

   Verbs that act after backtracking

       The following verbs do nothing when they are encountered. Matching con-
       tinues with what follows, but if there is no subsequent match,  causing
       a  backtrack  to  the  verb, a failure is forced. That is, backtracking
       cannot pass to the left of the verb. However, when one of  these  verbs
       appears inside an atomic group or an assertion that is true, its effect
       is confined to that group, because once the  group  has  been  matched,
       there  is never any backtracking into it. In this situation, backtrack-
       ing can "jump back" to the left of the entire atomic  group  or  asser-
       tion.  (Remember  also,  as  stated  above, that this localization also
       applies in subroutine calls.)

       These verbs differ in exactly what kind of failure  occurs  when  back-
       tracking  reaches  them.  The behaviour described below is what happens
       when the verb is not in a subroutine or an assertion.  Subsequent  sec-
       tions cover these special cases.

         (*COMMIT)

       This  verb, which may not be followed by a name, causes the whole match
       to fail outright if there is a later matching failure that causes back-
       tracking  to  reach  it.  Even if the pattern is unanchored, no further
       attempts to find a match by advancing the starting point take place. If
       (*COMMIT)  is  the  only backtracking verb that is encountered, once it
       has been passed pcre_exec() is committed to finding a match at the cur-
       rent starting point, or not at all. For example:

         a+(*COMMIT)b

       This  matches  "xxaab" but not "aacaab". It can be thought of as a kind
       of dynamic anchor, or "I've started, so I must finish." The name of the
       most  recently passed (*MARK) in the path is passed back when (*COMMIT)
       forces a match failure.

       If there is more than one backtracking verb in a pattern,  a  different
       one  that  follows  (*COMMIT) may be triggered first, so merely passing
       (*COMMIT) during a match does not always guarantee that a match must be
       at this starting point.

       Note  that  (*COMMIT)  at  the start of a pattern is not the same as an
       anchor, unless PCRE's start-of-match optimizations are turned  off,  as
       shown in this output from pcretest:

           re> /(*COMMIT)abc/
         data> xyzabc
          0: abc
         data> xyzabc\Y
         No match

       For this pattern, PCRE knows that any match must start with "a", so the
       optimization skips along the subject to "a" before applying the pattern
       to  the first set of data. The match attempt then succeeds. In the sec-
       ond set of data, the escape sequence \Y is interpreted by the  pcretest
       program.  It  causes  the  PCRE_NO_START_OPTIMIZE option to be set when
       pcre_exec() is called.  This disables the optimization that skips along
       to the first character. The pattern is now applied starting at "x", and
       so the (*COMMIT) causes the match to  fail  without  trying  any  other
       starting points.

         (*PRUNE) or (*PRUNE:NAME)

       This  verb causes the match to fail at the current starting position in
       the subject if there is a later matching failure that causes backtrack-
       ing  to  reach it. If the pattern is unanchored, the normal "bumpalong"
       advance to the next starting character then happens.  Backtracking  can
       occur  as  usual to the left of (*PRUNE), before it is reached, or when
       matching to the right of (*PRUNE), but if there  is  no  match  to  the
       right,  backtracking cannot cross (*PRUNE). In simple cases, the use of
       (*PRUNE) is just an alternative to an atomic group or possessive  quan-
       tifier, but there are some uses of (*PRUNE) that cannot be expressed in
       any other way. In an anchored pattern (*PRUNE) has the same  effect  as
       (*COMMIT).

       The   behaviour   of   (*PRUNE:NAME)   is   the   not   the   same   as
       (*MARK:NAME)(*PRUNE).  It is like (*MARK:NAME)  in  that  the  name  is
       remembered  for  passing  back  to  the  caller.  However, (*SKIP:NAME)
       searches only for names set with (*MARK).

         (*SKIP)

       This verb, when given without a name, is like (*PRUNE), except that  if
       the  pattern  is unanchored, the "bumpalong" advance is not to the next
       character, but to the position in the subject where (*SKIP) was encoun-
       tered.  (*SKIP)  signifies that whatever text was matched leading up to
       it cannot be part of a successful match. Consider:

         a+(*SKIP)b

       If the subject is "aaaac...",  after  the  first  match  attempt  fails
       (starting  at  the  first  character in the string), the starting point
       skips on to start the next attempt at "c". Note that a possessive quan-
       tifer  does not have the same effect as this example; although it would
       suppress backtracking  during  the  first  match  attempt,  the  second
       attempt  would  start at the second character instead of skipping on to
       "c".

         (*SKIP:NAME)

       When (*SKIP) has an associated name, its behaviour is modified. When it
       is triggered, the previous path through the pattern is searched for the
       most recent (*MARK) that has the  same  name.  If  one  is  found,  the
       "bumpalong" advance is to the subject position that corresponds to that
       (*MARK) instead of to where (*SKIP) was encountered. If no (*MARK) with
       a matching name is found, the (*SKIP) is ignored.

       Note  that (*SKIP:NAME) searches only for names set by (*MARK:NAME). It
       ignores names that are set by (*PRUNE:NAME) or (*THEN:NAME).

         (*THEN) or (*THEN:NAME)

       This verb causes a skip to the next innermost  alternative  when  back-
       tracking  reaches  it.  That  is,  it  cancels any further backtracking
       within the current alternative. Its name  comes  from  the  observation
       that it can be used for a pattern-based if-then-else block:

         ( COND1 (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ ) ...

       If  the COND1 pattern matches, FOO is tried (and possibly further items
       after the end of the group if FOO succeeds); on  failure,  the  matcher
       skips  to  the second alternative and tries COND2, without backtracking
       into COND1. If that succeeds and BAR fails, COND3 is tried.  If  subse-
       quently  BAZ fails, there are no more alternatives, so there is a back-
       track to whatever came before the  entire  group.  If  (*THEN)  is  not
       inside an alternation, it acts like (*PRUNE).

       The    behaviour   of   (*THEN:NAME)   is   the   not   the   same   as
       (*MARK:NAME)(*THEN).  It is like  (*MARK:NAME)  in  that  the  name  is
       remembered  for  passing  back  to  the  caller.  However, (*SKIP:NAME)
       searches only for names set with (*MARK).

       A subpattern that does not contain a | character is just a part of  the
       enclosing  alternative;  it  is  not a nested alternation with only one
       alternative. The effect of (*THEN) extends beyond such a subpattern  to
       the  enclosing alternative. Consider this pattern, where A, B, etc. are
       complex pattern fragments that do not contain any | characters at  this
       level:

         A (B(*THEN)C) | D

       If  A and B are matched, but there is a failure in C, matching does not
       backtrack into A; instead it moves to the next alternative, that is, D.
       However,  if the subpattern containing (*THEN) is given an alternative,
       it behaves differently:

         A (B(*THEN)C | (*FAIL)) | D

       The effect of (*THEN) is now confined to the inner subpattern. After  a
       failure in C, matching moves to (*FAIL), which causes the whole subpat-
       tern to fail because there are no more alternatives  to  try.  In  this
       case, matching does now backtrack into A.

       Note  that  a  conditional  subpattern  is not considered as having two
       alternatives, because only one is ever used.  In  other  words,  the  |
       character in a conditional subpattern has a different meaning. Ignoring
       white space, consider:

         ^.*? (?(?=a) a | b(*THEN)c )

       If the subject is "ba", this pattern does not  match.  Because  .*?  is
       ungreedy,  it  initially  matches  zero characters. The condition (?=a)
       then fails, the character "b" is matched,  but  "c"  is  not.  At  this
       point,  matching does not backtrack to .*? as might perhaps be expected
       from the presence of the | character.  The  conditional  subpattern  is
       part of the single alternative that comprises the whole pattern, and so
       the match fails. (If there was a backtrack into  .*?,  allowing  it  to
       match "b", the match would succeed.)

       The  verbs just described provide four different "strengths" of control
       when subsequent matching fails. (*THEN) is the weakest, carrying on the
       match  at  the next alternative. (*PRUNE) comes next, failing the match
       at the current starting position, but allowing an advance to  the  next
       character  (for an unanchored pattern). (*SKIP) is similar, except that
       the advance may be more than one character. (*COMMIT) is the strongest,
       causing the entire match to fail.

   More than one backtracking verb

       If  more  than  one  backtracking verb is present in a pattern, the one
       that is backtracked onto first acts. For example,  consider  this  pat-
       tern, where A, B, etc. are complex pattern fragments:

         (A(*COMMIT)B(*THEN)C|ABD)

       If  A matches but B fails, the backtrack to (*COMMIT) causes the entire
       match to fail. However, if A and B match, but C fails, the backtrack to
       (*THEN)  causes  the next alternative (ABD) to be tried. This behaviour
       is consistent, but is not always the same as Perl's. It means  that  if
       two  or  more backtracking verbs appear in succession, all the the last
       of them has no effect. Consider this example:

         ...(*COMMIT)(*PRUNE)...

       If there is a matching failure to the right, backtracking onto (*PRUNE)
       causes  it to be triggered, and its action is taken. There can never be
       a backtrack onto (*COMMIT).

   Backtracking verbs in repeated groups

       PCRE differs from  Perl  in  its  handling  of  backtracking  verbs  in
       repeated groups. For example, consider:

         /(a(*COMMIT)b)+ac/

       If  the  subject  is  "abac",  Perl matches, but PCRE fails because the
       (*COMMIT) in the second repeat of the group acts.

   Backtracking verbs in assertions

       (*FAIL) in an assertion has its normal effect: it forces  an  immediate
       backtrack.

       (*ACCEPT) in a positive assertion causes the assertion to succeed with-
       out any further processing. In a negative assertion,  (*ACCEPT)  causes
       the assertion to fail without any further processing.

       The  other  backtracking verbs are not treated specially if they appear
       in a positive assertion. In  particular,  (*THEN)  skips  to  the  next
       alternative  in  the  innermost  enclosing group that has alternations,
       whether or not this is within the assertion.

       Negative assertions are, however, different, in order  to  ensure  that
       changing  a  positive  assertion  into a negative assertion changes its
       result. Backtracking into (*COMMIT), (*SKIP), or (*PRUNE) causes a neg-
       ative assertion to be true, without considering any further alternative
       branches in the assertion.  Backtracking into (*THEN) causes it to skip
       to  the next enclosing alternative within the assertion (the normal be-
       haviour), but if the assertion  does  not  have  such  an  alternative,
       (*THEN) behaves like (*PRUNE).

   Backtracking verbs in subroutines

       These  behaviours  occur whether or not the subpattern is called recur-
       sively.  Perl's treatment of subroutines is different in some cases.

       (*FAIL) in a subpattern called as a subroutine has its  normal  effect:
       it forces an immediate backtrack.

       (*ACCEPT)  in a subpattern called as a subroutine causes the subroutine
       match to succeed without any further processing. Matching then  contin-
       ues after the subroutine call.

       (*COMMIT), (*SKIP), and (*PRUNE) in a subpattern called as a subroutine
       cause the subroutine match to fail.

       (*THEN) skips to the next alternative in the innermost enclosing  group
       within  the subpattern that has alternatives. If there is no such group
       within the subpattern, (*THEN) causes the subroutine match to fail.

SEE ALSO

       pcreapi(3), pcrecallout(3),  pcrematching(3),  pcresyntax(3),  pcre(3),
       pcre16(3), pcre32(3).

AUTHOR

       Philip Hazel
       University Computing Service
       Cambridge CB2 3QH, England.

REVISION

       Last updated: 08 January 2014
       Copyright (c) 1997-2014 University of Cambridge.


GUI Overview

The Dyalog APL GUI is based upon the concepts of objects, properties, events and methods.

Objects

Objects are instances of classes that contain information and provide functionality. Most Dyalog APL objects are GUI objects that may be displayed on the screen and with which you can interact. An example of an object is a push-button (an instance of class Button) which you may press to cause the program to take a particular action. Objects are defined in hierarchies.

Properties

Each object has an associated set of properties which describe how it looks and behaves. For example, a Button has a property called Caption which defines the character string to be displayed in it.

Events

During interaction with the user, an object is capable of generating events.

An example is the Select event. For a Button object, this event is generated when the user presses the Button. This can be done in several ways. Firstly, the user may click the left mouse button over the object. Secondly, under certain circumstances, the Select event can be generated when the user presses the Enter key. Finally, the event will occur if the user presses a "short-cut" (mnemonic) key that is associated with the Button.

Methods

Methods are effectively functions that an object provides; they are things that you may invoke to make the object do something for you. In Dyalog APL, the distinction between methods and events is tenuous, because events also make objects perform actions and you may generate events under program control. For example, a Scroll event is generated by a scrollbar when the user moves the thumb. Conversely, you can make a scrollbar scroll by generating a Scroll event. Nevertheless, the concept of a method is useful to describe functions that can only be invoked by a program and are not directly accessible to the user.

Object Management Functions

This is a set of system functions used to create objects, set properties, respond to events, and call methods.


Objects Categorised

Objects: A-Z

System Objects
Root | system-level object
Printer | for hard-copy output
Clipboard | provides access to Windows clipboard
Container Objects
CoolBand | represents a band in a CoolBar
CoolBar | a container for CoolBand objects
Form | top-level Window
MDIClient | container for MDI windows
SubForm | acts as an MDI window or a constrained Form
Group | a frame for grouping Buttons and other objects
Static | a frame for drawing and clipping graphics
StatusBar | ribbon status bar
TabBar | contains TabBtns (tabs)
TabControl | contains TabButtons (tabs)
ToolBar | ribbon tool bar
ToolControl | standard Windows tool control
PropertySheet | contains PropertyPages
PropertyPage | tabbed or paged container for other controls
Splitter | divides a container into panes
Menu
MenuBar | pull-down menu bar
Menu | pop-up menu
MenuItem | selects an option or action
Separator | separator between items
Action |
Button | selects an option
ToolButton | performs an action or selects an option
TabBtn | selects a tabbed SubForm
TabButton | selects a tabbed SubForm
Scroll | scroll bar
UpDown | spin buttons
Locator | graphical (positional) input device
Timer | generates events at regular intervals
SysTrayItem | an item that you can create in the Windows System Tray
Information
Animation | displays simple animations from .AVI files
Label | displays static text
StatusField | displays status information
MsgBox | displays a message box
TipField | displays pop-up context sensitive help
ProgressBar | displays the progress of a lengthy operation
Input & Selection
Calendar | displays a month calendar control
DateTimePicker | an editable date/time field with an optional drop-down Calendar.
ColorButton | allows the user to select a colour.
Grid | displays a data matrix as a spreadsheet
Edit | text input field
ButtonEdit | text input field with dropdown button
RichEdit | text input with word-processing capabilities
Spinner | input field with spin buttons
List | for selecting an item
ListView | displays a collection of items for selection
Combo | edit field with selectable list of choices
ComboEx | extended version of Combo
TreeView | displays a hierarchical collection of items
TrackBar | a slider control for analogue input/output
FileBox | prompts user to select a file
BrowseBox | prompts user to browse for a folder or other resource.
Resource
Font | loads a font
Bitmap | defines a bitmap
Icon | defines an icon
ImageList | defines a collection of bitmaps or icons
Metafile | loads a Windows Metafile
Cursor | defines a cursor
Graphical Output
Circle | draws a circle
Ellipse | draws an ellipse
Marker | draws a series of polymarkers
Poly | draws lines
Rect | draws rectangles
Image | displays Bitmaps, Icons and Metafiles
Text | draws graphical text
Miscellaneous
ActiveXContainer | represents the application hosting a Dyalog APL ActiveXControl
ActiveXControl | represents an ActiveX control written in Dyalog APL
NetClient | provides access to .NET Classes
NetControl | instantiates a .NET Control.
NetType | exports an APL namespace as a Net Class
OCXClass | provides access to OLE Custom Controls
OLEClient | provides access to OLE Automation objects
OLEServer | enables APL to act as an OLE Automation server
SM | specifies a window for ⎕SM (character mode interface)
TCPSocket | provides an interface to TCP/IP sockets


Objects A-Z

Objects: Categorised

Object | Description
ActiveXContainer | represents the application hosting a Dyalog APL ActiveXControl
ActiveXControl | implements an ActiveX control written in Dyalog APL
Animation | plays simple AVIs
Bitmap | can be used to fill an area, or as a background pattern
BrowseBox | allows the user to browse for a folder or other resource
Button | used to perform a task or select an option
ButtonEdit | single-line input field with custom button
Calendar | displays a month calendar control
Circle | draws circles, arcs and pies
Clipboard | provides access to the Windows clipboard
ColorButton | allows the user to select a colour
Combo | combines text entry field with list of choices
ComboEx | an extended version of the Combo object that provides additional features including item images
CoolBand | represents a band in a CoolBar
CoolBar | acts as a container for CoolBand objects
Cursor | creates user-defined cursor
DateTimePicker | an editable date/time field with an optional drop-down Calendar
Edit | single or multi-line edit box for entering data
Ellipse | draws ellipses, elliptical arcs and pies
FileBox | standard File Selection dialog box
Font | a font resource
Form | window that acts as a container for other objects
Grid | spreadsheet object for editing data
Group | used to group a related set of controls together visually, and to impose "radio-button" behaviour
Icon | can be displayed, or used when a Form is minimized
Image | graphical object for displaying bitmaps and icons
ImageList | specifies a collection of bitmaps or icons for a ListView or TreeView
Label | fixed text that the user cannot change
List | list of items from which the user can choose
ListView | collection of items from which the user can choose
Locator | moving line, rectangle or ellipse for graphics input
Marker | draws marker at a series of points
MDIClient | provides Multiple Document Interface (MDI) behaviour
Menu | displays a pulldown or pop-up menu
MenuBar | displays list of pulldown menus across top of Form
MenuItem | component of a Menu that performs action or makes choice
Metafile | provides access to Windows Metafiles
MsgBox | displays message in dialog box and waits for response
NetClient | Provides access to .NET Classes
NetControl | Provides access to .NET controls.
NetType | Exports a namespace as a .NET class
OCXClass | provides access to OLE Custom Controls
OLEClient | provides access to OLE Automation objects
OLEServer | enables APL to act as an OLE Automation server
Poly | draws lines, polygons and filled areas
Printer | controls output to a printer
ProgressBar | indicates the progress of a lengthy operation
PropertyPage | tabbed or paged container for other controls
PropertySheet | container for PropertyPages
Rect | draws filled and unfilled rectangles
RichEdit | an edit box with word-processing capabilities
Root | the system object that is the progenitor of all others
Scroll | horizontal or vertical scrollbar
Separator | horizontal or vertical line in Menu, or vertical break in MenuBar
SM | allows ⎕SM and ⎕SR to be used with GUI objects
Spinner | input field with spin buttons
Splitter | divides a Form or SubForm into resizable panes
Static | frame or box used to contain graphics
StatusBar | manages a set of StatusField objects
StatusField | displays context-sensitive help, or keyboard status
SubForm | child Form that is constrained within its parent
SysTrayItem | represents an item that you can create in the Windows system tray
TabBar | manages a set of TabBtn objects
TabBtn | brings forward an associated SubForm
TabButton | represents a tab or button in a TabControl
TabControl | represents the standard Windows tab control
TCPSocket | provides an interface to TCP/IP sockets
Text | displays or prints arbitrary text
Timer | generates events at regular intervals
TipField | displays pop-up context-sensitive help
ToolBar | manages a block of controls including Buttons
ToolButton | represents a or button in a ToolControl
ToolControl | represents the standard Windows tool control
TrackBar | slider control for analogue input/output
TreeView | displays a hierarchical list of items
UpDown | a pair of arrow buttons


Properties A-Z
Property | Description
Accelerator | specifies keystroke that will generate Select event
Active | determines whether object can generate events
Align | determines the position of text or for Scroll object
AlignChar | specifies a character for column alignment in a Grid
AlwaysShowBorder | specifies how the current cell in a Grid is displayed when the Grid loses focus
AlwaysShowSelection | specifies how the highlighted selection in an object is displayed when the object loses focus
APLVersion | reports the version of Dyalog APL being run
ArcMode | determines how arcs are drawn (Ellipse)
Attach | specifies how object is reconfigured when parent is resized
AutoArrange | whether or not items in a ListView are rearranged automatically
AutoBrowse | specifies whether or not functions and variables are fixed when an OLEClient is created
AutoConf | how a child reacts to its parent being resized
AutoExpand | whether rows and columns are added to a Grid
BandBorders | Specifies whether or not narrow lines are drawn to separate adjacent bands in a CoolBar
BCol | specifies background colour
Bits | defines the pattern for a Bitmap, Cursor, or Icon
Border | determines whether or not an object has a border
BtnPix | associates Bitmaps with Button, Menu and MenuItem objects
Btns | determines the buttons shown in a MsgBox
ButtonsAcceptFocus | affects the keyboard handling in a ToolControl
CalendarCols | Specifies the colours used for various elements in the Calendar object
Cancel | used to associate the Esc key with a particular Button
Caption | specifies text in an object
CBits | represents the picture in a Bitmap object
CellFonts | specifies fonts to be used by the cells in a Grid
CellHeights | specifies the heights of the cells in a Grid
CellSelect | specifies the type(s) of selection a user can perform in a Grid
CellSet | flags which cells in a Grid have values and which are empty
CellTypes | specifies the type of the cells in a Grid
Cells | specifies the widths of cells in a Grid
Changed | flags whether or not data in an object has been changed
CharFormat | specifies character formatting in a RichEdit
CharSet | specifies the character encoding of a Font object
CheckBoxes | specifies whether or not check boxes are displayed alongside items in a ListView or TreeView object
Checked | determines whether check mark is displayed by MenuItem
ChildEdge | specifies whether or not a CoolBand leaves space above and below its child window
ChildList | reports the types of object that may be children of an object
CircleToday | specifies whether or not a circle is drawn around the Today date in a Calendar object
ClassID | reports the CLSID of an OLEClient or OLEServer
ClassName | specifies the name of the OLE object to which an OLEClient object is to be connected
ClipCells | specifies whether or not columns of a Grid are clipped
CMap | defines a colour map for a Bitmap or Icon
ColLineTypes | specifies the appearance of vertical grid lines in a Grid
ColSortImages | specifies the images to be used to display sort images in the column titles of a Grid
ColTitle3D | specifies the appearance of column titles for a ListView
ColTitleAlign | specifies the alignment of column titles
ColTitleBCol | specifies the background colour for column titles
ColTitleDepth | specifies the structure of hierarchical column titles for a Grid
ColTitleFCol | specifies the colour of the row titles in a Grid
ColTitles | specifies the column titles for a Grid or ListView
Column | specifies the width of columns for a multi-column List
Container | the Object Representation of an ActiveXContainer object
Coord | specifies the coordinate system for an object
Cue | specifies text displayed in an empty input field
CurCell | identifies the current cell in a Grid
CurrentColor | Specifies the currently selected colour in a ColorButton object
CurrentState | reports the current state of a TCPSocket object
CursorObj | associates a cursor with an object
CustomColors | Specifies the custom colors associated with a ColorButton object
Decimals | specifies the number of decimal places for a Numeric field
Default | nominates a Button to be selected with the Enter key
DefaultColors | Specifies the default colours associated with a ColorButton object
Depth | specifies the structure of items for a TreeView
DevCaps | reports the device capabilities of the screen or printer
Directory | specifies the directory for a FileBox
Divider | controls the presence or absence of a recessed line in a ToolControl object
Dragable | specifies whether user may drag an object with the mouse
DragItems | specifies whether user may drag/drop items in a ListView
DrawMode | provides direct control over the low-level drawing operation performed by graphical objects
EdgeStyle | specifies 3-dimensional appearance
EditLabels | specifies whether or not the user may edit the labels in a ListView or TreeView
Elevated | affects the appearance of a CommandLink Button
Encoding | specifies how character data are encoded or translated for a TCPSocket
EnterReadOnlyCells | specifies whether or not the user may visit read-only cells in a Grid
EvaluationDays | Specifies the number of days before the evaluation version of a Dyalog APL application expires. PocketAPL only
Event | associates an event with a callback function or ⎕DQ termination
EventList | reports names of events generated by an object
ExportedFns | specifies the functions to be exposed as methods by an OLEServer object
ExportedVars | specifies the variables to be exposed as properties by an OLEServer object
FCol | specifies foreground colour
FieldType | specifies formatting and validation
FileMode | specifies the mode (read or write) for a FileBox object
File | specifies a filename
FillCol | specifies fill colour
Filters | specifies file filters for a FileBox
FirstDay | specifies the day that is considered to be the first day of the week for a Calendar object
Fixed | specifies whether a font is fixed-width or proportional
FixedOrder | specifies whether or not the CoolBar displays CoolBands in the same order
FlatSeparators | specifies whether or not separators are drawn between buttons in a TabControl object
FontList | provides a list of available fonts
FontObj | specifies the font to be used
Formats | data formats currently available from the Clipboard object
FormatString | defines a ⎕FMT specification to be used to format a numeric value
FStyle | specifies fill style
FullRowSelect | specifies whether or not the entire row is highlighted when an item in a ListView or a TreeView is selected
GridBCol | specifies the background colour for a Grid
GridFCol | specifies the colour of (all) grid lines for a Grid
GridLineFCol | specifies grid line colours for a Grid
GridLine | specifies grid line widths for a Grid
GridLines | specifies whether or not lines are displayed between items in a ListView object
GripperMode | specifies whether or not a CoolBand has a gripper bar
HAlign | specifies horizontal text alignment
Handle | Returns the window handle of an object
HasApply | Specifies whether or not a PropertySheet has an Apply button
HasButtons | Specifies whether or not a TreeView object displays buttons
HasClearButton | Specifies whether or not an Edit object displays an [image] button which may be used to clear the contents of the field.
HasHelp | Specifies whether or not a Help button is displayed or active
HasLines | Specifies whether or not a TreeView object displays tree lines
HasTicks | Specifies whether or not tick marks are displayed in a TrackBar
HasToday | Specifies whether or not the Today date is displayed in the bottom left corner of a Calendar object
Header | specifies whether or not column titles are displayed in a ListView
HeaderImageIndex | Specifies the images for each column title in a ListView
HeaderImageList | Specifies the images for column titles in a ListView
HelpButton | specifies whether or not a question (?) button appears in the title bar of a Form
HelpFile | reports the name of a help file associated with an OLE Control
HighlightHeaders | Specifies whether or not row and column headings in a Grid are highlighted to indicate the current selection
HintObj | specifies the object in which to display the Hint
Hint | specifies the text for a context sensitive help message
HotSpot | specifies the hotspot for a Cursor
HotTrack | specifies whether or not the tabs or buttons in a TabControl object are automatically highlighted by the mouse pointer
HScroll | determines whether an object has a horizontal scrollbar
IconObj | associates an Icon with a minimized Form
ImageCount | Reports the number of images in an ImageList
ImageIndex | Maps images in an ImageList to items in a ListView or TreeView
ImageListObj | Associates an ImageList with a ListView or TreeView
Index | position of items in Combo or List, or selected filter in a FileBox
Input | names of objects associated with cells of Grid
InputMode | specifies the behaviour of cursor keys etc. in a Grid
InputModeKey | specifies the key used to switch to Incell editing in a Grid
InputProperties | Specifies the mapping between the Values property of a Grid and properties of external objects (ActiveX controls and .NET classes) which are displayed in Grid cells
Interval | frequency with which a Timer generates events
Italic | specifies whether or not a font is italic
Items | list of items
ItemGroups | specifies item groupings for a ListView object
ItemGroupMetrics | specifies caption, colours and spacing for grouped items in a ListView object
Justify | determines how text is justified within an object
KeepBits | determines how Bitmap objects are stored in the workspace
KeepOnClose | determines whether or not namespaces are retained when their GUI components are destroyed
LastError | provides information about the most recent error reported by OLE
LateBind | specifies whether or not Type Information is read when an OLEClient is instantiated, and when an OLEServer hosts an external COM object
Limits | specifies minimum and maximum values for an object
LocalAddrName | specifies the host name of your computer
LocalAddr | specifies the IP address of your computer
Locale | specifies the language in which the OLE server, attached to an OLEClient, exposes its methods and properties
LocalPortName | specifies the port name of the local service that you wish to offer as a TCP/IP server
LocalPort | identifies the port number associated with a TCPSocket object
LStyle | specifies line style
LWidth | specifies line width
MapCols | specifies whether button colours in bitmaps and icons in an ImageList are re-mapped to reflect the users colour preferences
Masked | specifies the type of image in an ImageList
Mask | specifies the mask for a Cursor or Icon
MaxButton | determines whether or not a Form has a "maximize" button
MaxDate | specifies the largest date that may be displayed by a Calendar object
MaxLength | specifies the maximum number of characters that the user may enter into an object
MaxSelCount | specifies the maximum number of contiguous days that the user may select in a Calendar object
MDIActive | specifies the name of the active SubForm in an MDI application
MDIActiveObject | specifies a ref to the active SubForm in an MDI application
MDIMenu | nominates a particular Menu to be the MDI application menu
Metafile | accesses clipboard data in Windows Metafile format
MethodList | reports the names of methods provided by an OLE Control
MinButton | determines whether a Form has a "minimize" button
MinDate | Specifies the smallest date that may be displayed by a Calendar object
MonthDelta | specifies the number of months by which a Calendar object scrolls when the user clicks its scroll buttons
Moveable | determines whether a Form may be moved on the screen
MultiColumn | specifies whether or not a List displays items in more than one column
MultiLine | determines whether or not the tabs or buttons will be arranged in multiple flights or multiple rows/columns in a TabControl or ToolControl object
MultiSelect | specifies whether or not the user can select more than one button in a TabControl at the same time
NewLine | specifies whether or not a CoolBand starts a new row in a CoolBar
Note | specifies additional text for a CommandLink Button
OLEControls | reports the names of OLE Controls installed on the computer
OnTop | specifies that a Form is permanently raised to the front or specifies the level at which a graphic is drawn on a Grid
Orientation | specifies the orientation of the Printer
OtherButton | Specifies whether or not a ColorButton object displays an Other button, that allows access to custom colours
OverflowChar | specifies the character to be displayed in a Grid cell to indicate that its contents will not fit
Page | specifies the width of the paper for a RichEdit
PageActive | specifies the name of the current PropertyPage in a PropertySheet
PageActiveObject | specifies a ref to the current PropertyPage in a PropertySheet
PageSize | specifies the size of the thumb in a scrollbar
ParaFormat | specifies paragraph formatting for a RichEdit
Password | specifies the symbol for a password field
Picture | specifies a Bitmap, Icon or Metafile object to be drawn
PName | specifies the device for a Printer object, or the face name for a Font
Points | specifies points for graphical objects
Popup | specifies the name of a (popup) Menu object that is associated with a ToolButton
Posn | specifies the position of an object within its parent
PrintList | reports the list of installed printers
ProgressStyle | specifies the appearance of a ProgressBar control
PropList | reports the list of properties applicable to the object
QueueEvents | specifies how events are handled for an instance of an OCXClass object (an ActiveX control)
Radius | specifies the radius for a Circle
Range | specifies the range of a scrollbar
ReadOnly | specifies whether or not the user may change data in an Edit orSpinner, or the State of a Button
RealSize | specifies the size of a placeable Metafile
Redraw | specifies whether or not an object is automatically redrawn when required
RemoteAddrName | specifies the host name of the remote computer to which you wish to make a TCP/IP connection
RemoteAddr | identifies the port number associated with a service on a remote computer
RemotePortName | specifies the port name of the remote service to which you wish to make a TCP/IP connection
RemotePort | identifies the port number associated with a service on a remote computer
ReportBCol | specifies background colours for items in a ListView in Report View
ReportImageIndex | specifies images for individual column titles in a ListView in Report View
ReportInfo | specifies additional information for a ListView
ResizeCols | specifies whether or not the user may alter the width of columns in a Grid by dragging
ResizeColTitles | specifies whether or not the user may alter the height of the column titles in a Grid by dragging
ResizeRows | specifies whether or not the user may alter the height of rows in a Grid by dragging
ResizeRowTitles | specifies whether or not the user may alter the width of the row titles in a Grid by dragging
Rotate | specifies the angle of rotation for a font
RowHiddenDepth | identifies which rows in a Grid are hidden
RowLineTypes | specifies the appearance of horizontal grid lines in a Grid
Rows | number of rows displayed in drop-down list of a Combo
RowTitleAlign | specifies the alignment of the row titles in a Grid
RowTitleBCol | specifies the background colour for row titles
RowTitleDepth | specifies the structure of hierarchical row titles in a Grid
RowTitleFCol | specifies the colour of the row titles in a Grid
RowTitles | specifies the row titles for a Grid
RowTreeDepth | specifies the structure of rows for a Grid
RowTreeImages | specifies the images (bitmaps) for the treeview items in a Grid
RowTreeStyle | specifies the appearance of treeview items in a Grid
RTFText | specifies the contents of an object in Rich Text Format
RunMode | specifies the way in which an OLEServer object serves multiple clients
ScrollOpposite | specifies that unneeded tabs scroll to the opposite side of a TabControl
SelDate | identifies the range of dates that is currently selected in a Calendar object
SelectionBorderWidth | specifies the width of the border drawn around the block of selected cells in a Grid
SelectionColor | specifies the colour of the block of selected cells in a Grid
SelectionColorAlpha | specifies the transparency of the block of selected cells in a Grid
SelImageIndex | specifies which images in an ImageList are used to identify selected items in a TreeView
SelItems | specifies the selected item(s) in an object
SelRange | specifies the selected range in a TrackBar
SelText | specifies the selected text in an Edit or Combo
ServerVersion | specifies the version number of an OLEServer object
ShowCaptions | specifies whether or not the captions of individual ToolButton objects are drawn
ShowCueWhenFocused | specifies whether or not a Cue is displayed when the input field receives the input focus
ShowDropDown | specifies whether or not a drop-down menu symbol is drawn in a ColorButton or alongside ToolButton objects
ShowInput | determines how Combo and Button objects associated with cells of a Grid are displayed
ShowSession | specifies whether or not the APL Session window is displayed when an OLEServer object is started by an OLE client
ShowThumb | specifies whether or not the thumb is displayed in a TrackBar
SingleClickExpand | specifies whether or not an item in a TreeView control is expanded when the user selects the item
SIPMode | specifies the behaviour of the Input Panel (PocketAPL only)
SIPResize | specifies the resize behaviour of a Form when the Input Panel is raised and lowered. (PocketAPL only)
Sizeable | specifies whether user may resize an object using the mouse
Size | specifies the size of an object
SocketNumber | reports the Window handle of the socket attached to the TCPSocket object
SocketType | specifies the type of the TCP/IP socket for a TCPSocket object
SortItems | specifies whether or not the items in a List object are sorted
SplitObj1 | specifies the name of an object managed by a Splitter
SplitObj2 | specifies the name of an object managed by a Splitter
Start | specifies start angles for arcs of Circle and Ellipse objects
State | specifies the state of a Button or Form
Step | increments for movement
Style | specifies the style of an object
SysMenu | determines whether a Form has a standard system menu
TabFocus | specifies the focus behaviour for the TabControl object
TabIndex | Specifies the tabbing order for controls
TabJustify | Specifies the positions at which the picture and caption are drawn within a TabButton
TabObj | specifies name of SubForm associated with a TabBtn
TabSize | specifies the size of fixed size tabs or buttons in a TabControl object
TargetState | reports the intended final state of a TCPSocket object
Text | specifies/reports the text in an Edit, MsgBox, or Combo
TextSize | reports the bounding rectangle for text
Thumb | specifies the position of the thumb in a scrollbar
ThumbRect | reports the extents of the thumb in a TrackBar
TickAlign | specifies the alignment of tick marks in a TrackBar
TickSpacing | specifies the spacing of tick marks in a TrackBar
TipObj | specifies the object in which to display the Tip
Tip | specifies the text for a pop-up help message
TitleHeight | specifies the height of the column titles in a Grid
Title | specifies the width of the row titles in a Grid
Today | specifies today's date in a Calendar object
ToolboxBitmap | reports the bitmap image associated with an OLE Control
TrackRect | reports the extents of the slider in a TrackBar
Translate | specifies whether or not an object performs ⎕AV translation
Transparent | specifies whether or not a ToolControl is transparent
TypeLibFile | reports the name of the file in which the Type Library for an OLEServer object is stored
TypeLibID | reports the value of the globally unique identifier (GUID) of the Type Library associated with an OLEServer object
TypeList | reports the names of data types associated with an OLE Control
Type | specifies the type of an object
Underline | specifies whether or not a font is underlined
ValidIfEmpty | specifies whether or not an empty Edit object is deemed to be valid
VAlign | specifies vertical text alignment
Value | value of a number, date or time in an Edit or Label object
Values | the data matrix in a Grid
VariableHeight | specifies whether or not a CoolBar displays bands at the minimum required height, or all the same height
View | specifies how items in a ListView are arranged
Visible | specifies whether or not an object is currently visible
VScroll | specifies whether or not an object has a vertical scrollbar
WantsReturn | specifies how the Enter key is treated by an edit box
WeekNumbers | specifies whether or not a Calendar object displays week numbers
Weight | specifies the weight (boldness) of a font
WordFormat | specifies word formatting for a RichEdit
Wrap | specifies whether or not an object wraps its contents
XRange | specifies origin and scale on the x-axis
Yield | specifies how frequently Dyalog APL/W yields control
YRange | specifies origin and scale on the y-axis


Events A-Z
Event | Num | Description
All | 0 | This is shorthand for "all events". It is not an event in its own right. See Special Case for All events.
ActivateApp | 139 | User has switched to/from the APL application
AddCol | 153 | appended a column to a Grid object
AddRow | 152 | appended a row to a Grid object
AmbientChanged | 533 | reported when any of the ambient properties change in an application hosting an ActiveXControl object
AnimStarted | 294 | reported just before an AVI clip starts playing in an Animation object.
AnimStopped | 295 | reported just after an AVI clip stops playing in an Animation object.
BadValue | 180 | attempted to leave Edit object with invalid text
BalloonHide | 862 | reported when a BalloonTip is displayed
BalloonShow | 861 | reported when a BalloonTip disappears
BalloonTimeout | 863 | reported when a BalloonTip is dismissed
BalloonUserClick | 864 | reported when a BalloonTip is clicked
BeginEditLabel | 300 | signals the start of an edit operation in a ListView or TreeView object
CalendarDblClick | 273 | reported when the user double-clicks the left mouse button over a Calendar object
CalendarDown | 271 | reported when the user depresses the left mouse button over a Calendar object
CalendarMove | 274 | reported when the user moves the left mouse button over a Calendar object
CalendarUp | 272 | reported when the user releases the left mouse button over a Calendar object
CellChanged | 164 | modified and updated the contents of a cell in a Grid object
CellChange | 150 | modified the contents of a cell in a Grid object
CellDblClick | 163 | double-clicked the mouse on a cell in a Grid
CellDown | 161 | depressed a mouse button over a cell in a Grid
CellError | 157 | input invalid data into a cell in a Grid
CellMove | 151 | moved to a new cell in a Grid object
CellOver | 160 | mouse moved over a cell in a Grid object
CellUp | 162 | released a mouse button over a cell in a Grid
Change | 36 | altered the text in an Edit or Combo
ClickComment | 225 | user has clicked the mouse in a comment window of a Grid
ClipChange | 120 | data in the clipboard has changed
Close | 33 | Form is about to be closed
CloseUp | 46 | reported by a DateTimePicker object just before the drop-down calendar is hidden
ColorChange | 430 | user has selected a colour in a ColorButton
ColumnClick | 320 | user has clicked on a heading in a ListView
Configure | 31 | position and/or size of an object is about to change
ContextMenu | 410 | user has performed a standard Windows action to display a ContextMenu
Create | 34 | reported after an object has been created
DateTimeChange | 267 | user has changed the DateTime value in a DateTimePicker object
DDE | 50 | DDE message has been received or sent
DisplayChange | 137 | user has changed screen resolution or number of colours
DockAccept | 483 | reported by a host object just before it accepts a client object docking operation
DockCancel | 485 | user has aborted a docking operation by pressing Escape
DockEnd | 484 | reported by a client object after it has been successfully docked in a host object
DockMove | 481 | reported by a host object when a dockable object (the client) is dragged over it
DockRequest | 482 | reported by a client object just before it is docked in a host object, when the user releases the mouse button
DockStart | 480 | reported by a client object when the user starts to drag it using the mouse
DragDrop | 11 | moved an object using drag & drop operation
DropDown | 45 | user has clicked the drop-down button in an object, just before the drop-down part is displayed
DropFiles | 450 | user has drag/dropped a file icon onto an object
DropObjects | 455 | user has drag/dropped an object icon from the Workspace Explorer or Find Objects tool onto an object
DyalogCustomMessage1 | 95 | allows external applications and dynamic link libraries to insert events into the Dyalog APL/W message queue
EndEditLabel | 301 | signals completion of an edit operation in a ListView or TreeView object
EndSplit | 282 | reported when user releases the left mouse button to signify the end of a drag operation on a Splitter object
ExitApp | 132 | selected End Task from the Windows Task List
ExitWindows | 131 | requested Windows to terminate
Expanding | 302 | reported by a TreeView object as it is about to expand
Expose | 32 | exposed part or all of a Form or a Static
FileBoxCancel | 72 | selected the Cancel button in a FileBox
FileBoxOK | 71 | selected the Ok button in a FileBox
FontCancel | 242 | user has pressed the Cancel button or closed the font selection dialog box
FontOK | 241 | user has pressed the OK button in the font selection dialog box
FrameContextMenu | 411 | user has clicked the right mouse button over the non-client area of an object
GesturePan | 494 | generated by a Pan gesture
GesturePressAndTap | 497 | generated by a press-and-tap gesture
GestureRotate | 495 | generated by a rotate gesture
GestureTwoFingerTap | 496 | generated by a two-finger-tap gesture
GestureZoom | 493 | generated by a zoom gesture
GetDayStates | 266 | reported when a Calendar object requires the Dyalog program to provide day state information for the range of dates it is about to display
GetTipText | 325 | reported by a TreeView or ListView object just before it displays a tip for a specific row
GotFocus | 40 | user has moved the keyboard focus to a new object
GridCopy | 191 | reported when the user presses Ctrl+Insert and there are selected cells in the Grid
GridCopyError | 196 | the user has pressed Ctrl+Insert and there is more than one block of selected cells in the Grid and the blocks are non-conformable
GridCut | 190 | the user has pressed Shift+Delete and there are selected cells in the Grid
GridDelete | 193 | the user has pressed Delete and there are selected cells in the Grid
GridDropSel | 195 | the user has drag/dropped a selected block of cells in the Grid
GridKeyPress | 24 | user has pressed a key in a Grid cell
GridPaste | 192 | the user has pressed Shift+Insert and there is data in the clipboard that is in a suitable format for the Grid
GridPasteError | 194 | the user has pressed Shift+Insert and there is data in the clipboard, but the system is unable to paste the data into the Grid
GridSelect | 165 | user has changed the selection in a Grid
Help | 400 | user has clicked the Question (?) button and then clicked on an object
HideComment | 224 | generated just before a comment window is hidden as a result of the user moving the mouse-pointer away from a commented cell
HScroll | 39 | requested movement in horizontal scrollbar of Form
HThumbDrag | 442 | user has dragged the thumb of the horizontal scrollbar of a Form or SubForm
Idle | 130 | generated when system is idle
IndexChanged | 210 | user has scrolled the data in a Grid so that the value of its Index property has changed
ItemDblClick | 342 | user has double-clicked on an item in a ListView or TreeView object
ItemDown | 340 | user has depressed the left mouse button over an item in a ListView or TreeView object
ItemUp | 341 | user has released the left mouse button over an item in a ListView or TreeView object
KeyError | 23 | pressed an invalid key on the keyboard
KeyPress | 22 | pressed a key on the keyboard
Locator | 80 | terminated interaction with a Locator object
LostFocus | 41 | object has lost the input focus
MDIActivate | 42 | MDI SubForm becomes the active one
MDIDeactivate | 43 | MDI SubForm is deactivated
MouseDblClick | 5 | double-clicked a mouse button
MouseDown | 1 | pressed mouse button down
MouseEnter | 6 | moved the mouse into the object
MouseLeave | 7 | moved the mouse out of the object
MouseMove | 3 | user has moved the mouse
MouseUp | 2 | user released a mouse button
MouseWheel | 8 | user rotated the mouse wheel
MsgBtn1 | 61 | user selected first button in a MsgBox
MsgBtn2 | 62 | user selected second button in a MsgBox
MsgBtn3 | 63 | user selected third button in a MsgBox
PageActivate | 360 | user has switched to a new PropertyPage
PageApply | 350 | user has clicked Apply in a PropertySheet
PageBack | 353 | user has clicked Back in a PropertySheet
PageCancel | 351 | user has clicked Cancel in a PropertySheet
PageChanged | 356 | user has altered Changed property of a PropertyPage
PageDeactivate | 361 | user has switched to a new PropertyPage
PageFinish | 355 | user has clicked Finish in a PropertySheet
PageHelp | 352 | user has clicked Help in a PropertySheet
PageNext | 354 | user has clicked Next in a PropertySheet
PreCreate | 534 | Reported when an instance of an ActiveXControl is created
Protected | 470 | user has attempted to alter protected text in a RichEdit object
Retracting | 304 | reported by a TreeView object as it is about to retract
Scroll | 37 | requested a movement of the thumb in scrollbar
SelDateChange | 265 | reported when the user changes the date that is selected in a Calendar object
Select | 30 | user has selected the object
ServiceNotification | 94 | reported when Windows requests a change in the state of an APL service
SetColSize | 176 | generated when column width changes in a Grid
SetItemPosition | 322 | generated when the user drag-drops an item in a ListView
SetRowSize | 175 | generated when row height changes in a Grid
SetSpinnerText | 421 | user has clicked a spin button in a Spinner object
SetWizard | 365 | user has clicked Next or Back in a PropertySheet
ShowComment | 223 | generated when the user rests the mouse pointer over a commented cell
Spin | 420 | user has clicked a spin button in a Spinner object
Splitting | 281 | reported while a Splitter object is being dragged, between a StartSplit and an EndSplit
StartSplit | 280 | reported when the user depresses the left mouse button over a Splitter object
StateChange | 35 | Form is about to change state
SysColorChange | 134 | system colour scheme has changed
TCPAccept | 371 | reported when a client connects to a server TCPSocket object
TCPClose | 374 | reported when the remote end of a TCP/IP connection breaks the connection
TCPConnect | 372 | reported when a server accepts the connection of a client TCPSocket object and is reported by the client
TCPError | 370 | generated when a fatal TCP/IP error occurs and is reported by a TCPSocket object
TCPGotAddr | 377 | reported when a host name (specified by the RemoteAddrName or LocalAddrName property) is resolved to an IP address
TCPGotPort | 378 | reported when a port name (specified by the RemotePortName or LocalPortName property) is resolved to a port number
TCPReady | 379 | reported when the TCP/IP buffers are free and there is no data waiting to be sent in the internal APL queue
TCPRecv | 373 | reported when data is received by a TCPSocket object
ThumbDrag | 440 | user is dragging the thumb in a TrackBar
Timer | 140 | event generated by a Timer object
VScroll | 38 | requested movement in vertical scrollbar of Form
VThumbDrag | 441 | user has dragged the thumb of the vertical scrollbar of a Form or SubForm
WinIniChange | 133 | WIN.INI has changed


Methods A-Z
Method | Num | Description
Abort | 103 | abort a print job
AddChildren | 310 | adds child items to an item in a TreeView
AddComment | 220 | adds a comment to a Grid
AddItems | 308 | adds items to a TreeView
Animate | 29 | produces special effects when showing or hiding objects
AnimClose | 291 | closes the AVI file that is currently loaded in an Animation object.
AnimOpen | 290 | opens an AVI file in an Animation object.
AnimPlay | 292 | plays an AVI clip in an in an Animation object.
AnimStop | 293 | stops an AVI clip that is playing in an in an Animation object.
Browse | 585 | retained for compatibility with previous versions of Dyalog, but is no longer relevant and has no effect
CancelToClose | 367 | changes the buttons in a PropertySheet
CellFromPoint | 200 | converts from Grid coordinates to cell coordinates
ChooseFont | 240 | displays the standard Windows font selection box
ColChange | 159 | sets new values for a column of cells in a Grid
ColSorted | 174 | sets the sort image to be displayed in the column title of a Grid
DateToIDN | 264 | Converts a date from ⎕TS format into an IDN suitable for use in a Calendar object
DelCol | 155 | deletes a column from a Grid object
DelComment | 221 | deletes a comment from a Grid
DeleteChildren | 311 | deletes child items from a parent item in a TreeView
DeleteItems | 309 | deletes items from a TreeView
DeleteTypeLib | 521 | removes a loaded Type Library from the workspace
DelRow | 154 | deletes a row from a Grid object
Detach | 270 | detaches the GUI component from an object
DuplicateColumn | 178 | Duplicates a column in a Grid object
DuplicateRow | 177 | Duplicates a row in a Grid object
FileRead | 90 | causes a graphical object to be read from a file
FileWrite | 91 | causes a graphical object to be written to a file
Flush | 135 | flushes all pending output
GetBuildID | 992 | obtains the Build ID of a Dyalog executable.
GetCellRect | 201 | obtains the extents of a particular Grid cell
GetCommandLine | 145 | obtains the entire command line that was used to start Dyalog APL
GetCommandLineArgs | 148 | obtains the command line and arguments (as a nested vector) that was used to start Dyalog APL
GetComment | 222 | obtains the comment associated with a cell in a Grid
GetEnvironment | 510 | obtains information about one or more Dyalog parameters
GetEventInfo | 551 | obtains information about an OLE Control event
GetFocus | 511 | obtains the name of the object that currently has the input focus
GetItemHandle | 313 | obtains the window handle of an item in a TreeView
GetItemPosition | 323 | obtains the position of an item in a ListView
GetItemState | 306 | obtains the status of an item in a TreeView
GetMethodInfo | 552 | obtains information about an OLE Control method
GetMinSize | 275 | Obtains the minimum size that you must specify for a Calendar object for it to display a complete month
GetParentItem | 312 | obtains the index of the parent of an item in a TreeView
GetPropertyInfo | 550 | obtains information about an OLE Control property
GetServiceState | 92 | obtains the state of an APL service
GetTextSize | 146 | obtains the size of the bounding rectangle of a text item in a given font
GetTypeInfo | 553 | obtains information about an OLE Control data type
GetVisibleRange | 262 | Obtains the range of dates that is currently visible in a Calendar object
GreetBitmap | 138 | Displays or remove a bitmap, typically during initialisation of a Dyalog runtime application
IDNToDate | 263 | Used to convert a date from an IDN into ⎕TS format
ListTypeLibs | 520 | Obtains the names and CLSIDs of all the loaded Type Libraries.
LockColumns | 227 | Locks/unlocks columns in a Grid object
LockRows | 226 | Locks/unlocks rows in a Grid object
MakeGIF | 261 | Generates a GIF representation of a picture from a Bitmap object
MakePNG | 260 | Generates a PNG representation of a picture from a Bitmap object
MDIArrange | 112 | MDIClient to arrange minimised SubForm icons
MDICascade | 110 | MDIClient to overlap its SubForms
MDITile | 111 | MDIClient to rearrange SubForms in row or column
NameFromHandle | 136 | obtains the name of an object from its handle
NewPage | 102 | throws a new page on a Printer
OLEAddEventSink | 540 | Connects a named event sink to a COM object
OLEDeleteEventSink | 541 | Disconnects a named event sink from a COM object
OLEListEventSinks | 542 | Returns the names of event sinks that are currently connected to a COM object
OLEQueryInterface | 543 | Used to obtain the methods and properties associated with a particular interface that is provided by a COM object
OLERegister | 530 | used to register an OLEServer object and may be used to install Dyalog OLE Servers as part of a run-time installation
OLEUnregister | 531 | used to unregister an OLEServer object that has previously been saved by Dyalog APL
Print | 100 | spools Printer output
ProgressStep | 250 | increments the thumb in a ProgressBar
RowChange | 158 | sets new values for a row of cells in a Grid
RowSetVisibleDepth | 173 | set the maximum visible depth of data in rows of a Grid
RTFPrint | 461 | prints the contents of a RichEdit
RTFPrintSetup | 460 | displays a print setup dialog box
SetCellSet | 171 | changes CellSet property for a cell in a Grid.
SetCellType | 156 | changes CellTypes property for a cell in a Grid
SetEventInfo | 547 | Used to register an event that may be generated by an ActiveXControl object
SetFinishText | 366 | sets the caption of the Finish button in a Wizard-style PropertySheet.
SetFnInfo | 545 | Used to describe an APL function that is to be exported as a method, or as a property, of an ActiveXControl object
SetServiceState | 93 | sets the state of an APL service
SetItemImage | 315 | allocates a picture icon to an item in a TreeView
SetItemState | 307 | sets the status of an item in a TreeView
SetMethodInfo | 556 | Used to describe a method that is exported by a COM object
SetPropertyInfo | 554 | Used to describe a property that is exported by a COM object
Setup | 101 | displays printer setup dialog box
SetVarInfo | 546 | Used to describe an APL variable that is to be exported as a property of an ActiveXControl object
ShowBalloonTip | 860 | displays a BalloonTip
ShowHelp | 580 | displays the help file associated with an OLE Control
ShowItem | 316 | displays a particular item in a TreeView
ShowProperties | 560 | displays the property sheet associated with an OLE Control
ShowSIP | 25 | Raise or lowers the Input Panel (Pocket APL only)
TCPGetHostID | 376 | obtains the IP Address of your PC
TCPSend | 375 | used to send data to a remote process connected to a TCPSocket object
TCPSendPicture | 380 | Transmits a picture represented by a Bitmap object to a TCP/IP socket
Undo | 170 | reverses last change made to a Grid object
Wait | 147 | same as executing ⎕DQ on the object


ActiveXContainer Object
Parents Properties Methods Events
Purpose: The ActiveXContainer object represents the application that is currently hosting an instance of an ActiveXControl object.

Description

An ActiveXContainer is used to represent the host application that is hosting an ActiveXControl object, and provides access to its ambient properties such as font, and colour.

An ActiveXContainer object is created using the Container property of the ActiveXControl object.

For example, the following expression, executed within an ActiveXControl instance creates an ActiveXContainer named 'CONT'

      'CONT' ⎕NS ⎕WG'Container'

The ambient properties of the host application are reported by the FontObj, BCol and FCol properties which are all read-only.

The ActiveXContainer object supports the AmbientChanged event which is reported when any of the ambient properties change. This event allows the ActiveXContainer to react to such changes.


ActiveXControl Object
Parents Children Properties Methods Events
Purpose: The ActiveXControl object represents a Dyalog APL namespace as an ActiveX control.

Description

The ActiveXControl object represents a Dyalog APL namespace as an ActiveX control.

During development, an ActiveXControl is a container object that is the child of a Form and acts as a wrapper for one or more other GUI objects.

To make an ActiveXControl available to another application, you must select Make OCX from the Session File menu. This creates an .OCX file that contains your entire workspace and all of the ActiveXControls within it.

Once an ActiveXControl has been saved in an .OCX file, any application that supports ActiveX may create and use instances of it.

When an ActiveX control is loaded by a host application, it and any code that it requires, is loaded into the host application's address space; it does not run in a separate address space.

During development, an ActiveXControl is powered by the development version of Dyalog APL. However, an ActiveXControl object that is loaded by a host application, is powered by a DLL version of Dyalog APL. This automatically gets loaded when a host application creates the first instance of any Dyalog APL ActiveX control. However, within a single host application, other instances of the same or other Dyalog APL ActiveX controls share the same copy of DYALOG.DLL.

Like the development and run-time versions of Dyalog APL, DYALOG.DLL has an active workspace. When an application loads an ActiveXControl, DYALOG.DLL copies the top-level namespace that owns the ActiveXControl, together with everything it contains, into the active workspace. For example, if the ActiveXControl is named Controls.Form1.Ctrl1, the act of creating the first instance of Ctrl1 will cause the entire contents of the Controls namespace to be copied, from the corresponding .OCX file, into the active workspace. This affords the potential for controls from different OCX files to clash, but the name clash conflict is restricted to just one name.

Each instance of an ActiveXControl, is represented by a separate namespace which is automatically cloned from the original ActiveXControl namespace. Each instance namespace is entirely separate from any other instance namespace and there is no way for one instance to reference or see any other instance; nor can it reference the original class namespace from which it was cloned. In fact, each instance appears to itself to be the one and only original class namespace. Using the previous example, each instance of Ctrl1 believes that its full pathname is #.Controls.Form1.Ctrl1, although each instance is in fact a separate clone of that namespace.

When an application creates an instance of an ActiveXControl, it does so as the child of some object within its own GUI hierarchy. From the instance's viewpoint, its parent Form is replaced by a different GUI object that imposes position, size, font, background colour, and other ambient properties.

The external name of an ActiveXControl is made up of the character vector defined by the ClassName property, prefixed by the string "Dyalog ", and followed by the string " Control". If ClassName is empty (which is the default), the name of the ActiveXControl namespace is inserted instead. Note that the name should not include APL symbols such as ∆.ClassName may only be specified when you create the ActiveXControl with ⎕WC and may not be changed using ⎕WS.

The Coord property is read-only and its value is always 'Pixel'. If you wish to use a different co-ordinate system for the children of an ActiveXControl object, it is necessary to set Coord separately on each one of them.

Posn and Size are negotiable properties. When an instance of the ActiveXControl is created, the values of Posn and Size will be assigned by the host application. You may change these values using ⎕WS, but the host application has the right to refuse them and there is no guarantee that you will get what you set.

The Border and EdgeStyle properties may be used to control the outline appearance of the ActiveXControl object.

The Dragable and KeepOnClose properties apply only during development and are otherwise ignored.

The ToolboxBitmap property specifies the name of a Bitmap object that may be used by a host application to represent the ActiveXControl when its complete visual appearance is not required.. For example, if you add an ActiveX control to the Microsoft Visual Basic development environment, its bitmap is added to the toolbox. The Bitmap should therefore be of an appropriate size, usually 24 x 24 pixels.

The Container property provides access to an ActiveXContainer object that represents the host application itself. This may be used to obtain the values of ambient properties, or to access methods exposed by the host application via OLE interfaces.

When an instance of an ActiveXControl is created, it generates first a PreCreate event, and then a Create event. The PreCreate event is generated at the point the instance is made.

The Create event is generated at the point when the host application requires the instance to appear visually. If, as is recommended, you create child controls of the instance when it is created, you must respond to the Create event, because at the time that PreCreate is generated, the object does not have a window.

Host applications which support two different modes of operation, namely design mode and run mode, differ in the way that they create instances of ActiveX controls. Microsoft Access does not require an ActiveX control to appear properly in design mode. Instead, it draws a simple box containing just the name of the object. If your ActiveXControl is hosted by Microsoft Access, it will get a PreCreate Event when an instance is created in design mode, and a Create event only when it enters run mode. Microsoft Visual Basic, however, requires the object to draw itself immediately, even in design mode, and so a Create event will be generated immediately after a PreCreate event in this case.


Animation Object
Parents Children Properties Methods Events
Purpose: The Animation object displays simple animations from basic .AVI files or resources.

Description

The Animation object displays simple animations from basic .AVI files or resources.

The Animation object can only play AVI files or resources that have no sound and can only display uncompressed AVI files or .AVI files that have been compressed using Run-Length Encoding (RLE).

For more sophisticated animations, you may use the Windows Media Player (OCX).

To display an AVI file, you must first use the AnimOpen method to open it. If the AutoPlay property is set to 1, the animation will play immediately. Otherwise, only the first frame will be displayed.

The Align property may be 'None' or 'Centre' ('Center'). If Align is 'None', the Animation window is automatically resized to fit the AVI being played. If Align is 'Centre', the AVI is centred in the Animation window. If the window is too small, the AVI is clipped.

The AnimPlay method may be used to play the animation and allows you to specify the start, number of frames, and repeat count.

The AnimStop method causes the animation to stop.

The AnimClose method closes the current AVI file and resets the contents of the object's window to its background colour.

The AnimStarted and AnimStopped events are reported when the animation starts and stops respectively.


Bitmap Object
Parents Children Properties Methods Events
Purpose: A graphical object used to represent a bitmap which may be used both to display a picture or as a pattern (brush) used to fill other objects.

Description

A Bitmap may be created either from a file (.BMP, .GIF or .PNG) or from APL arrays. To create a Bitmap object using ⎕WC, you can either specify the File property or the CBits property, or the Bits and CMap properties.

If you specify File, it should contain the name of a bitmap file from which the bitmap is to be read. If omitted, a .BMP file extension is added. You may also load a Bitmap from a DLL or from the DYALOG.EXE executable. See File property for details.

If instead you want to create a Bitmap dynamically from APL variables, you may do so in one of two ways.

For a palette of up to 256 colours, you may specify the image using the Bits and CMap properties. The alternative is to use the CBits property which works for any size of colour palette.

If MaskCol is non-zero, it specifies the transparent colour for the Bitmap. Any pixels specified with the same colour will instead be displayed in whatever colour is underneath the Bitmap. This achieves similar behaviour to that of an Icon.

The KeepBits property has the value 0 or 1, and controls how a Bitmap is saved in the workspace. A value of 0 (the default) means that the values of CBits, Bits and CMap are not kept in the workspace. If you request the values of CBits, Bits or CMap with ⎕WG, they are obtained directly from the corresponding Windows bitmap resource. When the workspace is )LOADed, the Bitmap is recreated from the associated file defined by the value of the File property. Note that if this file doesn't exist when the workspace is )LOADed, the Bitmap is not created, but no error is generated. However, when you reference the object you will get a VALUE ERROR.

If KeepBits is 1, the values of CBits, Bits and CMap are stored permanently in the workspace, and are used to rebuild the Bitmap when the workspace is )LOADed. In this case, the file name (if any) is ignored. Setting KeepBits to 1 uses more workspace, but may be more convenient if you want to distribute applications.

The Size property allows you to query the size of a Bitmap without having to retrieve the CBits or Bits property and then take its "shape". This will be noticeably faster for a large Bitmap. If you set the Size property using ⎕WS the Bitmap is scaled to the new size.

A useful feature of a Bitmap is that it can be the parent of any of the graphical objects. This allows you to create or edit a bitmap by drawing lines, circles, etc. in it.

The FileRead (90) and FileWrite (91) methods allow you to dynamically manage bitmap files (.BMP). The expression:

      bmname.FileWrite

causes the Bitmap called bmname to be written to the file specified by the current value of the File property. The file is automatically written in standard bitmap format. Similarly, the expression:

      bmname.FileRead

causes the Bitmap called bmname to be redefined from the bitmap file specified by the current value of the File property.

The MakeGIF and MakePNG methods may be used to convert the image represented by a Bitmap object into a GIF or PNG data stream, suitable for display in a web browser. The TCPSendPicture method may be used to transfer a Bitmap on a TCP/IP socket.

Using a bitmap is always a 2-stage process. First you create a Bitmap object with ⎕WC. Then you use it by specifying its name as a property of another object.

The Picture property specifies the name of a Bitmap to be displayed in an ActiveXControl, Button, Form, Group, Image, MDIClient, Sm, Static, StatusBar, StatusField, SubForm, TabBar, or ToolBar.

The BtnPix property specifies three Bitmaps to be used to represent the 3 states of a Button, Menu or MenuItem.

The FStyle property specifies the name of a Bitmap to be used as a pattern to fill a Poly, Ellipse or Rect object.


BrowseBox Object
Parents Children Properties Methods Events
Purpose: The BrowseBox object allows the user to browse for and select a folder or other resource.

Description

For full functionality as described here, the BrowseBox object requires the Windows Shell Library SHELL32.DLL Version 4.71 or higher. The BrowseBox object also supports the enhanced functionality provided by SHELL32.DLL Version 5 (Windows 2000) if present.

The BrowseBox object is a dialog box that allows the user to browse for and select a folder (directory) or other resource.

The BrowseFor property specifies the type of resource and may be 'Directory'(the default), 'File', 'Computer' or 'Printer'.

The StartIn property specifies the path name where browsing should start.

The HasEdit property specifies whether or not the dialog box contains an edit field into which the user can type the name of the folder or other resource, rather than browsing for it. The default is 0.

A BrowseBox may only be used by the execution of a modal ⎕DQ. The action code for the FileBoxOK and FileBoxCancel events must be set to 1 so that the appropriate result is returned by the modal ⎕DQ.

After the user has pressed OK or Cancel, the Target property contains the name of the chosen folder or other resource.

Example:

     ∇ DIR←{START_DIR}GetDir CAPTION;BB;MSG
[1]    ⍝ Ask user for a Directory name
[2]    ⍝ CAPTION specifies Caption for dialog box
[3]    ⍝ START_IN (optional) specifies starting directory
[4]    ⍝ DIR is empty if user cancels
[5]    :With 'BB'⎕WC'BrowseBox'
[6]        :If 2=⎕NC'START_DIR'
[7]            StartIn←START_DIR
[8]        :Else
[9]            StartIn←''
[10]       :EndIf
[11]       onFileBoxOK←onFileBoxCancel←1
[12]       Caption←CAPTION
[13]       HasEdit←1
[14]       MSG←⎕DQ''
[15]       :If 'FileBoxOK'≡2⊃MSG
[16]           DIR←Target ⍝ = 3⊃MSG
[17]       :Else
[18]           DIR←''
[19]       :EndIf
[20]   :EndWith
     ∇


Button Object
Parents Children Properties Methods Events
Purpose: Allows the user to initiate an action or to select an option using a button.

Description

The type of button displayed is determined by the Style property which may take the value 'Push', 'Radio', 'Check', 'Toggle', 'Split' or 'CommandLink'. Under Windows, 'Toggle' and 'Check' are treated identically.

'Split' and 'CommandLink' apply only to Windows Vista and later and require Native Look and Feel . Otherwise the use of these Styles will produce a Button with Style 'Push'.

Push buttons are used to generate actions. When the user "presses" a pushbutton, it generates a Select event (30). To cause an action, you simply associate the name of a callback function with this event for the Button in question.

Radio buttons and Check boxes are used to select options. They each have two states between which the user can toggle by clicking the mouse. When the Button (option) is selected, its State property has the value 1; otherwise it is 0.

Only one of a group of Radio buttons which share the same parent can be set (State is 1) at any one time. Radio buttons are therefore used for a set of choices that are mutually exclusive. Check boxes however, may be set together to signify a combination of options. These are used for making choices which are not mutually exclusive.

Radio and Check buttons also generate Select events when their State changes, and you can attach callback functions to these events to keep track of their settings. However, as Radio and Check buttons are not normally used to generate actions, it is perhaps easier to wait until the user signifies completion of the dialog box in some way, and then query the State of the buttons using ⎕WG. For example, if you have a set of Radio or Check buttons in a Group called f1.options, the following statements retrieve their settings.

      OPTIONS ← (⎕WN 'f1.options') ⎕WG¨⊂'State'

or

      OPTIONS ← ⎕WG∘'State' ¨ ⎕WN 'f1.options'

The Caption property determines the text displayed in the Button. Its default value is an empty vector. If the Caption property contains one or more linefeed characters (⎕UCS 10) the text is centre-justifed (Style 'Push' only) or top-left justified and automatically wraps on white-space characters (such as space and tab) to fit in the width provided.

If Style is 'Radio' or 'Check', the text may be aligned to the left or right of the button graphic using the Align property. Its default value is 'Right'.

The CommandLink button has an icon displayed to the left of its Caption. The appearance of the icon is controlled by the Elevated property. Elevation is a feature of User Account Control in Windows 7. In addition to the Caption, additional text may be defined by its Note property. If provided, this is displayed below the Caption.

The Split Button has a drop-down button, similar to that provided by a Combo object.

If Posn is omitted, the button is placed in the centre of its parent. If either element of Posn is set to ⍬, the button is centred along the corresponding axis.

If Size is not specified, the size of the button is determined by its Caption. If either element of Size is set to ⍬ the corresponding dimension is determined by the height or width of its Caption. This does not apply to multi-line buttons whose dimensions should be specified explicity. If Caption is not specified, or is set to an empty vector, the value of Size is set to a default value.

Button colours can be specified using FCol and BCol. However, pushbuttons (Style 'Push') ignore BCol and instead use the standard Windows colour.

The Picture property is used to display a bitmap on a pushbutton. This property is a 2-element array containing the name of a Bitmap object and the "mode" in which it is to be displayed. The default mode (3) is the most useful, as it causes the Bitmap to be superimposed on the centre of the Button. The surrounding edges of the Button (which gives it its 3-dimensional appearance and pushbutton behaviour) are unaffected. Note that if Picture is set on a Button whose Style is 'Radio' or 'Check', the Button assumes pushbutton appearance, although its 'Radio' / 'Check' behaviour is preserved.

An alternative is to use the BtnPix property. This property specifies the names of up to 3 Bitmap objects. The first Bitmap is displayed when the State of the Button is 0. The second is displayed when its State is 1. The third is shown when the Button is inactive (Active 0). BtnPix is more flexible than Bitmap, but if you want your Button to exhibit pushbutton behaviour, you must design your bitmap accordingly.

The ReadOnly property is Boolean and specifies whether or not the user may change the state of the Button. It applies only to Style 'Radio' and Style 'Check'.

The user can interact with the Button by clicking it, which generates a Select Event or (Style 'Split') the drop-down which generates a DropDown Event.


ButtonEdit Object
Parents Children Properties Methods Events
Purpose: Allows user to enter or edit data.

Description

The ButtonEdit object combines a single-line input field with a customisable button. It provides the same user and programmer interfaces as an Edit object (Style 'Single').

The appearance of the button, which is displayed to the right of the input field, is determined by the ImageListObj property. When clicked, the object generates a DropDown event. There is no default processing for this event; it is up to the programmer to take the appropriate action via a callback function.

The following picture illustrates two ButtonEdit objects

     ∇ Example;BK;White;dyalog
[1]    dyalog←2 ⎕NQ'.' 'GetEnvironment' 'Dyalog'
[2]    'F'⎕WC'Form' 'ButtonEdit'('Coord' 'Pixel')('Size' 200 240)
[3]    'F'⎕WS'Coord' 'Pixel'
[4]    'F.IL1'⎕WC'ImageList'('Size' 16 16)('Masked' 1)
[5]    'F.IL1.Time'⎕WC'Icon'(dyalog,'\ws\arachnid.ico')
[6]    'F.BE1'⎕WC'ButtonEdit' ''(30 20)(⍬ 200)
[7]    F.BE1.(Cue ShowCueWhenFocused)←'Enter data' 1
[8]    F.BE1.(ImageListObj ImageIndex)←F.IL1 1
[9]
[10]   'F.fnt'⎕WC'Font' 'APL385 Unicode' 16
[11]   BK←16 16⍴256⊥White←255 255 255
[12]   'F.Rotate'⎕WC'Bitmap'('CBits'BK)('MaskCol'White)
[13]   'F.Rotate.'⎕WC'Text' '⌽'(0 3)('FontObj'F.fnt)
[14]   BK←F.Rotate.CBits
[15]   'F.IL1.'⎕WC'Bitmap'('CBits'BK)('MaskCol'White)
[16]   'F.BE2'⎕WC'ButtonEdit' 'Hello World'(100 20)(⍬ 200)
[17]   F.BE2.(ImageListObj ImageIndex)←F.IL1 2
[18]   F.BE2.onDropDown←'Rotate'
     ∇

     ∇ Rotate msg
[1]    (⊃msg).Text←⌽(⊃msg).Text
     ∇

Note

For full functionality (in particular, for the Cue property to apply), the ButtonEdit object requires that Native Look and Feel is enabled.


Calendar Object
Parents Children Properties Methods Events
Purpose: The Calendar object provides an interface to the Month Calendar Control

Description

The Calendar object displays a calendar and allows the user to select a date or range of dates. The following illustration shows a default Calendar object.

The Calendar object will display as many full months as it can fit into the area specified by its Size property as shown below. The minimum size required to encompass a single month may be obtained using the GetMinSize method.

'F'⎕WC'Form' 'Example 2'('Size' 50 50)
'F.C'⎕WC'Calendar'('Size' 100 100)

The Today property is an IDN that specifies the current day. Its default value is today's date, i.e. the local date set on your computer.

The CircleToday property is either 0 or 1 (the default) and specifies whether or not the Today date is circled when the Calendar object is showing the corresponding month.

The HasToday property is either 0 or 1 (the default) and specifies whether or not the Today date is displayed (using the Windows short date format) in the bottom left of the Calendar object.

The WeekNumbers property is either 0 (the default) or 1 and specifies whether or not the Calendar displays week numbers.

The following example shows a Calendar with both CircleToday and HasToday set to 0 and WeekNumbers set to 1.

'F'⎕WC'Form' 'Example 3'('Size' 30 30)
'F.C'⎕WC'Calendar'('CircleToday' 0)('HasToday' 0)('WeekNumbers' 1)

The FirstDay property is an integer whose value is in the range 0-6. FirstDay specifies the day that is considered to be the first day of the week and which appears first in the Calendar. The default value for FirstDay depends upon your International Settings.

The MinDate and MaxDate properties are integers that specify the minimum and maximum IDN values that the user may display and select in the Calendar object. By default these properties specify the entire range of dates that the Windows Month Calendar control can provide.

The MonthDelta property specifies the number of months by which the Calendar object scrolls when the user clicks its scroll buttons. The default is empty (zilde) which implies the number of months currently shown.

The Style property may be either 'Single' (the default) or 'Multi'. If Style is 'Single', the user may select a single date. If Style is 'Multi', the user may select a contiguous range of dates. In this case, the maximum number of contiguous days that can be selected is defined by the MaxSelCount property which is an integer whose default value is 7.

The SelDate property is a 2-element integer vector of IDN values that identifies the first and last dates that are currently selected.

When the user selects one or more dates, the Calendar object generates a SelDateChange event. This event is also generated when the Calendar object is scrolled, and the selection changes automatically to another month.

The Calendar displays day numbers using either the normal or the bold font attribute and you may specify which attribute is to be used for each day shown. However, the Calendar object does not store this information beyond the month or months currently displayed.

When the Calendar control scrolls (and potentially at other times), it generates a GetDayStates event that, in effect, asks you (the APL program) to tell it which (if any) of the dates that are about to be shown should be displayed in bold.

If you wish any dates to be displayed using the bold font attribute, you must attach a callback function to the GetDayStates event which returns this information in its result. By default, all dates are displayed using the normal font attribute, so you only need a callback function if you want any dates to be displayed in bold.

You may also set the font attribute for particular days in the range currently displayed by calling GetDayStates as a method.

The CalendarCols property specifies the colours used for various elements in the Calendar object.

You may convert dates between IDN and ⎕TS representations using the IDNToDate and DateToIDN methods. Note that these methods apply to all objects and not just to the Calendar object itself.

The GetVisibleRange method reports the range of dates that is currently visible in the Calendar object.


Circle Object
Parents Children Properties Methods Events
Purpose: A Graphical object to draw circles, arcs, and pie-slices.

Description

The Points property contains the co-ordinates of the centre of the circle. The size of the circle is determined by the Radius property. This specifies the radius along the x-axis, the height is calculated so that the object is circular.

The RadiusMode property determines whether or not the circle is adjusted by a pixel, if required in order to appear perfectly round and perfectly centred. The default value is 0 (no adjustment is made).

The Start and/or End properties are used to draw partial circles. They specify start and end angles respectively, measuring from the x-axis in a counter-clockwise direction and are expressed in radians. The type of arc is controlled by ArcMode as follows :

ArcMode Effect

0 | An arc is drawn from Start to End.
1 | An arc is drawn from Start to End. In addition, a single straight line is drawn from one end of the arc to the other, resulting in a segment.
2 | An arc is drawn from Start to End. In addition, two lines are drawn from each end of the arc to the centre, resulting in a pie-slice

.

Points, Radius, Start and End can specify vectors so that several arcs, circles, pie slices, etc. can be drawn in one call (and with one name).

If Start is specified, but not End, end angles default to (¯1↓+\Start),○2. If End is specified, but not Start, start angles default to 0,¯1↓+\End

This means that you can draw a pie-chart using either Start or End angles; you do not have to specify both.

Examples:

A circle whose centre is (50,50) and radius 20

      'g.p1' ⎕WC 'Circle' (50 50) 20

An arc

      'g.arc' ⎕WC 'Circle' (50 50) 20 ('Start' (○0.75))('End' (○1.25))

Complete pie

      Data←12 27 21 40
      ANGLES←0,¯1↓((○2)÷+/Data)×+\Data
      COLS←(255 0 0)(0 255 0)(255 255 0)(0 0 255)
      PATS←1 2 3 4
      'g.pie' ⎕WC 'Circle' (50 50) 20 ('Start' ANGLES)
                  ('ArcMode' 2) ('FCol' (⊂0 0 0))
                  ('FStyle' PATS) ('FillCol' COLS)

Same pie as above, but 2nd slice is exploded by changing its centre and 4th slice is shrunk by reducing its radius :

      CY←50 52 50 50  ⍝ y-coord of centres
      R←20 20 20 17.5 ⍝ radii
      'g.pie' ⎕WC 'Circle' (50 CY) R ('Start' ANGLES)
                  ('ArcMode' 1) ('FCol' (⊂0 0 0))
                  ('FStyle' PATS) ('FillCol' COLS)


Clipboard Object
Parents Children Properties Methods Events
Purpose: This object provides access to the Windows clipboard.

Description

When an application places data in the Windows clipboard, it may store it in one or more formats. An application wishing to retrieve data from the clipboard can then choose which format to read it in. Dyalog APL supports standard clipboard formats, including CF_TEXT, CF_BITMAP and CF_METAFILE. If there is any data in the clipboard, the Formats property lists the formats in which it may be retrieved.

In addition, the Array property may be used to set or retrieve clipboard contents in Dyalog APL array format.

Data is read from the clipboard using ⎕WG, specifying the name of the appropriate property for the data that you want.

If the data has been stored in CF_Text format, the value of Formats will include 'Text' and you may retrieve the data by querying the value of the Text property with ⎕WG.

If the data has been stored in device-independent bitmap format, the value of Formats will include 'CBits', 'Bits' and 'CMap'. To retrieve the bitmap pattern and colour map, you may query the values of the CBits, or Bits and CMap properties using ⎕WG.

If the data has been stored in device-dependent bitmap format, only the bitmap pattern is available and Formats will contain 'Bits' but not 'CMap'. In this case you can query the Bits property but not CMap without which you cannot realise the bitmap. However, if data was posted in this format, it is highly probable that the current Windows colour map applies to it. For a standard 16-colour device this is given under the description of the CMap property.

The following example retrieves text from the clipboard :

      'CL' ⎕WC 'Clipboard'
      Data ← 'CL' ⎕WG 'Text'

The next example retrieves a bitmap from the clipboard and defines it as a Bitmap object named 'BM' ready for use :

      'BM' ⎕WC 'Bitmap' '', 'CL' ⎕WG 'Bits' 'CMap'

Data may be placed in the clipboard using ⎕WC or ⎕WS. To store text, you simply set the Text property. You may use a simple character vector or matrix, or a vector of character vectors. For example :

      'CL' ⎕WS 'Text' 'Hello World'

To store a bitmap you can set either the Picture property to the name of a Bitmap object, or you can set the Bits and CMap properties explicitly. The former is more efficient, especially for large bitmaps, for example :

      'CL' ⎕WS 'Bitmap' 'BM'

or

      Bits CMap ← 'BM' ⎕WG 'Bits' 'CMap'
      'CL' ⎕WS ('Bits' Bits)('CMap' CMap)

Note that if you use the latter method, you must set both properties in one ⎕WS statement. This is also true if you wish to store data in both Text and Bitmap formats together.

The Metafile property allows graphical information to be restored in and retrieved from the clipboard in Windows Metafile format. See the description of the Metafile property for details.

A ClipChange (120) event is generated when another application places data in the clipboard.


ColorButton Object
Parents Properties Methods Events
Purpose: The ColorButton object allows the user to select a colour.

Description

The ColorButton object displays a coloured box, with an optional drop down button. When the user clicks the ColorButton with the left mouse button, a colour selection drop-down appears below it, allowing the user to select a new colour.

The CurrentColor property (default 0 0 0) is a 3-element integer vector that specifies and reports the RGB value of the currently selected colour.

The DefaultColors property is a nested matrix which specifies the RGB values of the colours shown in the colour selection box. The shape of DefaultColors determines the number of rows and columns in the colour selection drop-down. Each element of DefaultColors is a 3-element integer vector specifying an RGB colour value.

The OtherButton property is Boolean and specifies whether or not the user can select a colour using the Windows colour selection dialog box.

If OtherButton is 1 (the default), the final row of the colour selection drop-down contains a button labelled "Other…". If the user clicks this button, the standard Windows colour selection dialog box is displayed, allowing the user to select any colour that the computer can render.

If OtherButton is 0, the button labelled "Other…" is not present and the user is restricted to the choice of colours provided by the DefaultColors property.

The CustomColors property is a 1-row, 16-column nested matrix which specifies the RGB values of the Colours displayed in the Custom colors section of the Windows colour selection dialog box. Each element of CustomColors is a 3-element integer vector specifying an RGB colour value.

The ShowDropDown property is Boolean (default 1) and specifies whether or not a drop-down button is displayed in the ColorButton object.

When the user clicks a ColorButton with the left mouse button, the object generates a DropDown event just before it displays the colour selection drop-down. This event may be used to set the DefaultColors and/or CustomColors properties dynamically.

When the user selects a new colour, the ColorButton generates a ColorChange event.

Note that Pocket PC 2002 colour selection dialog box does not provide the facility to select custom colours, so this functionality is not available in PocketAPL.


Combo Object
Parents Children Properties Methods Events
Purpose: This object combines an input area with a list box and allows the user to enter a selection by typing text or by choosing an item from the list.

Description

Three types of Combo box are provided by the Style property which may be 'Drop' (the default), 'Simple' or 'DropEdit'.

The Items property specifies the list of items which are displayed in the list box and from which the user can choose.

The SelItems property is a Boolean vector which specifies which (if any) of the items is selected. When the user chooses an item from the list, it is copied to the edit field and a Select event is generated. At this point you may use SelItems to identify the chosen item. You can also use SelItems to pre-select the contents of the edit field.

If the Style is 'Simple' or 'DropEdit', the user may type text into the edit field. In these cases, the contents of the edit field may also be specified or queried using the Text property.

Note that if the user first selects an item from the list box, then changes it in the edit field, the entry in the list box is automatically deselected. There is therefore no conflict between the value of Text and the value of SelItems.

Warning: Windows truncates the contents of the edit field (reflected in the value of the Text property) to 510 characters.

For a Combo with Style 'Simple', the Index property specifies or reports the position of Items in the list box as a positive integer value. If Index has the value "n", it means that the "nth" item in Items is displayed on the top line in the list box. Note that Index can only be set using ⎕WS and not by ⎕WC and is ignored if all the Items fit in the list box. The default value for Index is ⎕IO.

The SelText property identifies the portion of the edit field that is highlighted. It is not applicable to a Combo with Style 'Drop' as the user cannot enter or change data in its edit field.

The height of a Combo object with Style 'Drop' or 'DropEdit' is defined in a manner that is different from other objects. The height of the edit field is fixed, and is dependent only upon the size of the font. The height of the associated drop-down list box is determined by the Rows property. The first element of the Size property (height) is ignored. For a Simple combo box (whose listbox is permanently displayed), the overall height is determined by the first element of Size. Rows is a "read-only" property.

The VScroll property specifies whether or not a vertical scrollbar is provided. The default value 0 means no scrollbar, setting VScroll to ¯1 or ¯2 specifies that the Combo has a vertical scrollbar.

If the Style is 'Simple' or 'DropEdit', the HScroll property determines whether or not the edit field may be scrolled. If HScroll is 0, the data is not scrollable, and the user cannot enter more characters once the field is full. If HScroll is ¯1 or ¯2 the field is scrollable, and there is no limit on the number of characters that can be entered. In neither case however is a horizontal scrollbar provided. If Style is 'Drop', the user is not allowed to enter data into the edit field anyway, and the value of HScroll is ignored.

VScroll and HScroll may only be set when the object is created and may not subsequently be changed.

Note that when you change the Items property using ⎕WS, the Text, SelItems and SelText properties are all reset to their default values.

The Combo object will report a Select event (if enabled) when the user chooses an item from the list box. It will generate a Change event (if enabled) when the user manually alters the contents of the edit field and then changes the focus to another object.


ComboEx Object
Parents Children Properties Methods Events
Purpose: The ComboEx object is an extended version of the Combo object that provides additional features including item images

Description

The ComboEx object is a ComboBox that supports item images and indenting. It is a superset of the Combo object and supports all its functionality. For further details, see Combo.

For most purposes, you can use the ComboEx object in place of the Combo object whether or not you make use of the extended features of the ComboEx.

Like the basic Combo, the list of text items in the ComboEx is specified by the Items property. You may associate images with each of the text items using the ImageListObj, ImageIndex and SelImageIndex properties.

To do so, ImageListObj specifies the name of an ImageList object that contains a set of images. ImageIndex and SelImageIndex map individual images from the ImageList to each of the text items specified by Items. ImageIndex specifies the image to be displayed when the item is not selected; SelImageIndex specifies the image to be displayed when the item is selected.

The Indents property specifies the amount by which each of the items are indented in units of 10 pixels

The appearance of the items is additionally controlled by the EditImage and EditImageIndent properties. These are Boolean and their effect is summarised in the table below. Notice that Images are displayed only if both these properties are set to 1 (which is the default).

There are certain restrictions that apply to a ComboEx object with Style 'Simple', namely:

  • images and indents do not apply to the edit control portion of the object.
  • the object may not redraw properly if EditImage and/or EditImageIndent are set to 0 or if CaseSensitive or PathWordBreak are set to 1.
  • PathWordBreak does not work.
 | EditImageIndent
EditImage | 0 | 1
0 | No images displayed, item text is indented as specified by Indents | No images displayed, item text is indented as specified by Indents plus the width of the images in ImageList
1 | No images displayed, item text is indented as specified by Indents | Images are displayed, items are indented as specified by Indents


CoolBand Object
Parents Children Properties Methods Events
Purpose: The CoolBand object represents an area in a CoolBar that contains a child window.

Description

The CoolBand object is a container object that represents a band in a CoolBar.

A CoolBand can have any combination of a gripper bar, a bitmap, a text label, and a single child object.

A CoolBand may not contain more than one child object, but that child object may itself be a container such as a ToolControl or a SubForm.

The Caption property specifies a text string to be displayed to the left of the CoolBand. The colour of the text is specified by the FCol property.

The ImageIndex property specifies an optional picture which is to be displayed alongside the Caption. If specified, ImageIndex is an index into an ImageList whose name is referenced via the ImageListObj property of the parent CoolBar.

The background in a CoolBand may be specified using its BCol or Picture properties. Although typically, the visible background area is small, it is visible through a transparent ToolControl.

The ChildEdge property specifies whether or not the CoolBand leaves space above and below its child window.

The GripperMode property specifies whether or not the CoolBand has a gripper bar which is used to reposition and resize the CoolBand within its parent CoolBar. GripperMode may be 'Always'(the default), 'Never' or 'Auto'.

The position of a Cool Band within a CoolBar is determined by its Index and NewLine properties, and by the position and size of preceding CoolBand objects in the same CoolBar. For a CoolBand, Posn is a read-only property that reports its position but Posn may not be used to set it.

The Index property specifies the position of a CoolBand within its parent CoolBar, relative to other CoolBands and is ⎕IO dependant. Initially, the value of Index is determined by the order in which the CoolBands are created. You may re-order the CoolBands within a CoolBar, under program control, by changing Index with ⎕WS.

The NewLine property specifies whether or not the CoolBand occupies the same row as an existing CoolBand, or is displayed on a new line within its CoolBar parent. The value of NewLine in the first CoolBand in a CoolBar is always 1, even if you specify it to be 0. You may move a CoolBand to the previous or next row by changing its NewLine property (using ⎕WS) from 1 to 0, or from 0 to 1 respectively.

The 2nd element of the Size property determines the width of the CoolBand; the value of the 1st element is read-only.

Size may only be specified by ⎕WC. However, when you create a CoolBand, it will automatically occupy all the available space in the current row, to the right of any preceding CoolBands. Only when you create another CoolBand in the same row, will the Size of the first CoolBand be honoured. The rightmost CoolBand will always extend to the right edge of the CoolBar, whatever its Size.

If you create two or more CoolBands in the same row and you do not specify Size, the first CoolBand will be maximised, and the others minimised.

When the user drags a CoolBand to a different row its Index and NewLine properties may change, as may the Index and NewLine properties of any another CoolBand that is affected by the operation.

If you wish to remember the user's chosen layout when your application terminates, you must store the values of Index, Size and NewLine for each of the CoolBands. When your application is next started, you must re-create the CoolBands with the same values of these properties.


CoolBar Object
Parents Children Properties Methods Events
Purpose: The CoolBar object acts as a container for CoolBand objects.

Description

The CoolBar and CoolBand objects provide an interface to Windows Rebar Controls

A CoolBar contains one or more bands (CoolBand objects). Each band can have any combination of a gripper bar, a bitmap, a text label, and a single child object.

Using the gripper bars, the user may drag bands from one row to another, resize bands in the same row, and maximise or minimise bands in a row.

The following example illustrates a CoolBar containing 2 CoolBands each of which is displaying a ToolControl object.

'F'⎕WC'Form' 'CoolBar Object with ToolControls'('Size' 25 50)
'F.IL'⎕WC'ImageList'('Masked' 0)('MapCols' 1)
'F.IL.'⎕WC'Bitmap'('ComCtl32' 120)⍝ STD_SMALL

'F.CB'⎕WC'CoolBar'

:With 'F.CB.C1'⎕WC'CoolBand'
    'TB'⎕WC'ToolControl'('ImageListObj' '#.F.IL')
    'TB.B1'⎕WC'ToolButton' 'New'('ImageIndex' 7)
    'TB.B2'⎕WC'ToolButton' 'Open'('ImageIndex' 8)
    'TB.B3'⎕WC'ToolButton' 'Save'('ImageIndex' 9)
:EndWith

:With 'F.CB.C2'⎕WC'CoolBand'
    'TB'⎕WC'ToolControl'('ImageListObj' '#.F.IL')
    'TB.B1'⎕WC'ToolButton' 'Cut'('ImageIndex' 1)
    'TB.B2'⎕WC'ToolButton' 'Copy'('ImageIndex' 2)
    'TB.B3'⎕WC'ToolButton' 'Paste'('ImageIndex' 3)
    'TB.B4'⎕WC'ToolButton' 'Undo'('ImageIndex' 4)
    'TB.B5'⎕WC'ToolButton' 'Redo'('ImageIndex' 5)
:EndWith

The CoolBar allows the user to organise the CoolBands within it as required. The next three pictures illustrate this feature.

after user has moved band 2 into row 1

after user has maximised band 1

after user has maximised band 2

The second example illustrates a CoolBar containing 3 CoolBands displaying an Edit, Combo and multi-line Edit respectively.

'F'⎕WC'Form' 'CoolBar Object with simple controls'('Size' 25 40)
'F'⎕WS'Coord' 'Pixel'

'F.CB'⎕WC'CoolBar'

:With 'F.CB.C1'⎕WC'CoolBand'
    'E1'⎕WC'Edit' 'Edit1'
:EndWith

:With 'F.CB.C2'⎕WC'CoolBand'
    'C1'⎕WC'Combo'('One' 'Two' 'Three')('SelItems' 0 1 0)
:EndWith

:With 'F.CB.C3'⎕WC'CoolBand'
    'E2'⎕WC'Edit'(3 5⍴'Edit2')('Style' 'Multi')
:EndWith

The VariableHeight property specifies whether or not the CoolBar displays bands in different rows at the minimum required height (the default), or all the same height.

The BandBorders property specifies whether or not narrow lines are drawn to separate adjacent bands. The default is 0 (no lines).

The DblClickToggle property specifies whether or not the user must single-click (the default) or double-click to toggle a child CoolBand between its maximised and minimised state.

The FixedOrder property specifies whether or not the CoolBar displays CoolBands in the same order. If FixedOrder is 1, the user may move bands to different rows, but the band order is static. The default is 0. Note that when the user moves a CoolBand within a CoolBar, its Index and (potentially) NewLine properties will change to reflect its new position.

If you wish to display pictures in one or more of the CoolBands owned by a CoolBar, you do so by setting the ImageListObj property to the name of an ImageList object which contains the pictures. Pictures are allocated to individual CoolBands via their ImageIndex properties.


Cursor Object
Parents Children Properties Methods Events
Purpose: This object defines a cursor.

Description

The File property defines the name of a cursor file associated with the Cursor object, or it specifies the name of a DLL and the resource number or name of the cursor therein. If you omit the file extension, the system assumes .CUR. To use an animated cursor you must therefore specify the .AMI extension explicitly.

If the value of the File property is set by ⎕WS, no immediate action is taken, but the corresponding file may subsequently be read or written using the FileRead or FileWrite methods.

The Bits and Mask properties define the appearance of the cursor. Both are Boolean matrices with a shape of 32 32. The colour of each pixel in the cursor is defined by the following table. Note that a 0 in Bits combined with a 1 in Mask causes the corresponding pixel to be the colour of the background. This is used to give the cursor a non-rectangular shape.

Bits | 0 | 1 | 0 | 1
Mask | 0 | 0 | 1 | 1
Pixel | Black | White | Background | Inverse

The HotSpot property determines the point within the cursor that registers its position over another object.

A Cursor is used by setting the CursorObj property of another object to its name or ref.


DateTimePicker Object
Parents Children Properties Methods Events
Purpose: The DateTimePicker object is an editable date/time field with an optional drop-down Calendar.

Description

The DateTimePicker object represents the built-in Windows date and time picker control. For most purposes, the DateTimePicker supersedes the use of Label, Edit and Spinner objects for displaying and entering dates and times. Unlike the Edit and Spinner objects, it is not possible for the user to enter an invalid date or time into a DateTimePicker.

The Style property may be either 'Combo'(the default) or 'UpDown'. The former provides a drop-down calendar that behaves in the same way as the Calendar object and whose appearance and behaviour is controlled by a set of properties namely CalendarCols, CircleToday, HasToday, MaxDate, MinDate, MonthDelta, Today and WeekNumbers that are common to the Calendar. Note that the Style property may only be set when the object is created.

If Style is 'Combo', the Align property specifies the horizontal alignment of the drop-down Calendar which may be 'Left'(the default) or 'Right'.

If Style is 'UpDown', the DateTimePicker includes instead a pair of spinner buttons that allow the user to increment and decrement values in the various sub-fields provided by the control.

The DateTime property represents the date and time value that is currently displayed in the object. This is a 4-element vector containing the IDN, hour, minutes and seconds respectively.

The FieldType property specifies one of a set of pre-defined date/time formats to be used by the control. This is a character vector that may be empty (the default), 'Date', 'DateCentury', 'LongDate', 'Time'or 'Custom'. Specifying an empty vector is the same as specifying 'Date'. Note that 'DateCentury' always displays a 4-digit year, regardless of the user's Windows settings.

If FieldType is set to 'Custom', the format is defined by the CustomFormat property. CustomFormat is a character vector that may contain a mixture of date/time format elements and body text.

The HasCheckBox property is a Boolean value (default 0) that specifies whether or not a checkbox is displayed in the object. This allows the user to specify whether or not the date/time displayed in the DateTimePicker is applicable.


Edit Object
Parents Children Properties Methods Events
Purpose: Allows user to enter or edit data.

Description

The value of the Style property, which may be 'Single' or 'Multi', determines whether the object presents a single-line data entry field or an area for viewing and editing a large block of text.

Single-Line Edit

The FieldType property (which applies only to a single-line Edit object) is either an empty vector (the default) or specifies the type of the field as reflected by its Value property. If FieldType is empty, the Value of the field may be a number or a character vector, according to the contents defined by its Text property (this is always a character vector).

If FieldType is 'Char', the Value of the field is forced to be a character vector, even if the contents defined by its Text property is entirely numeric.

If FieldType is 'Numeric', 'LongNumeric', 'Currency', 'Date', 'LongDate', or 'Time' the Value contains a number. For fields of these types, basic validation is provided during user input. The field is revalidated when the user attempts to "leave" it and at this point the object will generate a BadValue event if its contents are inconsistent with its FieldType.

Note that when an Edit object is used as the Input property of a Grid, it is the Value of the Edit object (and not its Text property) that is used to update the Values property (i.e. the contents of) the Grid when the user moves away from the cell.

The MaxLength property defines the maximum number of characters that the user may enter into the object.

The ValidIfEmpty property may be 0 (the default) or 1 and specifies whether or not the Edit field is deemed to be valid if it is empty.

The Password property specifies the character that is displayed in response to the user typing a character. Normally, Password is empty (the default) and the object displays the character that was entered. However, if you set Password to (say) an asterisk (*) this symbol will be displayed instead of the characters the user has entered. Note however that the Text and Value properties will reflect what the user typed.

The HScroll property determines whether or not the data may be scrolled. If HScroll is 0, the data is not scrollable, and the user cannot enter more characters once the field is full. If HScroll is ¯1 or ¯2 the field is scrollable, and there is no limit on the number of characters that can be entered. In neither case however is a horizontal scrollbar provided. HScroll may only be set when the object is created and may not subsequently be changed.

Multi-Line Edit

If the Style is 'Multi', Text may set using a simple character vector, a simple matrix, or a vector of vectors. If Text is specified by a matrix or by a vector of vectors, "new-line" characters are automatically added at the end of each line in the Edit control.

The user may insert a "new-line" character in the text by pressing Ctrl-Enter. If Text was set by a matrix, it is returned as a matrix. Otherwise it is returned as a vector of vectors. "New-line" characters are not returned. If Text was not specified by ⎕WC or ⎕WS it is returned an empty matrix (1 0⍴''). However, if Text was not specified, but the user types and then empties the field, it is returned as an empty nested array (,⊂'')

The Justify property determines whether the text in a multi-line Edit object is 'Left', 'Right', or 'Centre' justified. Setting Justify to 'Centre' or 'Right' also forces word-wrapping and disables horizontal scrolling, whatever the value of HScroll. Note that the keyword 'Centre' may also be spelled 'Center'. Justify may only be specified when the object is created using ⎕WC.

If Justify is 'Left', the HScroll property determines whether or not text may be scrolled horizontally. If HScroll is set to ¯2, each individual line may be any length, but the object does not have a horizontal scrollbar. Sideways scrolling is achieved using the cursor keys, or by typing. If HScroll is ¯1, each individual line may be of any length and the object will have a horizontal scrollbar. If HScroll is 0, lines are automatically "word-wrapped" at the right edge of the object. This means that the number of lines displayed may be greater than the number of lines implied by the rows of the matrix or the number of vectors supplied. In particular, if you specify a single long vector, it will be broken up into lines for you on the display, but still returned as a single vector by ⎕WG.

The VScroll property determines whether or not data may be scrolled vertically and whether or not the object has a vertical scrollbar. A value of 0 inhibits scrolling; ¯2 means scrollable, without a scrollbar; ¯1 means scrollable with a scrollbar. VScroll may only be set when the object is created and may not subsequently be changed.

The setting of Justify forces word-wrapping.

The SelText property identifies the portion of the text that is selected. It may be used to pre-select (and highlight) a part of the text, or to report the part of the text selected by the user. SelText is a 2-element integer vector which specifies the start and end of the selected area. Its structure depends upon the nature of the data specified by Text. See the description of SelText for details.

If the user changes any data in the field and attempts to change focus to another object, the Edit object will generate a Change event. You can use this to validate the new data in the field.

Note

For full functionality (in particular, for the Cue property to apply), the Edit object requires that Native Look and Feel is enabled.


Ellipse Object
Parents Children Properties Methods Events
Purpose: A Graphical object to draw ellipses, arcs, and pie-slices.

Description

This object duplicates much of the functionality of the Circle object, but differs in two major respects. Firstly, ellipses, circles, and arcs are specified in terms of their bounding rectangles, rather than in terms of their centre(s) and radii. Secondly, the Ellipse object behaves like any other (rectangular) object when it is resized by its parent. The Circle object behaves differently in that when resized by its parent, it maintains a constant ratio between its physical height and width.

The Points property specifies one or more sets of co-ordinates which define the position(s) of one or more bounding rectangles. The position is defined to be the position of the corner that is nearest to the origin of its parent. The default is therefore its top-left corner.

The Size property specifies the height and width of each bounding rectangle, measuring away from the origin. To obtain a perfect circle, you must take the aspect ratio of the device into account. This is available from the DevCaps property of the Root and Printer objects. Alternatively you can use the Circle object.

The Start and/or End properties are used to draw partial ellipses and circles. They specify start and end angles respectively, measuring from the x-axis at the centre of the bounding rectangle in a counter-clockwise direction and are expressed in radians. The type of arc is controlled by ArcMode as follows:

ArcMode | Effect
0 | An arc is drawn from Start to End.
1 | An arc is drawn from Start to End. In addition, a single straight line is drawn from one end of the arc to the other, resulting in a segment.
2 | An arc is drawn from Start to End. In addition, two lines are drawn from each end of the arc to the centre, resulting in a pie-slice.

LStyle and LWidth define the style and width of the lines used to draw the boundaries of the ellipse(s), circle(s) or arc(s). FCol and BCol determine the colour of the lines.

FStyle specifies whether or not the ellipse(s), circle(s) or arc(s) are filled, and if so, how. For a solid fill (FStyle 0), FillCol defines the fill colour used. For a pattern fill (FStyle 1-6) FillCol defines the colour of the hatch lines and BCol the colour of the spaces between them.

The value of Dragable determines whether or not the object can be dragged. The value of AutoConf determines whether or not the Ellipse object is resized when its parent is resized.

The structure of the property values is best considered separately for single and multiple ellipses, circles or arcs.

Single Ellipse, Circle or Arc

For a single ellipse, circle or arc, Points is a 2-element vector which specifies the y-coordinate and x-coordinate of the top-left corner of the bounding rectangle.

Size is also a simple 2-element vector whose elements specify the height and width of the bounding rectangle.

LStyle and LWidth are both simple scalar numbers.

FStyle is either a single number specifying a standard fill pattern, or the name of a Bitmap object which is to be used to fill the ellipse, circle or arc.

FCol, BCol and FillCol are each either single numbers representing standard colours, or 3-element vectors which specify colours explicitly in terms of their RGB values.

Examples:

First make a Form :

      'F' ⎕WC 'Form'

Draw a complete ellipse within the bounding rectangle located at (y=10, x=5) with (height=30, width=50) :

      'F.E1' ⎕WC 'Ellipse' (10 5)(30 50)

Draw an elliptical arc within the same bounding rectangle as above, occupying the upper right quadrant (0 to 90 degrees):

      'F.E1' ⎕WC 'Ellipse' (10 5)(30 50)('End'(○0.5))

Ditto, but between 45 and 135 degrees :

      'F.E1' ⎕WC 'Ellipse' (10 5)(30 50)('Start'(○0.25))('End'(○0.75))

Ditto, but join the points of the arc to the centre of the ellipse, making a "pie-slice":

      'F.E1' ⎕WC 'Ellipse' (10 5)(30 50)('Start'(○0.25))('End'(○0.75))('ArcMode' 2)

Ditto, but use a green line and solid red fill :

      'F.E1' ⎕WC 'Ellipse' (10 5)(30 50)('Start'(○0.25))('End'(○0.75))('ArcMode' 2)('FCol' 0 0 255)('FStyle' 0)('FillCol' 255 0 0)

Multiple Ellipses, Circles or Arcs

To draw a set of ellipses, circles, or arcs with a single name, Points may be a simple 2-element vector (specifying the location of all the bounding rectangles), or a 2-column matrix whose first column specifies their y-coordinates and whose second column specifies their x-coordinates, or a 2-element nested vector whose first element specifies their y-coordinate(s) and whose second element specifies their x-coordinate(s).

Likewise, Size may be a simple 2-element vector (applying to all the bounding rectangles), or a 2-column matrix whose first column specifies their heights and whose second column specifies their widths, or a 2-element nested vector whose first element specifies their height(s) and whose second element specifies their width(s).

If specified, Start and/or End define arcs in terms of the angles made by drawing a line from the centre of the bounding box to the two ends of the arc. Both properties may be simple scalars, or vectors containing one element per arc drawn.

If Start is specified, but not End, end angles default to (¯1↓+\Start),○2. If End is specified, but not Start, start angles default to 0,¯1↓+\End

This means that you can draw a pie-chart using either Start or End angles; you do not have to specify both.

ArcMode, LStyle and LWidth may each be simple scalar values (applying to all the ellipses, circles or arcs) or simple vectors whose elements refer to each of the corresponding ellipses, circles or arcs in turn.

FStyle may be a simple scalar numeric or a simple character vector (Bitmap name) applying to all rectangles, or a vector whose elements refer to each of the corresponding ellipses, circles or arcs in turn.

Similarly, FCol, BCol and FillCol may each be single numbers or a single (enclosed) 3-element vector applying to all the rectangles. Alternatively, these properties may contain vectors whose elements refer to each of the rectangles in turn. If so, their elements may be single numbers or nested RGB triplets, or a combination of the two.

The Coord, Dragable and Data properties are specified for the object as a whole, and may not be allocated different values for each individual ellipse, circle or arc that is drawn.

Examples

First make a Form :

      'F' ⎕WC 'Form'

Draw two ellipses in bounding rectangles located at (y=5, x=10) and (y=5, x=60), each of (height=40, width=10)

      'F.E1' ⎕WC 'Ellipse' ((5 5)(10 60)) (40 10)

Ditto, using scalar extension for (y=5) :

      'F.E1' ⎕WC 'Ellipse' (5(10 60)) (40 10)

Ditto, but draw the first with (height=40, width=30) and the second with (height=20, width=10) :

      'F.E1' ⎕WC 'Ellipse' (5(10 60)) ((40 20)(30 10))

Draw an elliptical Pie-Chart in a bounding rectangle located at (y=5, x=10) with a height and width equal to 40% of the height and width of the parent Form. Each of the 4 pie-slices is bounded by a black line :

      Data ←12 27 21 40
      ANGLES←0,¯1↓((○2)÷+/Data)×+\Data
      COLS←(255 0 0)(0 255 0)(255 255 0)(0 0 255)
      PATS←1 2 3 4

      'F.PIE' ⎕WC 'Ellipse'(5 10)(40 40)
                  ('Start' ANGLES)('ArcMode' 2)
                  ('FCol' (⊂0 0 0))('FStyle' PATS)
                  ('FillCol' COLS)


FileBox Object
Parents Children Properties Methods Events
Purpose: Prompts user to select a file.

Description

The FileBox object implements the standard Windows FileSelection Dialog Box. This is a "modal" object. When you create a FileBox with ⎕WC, it is initially invisible and the user cannot interact with it. To use it, you must execute ⎕DQ with the name of the FileBox as its right argument. This causes the FileBox to be displayed. During the "local" ⎕DQ the user may interact only with the FileBox, or with other applications. When the user terminates the operation (by pressing the "Save", "Open", or "Cancel" Buttons, or by closing the window) the "local" ⎕DQ terminates, and the FileBox disappears.

When the "local" ⎕DQ is terminated, the FileBox generates either an FileBoxOK(71) or FileBoxCancel(72) event. The former is generated when the user presses the "Save" or "Open" button; the latter when the user presses the "Cancel" button or closes the FileBox.

The FileMode property is a character vector which indicates the mode in which the selected file is going to be opened. FileMode may be 'Read' (the default) or 'Write'. If FileMode is 'Write', files listed in the File Selection Box are "greyed", although they may still be selected.

The Caption property determines the text that appears in the title bar of the FileBox window. If undefined, Caption defaults to "Save As" if FileMode is 'Write' or to "Open" if FileMode is 'Read'. Similarly, if FileMode is 'Write', the button captions are "Save" and "Cancel", and if FileMode is 'Read' the button caption are "Open" and "Cancel".

The Directory property contains a simple character vector which specifies the initial directory from which a list of suitable files is displayed.

      'F' ⎕WC 'FileBox' 'The FileBox Object' 'C:\WDYALOG'
      ⎕DQ 'F'

The Style property specifies whether the user may choose a single file name ('Single' which is the default) or several file names ('Multi').

The Filters property is a nested scalar or vector containing a list of filters. Each filter is a 2-element vector of character vectors which contain a file type mask and a file type description respectively. The file type descriptions appear in a drop-down combo box labelled "List File of Type". When the user selects one of these, the currently selected directory is searched for files which match the corresponding mask. The default value of Filters is an empty vector. This gives a file type mask of "*.*" and a file type description of "All Files (*.*)". Hence an empty vector is equivalent to (⊂'*.*' 'All Files (*.*)').

The Index property determines which of the filters is initially selected. Its default value is ⎕IO.

Note that when ⎕DQ terminates with FileBoxOK, the File, Directory, and Index properties are updated to reflect the contents of the fields within the FileBox.

The operating system imposes limits on both the length of the name of the file, and on the total path length. In version 17.0attempting to set the File or Directory Properties to too long a name will generate a DOMAIN ERROR, while attempting to use too long a File name within the FileBox will result in the appearence of an error MessageBox.


Font Object
Parents Children Properties Methods Events
Purpose: Loads a font resource

Description

This object loads a Windows font into memory ready for use by another object. The characteristics of the font are specified by its properties as follows :

PName | A character vector containing the name of the font face. The default is 'System'. Note that case is ignored when you specify the name, although it will be returned correctly by ⎕WG.
Size | An integer that specifies the character height of the font in pixels.
Fixed | A Boolean value that specifies whether the font is fixed-width (1) or proportional (0).
Italic | A Boolean value that specifies whether the font is italicised (1) or not (0).
Underline | A Boolean value that specifies whether the font is underlined (1) or not (0).
Weight | An integer in the range 0-1000 that specifies how bold or heavy the font is (1000 = most bold).
Rotate | A numeric scalar that specifies the angle of rotation of the font in radians. The angle is measure from the x-axis in a counter-clockwise direction.
CharSet | An integer that specifies the character encoding.

The Coord property may be set to 'Pixel', 'ScaledPixel' or 'RealPixel' when the object is created, but Coord may not subsequently be changed.

If Coord is 'Pixel', it is interpreted as either 'RealPixel' or 'ScaledPixel' according to the value of the DYALOG_PIXEL_TYPE parameter, which is either ScaledPixel or RealPixel. See DYALOG_PIXEL_TYPE.

If this parameter is not specified, the default is RealPixel. So by default, when you set Coord to Pixel, it will be treated as RealPixel.

If you are using 'ScaledPixel', this means that your fonts will also be scaled up automatically, as well as the sizes of the controls in which they are used.

When you ask Windows to allocate a font, you may specify as many or as few of these properties as you wish. Windows actually supplies the font that most closely matches the attributes you have specified. The matching rules it uses are complex, and may be found in the appropriate Windows documentation.

The values of the above properties after ⎕WC or ⎕WS reflect the attributes of the font which has been allocated by Windows, and not necessarily the values you have specified. Furthermore, it is possible that changing the value of one property will cause the values of others to be changed.


Form Object
Parents Children Properties Methods Events
Purpose: This is a top-level window used to contain other objects (controls).

Description

The Posn property specifies the location of the internal top-left corner of the window relative to the top-left corner of the screen. If the window has a title bar and/or border, you must allow sufficient space for them. Similarly, the Size property specifies the internal size of the window excluding the title bar and border. The default for Size is 50% of the screen height and width. The default for Posn places the Form in the middle of the screen.

Normally, a Form has a title bar, a system menu box, a border and maximise and minimise buttons. To disable the System Menu box, set SysMenu to 0. To disable one or both of the maximise/minimise buttons, set MaxButton and/or MinButton to 0.

The HelpButton property specifies that a Question (?) button appears in the title bar of the Form. However, this does not apply if the Form has a maximise or minimise button which both take precedence. The user may obtain help by clicking on the Question (?) button and then on a control in the Form. It is up to you to provide the help by responding to the Help event on the control.

By default, a Form may be moved and resized using the mouse. These actions are achieved by dragging on the title bar and border respectively. It follows that a Form that is Moveable must have a title bar, and one that is Sizeable must have a border, regardless of the value of other properties. Also, if you specify any of SysMenu, MaxButton or MinButton, the window must have a title bar in which to place these controls. A title bar itself requires a border. To obtain a window without a title bar, you must therefore set Moveable, SysMenu, MaxButton and MinButton to 0. Note that setting Caption does not force a title bar on the window.

If Sizeable is 1, the window will have a double-line border, regardless of the values of other properties. If Sizeable is 0, and any one or more of Moveable, SysMenu, MaxButton, MinButton or Border is 1, the window will have a 1-pixel border. Only if all these properties are 0 will the window be borderless. To obtain a dialog box that may only be moved or closed, set Border to 2.

Note that the default value for Caption is an empty character vector which results in a blank title.

To obtain a standard dialog box with 3-dimensional appearance, create a Form with Border set to 2 and EdgeStyle set to 'Dialog', for example:

  'F' ⎕WC 'Form' 'Dialog Box' ('EdgeStyle' 'Dialog')('Border' 2)

The State property has the value 0 if the window is currently displayed in its "normal" state, 1 if it is currently displayed as an icon, and 2 if it is currently maximised and displayed full-screen. This property does not just report the current state, but can be used to set the state under program control.

The VScroll and HScroll properties determine whether or not a Form has a vertical and horizontal scrollbar respectively. These properties are set to ¯1to obtain a scrollbar. Their default value is 0 (no scrollbar). VScroll and HScroll may only be set when the object is created and may not subsequently be changed. The Range property is a 2-element vector that specifies the maximum value for the vertical and horizontal scrollbars respectively. The PageSize property is a 2-element vector that specifies the sizes of the thumbs in each scrollbar. The Step property is a 4-element vector that specifies the sizes of the small and large change. Its first two elements refer to the vertical scrollbar, elements 3 and 4 refer to the horizontal scrollbar. The Thumb property is a 2-element vector that both reports and sets the position of the thumb in the vertical and horizontal scrollbars respectively. When the user attempts to move the thumb in one of the scrollbars, the Form generates a VScroll or HScroll event.

VScroll and HScroll cannot be changed using ⎕WS. However, you can make a scrollbar disappear by setting the corresponding element of Range to 1, thus allowing you to dynamically switch the scrollbar off and on. Note however that doing so will change the size of the Form.

Setting the FontObj property on a Form does not affect the text in its title bar. However, the value of FontObj will (unless over-ridden) be inherited by all of the objects within the Form.

The background of the Form may be coloured using BCol. The default value for BCol is the Windows Button Face colour unless EdgeStyle is set to 'None' or 'Default' in which case it is the Windows background colour. Alternatively, the background of a Form can be defined using a Bitmap or Metafile object whose name is defined by the Picture property. A Metafile is automatically scaled to fit the Form. A Bitmap can be tiled or scaled. See Picture property for details.

The OnTop property is either 0 or 1. If it is 0, the Form assumes its normal position within the stack of windows on the screen and is only brought to the front when it receives the input focus. If OnTop is set to 1, the Form is always brought to the front even when it doesn't have the focus. If more than one Form has OnTop set to 1, the stacking order of this set of Forms is defined by the order in which they were created.

A Form can be created as a child of another Form. If so, it has the following characteristics:

  • A child Form always appears on top of its parent Form (although it is not constrained by it)
  • When you minimize a parent Form, its child Forms disappear.
  • Making the parent Form invisible or inactive has no effect on a Child Form.

Note that the Posn and Size properties of a child Form are expressed in screen coordinates and are not given relative to its parent.


Grid Object
Parents Children Properties Methods Events
Purpose: Spreadsheet object for displaying and editing data.

Description

The Values property is a matrix whose elements are displayed in the cells of the Grid. An element (and therefore a cell) may contain a single number, a single character, a character vector or a character matrix.

The CellHeights property specifies the height of each of the rows of the spreadsheet. It may be a single value which applies to all rows, or a vector with one element per row. The CellWidths property determines the width of each column of the spreadsheet. It too may be a single value or a vector with one element per column.

The RowTitles property is either an empty character vector (the default) or a vector of character vectors that specify row titles displayed to the left of the cells in the Grid. If RowTitles is not specified, the Grid labels each row with its row number. The ColTitles property is similar and is used to specify column headings. If ColTitles is not specified, the Grid displays "standard" spreadsheet column headings A-Z, then AA-AZ and so forth.

The TitleHeight property specifies height of the column headers. If this is set to 0, the column titles will not be displayed. Similarly, the TitleWidth property specifies the width of the row titles and again a value of zero disables the row titles.

The FontObj property may be used to specify the font to be used for the Grid as a whole, including the titles. The CellFonts property may be used to specify fonts for individual cells.

The FCol and BCol properties may each specify a single colour for the Grid as a whole, or may specify a vector of colours whose elements are mapped to individual cells through the CellTypes property.

The CellFonts property is either a character vector or a vector of character vectors that specifies the name of a single font object to be used for all cells in the Grid, or a vector of character vectors that specifies a set of font objects that are mapped to individual cells through the CellTypes property.

The Input property is a character vector that specifies the name of an object which is to be associated with every cell in the Grid, or a vector of names whose elements are mapped to individual cells through the CellTypes property. These objects may be of type Button, ColorButton, Combo, Edit, Label, Spinner or TrackBar. In addition, the Input property may specify instances of OCXClass objects (ActiveX controls) and NetType objects (.NET classes).

If the Input property is empty (the default) the user may browse the data in the spreadsheet but may not alter it. Furthermore, no feedback is provided as to which is the current cell. If the Input property specifies the name of an object that is the child of the Grid itself, this object floats from cell to cell as the user moves around the spreadsheet, and the current cell is identified by its presence.

If the Input property specifies the name of an external object (that is, an object that is not a child of the Grid), the contents of the current cell are copied into that object as the user moves around the spreadsheet. In addition, the current cell is identified by a thick border. In either case, the associated object is used to impose formatting and validation.

If the Input property specifies the name of a Label object, that object is used to impose formatting, but the data is protected and may not be changed. If the Label is a child of the Grid, it moves from cell to cell, and its characteristics (Border, FCol, BCol and FontObj) can be used to identify the current cell. If the Label is an external one, no visual feedback is provided; even though the current cell (reflected by the CurCell property) changes as the user moves around the Grid.

If the Input property specifies one or more instances of OCXClass objects (ActiveX controls) and NetType objects (.NET classes), the InputProperties property is used to map the Values property of the Grid to specific properties of the external object.

The CellTypes property is either an empty numeric matrix (the default) or an integer matrix of the same shape as Values. If specified, each element of CellTypes determines the index into various properties, including the FCol, BCol, CellFonts and Input properties, to be used for the corresponding cell. For example, if an element in CellTypes is 3, the 3rd element of FCol is used for the foreground colour of the corresponding cell, the 3rd element of BCol specifies the background colour, and so forth.

The CurCell property may be used to set or query the current cell. The current cell is the cell which the user has picked by clicking the mouse over it or by using the cursor keys. CurCell is a 2-element vector containing the current cell's row number and column number respectively and is ⎕IO dependent. The Index property specifies the row and column number of the cell in the top-left corner of the Grid. It too is ⎕IO dependent.

The AutoExpand property is a 2-element Boolean vector which specifies whether (1) or not (0) new rows and columns are added when the user presses the corresponding cursor key when at the end of the block of cells. Its default value is (0 0).

The Grid object reports a CellDown event when the user depresses a mouse button over a cell. The event message contains the row and column address of the cell in question which is ⎕IO dependent. It also reports a similar CellUp event when the mouse button is released and a CellDblClick event when it is double-clicked. The number of the mouse button and the state of the shift keys are also reported.

When the user moves to another cell, the Grid object reports a CellMove event. This simply reports the address of the new cell and may be used to take some appropriate action when a particular cell is picked. If the user alters the data in a cell and then attempts to move to another, the Grid reports a CellChange event. This can be used to perform validation.

Alternatively, the Grid may report a CellChanged event which occurs after the Values property has been updated with the new cell contents. This may be used to perform immediate recalculation.

The AddRow event is generated if the current cell is in the last row of the Grid and the user presses Cursor Down. By default, this operation adds a new row to the Grid, but you can attach a callback to the AddRow and selectively disable this default action if required. The AddCol event works in a similar manner for columns. Although the user has no direct means of inserting a row or column, your application can do this by calling AddRow or AddCol as a method on the Grid object. Typically this would be done in response to the user selecting a MenuItem or pressing a Button.

The ColChange, RowChange, DelRow, DelCol and Undo methods allow your application to perform these corresponding operations.

The Grid object maintains a buffer of the most recent 8 changes made by the user since the Values property was last set by ⎕WC or ⎕WS. Your application can restore these changes one by one by calling the Undo method. The Undo method restores the most recent change made by the user and removes that change from the undo stack. It is therefore not possible to "undo an undo".

The Grid supports the selection of a block or blocks of cells using the mouse and/or the keyboard. The ability to select a range of cells is determined by the CellSelect property. When the user performs a selection, the Grid generates a GridSelect event. The range of cells currently selected is given by the SelItems property.

If a block of cells has been selected, the user may delete the contents, and cut or copy the contents of the cells to the clipboard by pressing Delete, Shift+Delete or Ctrl+Insert respectively. These operations also generate GridDelete, GridCut and GridCopy events which you can selectively disable using a callback function. You can also perform these operations under program control by calling them as methods.

If more than one block of cells has been selected, these operations are honoured only if the blocks begin and end on the same rows or begin and end on the same columns. If so, the data placed in the clipboard is the result of joining the blocks horizontally or vertically as appropriate.

The user may paste data from the clipboard into a Grid by pressing Shift+Insert. Data is pasted into the currently selected block of cells, or, if there is no selection, data is pasted starting at the current cell (CurCell). The operation also generates a GridPaste event, and, if the operation cannot proceed, a GridPasteError event.

If you move the mouse pointer over any of the four edges of a selected block of cells, the cursor changes to an arrow. You may now click and drag the border of the selected cells with the mouse.

If you press the Ctrl key at the same time, the contents of the selected cells are copied to the new location, replacing the values in the block of cells onto which they are dropped. Otherwise, the operation is treated as a move and the original block of cells is emptied. This operation also generates a GridDropSel event. You may only move or copy a single block of cells in this way.

The user may be permitted to resize the rows and/or columns of a Grid. This is controlled by the ResizeRows and ResizeCols properties whose default values are 0. To allow the user to resize, set either or both to 1. You can also specify a Boolean vector to allow specific rows/columns to be resized while others are fixed. Two additional properties named ResizeRowTitles and ResizeColTitles determine whether or not the user may alter the width of the row titles and the height of the column titles.

If resizable, the cursor changes to a double-heads arrow when the user moves the mouse pointer over the lines between the row and/or column titles. The user may click and drag with the mouse to the desired size. The user may also double-click. This causes the row or column to be resized to fit the data. Both operations generate a SetColSize, or SetRowSize event.

When you edit data in a Grid, the editing behaviour and the action of the cursor movement keys is determined by the InputMode and InputModeKey properties.

The GridFCol property specifies the colour of all the grid lines. Alternatively, the GridLineFCol, GridLineWidth, RowLineTypes and ColLineTypes properties may specify the appearance for individual grid lines.

The GridBCol property specifies the colour used to fill the area between the end of the last column of data and the right edge of the Grid and between the bottom row of data and the bottom edge of the Grid.

The RowTitleFCol and ColTitleFCol properties specify the colours to be used for the row and column titles respectively.

The ClipCells property determines whether or not the Grid displays partial cells. The default is 1. If you set ClipCells to 0, the Grid displays only complete cells and automatically fills the space between the last visible cell and the edge of the Grid with the GridBCol colour.

The CellSet property is a Boolean array that marks which cells are set (i.e. have values) and which are empty. This allows you to edit large numeric matrices which contain empty cells without a severe workspace penalty.

The HScroll and VScroll properties specify whether or not horizontal and vertical scrollbars are displayed. Either property may be given the value ¯3 which forces the corresponding scrollbar to appear always. VScroll and HScroll may only be set when the object is created and may not subsequently be changed.

The Grid object supports comments in a manner that is consistent with the way that comments are handled by Microsoft Excel. If a comment is associated with a cell, a small red triangle is displayed in its top right corner. When the user rests the mouse pointer over a commented cell, the comment is displayed as a pop-up with an arrow pointing back to the cell to which it refers. The comment disappears when the mouse pointer is moved away. This is referred to as tip behaviour. Comments may also be associated with row and column titles.

Grid comments are managed by a set of methods, namely AddComment, DelComment, GetComment, ShowComment, HideComment and ClickComment.

You may lock individual rows and columns using the LockRows and LockColumns methods. This facility is however not supported in combination with hierarchical rows and/or columns which are specified by RowTitleDepth and ColTitleDepth.

The Grid can display a TreeView like interface on the Row titles. In this mode, the Grid automatically shows and hides row of data as the end user expands and contracts nodes of the tree.

The RowTreeDepth property is used to specify the depth of rows in the Grid.

The appearance of the tree is determined by the RowTreeStyle property.

User defined bitmaps can be used instead of the default Images by setting the RowTreeImages property.

The Grid generates Expanding and Retracting events when the user interacts with the tree.

The RowSetVisibleDepth method can be used to set the visible depth of the tree.


Group Object
Parents Children Properties Methods Events
Purpose: This object is used to group a related set of controls together visually, and to impose "radio-button" behaviour.

Description

A Group is displayed as an empty box with a border around it whose appearance is defined by the EdgeStyle property. The Caption property defines a string of text that is displayed in the top left border. The default value is an empty vector.

A Group will be resized if its parent Form or Group is resized. It can also be resized directly by the user if its Sizeable property is set to 1. By default, when a Group is resized, it automatically adjusts the size and position of its children to maintain the same proportions within it as before. The resizing of a Group and its children can be controlled using the AutoConf property or by enabling the Configure event (31).


HTMLRenderer Object

Description

The HTMLRenderer Object is a cross-platform mechanism for producing Graphical User Interfaces (GUI), based on HyperText Markup Language (HTML). It is intended to run on Windows, macOS and Linux (including Raspberry Pi).

HTMLRenderer is a built-in class, instances of which are created, altered and events processed using the Dyalog GUI framework functions ⎕WC/⎕WS/⎕WG, ⎕NEW and ⎕DQ/⎕NQ.

The HTMRenderer object is fully documented in the Dyalog APL Experimental Functionality – HTML Renderer manual. Note that the documentation for the HTML Renderer and the documentation for other GUI objects do not currently contain any references to each other.


Icon Object
Parents Children Properties Methods Events
Purpose: This object defines an icon.

Description

The File property specifies the name of an icon file (.ICO. .GIF or .PNG), or the name of a DLL or EXE file and the identity of the icon within it.

The Style property identifies the size of the icon and must be 'Large' or 'Small'. The former specifies a 32x32 icon and is the default; the latter specifies a 16x16 icon. The size of the icon is not embedded within the icon data, so it is essential to specify Style correctly. Note that a single file may contain both sizes of an icon. Style is only relevant when loading an Icon from file.

If the value of the File property is set by ⎕WS, no immediate action is taken, but the corresponding file may subsequently be read or written using the FileRead or FileWrite methods.

16-bit icons contain fewer than 256 colours and each pixel is either transparent or opaque. The images in such Icons are represented by the Bits, Mask and CMap properties.

32-bit icons are 24-bit images with an 8-bit alpha channel which specifies the degree of transparency of each pixel. The pixels in these Icons are represented by the CBits property.

CBits is a rank-2 numeric array whose dimensions represent the rows and columns of pixels in the Icon. The values in CBits represent the colour and of each pixel and also its transparency.

Bits is an integer matrix whose elements define the colours of each pixel in the icon in terms of their (0-origin) indices into CMap. When the icon is displayed on the screen, the way in which these colours combine with those currently displayed on the screen (the background) is specified by Mask. This is a Boolean matrix of the same size as Bits. The following table shows how the colour of each resulting pixel is determined.

Bits | Colour | 0 | Colour
Mask | 0 | 1 | 1
Pixel | Colour | Background | New Colour

If an element of Mask is 0, the corresponding element of Bits defines the colour of the resulting pixel that is displayed on the screen. If an element of Mask is 1, the resulting pixel that is displayed on the screen is either the current background colour or is a new colour chosen by MS-Windows to be visible against the background. A non rectangular icon is obtained by setting those elements of Bits and Mask that you want to exclude from the shape to be 0 and 1 respectively.

The size of Bits is restricted by the capabilities of the current display driver. Mask must have the same shape as Bits.

An Icon is used by setting the IconObj property or Picture property of another object to its name or ref.


Image Object
Parents Children Properties Methods Events
Purpose: Positions bitmaps and icons within an object.

Description

The Points property specifies the co-ordinates of one or more points at which the specified graphical objects are to be drawn.

The Picture property specifies the name(s) of Bitmap, Icon or Metafile object(s) that are to be drawn. It may be a simple character vector or a vector of vectors.

To draw a single graphic picture, the Picture property is a simple character vector specifying the name of a Bitmap, Icon or Metafile object. Points is either a 2-element vector or a 1-row, 2-column matrix whose elements specify the y-coordinate and x-coordinate respectively at which the object is to be drawn.

To draw the same picture at several different positions, the Picture property is a simple character vector specifying the name of the Bitmap, Icon or Metafile object. Points is either a 2-column matrix of y-coordinates and x-coordinates, or a nested vector whose first element contains the y-coordinates and whose second element contains the x-coordinates.

To draw several different pictures, the Picture property is a vector of character vectors specifying the names of several Bitmap, Icon and/or Metafile objects. Points is a 2-column matrix or 2-element nested vector as described above.

Setting the EdgeStyle property causes the picture to be surrounded by the appropriate border. For example, setting EdgeStyle to 'Plinth' produces a button-like appearance.

Setting the Size property causes the picture to be scaled to fit within the specified rectangle. It is only necessary to specify Size when an Image is used to draw a Metafile object. For a Bitmap or Icon, Size defaults to the size of the object being drawn.

The Dragable property specifies whether or not the Image can be dragged and dropped using the mouse.

Examples:

First make a Form

      'F' ⎕WC 'Form'

Then make two Bitmaps :

      'YES' ⎕WC 'Bitmap' 'C:\WDYALOG\WS\YES'
      'NO'  ⎕WC 'Bitmap' 'C:\WDYALOG\WS\NO'

Display the "YES" Bitmap at (20,10)

      'F.I' ⎕WC 'Image' (20 10)('Picture' 'YES')

Display the "YES" Bitmap at (20,10) and (20,50)

      'F.I' ⎕WC 'Image' (20(10 50))('Picture' 'YES')

Display the "YES" Bitmap at (20,10) and the "NO" Bitmap at (20,50)

      'F.I' ⎕WC'Image'(20(10 50))('Picture' 'YES' 'NO')


ImageList Object
Parents Children Properties Methods Events
Purpose: The ImageList object represents a set of bitmapped images.

Description

An ImageList object represents an array of bitmapped images which are used to depict items in a ListView or TreeView object, or the images in a CoolBar, Menu, TabControl or ToolControl.

Making an ImageList is a 2-step process. First, you create an (empty) ImageList specifying its Size and Masked properties. The former establishes the size of each of the bitmapped images in the array. The Masked property specifies whether the ImageList is to contain opaque or transparent images. Note that these properties must be established when the ImageList is created by ⎕WC and may not subsequently be changed using ⎕WS.

Next, you create a series of Bitmap or Icon objects as children of the ImageList. As you make each one, APL adds the corresponding image (or images) to the ImageList object. If the size of each of the Bitmap or Icon objects is equal to the Size of the ImageList itself, each child object corresponds to an image in the ImageList. However, if you add an object whose width is an exact multiple of the width of the ImageList, a corresponding number of images will be added.

For example, if the Size of the ImageList is 16x16 (the default) and you create a child Bitmap of size 16x48, three images (each of size 16x16) will be added to the ImageList. This is more efficient than building the images one-by-one. In other circumstances (where the size of the Bitmap or Icon is not equal to Size of ImageList), the Bitmap or Icon will be scaled to fit.

Note that when making Bitmaps or Icons as children of an ImageList, it is not necessary to name them because they are subsequently referenced only via the ImageIndex and SelImageIndex properties and not by name. The number of images in an ImageList is given by the read-only property, ImageCount.

The MapCols property, which must be specified at the time you create the object, specifies whether or not bitmap colours are remapped to reflect the user's colour preferences.

An ImageList is associated with a ListView or TreeView object by the ImageListObj property. Each item in the ListView or TreeView is then allocated a specific image in the ImageList by the ImageIndex and SelImageIndex properties.


Label Object
Parents Children Properties Methods Events
Purpose: Displays static text.

Description

This object displays a text label, a number, a date or a time value.

If FieldType is empty, the Label displays the text defined by its Caption property. If the Caption property contains one or more linefeed characters (⎕UCS 10) the Label becomes a multi-line Label which is top-left justified and automatically wraps on white-space characters (such as space and tab) to fit in the width provided.

If FieldType is 'Numeric', 'LongNumeric', 'Currency', 'Date', 'LongDate', or 'Time' the Label converts and formats the number defined by its Value property and displays this instead. See FieldType property for details.

The Border property determines whether or not the label has a border. A value of 0 means no border (the default). A value of 1 means that a 1-pixel border is drawn around the label.

By default, the value of the EdgeStyle property for a Label is 'None' and the value of BCol is 0 which is normally white, or grey if the parent object has a 3-dimensional appearance. You can change its appearance by setting EdgeStyle and/or BCol to different values.


List Object
Parents Children Properties Methods Events
Purpose: Allows the user to select one or more items from a list.

Description

The Items property is either a vector of character vectors or a character matrix, and determines the items in the List.

The size and position of the area used to display the list is defined by Size and Posn. If Size is not chosen to represent an exact number of lines of text, the bottom line of text may be clipped.

The Index property specifies or reports the position of Items in the list box as a positive integer value. If Index has the value "n", it means that the "nth" item in Items is displayed on the top line in the list box. However, it is ignored if all the Items fit within the List object. Note that Index can only be set using ⎕WS and not by ⎕WC. The default value for Index is ⎕IO.

The Style property may be 'Single' (the default) or 'Multi'. 'Single' allows only a single item to be selected. 'Multi' allows several items to be chosen. In either case, if the Select event is enabled, it is generated whenever the selection changes. If Style is 'Multi' the List will generate a Select event every time an item is added to the selected list.

Under Windows, you may select or de-select multiple items in a List object by pressing the Ctrl key at the same time as pressing the left mouse button.

The SelItems property is a Boolean vector with one element per element or row in Items and indicates which (if any) of the items is currently selected (and highlighted).

The VScroll property determines whether or not the list has a scrollbar. Its possible values are :

¯2 | scrollbar if required
¯1 | scrollbar if required
0 | no scrollbar

Note that data in a List is always scrollable if there are more items than will fit in the box. VScroll determines ONLY whether or not a scrollbar is provided.

The MultiColumn property is a Boolean value that specifies whether or not the List object displays its items in columns. The default is 0 which produces a single-column display. If MultiColumn is 1, the List object displays its items in columns whose width is defined by the ColumnWidth property.


ListView Object
Parents Children Properties Methods Events
Purpose: The ListView object displays a collection of items.

Description

The ListView object is a window that displays a collection of items, each item consisting of an icon and a label. The ListView provides several ways of arranging items and displaying individual items. For example, additional information about each item can be displayed in columns to the right of the icon and label. An example of the use of a ListView object is the "My Computer" Windows utility.

The Items property is a vector of character vectors that specifies the labels for the items displayed by the ListView. The ImageListObj property specifies the names of two ImageList objects that define two sets of icons; a large icon (32x32 pixel) set and a small icon (16x16 pixel) set. Alternatively, ImageListObj may be empty (no icons displayed) or contain just the name of a single large icon ImageList.

The View property contains a character vector that determines how the items are displayed. It may have one of the following values; 'Icon' (the default), 'SmallIcon', 'List' or 'Report'. When View is 'Icon' or 'SmallIcon', the items are arranged row-wise with large or small icons as appropriate. When View is set to 'List', the items are arranged column-wise using small icons. Examples of 'Icon' and 'List' views are illustrated below.

When View is set to 'Report', the items are displayed in a single column using small icons but with the matrix specified by ReportInfo displayed alongside. In this format, the Boolean Header property determines whether or not the object also provides column headings. Its default value is 1. The column headings themselves are specified by the ColTitles property. Their alignment (and the alignment of the data in the columns beneath them) is defined by the ColTitleAlign property.

The appearance of the column titles is further controlled by the ColTitle3D property. This is a Boolean value (default 1) which specifies whether or not the column titles have a 3-dimensional (plinth) appearance. Header and ColTitle3D may only be set when the object is created using ⎕WC and may not subsequently be changed by ⎕WS.

In 'Report' View, columns may be resized by the user dragging the bars between the titles, or under program control using the SetColSize event. A 'Report' view example is illustrated below.

The DragItems property is Boolean and specifies whether or not the user may drag an item from one position to another. Its default value is 1 (dragging is enabled).

The AutoArrange property is Boolean and specifies whether or not the items are automatically re-arranged whenever an item is repositioned by the user or moved under program control. Its default value is 0.

The EditLabels is a Boolean property (default 0) that determines whether or not the user may edit the labels which are specified by the Items property.

The Style property may be 'Single', which specifies that only one item may be selected at a time, or 'Multi' which permits multiple selections to be made. The default is 'Multi'.

The CheckBoxes property is Boolean and specifies whether or not check boxes are drawn to the left of items. Its default value is 0.

The GridLines property is Boolean and specifies whether or not grid lines are drawn between items. This applies only when View is 'Report'. Its default value is 0.

In 'Report' View, the ReportImageIndex property specify images to be displayed alongside each item, and overrides the images specified by ImageListObj. The HeaderImageList and HeaderImageIndex properties specify images to be displayed alongside each column title.

The following example illustrates the use of these properties.

The ReportBCol property specifies each item's background colour.

The FullRowSelect property is Boolean and specifies whether or not the entire row is highlighted to indicate selected items. This applies only when View is 'Report'. Its default value is 0.

The ItemGroups and ItemGroupMetrics properties allow you to display items in groups as illustrated below.

Note that this feature only applies if Native Look and Feel is enabled.


Locator Object
Parents Children Properties Methods Events
Purpose: Allows the user to input a point, ellipse, line or rectangle.

Description

This object is used to obtain graphical input from the user. Like a pop-up menu or a MsgBox, the Locator is a modal object whose interaction with the user is initiated by a "local" ⎕DQ.

This is terminated when the user releases a mouse button or presses any key other than a cursor movement key, Shift, Ctrl or Alt. It is usual to initiate the ⎕DQ for the Locator from within a callback function attached to a MouseDown (1) Event.

When the "local" ⎕DQ is terminated, a Locator (80) Event is generated. The associated event message contains the new position and size of the Locator, together with how the event was generated (keystroke or mouse button). To obtain the Locator's new position or size, you must enable the event by setting its "action" code to 1, or to the name of a suitable callback function.

The value of the Style property determines the type of locator displayed. It may be 'Point', 'Line', 'Rect', or 'Ellipse'. The default value is 'Rect'. The value of the Sizeable property is 0 or 1 and determines whether or not "rubberbanding" is enabled. Its default value is 1 which turns "rubberbanding" on. The Size property determines the initial size of the Locator when displayed by ⎕DQ. Its default value is (0,0).

If Style is 'Rect' the Locator displays a rectangle. One corner of the rectangle is positioned at Posn. The diagonally opposite corner is positioned at (Posn+Size). If Sizeable is 0, the entire rectangle is dragged as the mouse is moved. If Sizeable is 1, the

corner initially defined by (Posn+Size) is dragged (rubberbanding the rectangle) as the mouse is moved. The rectangle disappears when the operation is terminated. The new position or size of the rectangle is reported in the Locator event message.

If Style is 'Ellipse' the Locator displays an ellipse. One corner of the bounding rectangle of the ellipse is positioned at Posn. The diagonally opposite corner is positioned at (Posn+Size). If Sizeable is 0, the entire ellipse is dragged as the mouse is moved. If Sizeable is 1, the corner of the bounding rectangle initially defined by (Posn+Size) is dragged (rubberbanding the ellipse) as the mouse is moved. The ellipse disappears when the operation is terminated. The new position or size of the bounding rectangle of the ellipse is reported in the Locator event message.

If Style is 'Line' the Locator displays a line drawn between the points defined by Posn and Posn+Size. If Sizeable is 0, the line is dragged with the cursor as the mouse is moved. If Sizeable is 1, the end of the line initially defined by Posn+Size is dragged (rubberbanding the line) as the mouse is moved. The line disappears when the operation is terminated. The new position or size of the line is reported in the Locator event message.

If 'Style' is 'Point', the values of Sizeable and Size are ignored. During the ⎕DQ no visible feedback (other than the cursor) is provided as the user moves the mouse. When the ⎕DQ terminates, the new position of the Locator is reported in the Locator event message.

The Step property is a 2-element integer vector (default value 1 1) that specifies the increments (in pixels) by which the size or position of the Locator changes in the Y and X directions respectively as the user moves the Locator.

The Locator is normally initiated from a MouseDown (1) event, and it is natural to place it at the current cursor position. However, if you are using rubberbanding, you will normally want to have the cursor appear at the end or corner of the Locator that moves. If you start with a non-zero sized Locator, you must set Posn (which defines the fixed end or corner) to the current cursor position minus Size to achieve this effect.


Marker Object
Parents Children Properties Methods Events
Purpose: A graphical object used to draw polymarkers.

Description

The Points property specifies one or more sets of points at which one or more sets of polymarkers are to be drawn.

The Style property determines the symbol that is drawn at each of a set of points. Marker styles are specified either by numbers which represent the following symbol shapes .

0 | .
1 | +
2 | *
3 | ⎕
4 | ×
5 | ⋄
6 | ∘

or by character vectors containing the names of Bitmap or Icon objects.

The height of each symbol is specified by the value of the Size property. However this applies only to Styles 1-6 and is ignored if Style is 0 or the name of a Bitmap. The colour of each symbol is specified by the FCol property. The default is black.

The value of Dragable determines whether or not the object can be dragged. The value of AutoConf determines whether or not the Marker object is resized when its parent is resized.

The structure of the property values is best considered separately for single and multiple sets of polymarkers.

Single Set of Polymarkers

For a single set of polymarkers, Points is either a 2-column matrix of (y,x) co-ordinates, or a 2-element vector of y and x co-ordinates respectively.

Style and Size are both simple scalar numbers.

FCol is either a single number representing a standard colour, or a 3-element vector which specifies the marker colour explicitly in terms of RGB values.

First make a Form:

      'F' ⎕WC 'Form'

Draw a point at (y=20, x=10):

      'F.M1' ⎕WC 'Marker' (20 10)

Draw a row of points at (y=20, x=10, 20, ... 90) : (Note scalar extension of y-coordinate)

      'F.M1' ⎕WC 'Marker' (20(10×⍳9))

Draw "+" symbols at each corner of a box:

      Y ← 10 10 50 50
      X ← 10 50 50 10
      'F.M1' ⎕WC 'Marker' (Y X) 1

Ditto, but draw them 10% high:

      'F.M1' ⎕WC 'Marker' (Y X) 1 10

Ditto, but use "*" symbols in green:

      'F.M1' ⎕WC 'Marker' (Y X) 2 10 (0 255 0)

Multiple Sets of Polymarkers

To draw multiple sets of polymarkers with a single name, Points is a nested vector whose items are themselves 2-column matrices or 2-element nested vectors.

Style and Size may be simple scalars specifying a single type and/or size of symbol to be used for all the sets of polymarkers, or vectors specifying different symbols and/or sizes for each set.

FCol may be a single number or a single (enclosed) 3-element vector applying to all the sets of polymarkers. Alternatively, FCol may be a vector whose elements refer to each of the sets of polymarkers in turn. If so, the elements may be single numbers or nested RGB triplets, or a combination of the two.

First make a Form:

      'F' ⎕WC 'Form'

Draw a "⎕" at (10,20) and a "⋄" at (20,20):

      'F.M1' ⎕WC 'Marker'((1 2⍴10 20)(1 2⍴20 20)) (3 5)

Draw "+" symbols at each corner of one box and "○" symbols at each corner of another:

      Y1 X1 ← (10 10 50 50) (10 50 50 10)
      Y2 X2 ← (20 20 40 40) (20 40 40 20)
      'F.M1' ⎕WC 'Marker' ((Y1 X1)(Y2 X2)) (1 6)

Ditto, but draw the "+" symbols with height 2% and the "○" symbols 5%:

      'F.M1' ⎕WC 'Marker' ((Y1 X1)(Y2 X2)) (1 6) (2 5)

Ditto, but draw the "+" symbols in red and the "○" symbols in blue:

      'F.M1' ⎕WC 'Marker' ((Y1 X1)(Y2 X2)) (1 6) (2 5)
                          ('FCol' (255 0 0)(0 0 255))


MDIClient Object
Parents Children Properties Methods Events
Purpose: Implements Multiple Document Interface (MDI) behaviour.

Description

The multiple-document interface (MDI) is a document-oriented interface that is commonly used by word-processors, spreadsheets and other applications that deal with documents. An MDI application allows the user to display multiple documents at the same time, with each document displayed in its own window.

The MDIClient object is a container object that effectively specifies the client area within the parent Form in which the SubForm are displayed. The MDIClient object also imposes special MDI behaviour which is quite different from that where a SubForm is simply the child of another Form.

By default, the MDIClient occupies the entire client area within its parent Form. This is the area within the Form that is not occupied by CoolBars, MenuBars, ToolBars, ToolControls, TabBars, TabControls and StatusBars. In most applications it is therefore not necessary to specify the position and size of the MDIClient object, although you may do so if you want to reserve additional space in the parent Form for other objects.

Each of the four sides of an MDIClient object is automatically attached to the corresponding side of its parent Form and maintains its position when the parent Form is resized. This means that a default MDIClient always occupies the entire client area of its parent Form, regardless of how the parent is resized.

The appearance of the MDIClient may be changed using its Border, BCol and Picture properties. The EdgeStyle property has no direct effect and is provided only to pass on a value to its child Forms.

The MDIActive and MDIActiveObject properties contain the name of and a ref to the SubForm that currently has the focus. You may set these properties as well as query them.

You can call methods which cause the MDIClient to organise its child SubForms in some way. These methods are as follows:

MDICascade | Causes the MDIClient to organise its child Forms in an overlapping manner.
MDITile | Causes the MDIClient to arrange its child Forms as a row or column.
MDIArrange | Causes the MDIClient to arrange the icons associated with any minimised child Forms in an orderly fashion.


Menu Object
Parents Children Properties Methods Events
Purpose: This is a pop-up object which allows the user to initiate an action or to select an option using a "menu".

Description

For a Menu that is owned by a MenuBar or another Menu, the Caption property determines the text string that is displayed as the "choice". The Menu is then popped up by the user clicking on this text. It is automatically popped down when the user chooses an option (by selecting a MenuItem) or cancels the operation (by clicking elsewhere).

If a Menu belongs to a Form, SubForm or is a top-level object, it must be popped up by the application. This is commonly done in response to a MouseDown event. A Menu is popped-up by calling ⎕DQ with only the name of the Menu as its argument. The user may therefore not interact with any other object until a selection is made or until the operation is cancelled. When either occurs, the Menu is automatically popped down and de-activated, and its ⎕DQ terminates.

The Menu object does not have a Size property. Instead, its size is determined automatically by its contents.

If a Menu is owned by a MenuBar or by another Menu, its position within its parent is also calculated automatically, dependent on the order in which other related objects are established. The Posn property may however be used to insert a new Menu into an existing structure. For example, having defined three Menu objects as children of a MenuBar, you can insert a fourth one between the first and the second by specifying its Posn to be 2. Note that the value of Posn for the Menus that were previously second and third will then be reset to 3 and 4 respectively.

If a Menu is a child of a MenuBar which is itself a child of a Form or SubForm, the Align property can be set to 'Right'. This is used to position a single Menu (or MenuItem) at the rightmost end of a MenuBar. This does not apply if the MenuBar is owned by a ToolControl.

The BtnPix property is used to display a picture in a Menu. BtnPix specifies the names of, or refs to, three Bitmap objects. The first Bitmap is displayed when the Menu does not have the focus (normal), the second when it does have the focus (highlighted). The third Bitmap is displayed when the Menu is made inactive (Active property is 0). If Caption is also defined, it is displayed on top of the bitmaps.

If the Menu is a submenu (owned by a Menu), you may set its EdgeStyle property to 'Plinth'. This causes the Menu to take on an appearance that is similar to a pushbutton and be raised when not selected and recessed when selected. Note that to enable 3-dimensional appearance, you must set EdgeStyle to something other than 'None' for all the objects above the Menu in the tree.

EdgeStyle, BtnPix, Font, FCol and BCol do not affect the appearance of a Menu if it is the direct child of a MenuBar. However, the EdgeStyle property must be set to something other than 'None' if you want its children Menu and MenuItem objects to have a 3-dimensional appearance.


MenuBar Object
Parents Children Properties Methods Events
Purpose: Specifies a horizontal menu bar displayed at the top of a Form.

Description

Unless it is made invisible the MenuBar is always available to the user to initiate actions or to select options. A MenuBar has a fixed position and size.

It is possible to have more than one MenuBar associated with the same Form or SubForm, but only one of them should be Visible at any one time.

The following example illustrates how a menu structure can be built up from a MenuBar. For clarity, the example is indented, and the definition of the Event property is omitted.

      'F'           ⎕WC 'Form' 'Menu Example'
      'F.M'         ⎕WC 'MenuBar'
      'F.M.FILE'    ⎕WC 'Menu' '&File'
      'F.M.MAT'     ⎕WC 'Menu' '&Materials'
      'F.M.MAT.B'   ⎕WC 'MenuItem' '&Brick'
      'F.M.MAT.C'   ⎕WC 'MenuItem' '&Concrete'
      'F.M.MAT.S'   ⎕WC 'MenuItem' '&Stone'
      'F.M.MAT.SEP' ⎕WC 'Separator'
      'F.M.MAT.W'   ⎕WC 'Menu'     '&Wood'
      'F.M.MAT.W.O' ⎕WC 'MenuItem' '&Oak'
      'F.M.MAT.W.T' ⎕WC 'MenuItem' '&Teak'
      'F.M.MAT.W.M' ⎕WC 'MenuItem' '&Mahogany'

Note that putting a Separator (either Style) in a MenuBar has the effect of breaking the bar vertically, i.e. the next Menu or MenuItem you add will appear on the left-hand side on the line below.

The EdgeStyle property has no effect on the appearance of a MenuBar or of a direct child of a MenuBar. However, if you want the sub-menus to have a 3-dimensional appearance, you must set the EdgeStyle property of the MenuBar to something other than 'None'.

If the MenuBar is owned by a Form that is the parent of an MDIClient, you can set the MDIMenu property to the name of the Menu you wish to nominate as the window menu. This menu will automatically be updated with the Captions of the child SubForm and may be used to select the currently active one.


MenuItem Object
Parents Children Properties Methods Events
Purpose: This object allows the user to initiate an action or to select an option from a menu.

Description

The Caption property determines the text string that is displayed in its parent as the menu option. The size of a MenuItem is determined by the size of its Caption, or by the size of the largest object (Menu, MenuItem or Separator) with the same parent. The position of the MenuItem is normally determined by the order in which it is created in relation to other objects with the same parent. However, you can use the Posn property to insert a new MenuItem into an existing structure. For example, having defined three MenuItem objects as children of a Menu, you can insert a fourth one between the first and the second by specifying its Posn to be 2. Note that the value of Posn for the MenuItems that were previously second and third will then be reset to 3 and 4 respectively.

The Style property may be 'Check' (the default) or 'Radio'. Style determines the type of graphic displayed alongside the Caption if the MenuItem is checked.

The Checked property is a single number with the value 0 or 1. 0 means not checked (the default), 1 means checked and a tick mark or radio dot is placed alongside its Caption. This property is frequently used to indicate which of a choice of options is currently set.

If a MenuItem is a child of a MenuBar which is itself a child of a Form or SubForm, the Align property can be set to 'Right'. This is used to position a single MenuItem (or Menu) at the rightmost end of a MenuBar. This does not apply if the MenuBar is owned by a ToolControl.

If you set the EdgeStyle property to 'Plinth', the MenuItem will take on an appearance that is similar to a pushbutton and be raised when not selected and recessed when selected. Note that to enable 3-dimensional appearance, you must set EdgeStyle to something other than 'None' for all the objects above the MenuItem in the tree.

The BtnPix property is used to display a picture in a MenuItem. BtnPix specifies the names of, or refs to, three Bitmap objects. The first Bitmap is displayed when the MenuItem does not have the focus (normal), the second when it does have the focus (highlighted). The third Bitmap is displayed when the MenuItem is made inactive (Active property is 0). If Caption is also defined, it is displayed on top of the bitmaps.

Alternatively, you may display an image alongside the Caption using the ImageIndex property. This selects a picture from the ImageList associated with the ImageListObj property of the parent Menu.

EdgeStyle, BtnPix, FontObj, FCol and BCol are not effective if the MenuItem is the direct child of a MenuBar.

A MenuItem generates a Select event (if enabled) when the user chooses it.


Metafile Object
Parents Children Properties Methods Events
Purpose: This object represents a picture in Windows Metafile format.

Description

The Windows Metafile is a mechanism for representing a picture in terms of a collection of graphical components. Windows Metafiles are distributed in special files (.WMF) from which they are loaded into memory for use by an application. Once loaded a Metafile is a Windows "resource" that can be used in a variety of ways. The Metafile object represents this resource.

The File property specifies the name of a .WMF file from which the Metafile is to be loaded or to which it is to be saved. If you specify File with ⎕WC the Metafile object is loaded from it. If you specify File with ⎕WS no action takes place until you instruct the Metafile object to re-initialise itself from the file or to save itself to the file. These operations are performed using the FileRead and FileWrite methods. If you omit the File property in the argument to ⎕WC or if you specify a null vector, the Metafile object is initially empty. The following example loads the picture defined by the GOLF.WMF Metafile that is distributed with Microsoft Office.

      'GOLF' ⎕WC 'Metafile' 'C:\MSOFFICE\CLIPART\GOLF'

Whether or not the Metafile object is initialised from a file, you can add graphical components to it by creating child objects. However the Metafile behaves like a Bitmap object in that its children cannot be modified using ⎕WS nor can they be removed using ⎕EX. The components of a Metafile that has been initialised from a .WMF file also cannot be referenced in any way. It is therefore recommended that you use unnamed objects when you create the graphical components of a Metafile.

The following statements create an empty Metafile called MF and then draw a line and circle in it.

      'MF' ⎕WC 'Metafile'
      'MF.' ⎕WC 'Poly' (50(10 90))
      'MF.' ⎕WC 'Circle' (50 50) 30

Like the Bitmap, Icon, Font and Cursor objects, the Metafile is a resource that is not visible until it is used. This is done by setting the Picture property of another object (Form, Image, Static or SubForm) to the name of, or ref to, the Metafile object. For example, to display the Metafile MF in a Form, you could type :

      'TEST' ⎕WC 'FORM' ('Picture' 'MF')

You can also copy a Metafile object to the Windows Clipboard from where it can be pasted into another application. This is done by creating a Clipboard object and then setting its MetafileObj property to the name of the Metafile object to be exported. For example :

      'CL' ⎕WC 'Clipboard'
      'CL' ⎕WS 'MetafileObj' 'MF'

The FileWrite method may be used to save a Metafile object on a file. The following statements save the Metafile MF in a file called TEST.WMF.

      MF.File←TEST'
      MF.FileWrite

The Size property determines the granularity of the Metafile. Its default value is the size of its parent. If you intend to replay the Metafile at higher resolution, you should set Size accordingly.

The RealSize property specifies the suggested size of a Metafile in units of 0.01mm. Setting RealSize has the effect of making the Metafile placeable. Certain programs (such as Word for Windows) only support placeable metafiles.


MsgBox Object
Parents Children Properties Methods
Purpose: Provides a "modal" dialog box for displaying messages, errors, warnings and other information. The dialog box has a title, one or more lines of text, and up to three buttons.

Description

The Caption property determines the text displayed in the object's title bar.

The Text property determines the text to be displayed as the message.

The Style property determines the type of icon which is displayed. This is a character vector with one of the following values:

'Msg' | no icon (the default)
'Info' | information message icon
'Query' | query (question) icon
'Warn' | warning icon
'Error' | critical error icon

The Btns property determines the set of buttons to be displayed. It is a simple vector (one button) or a matrix with up to 3 rows, or a vector of up to 3 character vectors specifying the captions for up to 3 buttons. MS-Windows restricts you to a fixed set of button captions which are described below. However, the property has been designed more generally to be useful under different GUIs and perhaps later revisions of Windows. The buttons are arranged along the bottom of the dialog box in the order specified.

The Btns property may specify one of six sets of buttons as follows:

  • 'OK'
  • 'OK' 'CANCEL'
  • 'RETRY' 'CANCEL'
  • 'YES' 'NO'
  • 'YES' 'NO' 'CANCEL'
  • 'ABORT' 'RETRY' 'IGNORE'

If any other combination is specified, ⎕WC and ⎕WS will report a DOMAIN ERROR. The names of the buttons are however case-insensitive, so the system will accept 'ok', 'Ok', 'oK' or 'OK'. If Btns is not specified, it assumes a default according to Style as follows:

Style | Btns
'Msg' or 'Info' | 'OK'
'Warn' or 'Error' | 'OK' 'CANCEL'
'Query' | 'YES' 'NO'

The Default property may be used to determine which of the buttons is the "default" button, i.e. the one which initially has the focus and is "selected" when the user presses the Enter key. It has the value 1, 2 or 3. If Default is not specified, the first button is the "default" button. Note that if the user switches focus to another button and presses Enter, this action selects the button with the focus.

Like a pop-up (floating) Menu, the MsgBox object is unusual in that it is strictly modal. It is created by ⎕WC in the normal way, but at that stage is invisible and inactive. It is activated ONLY when ⎕DQ is called with the name of the MsgBox as the argument. When this is done, the MsgBox object pops up and is activated. Because there is no other object specified in the argument to ⎕DQ, all other objects are de-activated. The only thing that the user can do (within the APL application) is to press one of the buttons in the MsgBox. When this happens, the MsgBox automatically pops down, the callback function (if any) is fired, and then ⎕DQ terminates.

Notice that the position and size of the MsgBox are determined by Windows and are fixed, although the MsgBox may be moved by the user after it has been displayed.

The MsgBox object generates one of three events; MsgBtn1 (61), MsgBtn2 (62), or MsgBtn3 (63) depending upon which button is pressed.

   Caption←'Default MsgBox' ⋄ Text←'Hello World'
   'Msg' ⎕WC 'MsgBox' Caption Text ⋄ ⎕DQ 'Msg'

   Caption←'Information MsgBox' ⋄ Text←'Update Completed'
   'Msg' ⎕WC 'MsgBox' Caption Text 'Info' ⋄ ⎕DQ 'Msg'

   Caption←'Query MsgBox' ⋄ Text←'Save Changes'
   'Msg' ⎕WC 'MsgBox' Caption Text 'Query' ⋄ ⎕DQ 'Msg'

   Caption←'Warning MsgBox'
   Text←'Calculations will take 10 minutes'
   'Msg' ⎕WC 'MsgBox' Caption Text 'Warn' ⋄ ⎕DQ 'Msg'

   Caption←'Error MsgBox'
   Text←'Data out of range'
   'Msg' ⎕WC 'MsgBox' Caption Text 'Error' ⋄ ⎕DQ 'Msg'

   Caption←'Custom MsgBox'
   Text←⊂'You can have a multi-line'
   Text,←⊂'message if you want one'
   B←'ABORT' 'RETRY' 'IGNORE'
   'Msg' ⎕WC 'MsgBox' Caption Text 'Info' B ⋄ ⎕DQ 'Msg'


NetClient Object
Parents Children
Purpose: The NetClient object represents an instance of a Microsoft .NET class.

Description

The NetClient object represents an instance of a .NET class.

Normally, you create a NetClient object using the New method. For example:

      ⎕USING ←'System'
      DT1←DateTime.New 2002 4 30
      DT1.Type
NetClient

If, for any reason, you are unable to use the New method, you may create a NetClient object using ⎕WC. In this case, the ClassName property specifies the full name of the .NET class, and the ConstructorArgs property specifies the arguments for the constructor function if required.

      ⎕USING ←'System'
      'DT2'⎕WC'NetClient' 'System.DateTime'(1949 4 30)
      DT2.(Type ClassName ConstructorArgs)
 NetClient  System.DateTime  1949 4 30


NetType Object
Parents Children Properties Methods Events
Purpose: The NetType object is used to export a namespace as a Microsoft.NET class.

Description

The NetType object allows you to export an APL namespace as a .NET class that can be accessed by any conforming .NET client application.

The BaseClass property specifies the name of the .NET class from which the specified NetType object inherits. The default is System.Object.

When you create a NetType object, the name of its parent namespace specifies the name of the corresponding Microsoft .NET Namespace to which the NetType class belongs. If the NetType is created as a child of root, the corresponding Microsoft .NET Namespace is unnamed.


OCXClass Object
Parents Properties Methods Events
Purpose: This object provides access to OLE (ActiveX) Controls.

Description

This object loads an OLE Control into memory and defines a new class of object associated with it. The name of the new class is the name specified by the left argument of ⎕WC You may create an instance of the newly defined class using the name you assigned to the OCXClass object as the Type property.

Note that you may not create an instance of OCXClass using ⎕NEW.

Once you have defined a new OCXClass, the properties, events and methods it supports may be obtained from its PropList, EventList and MethodList properties. These are the properties, events and methods defined for the OLE control by its author.

The QueueEvents property determines how events reported by the ActiveX control are handled.

To find out how to use the OLE control, you must consult the appropriate documentation. However, a great deal of information about it can be obtained using the GetPropertyInfo, GetEventInfo, and GetMethodInfo methods.


OLEClient Object
Parents Children Properties Methods Events
Purpose: The OLEClient object provides access to an OLE Automation Server

Description

The OLEClient object allows you to control OLE Servers, which may be written in a variety of different programming languages, including Dyalog APL itself.

The ClassName property specifies the name of the OLE object to which the new object named by the left argument of ⎕WC is to be connected. A list of all the OLE Server objects installed on your system may be obtained from the OLEServers property of Root. ClassName may only be specified by ⎕WC.

Alternatively, the OLE object may be identified by the ClassID property.

The AutoBrowse property and Browse method are no longer relevant and are ignored. They are retained only for backwards compatibility with previous versions of Dyalog APL.

Note that the PropList and MethodList properties of an OLEClient instance contain the names of the properties and methods exposed by the corresponding OLE Object in addition to the generic properties and methods of the OLEClient class.

If you call an OLE method with an invalid parameter, set a read-only property, or assign it an invalid value, the LastError property of the OLEClient and Root objects will contain error information generated by OLE.


OLEServer Object
Parents Children Properties Methods Events
Purpose: The OLEServer object is used to establish a namespace as an OLE Server object that can be used by an OLE Automation client.

Description

The OLEServer object allows you to export an APL namespace so that its functions and variables become directly accessible to an OLE Automation client application such as Microsoft Visual Basic or Microsoft Excel.

An OLEServer may be saved as an out-of-process OLE server (in a workspace) or as an in-process OLE server (in a DLL). See Interface Guide for details.

When you create an OLEServer object, APL allocates various OLE attributes to it. For example, the CLSID, which uniquely identifies the object, is assigned at this stage. However, the object is not actually registered until you execute )SAVE.

Registration involves updating the Windows registry with information about the object itself, such as its name, the command required to obtain it and so forth. Registration also records information about all of the functions and variables that your object exposes. Registration is therefore a non-trivial operation and should be delayed until the point when you are ready to test your OLEServer.

You may create an empty OLEServer object and then define functions and variables within it. Alternatively, you may convert an existing namespace which is already populated with functions and variables. The latter method is recommended as it implies less registry activity during the development of the object.

The ExportedFns and ExportedVars properties specify the names of the functions and variables that will be exposed by the object to OLE clients.

The RunMode property is a character vector that specifies how the object serves multiple clients. It may be 'MultiUse' (the default), 'SingleUse', or 'RunningObject'.

The ShowSession property is either 0 (the default) or 1 and specifies whether or not the APL Session window is displayed when the first instance of the OLEServer is created.

RunMode and ShowSession apply only to out-of-process OLEServers.


Poly Object
Parents Children Properties Methods Events
Purpose: A graphical object used to draw lines, polygons, and filled areas.

Description

The Points property specifies one or more sets of co-ordinates through which one or more lines are drawn. The resulting polygon(s) may also be filled.

LStyle and LWidth define the style and width of the lines. FCol and BCol determine the colour of the lines.

FStyle specifies whether or not the polygon(s) are filled, and if so, how. For a solid fill (FStyle 0), FillCol defines the fill colour used. For a pattern fill (FStyle 1-6) FillCol defines the colour of the hatch lines and BCol the colour of the areas between them.

Note that if you specify filling, you do not have to define a closed polygon. The first and last points will automatically be joined for you if necessary.

The value of Dragable determines whether or not the object can be dragged. The value of AutoConf determines whether or not the Poly object is resized when its parent is resized.

The structure of the property values is best considered separately for single and multiple polylines or polygons.

Single Polyline or Polygon

For a single polyline or polygon, Points is either a 2-column matrix of (y,x) co-ordinates, or a 2-element vector of y and x co-ordinates respectively.

LStyle and LWidth are both simple scalar numbers.

FStyle is either a single number specifying a standard fill pattern, or the name of a Bitmap object which is to be used as a "brush" to fill the polygon.

FCol, BCol and FillCol are each either single numbers representing standard colours, or 3-element vectors which specify colours explicitly in terms of their RGB values.

First make a Form :

      'F' ⎕WC 'Form'

Draw a single line from (y=20, x=10) to (y=30, x=50)

      'F.L1' ⎕WC 'Poly' ((20 30)(10 50))

or

      L ← 2 2⍴20 10 30 50
      'F.L1' ⎕WC 'Poly' L

Draw a horizontal line from (y=20, x=10) to (y=20, x=50). Note scalar extension of y-coordinate.

      'F.L1' ⎕WC 'Poly' (20(10 50))

Draw an empty box in green :

      Y ← 10 10 50 50 10
      X ← 10 50 50 10 10
      'F.L1' ⎕WC 'Poly' (Y X) (0 255 0)

Ditto, using a green/blue dashed line (LStyle 1) :

      'F.L1' ⎕WC 'Poly' (Y X) (0 255 0)(0 0 255) 1

Draw a red filled rectangle with a black border 5 pixels wide :

      'F.L1' ⎕WC 'Poly' (Y X) (0 0 0) ('LWidth' 5)('FStyle' 0)('FillCol' 255 0 0)

Multiple Polylines/Polygons

To draw a set of polylines or polygons with a single name, Points is a nested vector whose items are themselves 2-column matrices or 2-element nested vectors.

LStyle and LWidth may each be simple scalar values (applying to all the polylines) or simple vectors whose elements refer to each of the corresponding polylines in turn.

FStyle may be a simple scalar numeric or a simple character vector (Bitmap name) applying to all polylines, or a vector whose elements refer to each of the corresponding polylines in turn.

Similarly, FCol, BCol and FillCol may each be single numbers or a single (enclosed) 3-element vector applying to all the polylines. Alternatively, these properties may contain vectors whose elements refer to each of the polylines in turn. If so, their elements may be single numbers or nested RGB triplets, or a combination of the two.

First make a Form :

      'F' ⎕WC 'Form'

Draw two concentric triangles :

      BY ← 10 10 50 10
      BX ← 15 65 40 15
      RY ← 15 15 40 15
      RX ← 25 55 40 25
      'F.L1' ⎕WC 'Poly' ((BY BX)(RY RX))

Or, using matrices :

      BT ← BY,[1.5]BX
      RT ← RY,[1.5]RX
      'F.L1' ⎕WC 'Poly' (BT RT)

Ditto, but draw the first blue, the second red :

      'F.L1' ⎕WC 'Poly' (BT RT) ((0 0 255)(255 0 0))

Ditto, but make the lines 3 pixels wide :

      'F.L1' ⎕WC 'Poly' (BT RT) ((0 0 255)(255 0 0))('LWidth' 3)

Ditto, but make the line widths 3 and 6 pixels respectively :

      'F.L1' ⎕WC 'Poly' (BT RT) ((0 0 255)(255 0 0))('LWidth' 3 6)

Draw the first hollow, but fill the second in green :

      'F.L1' ⎕WC 'Poly' (BT RT) ('FStyle' ¯1 0)('FillCol' (⊂0 255 0))


Printer Object
Parents Children Properties Methods Events
Purpose: To provide printer output.

Description

The PName property is a character vector which specifies the name of an installed printer and the device to which it is attached. The name and device are separated by a comma (,). All valid values of PName can be obtained from the PrintList property of the Root object.

If not specified, the default value of PName is (⊃'.' ⎕WG 'PrintList').

The DevCaps property reports the size of the printable area of the page in pixels (dots) and in millimetres. It also reports the number of colours available. This is 2 on a monochrome printer (black and white), although grey scales may be available.

The FontList property provides a list of fonts that are applicable and includes TrueType and printer fonts. This list is typically different from that obtained from the FontList property on the Root object which lists those fonts that apply to the screen.

The Orientation property specifies the orientation of the page and may be either 'Portrait' or 'Landscape'.

The graphics objects listed above may be printed in much the same way as they may be displayed on a Form or Static. The differences are :

Once an object has been created, it will be printed, even if its name is subsequently expunged.

An object does not replace an existing one which has the same name.

The act of changing one or more properties of a named object causes the object to be printed a second time. For example, changing the Posn of an object will print it again at a different place.

In general it is recommended that you use unnamed objects for printing.

The Printer object five methods :

Name | Event | Description
Print | 100 | Sends output to print spooler
Setup | 101 | Displays Printer Set-up dialog box
NewPage | 102 | Throws a new page
Abort | 103 | Aborts the print job
RTFPrintSetup | 460 | Displays Printer Set-up dialog box

Examples:

Start a print job on the default printer

      'PR1' ⎕WC 'Printer'

Write a centred heading at the top of the page using a proportional font

      'PR1.' ⎕WC 'Text' 'Report Title' (0 50)('HAlign' 1) ('FontObj' 'Roman' 64)

Draw a line across the page, 2 pixels wide

      'PR1.' ⎕WC 'Poly' (2(0 100)) ('LWidth' 2)

Print a character matrix. Note that a fixed width font is used.

      REPORT ← 'I6' ⎕FMT ?20 6⍴1000
      'PR1.' ⎕WC 'Text' REPORT (10 0)('FontObj' 'DyalogAPL')

Throw a new page

      PR1.NewPage

Spool output

      ⎕EX 'PR1'


ProgressBar Object
Parents Children Properties Methods Events
Purpose: The ProgressBar object is used to indicate the progress of a lengthy operation.

Description

The ProgressBar object is a window that an application can use to indicate the progress of a lengthy operation. The appearance of the bar in the ProgressBar is determined by the ProgressStyle property.

If ProgressStyle is Normal or Smooth, the size of the bar, intended to indicate the amount of progress, is determined using the Thumb property in relation to its Limits property, and/or using the ProgressStep method. This can be updated as appropriate in the application logic or by using a Timer.

The range of a ProgressBar is specified by the Limits property. This is a 2-element integer vector defining its minimum and maximum values. The position of the filled rectangle is specified by the Thumb property. You can update the ProgressBar by using ⎕WS to set the value of the Thumb directly, or by using the ProgressStep method. The latter causes the Thumb to be updated by the value of the Step property.

If you attempt to set the Thumb to a value greater than its maximum value (using either method) the behaviour depends upon the value of the Wrap property which is Boolean and has a default value of 1. If Wrap is 1, the value obtained when you set the Thumb property is given by the expression:

      LIMITS[1]+(1+LIMITS[2]-LIMITS[1])|THUMB-LIMITS[1]

where THUMB is the value to which you set the Thumb property and LIMITS is the value of the Limits property. This causes the highlighted rectangle to begin filling again from the left.

If ProgressStyle is Marquee, the size of the bar is fixed and its position changes with time according to the value of the Interval property. The values of Thumb, Limits, Wrap and Step are irrelevant.


PropertyPage Object
Parents Children Properties Methods Events
Purpose: The PropertyPage object represents a single page in a PropertySheet.

Description

The PropertyPage object represents a single page within a PropertySheet.

The Posn and Size properties are read-only properties determined by the parent PropertySheet and may not be changed using ⎕WC or ⎕WS.

The HasHelp property is either 1 (the default) or 0. If the parent PropertySheet has a "Help" button (determined by its own HasHelp property) this property determines whether or not the Help button is active when the PropertyPage is the current page. If the HasHelp property of a PropertyPage is 0, the Help button on the parent PropertySheet will be temporarily disabled when that PropertyPage is displayed.

The PropertyPage object generates a PageActivate event when it becomes the current page and a PageDeactivate event when another page is selected. These events may not be disabled by a callback function.

If the user presses the Cancel button, the current PropertyPage generates a PageCancel event. This is followed by a Close event which is reported by the parent PropertySheet.

Other properties and behaviour depend upon the Style of the parent PropertySheet which may be 'Standard' or 'Wizard'

Standard Behaviour

In a Standard PropertySheet, the Caption property of each PropertyPage specifies the text that is written in its tab.

PropertyPage objects owned by a Standard PropertySheet generate PageCancel, PageApply and PageHelp events. These events are all caused by the user pressing the corresponding button in the parent PropertySheet.

Conventionally, the Apply button is initially inactive. When the user changes an item on any of the PropertyPages, the Apply button immediately becomes active. When the user clicks the Apply button, the application responds (normally by changing the appropriate properties) and then the Apply button becomes inactive once again. This process is controlled as follows.

The Changed property is a Boolean value that determines whether or not a PropertyPage is marked as having been in any way altered. The Apply button is active if the value of the Changed property for any of the PropertyPages is 1, and is inactive otherwise

Initially, the value of the Changed property for all of the PropertyPages is 0 and the Apply button is therefore inactive. If the user alters a control on a PropertyPage, by, for example typing into an Edit object or changing the State of a Radio Button, the PropertyPage immediately generates a PageChanged event with the parameter 1. The default processing for this event is to set the Changed property of the PropertySheet (to 1). This in turn activates the "Apply" button. If you return 0 from a callback on the PageChanged event, the Changed property remains 0 and the Apply button remains inactive.

When the user clicks the Apply button, each of the PropertyPages whose Changed flag is currently set to 1 generates a PageApply event. The default processing for this event is to generate a PageChanged event with the parameter 0. This is turn resets the Changed property of the PropertyPage to 0. Once all of the Changed flags have been reset, the Apply button becomes inactive. If you return 0 from a callback on any of the PageChanged events, the Changed property for the corresponding PropertyPage remains 1 and the Apply button remains active.

You may control the value of the Changed property using ⎕WS or by calling PageChanged as a method. In all cases, the Apply button is active if the value of Changed on any PropertyPage is 1, and inactive otherwise.

Wizard Behaviour

If the PropertyPage is owned by a Wizard PropertySheet, its Caption property specifies the text that appears in the title bar of the PropertySheet window when the PropertyPage is the current page. Note that a Wizard PropertySheet ignores its own Caption property.

There are effectively 3 page changing buttons on a Wizard PropertySheet, named Back, Next and Finish. The Next and Finish buttons actually occupy the same position and are mutually exclusive. The captions on the buttons are language-dependent.

Conventionally, the buttons change according to which of the PropertyPages is currently displayed. If the first one is displayed, the Next button is active but the Back button is inactive. When a middle page is displayed, both the Next and Back buttons are active. When the last page is displayed, the caption on the Next button changes to Finish. However, in some applications, the Back button may be disabled to prevent the user returning to a previous page.

When the user clicks the Back or Next button, the PropertyPage generates a PageBack or PageNext event followed by a PageDeactivate event. The new PropertyPage then generates a PageActivate event. These are followed by a SetWizard event which is generated by the parent PropertySheet and actually controls the state of the buttons. When the user clicks the Finish button, the PropertyPage generates a PageFinish event alone. All of these events reported by the PropertyPage are reported for information only. Returning 0 from a callback function has no effect. You may however control the buttons using the SetWizard event.


PropertySheet Object
Parents Children Properties Methods Events
Purpose: The PropertySheet object represents a standard multi-page dialog box.

Description

There are two different kinds of PropertySheet which you select using the Style property. This may only be set when the PropertySheet is created using ⎕WC and Style may not subsequently be changed using ⎕WS.

If Style is Standard (the default), the PropertySheet displays a set of pages (each represented by a PropertyPage) as a set of tabbed forms as illustrated below. The user selects the current page by clicking on the appropriate tab. This Style allows the user to select any page at any time and does not oblige the user to visit any but the first page you choose to display. This Style is useful for displaying groups of options or settings that the user may change.

If Style is Wizard, the PropertySheet displays its pages in succession starting with the first. The user steps from one to another using the Next and Back buttons and may be forced to visit all the pages in a prescribed order. This Style is useful for data entry or for asking the user to make a series of choices.

The Caption property specifies the text written in the window title bar, but only applies if the Style is Standard. The title bar text of a Wizard PropertySheet is specified by the Caption of the current PropertyPage.

The HasApply and HasHelp properties are Boolean and specify whether or not the PropertySheet has "Apply" and "Help" buttons respectively. These properties may only be set when the object is created using ⎕WC. They both have default values of 1.

The FontObj and EdgeStyle properties have no effect on the appearance of the PropertySheet itself, but may be used to define the default appearance of its children.


Rect Object
Parents Children Properties Methods Events
Purpose: A graphical object used to draw boxes.

Description

The Points property specifies one or more sets of co-ordinates which define the position(s) of one or more rectangles. The position of a rectangle is defined to be the position of the corner that is nearest to the origin of its parent. The default is therefore its top-left corner. The Size property specifies the height and width of each rectangle, measuring away from the origin.

The Radius property specifies the curvature of the corners of the rectangle.

LStyle and LWidth define the style and width of the lines used to draw the boundaries of the rectangle(s). FCol and BCol determine the colour of the lines.

FStyle specifies whether or not the rectangle(s) are filled, and if so, how. For a solid fill (FStyle 0), FillCol defines the fill colour used. For a pattern fill (FStyle 1-6) FillCol defines the colour of the hatch lines and BCol the colour of the spaces between them.

The EdgeStyle property may specify a 3-dimensional effect. If so, the boundary line around the rectangle is replaced by a border designed to achieve the desired effect.

The value of Dragable determines whether or not the object can be dragged. The value of AutoConf determines whether or not the Rect object is resized when its parent is resized.

The structure of the property values is best considered separately for single and multiple rectangles :

Single Rectangle

For a single rectangle, Points is either a 2-column matrix of (y,x) co-ordinates, or a 2-element vector of y and x co-ordinates respectively.

Size is a simple 2-element vector whose elements specify the height and width of the rectangle respectively.

Radius is a 2-element vector which specifies the major (y-axis) and minor (x-axis) radii of an ellipse used to draw the corners of the rectangle. Its default value is (0 0) which yields right-angled corners.

LStyle and LWidth are both simple scalar numbers.

FStyle is either a single number specifying a standard fill pattern, or the name of a Bitmap object which is to be used as a "brush" to fill the rectangle.

FCol, BCol and FillCol are each either single numbers representing standard colours, or 3-element vectors which specify colours explicitly in terms of their RGB values.

First make a Form :

      'F' ⎕WC 'Form'

Draw a single rectangle at (y=10, x=5) with height=30, width=50 :

      'F.R1' ⎕WC 'Rect' (10 5)(30 50)

Ditto with rounded corners (radii 10) :

      'F.R1' ⎕WC 'Rect' (10 5)(30 50)(10 10)

Ditto, but use a red line :

      'F.R1' ⎕WC 'Rect' (10 5)(30 50)(10 10)(255 0 0)

Ditto, but fill in green

      'F.R1' ⎕WC 'Rect' (10 5)(30 50)(10 10)(255 0 0) ('FStyle' 0)(0 255 0)

Multiple Rectangles

To draw a set of rectangles with a single name, Points may be a simple 2-element vector (specifying the location of all the rectangles), or a 2-column matrix whose first column specifies their y-coordinates and whose second column specifies their x-coordinates, or a 2-element nested vector whose first element specifies their y-coordinate(s) and whose second element specifies their x-coordinate(s).

Likewise, Size may be a simple 2-element vector (applying to all the rectangles), or a 2-column matrix whose first column specifies their heights and whose second column specifies their widths, or a 2-element nested vector whose first element specifies their height(s) and whose second element specifies their width(s).

Radius may be a simple 2-element vector (applying to all the rectangles), or a 2-column matrix whose first column specifies major radii and whose second column specifies minor radii, or a 2-element nested vector whose first element specifies major radii and whose second element specifies minor radii.

LStyle and LWidth may each be simple scalar values (applying to all the rectangles) or simple vectors whose elements refer to each of the corresponding rectangles in turn.

FStyle may be a simple scalar numeric or a simple character vector (Bitmap name) applying to all rectangles, or a vector whose elements refer to each of the corresponding rectangles in turn.

Similarly, FCol, BCol and FillCol may each be single numbers or a single (enclosed) 3-element vector applying to all the rectangles. Alternatively, these properties may contain vectors whose elements refer to each of the rectangles in turn. If so, their elements may be single numbers or nested RGB triplets, or a combination of the two.

First make a Form :

      'F' ⎕WC 'Form'

Draw two rectangles at (y=5, x=10) and (y=5, x=60) each of (height=40, width=10)

      'F.R1' ⎕WC 'Rect' ((5 5)(10 60)) (40 10)

Ditto, using scalar extension for (y=5) :

      'F.R1' ⎕WC 'Rect' (5(10 60)) (40 10)

Ditto, but draw the first with (height=40, width=30) and the second with (height=20, width=10) :

      'F.R1' ⎕WC 'Rect' (5(10 60)) ((40 20)(30 10))

Draw two rectangles at (y=5, x=10) and (y=5, x=60) each of (height=40, width=10) and with rounded corners of radii (10,10) :

      'F.R1' ⎕WC 'Rect' (5(10 60)) (40 10) (10 10)

Ditto, using a green line for both :

      'F.R1' ⎕WC 'Rect' (5(10 60)) (40 10) (10 10)(⊂0 255 0)

Ditto, but using red and blue lines respectively :

      'F.R1' ⎕WC 'Rect' (5(10 60)) (40 10) (10 10)((255 0 0)(0 0 255))


RichEdit Object
Parents Children Properties Methods Events
Purpose: The RichEdit object is a multi-line text editor that provides a wide range of word-processing capabilities.

Description

A RichEdit object is a window in which the user can enter and edit text. The text can be assigned character and paragraph formatting. Although the corresponding control can include embedded OLE objects, this is not yet supported by Dyalog APL.

The RichEdit object provides a programming interface for formatting text. However, your application must implement any user interface components necessary to make formatting operations available to the user. For example, your program can set the colour and font of a particular block of text, but the RichEdit itself provides no facilities for the user to do this directly. It is up to you to provide these.

The File property specifies the name of a file associated with the object. Data in the file is assumed to be in rich text format, and the default extension for the file is .RTF. You can read the file into the object by calling FileRead and you can write the contents to the file by calling FileWrite. You can also print the contents of the object by calling RTFPrint.

The Text property may be used to set or retrieve the text of the RichEdit, but ignores formatting information. Text may set using a simple character vector, a simple matrix, or a vector of vectors. If Text is specified by a matrix or by a vector of vectors, "new-line" characters are automatically added at the end of each line in the RichEdit control.

The user may insert a "new-line" character in the text by pressing Ctrl-Enter. If Text was set by a matrix, it is returned as a matrix. Otherwise it is returned as a vector of vectors. "New-line" characters are not returned. If Text was not specified by ⎕WC or ⎕WS it is returned an empty matrix (1 0⍴'').

The RTFText property may be used to set or retrieve the contents of the RichEdit, including text and formatting.

The PageWidth property defines the width of the text within the object. Text entered into the object is automatically wrapped according to PageWidth. This property also defines the width when the text is printed.

You can set the default character format or the format of a particular block of text using the CharFormat property. If there is no selection, setting CharFormat defines the default character format that applies at the current insertion position and establishes the appearance of all of the text (font, colour, size etc.) that the user subsequently enters here. If there is a selection, setting CharFormat sets the character format for the selected block of text.

The WordFormat property is similar to CharFormat except that is sets the format for the selected word(s) or, if there is no selection, for the word containing the insertion point.

The ParaFormat property defines the paragraph formatting which includes alignment, indentation and the location of tab stops. When you set ParaFormat with ⎕WS, the formatting is applied to the current selection. If there is no selection, it defines the default paragraph formatting at the insertion point.

All of the dimensions used for text and paragraph formatting are specified in Twips. You can convert from pixels to Twips and vice versa using the DevCaps property of either Root or the Printer object as appropriate.

The behaviour of the Enter key is defined by the WantsReturn property. If WantsReturn is 1 (the default), the Enter key inputs a new line into the RichEdit object. If WantsReturn is 0 the Enter key is ignored by the RichEdit object and may instead generate a Select event on a Button. In this case the user must press Ctrl+Enter to input a new line.

The user may copy and paste information (in RTF format) between a RichEdit object and the Windows clipboard. The Clipboard object also has an RTFText property that supports RTF format

If the user attempts to alter text that is protected (see CharFormat) the RichEdit object reports a Protected event.

You may print the contents of a RichEdit object using the RTFPrint method. You may display a print set-up dialog box using the RTFPrintSetup method.


Root Object
Children Properties Methods Events
Purpose: This is an invisible "system" object that acts as the parent of all other objects.

Description

There is a single Root object called '.' which is always present. It cannot be created using ⎕WC nor can it be destroyed.

The Caption and IconObj properties of '.' are used to identify a Dyalog APL/W application as distinct from the APL Session. The Caption property specifies the application name that is displayed when you cycle through running applications using Alt+Tab and by the Windows Task List. The IconObj property specifies the name of an Icon object that is displayed alongside the application name in the box displayed by Alt+Tab. For these to take effect, your application must have at least one visible and active Form.

For the Root object, the value of Posn is (0,0). The value of Size is either (100,100) if Coord is 'Prop', or the size of the screen in pixels if Coord is 'Pixel'. XRange and YRange both have the value (0,100). The DevCaps property reports the physical size of the screen in terms of both pixels and millimetres. It also reports the number of colours available.

The FontList property provides a list of all the character fonts that are available. The PrintList property provides a list of all the installed printers. These properties are read-only and may not be changed using ⎕WS

As the default value of Coord is 'Inherit' for all other objects, the value of Coord for '.' defines the default co-ordinate system. It may be either 'Prop' (the default) or 'Pixel'. 'Inherit' and 'User' are not allowed.

The CursorObj property is used to define a cursor for the application as a whole. Its default value is an empty character vector. If it is set to any value other than '' or 0, the selected cursor overrides the CursorObj values for all other objects. If you want to indicate that the application is "busy", you can therefore set the CursorObj property on '.' to an hourglass for the duration of the operation, e.g.

      '.' ⎕WS 'CursorObj' 1  ⍝ Set cursor to an hourglass

[lengthy process...]

      '.' ⎕WS 'CursorObj' 0  ⍝ Reset cursor

The Yield property specifies how frequently APL yields to Windows during the execution of code. Its default value is 200 milliseconds.

The EdgeStyle property is used to determine whether or not objects may have 3-dimensional effects. Setting EdgeStyle to 'None' disables 3-dimensional effects on all Forms and controls. Setting EdgeStyle to any other value enables 3-dimensional effects for these objects.

The ExitApp and ExitWindows events can be used to prevent the user closing your application from the Windows Task List or by terminating Windows.

The expression ⎕EX '.' deletes all objects owned by the current thread except the Root object itself. In addition, if this expression is executed by thread 0, it resets all the properties of '.' to their default values.

Exposing Root members

The Properties, Methods and Events of the Root object are always accessible using the system functions ⎕WS, ⎕WG and ⎕NQ but may also be optionally accessed directly as if they were global variables or functions in the workspace.

For example, if Root members are exposed, the following expression will set the application cursor (GUI) to an hourglass:

      CursorObj←1

There are a number of elements that control whether or not Root members are exposed.

  1. The fundamental mechanism is a flag that is saved in every workspace. If this flag is set, the members of the Root object are exposed; if not, they are not exposed.
  2. This flag may be changed dynamically using the Options/Object Syntax/Expose Root Properties menu item on the Session or using 2401⌶. If the workspace is subsequently saved, the current value of the flag is saved with it.
  3. The value of the flag in a CLEAR WS is determined by the PropertyExposeRoot parameter. Under Windows, this parameter is associated with the Expose properties of Root checkbox on the Object Syntax Tab of the Configuration dialog box. When you change the value of this checkbox and close the Configuration dialog by clicking OK, the value of the PropertyExposeRoot parameter is immediately updated in the user's section of the Registry. However, the value of the flag in the current workspace is not changed. The PropertyExposeRoot parameter only defines the value of the flag in a CLEAR WS, so if you subsequently type )CLEAR, the current value of the parameter in the Registry determines whether or not Root members are exposed and sets the flag in the workspace accordingly.

For further information, see The Options Menu, PropertyExposeRoot, and Expose Root Properties.

Notes:

  1. When Root members are exposed, the first reference or assignment to a member, associates that name (with a nameclass of ¯2.6 or ¯3.6) with that member. If, having referenced a member in this way, you subsequently hide Root members using (2401⌶0), that name remains connected to that member and the member remains exposed. This association may however be removed by erasing the name.
  2. If Root members are not exposed, you are free to define an APL object with the same name as one of the members. If you subsequently expose Root members using (2401⌶1), the name remains associated with the APL object and not with a member of Root. If you then erase the name and re-reference or re-assign it, the name will be associated with the corresponding member.


Scroll Object
Parents Children Properties Methods Events
Purpose: Provides a vertical or horizontal scrollbar.

Description

The Scroll object provides a vertical or horizontal scrollbar that can be used as a "free-standing" object or can be "attached" to the side of its parent.

An "attached" scrollbar is one that extends along one edge of a Form, SubForm or Group and has a standard width or height. When the Form or Group is resized, a vertical attached scrollbar is resized vertically but remains the same width and stays fixed to the side of its parent. Similarly, a horizontal attached scrollbar is resized horizontally but remains the same height.

For most purposes, the use of the Scroll object to provide attached scrollbars in a Form has been superseded by the provision of scrollbars as a property of a Form.

A "free-standing" scrollbar is typically used as a "scale" for selecting a numeric value from a range and may appear and behave rather differently from a standard attached scrollbar. Firstly, a free-standing scrollbar will normally be positioned at an arbitrary position within its parent Form or Group and be associated with other objects such as Labels and Edit fields. Secondly, when its parent Form or Group is resized, it is probably desirable that the scrollbar reacts in the same way as the other child objects, so that the overall appearance of the layout is maintained.

The Align property determines whether or not a scrollbar is attached, and if so, to which side of the parent Group or Form it is fixed. The direction of the scrollbar is determined by the VScroll and HScroll properties, which are mutually exclusive. The position and size of the scrollbar are determined by Posn and Size.

To obtain an "attached" scrollbar, it is sufficient for most purposes to specify only the Align property. If so, the direction of the scrollbar and its position and size (which are otherwise defined by VScroll, HScroll, Posn and Size) are determined automatically for you.

To obtain a "free-standing" scrollbar, it is recommended for most purposes that you set Align to 'None' and define the orientation, position and size of the scrollbar explicitly using VScroll or HScroll, Posn and Size.

VScroll and HScroll may only be set when the object is created and may not subsequently be changed.

If you do attach a "free-standing" scrollbar to a particular side of its parent using Align, it will maintain its physical position (in pixels) relative to the side to which it is attached, and its dimension in that direction will remain fixed.

The Align property is a character vector containing 'Top', 'Bottom', 'Right', 'Left' or 'None'. If you specify Align 'Right' you get a vertical scrollbar attached to the right-hand edge of the parent Form or Group. Align 'Left' also produces a vertical scrollbar, but one that is attached to the left-hand edge. Align 'Top' and 'Bottom' each produce horizontal scrollbars, attached to the top and bottom edges of the Form or Group respectively.

Note that the default value of Align is 'Right' unless HScroll is set to ¯1 in which case it is 'Bottom'. It must therefore be explicitly set to 'None' if you want a non-attached "free-standing" scrollbar.

VScroll and HScroll are used to specify the orientation of the scrollbar explicitly, usually in conjunction with Align set to 'None'. VScroll or HScroll may be specified when the object is created by ⎕WC, but cannot be changed using ⎕WS. The two properties are mutually exclusive. Each of them may be set to 0 or ¯1, where ¯1 means "true" and 0 means "false". Thus (VScroll ¯1) defines a vertical scrollbar, while (HScroll ¯1) specifies a horizontal one. Setting either property to ¯1 automatically causes the other to be set to 0. If you try to set both to ¯1, VScroll takes precedence and HScroll is reset to 0.

[Note: the reason for using two properties where one would be sufficient is to allow for the possible future implementation of scrolling groups as provided by ⎕SM/⎕SR.]

Scrolling is controlled by the Thumb, Range and Step properties.

Thumb sets and reports the current position of the "thumb" as an integer in the range 1 to the value of the Range property.

Step determines the size of changes reported when the user clicks a scroll arrow (small change) or clicks on the body of the scrollbar (large change). Step is a 2-element numeric vector whose first element specifies the value of the "small change" and whose second element specifies the value of the "large change". The PageSize property specifies the sizes of the thumb in the scrollbar.

Examples of Attached Scrollbars:

      'F' ⎕WC 'Form' 'Default Scroll Bar'
      'F.SCR' ⎕WC 'Scroll'

      'F' ⎕WC 'Form' 'Default Horizontal Scroll Bar'
      'F.SCR' ⎕WC 'Scroll' ('HScroll' ¯1)

Examples of Free-Standing Scrollbars:

      'F' ⎕WC 'Form' 'Non-Default Scroll Bar'
      'F.SCR' ⎕WC 'Scroll' (5 45)(90 10)
                  ('Align' 'None')('VScroll' ¯1)

      'F' ⎕WC 'Form' 'Horizontal Scroll Bars'
      'F.SC1' ⎕WC 'Scroll' (15 15)(15 70)
                  ('Align' 'None')('HScroll' ¯1)
      'F.SC2' ⎕WC 'Scroll' (40 40)(20 20)
                  ('Align' 'None')('HScroll' ¯1)
      'F.SC3' ⎕WC 'Scroll' (85 5)(10 90)
                  ('Align' 'None')('HScroll' ¯1)


Separator Object
Parents Children Properties Methods Events
Purpose: A horizontal or vertical line used to separate items in a menu.

Description

This object provides a vertical or horizontal line to separate items in a Menu. It may also be used to split a MenuBar over more than one line.

The orientation of the Separator is determined by its Style property, which may be 'Horz' (horizontal) or 'Vert' (vertical). The default is 'Horz'.

If you want to provide a menu with a 3-Dimensional (pushbutton) appearance, you should also set the EdgeStyle property on any Separator objects in it. Alternatively, you can achieve the same effect by setting the background colour (BCol) for the Separators to grey (192 192 192).

The Posn property is a single integer number which specifies the positional index of the Separator relative to the other objects in the Menu. A Separator does not generate any events.

Like other components of a menu, the position of a Separator is normally determined by the order in which it is created in relation to other objects with the same parent. However, you can use the Posn property to insert a Separator into an existing structure. For example, having defined three MenuItem objects as children of a Menu, you can insert a Separator between the first and the second by specifying its Posn to be 2. Note that the value of Posn for the MenuItems that were previously second and third will then be reset to third and fourth respectively.

If you put a Separator (either Style) into a MenuBar, it has the effect of adding another line to it. Any items added after the Separator will appear in the new line.


SM Object
Parents Children Properties Methods Events
Purpose: Defines a window for ⎕SM/⎕SR.

Description

This object defines a window for ⎕SM/⎕SR and allows you to combine the functionality of ⎕SM/⎕SR with the "windows" GUI. For example, you can define a Form with a MenuBar at the top and a ⎕SM window beneath it, with perhaps some Buttons alongside.

To allow the user to interact with both ⎕SM and other top-level objects, you must specify the names of these objects in the right argument of ⎕SR. Thus the statement:

      CTX ← KEYS CTX ⎕SR 1 2 3 'Form1'

allows the user to interact with fields (rows) 1-3 of ⎕SM and with the object 'Form1' and its children. Callback functions associated with events in 'Form1' will be executed automatically by ⎕SR. If an enabled event without a callback occurs, the event will be placed on ⎕DQ's internal queue and ⎕SR will terminate. The nature of the termination (i.e. that it was caused by an event in an object) is reported by the value 131072 (2*17) in the fourth element of ⎕SR's result. The specific event (Configure, MouseUp, etc.) is however not reported. It is therefore generally preferable to use callbacks.

The Posn, Size and Coord properties allow you to specify the position and size of the window occupied by ⎕SM within its parent Form. Note however that the ⎕SM window will automatically be sized to be an exact number of characters in height and width which will be reported in ⎕SD.

The Border property may be used to specify a border around the outside of the ⎕SM window. It is a number with the value 0 (no border) or 1 (1 pixel border). The default is 0. The EdgeStyle property may be used to give the object a 3-dimensional appearance. Its default value is 'Recess'. The area within the SM object that is defined by ⎕SM is necessarily a multiple of the character size. The region between this area and the outer edges of the object is coloured by the background colour specified by BCol, or may be filled with a bitmap specified by Picture.

If the user resizes the Form which contains the SM object, the SM object will generate a Configure event if enabled. If the Configure event is not enabled, ⎕SR will terminate with a RESIZE error which can be trapped using ⎕TRAP. Either method can be used to reformat ⎕SM as appropriate.

The MouseDown event can be used to bring up a pop-up menu. Note however that mouse events are not reported over ⎕SM fields because ⎕SR uses these to position the cursor.

The illustration shown below was produced as follows :

      'TEST'      ⎕WC 'Form' 'SM Object' (60 10)(40 50)
      'TEST.MB'   ⎕WC 'MenuBar'
      'TEST.MB.F' ⎕WC 'Menu' '&File'
      'TEST.MB.O' ⎕WC 'Menu' '&Options'
      'TEST.B1'   ⎕WC 'Button' '&OK' (84 2)
      'TEST.B2'   ⎕WC 'Button' '&Cancel' (84 78)
      'TEST.S'    ⎕WC 'SM'(2 2)(80 96)('BCol'192 192 192)
      ⎕SM←↑('The answer is' 5 10)(42 5 30)


Spinner Object
Parents Children Properties Methods Events
Purpose: The Spinner object allows the user to enter a value, using an UpDown object to adjust it as required.

Description

The Spinner object is a special Dyalog APL composite object that consists of an edit field and a pair of spin buttons. The user may enter a value by typing in the edit field and may adjust the value with the spin buttons. The Spinner may cycle through a pre-defined set of values specified by the Items property or through a range of values specified by the Limits property. The FieldType property supports all of the standard data types, i.e. Char, Numeric, LongNumeric, Currency, Date, LongDate and Time.

The Limits property is a 2-element numeric vector that specifies the minimum and maximum value of the object. The Step property specifies the amount by which the value is incremented or decremented by the spin buttons. The current value in the object is defined by the Thumb and Value properties, which are usually identical. If ReadOnly is 0, the user may type a value into the edit field which will be validated and converted according to the FieldType. In this case, the Value and the Thumb properties may be different.

An alternative way to use the Spinner object is to specify the Items property. This defines a discrete set of values through which the user may cycle, and the object behaves rather like a Combo without a drop-down list. In this case, the Limits property is automatically set to (1,⊃⍴Items), Thumb refers to the index into the list of Items, and Step specifies the amount by which this index is updated by the spin buttons. For example, if you set Step to 3, the spin buttons would display every third item. The Items property may be a character matrix, a vector of character vectors, or a numeric vector and will be formatted according to the FieldType. For example, if you wanted the user to select one of a set of specific dates, you would set the FieldType to Date or LongDate and the Items property to the day numbers (since 1 January 1900) corresponding to the dates you require. The ReadOnly property specifies whether or not the user may enter data into the edit field. A value typed in by the user will be converted and formatted according to the FieldType but need not correspond to a value in Items.

In operation, the value in the Spinner is adjusted by the Step each time one of the spin buttons is clicked. If the user holds a spin button down, the value is adjusted at the rate defined for the keyboard repeat rate. Furthermore, the size of each adjustment is increased according to the length of time the button stays depressed. After 1 second, the amount is increased to (2 × Step). after 2 seconds, to (4 × Step), after 3 seconds to (8 × Step) and so forth until the amount of adjustment exceeds one quarter of the range (Limits[2]⍎Limits[1]).

When the value in the spinner reaches its top or bottom limit, it will wrap around to the opposite limit if the value of the Wrap property is 1 (the default). Otherwise it will stick.

The MaxLength property defines the maximum number of characters that the user may type into the edit field. The Decimals property specifies the number of decimal places to which a numeric value is displayed and applies only if the FieldType is Numeric or LongNumeric.

The Spinner generates two special events, Spin and SetSpinnerText. The Spin event is generated each time the value of the Thumb is about to be updated and reports the new value and the difference between it and the current value. You may prevent the Thumb from being updated by returning 0 from a callback function, or you may alter the new value of the Thumb by returning a modified message. The SetSpinnerText event is generated after the Thumb has been reset but before the edit field has been updated. It reports the new value of the Thumb and the text that is about to be written into the edit field. By returning a modified event message from a callback, this event allows your application to respond dynamically to the spin buttons and to control the text in the edit field directly.

Like an Edit object, the Spinner has a Changed property and generates a Change event when loses the focus after the value of its Text and/or Thumb property has been altered.

If FieldType is Numeric, LongNumeric, Currency, Date, LongDate or Time, the Spinner will generate a BadValue event when it loses the focus if the text in the edit field (i.e. the Text property) is in conflict with the FieldType property and cannot be converted to an appropriate number, or is outside the range specified by the Limits property. If the edit field is empty, a BadValue event will be generated if ValidIfEmpty is 0, but not if it is set to 1.


Splitter Object
Parents Children Properties Methods Events
Purpose: The Splitter object divides a container into resizable panes.

Description

The Splitter divides the client area of a Form or SubForm into resizable panes. Each pane created this way may be empty or be occupied by a single object. If the object in a pane is itself a container object, such as a SubForm, it may have a number of other controls within it.

A single Splitter may manage the geometry of 0, 1 or 2 other objects, which, together with the Splitter itself, share the same parent. The two objects are named by the SplitObj1 and SplitObj2 properties respectively.

A Splitter may manage objects of the following types:

Button | Calendar | Combo | Edit | Grid | Group
Label | List | ListView | MDIClient | ProgressBar | RichEdit
Scroll | Spinner | Static | StatusBar | SubForm | TabBar
TabControl | ToolBar | TrackBar | TreeView | UpDown |

If Style is 'Vert' (the default), the Splitter is drawn vertically in its parent with the first object (SplitObj1) positioned to its left, and the second object (SplitObj2) to its right. See Splitter: Example 1.

If Style is 'Horz', the Splitter is drawn horizontally in its parent with the first object (SplitObj1) positioned above, and the second object (SplitObj2) below. See Splitter: Example 2.

The Style property must be set when the object is created with ⎕WC and may not subsequently be changed using ⎕WS.

The Posn and Size properties are partially read-only, in that only one dimension of the value may be specified. If Style is 'Vert', you may specify the x-coordinate and the width of the Splitter, but you may not specify its y- coordinate nor its height. If Style is 'Horz', you may specify the y-coordinate and the width of the Splitter, but you may not specify its x-coordinate nor its length.

When the user positions the mouse pointer directly over the Splitter object, the cursor changes (by default) to a double-headed arrow (direction in accordance with Style). The user may now depress the left mouse button and drag the Splitter to a new position, resizing the objects named by SplitObj1 and SplitObj2 in the process.

You can select a different cursor using the CursorObj property. Note that setting the CursorObj property to 0 selects the default cursor, which is the appropriate double-headed arrow.

When the user depresses the mouse button, the Splitter generates a StartSplit event. When the user releases the mouse button, the Splitter generates an EndSplit event. If full-drag is in effect, the Splitter also reports Splitting events as it is dragged. All these events report the new or current position of the Splitter object and are provided for information only.

Note that the objects named by SplitObj1 and SplitObj2 and any sub-objects they contain will generate Configure events when they are resized by the Splitter.

Alignment

The Align property specifies how a Splitter behaves when its parent is resized and may be 'None', 'Left', 'Right', 'Top' or 'Bottom'.

If Align is 'None', the Splitter moves as its parent is resized, so that it divides its parent in the same proportions as before. This is the default.

Any other value of Align attaches the Splitter to the corresponding edge of its parent. For example, if Align is 'Left', the width of the object to the left of the Splitter remains fixed when its parent is resized horizontally by the user.

Like the Style property, Align may be set only when the object is created with ⎕WC and may not subsequently be changed using ⎕WS.

Using Multiple Splitters

If you want to divide a Form into more than 2 resizable panes, there are two possible approaches, each with its own different characteristics.

The first approach is a hierarchical one using SubForms. This example shows how you can create a Form containing three resizable Edit objects.

First, you create an Edit, a SubForm, and a Splitter as children of the Form, using the Splitter to divide the Form into two panes, one for the Edit and the other for the SubForm. Next, you create two Edit objects and a Splitter as children of the SubForm, using the second Splitter to divide the SubForm into two. You can continue with this approach to any reasonable depth. See Splitter: Example 3.

Notice that, by default, when the first Splitter is shifted to the left, both panes in the SubForm expand equally.

The second approach is to create multiple Splitters at the same level, i.e. owned by the same parent. See Splitter: Example 4.

In this case, the third Edit object F.E3 is unaffected by movement of the leftmost Splitter F.S1. Note also, that the first Splitter F.S1 may not be dragged further right than the second Splitter F.S2.

Using the non-hierarchical approach, horizontal and vertical Splitters may be combined in interesting ways. This can also be achieved using nested SubForms, but at the expense of a complex object hierarchy. See Splitter: Example 5.

Notice that in this example, with the exception of the last Splitter F.S4, it is necessary only to specify the SplitObj1 property for each of the Splitters. The reason is that the first four Splitters only manage one object directly. For example, the object to the right of F.S1 is in fact a horizontal Splitter F.S2. Dragging F.S1 changes the length of F.S2 which in turn changes the width of F.E2. and F.E3.

Colliding Splitters

If you have two or more vertical Splitters or two or more horizontal Splitters in the same parent object, it is possible for the user to make the Splitters collide. This can occur by dragging one of the Splitters into the other, or, unless both Splitters have Align set to 'None', by shrinking the parent.

When Splitters collide, the object being dragged by the user (a Splitter or a border of the parent) takes precedence over the setting of Align, and temporarily pushes other Splitters along in its direction of travel. If and when the operation is reversed, the other Splitters are pulled back to their original positions.


Static Object
Parents Children Properties Methods Events
Purpose: This object is primarily used to display graphics in a sub-window.

Description

The overall appearance of an empty Static object is controlled by the value of its Style property which may be one of the following character vectors:

'BlackFrame' | 'BlackBox'
'GreyFrame' or 'GrayFrame' | 'GreyBox' or 'GrayBox'
'WhiteFrame' | 'WhiteBox'

Note that the colours implied by the Style are not "hard-coded" but are actually defined by the current Windows colour scheme as follows:

Black | Window Border Colour
Grey/Gray | Desktop Colour
White | Window Background Colour

If the background colour of the Form is also set to the Window Background Colour, it follows that the Styles 'WhiteFrame' and 'WhiteBox' make the Static itself invisible (against the background), although the contents of the Static will show. This makes the Static appear like an invisible clipping window.


StatusBar Object
Parents Children Properties Methods Events
Purpose: This object is used to manage StatusField objects which display information for the user.

Description

The StatusBar is a container object that manages StatusFields. StatusField objects display textual information and are typically used for help messages and for monitoring the status of an application. They can also be used to automatically report the status of the Caps Lock, Num Lock, Scroll Lock, and Insert keys.

'TEST'⎕WC'Form' 'StatusBar' ('EdgeStyle' 'Default')
'TEST.SB'⎕WC'StatusBar'
'TEST.SB.S1'⎕WC'StatusField' 'Field1:' 'text1'
'TEST.SB.S2'⎕WC'StatusField' 'Field2:' 'text2'
'TEST.SB.S3'⎕WC'StatusField' 'Field3:' 'text3'

The Align property determines to which side of the parent Form or SubForm the StatusBar is attached. By default, a StatusBar is positioned along the lower edge of the Form (Align 'Bottom'). Using the Align, Posn and Size properties you may create StatusBars in different positions and with differing sizes if you wish. Notice that the Align property controls how the StatusBar reacts to its parent Form being resized. If Align is 'Top' or 'Bottom', the StatusBar remains fixed in height but stretches and shrinks sideways with the Form. If Align is 'Left' or 'Right', the StatusBar remains fixed in width and stretches and shrinks vertically with the Form.

By default a StatusBar has a Button Face colour background and the value of its EdgeStyle property is 'Default'. This gives it the appearance shown above.

Unless you specify the position and size of its children, a StatusBar automatically manages their geometry. The first StatusField is positioned just inside its top left corner. If Align is 'Top' or 'Bottom', the next StatusField is positioned alongside the first but with a small gap between them. Subsequent StatusFields are added in a similar fashion. If Align is 'Left' or 'Right', the second and subsequent StatusFields are added below the first with a similar gap between them. In either case you can position and size the StatusFields explicitly if you wish.

If you attempt to add a StatusField that would extend beyond the right edge (Align 'Top' or 'Bottom') or bottom edge (Align 'Left' or 'Right') the behaviour depends upon the value of HScroll or VScroll. If HScroll is 0 (the default) and Align is 'Top' or 'Bottom', the StatusField is added below the first one, thereby starting a new row. If VScroll is 0 (the default) and Align is 'Left' or 'Right', it is added to the right of the first one thereby starting a new column. If HScroll or VScroll is ¯1 or ¯2, the new StatusField is simply positioned in the same row or column and may be scrolled into view using a mini scrollbar. A value for HScroll or VScroll of ¯1 causes the mini scrollbar to be permanently present in the Scroll Bar. A value of ¯2 causes it to appear only when required.

VScroll and HScroll may only be set when the object is created and may not subsequently be changed.


StatusField Object
Parents Children Properties Methods Events
Purpose: This object is used to display information for the user.

Description

The StatusField object provides an area for displaying context sensitive help messages, keyboard status, and other application dependant information.

By default a StatusField is a recessed rectangle in which information is displayed. It has a Caption and a Text property, which by default are empty, but either or both of which can be used to present information. The Caption is left justified in the field and the Text is displayed immediately to its right. Typically, you would use the Caption property as a title to describe the information that the StatusField displays, and the Text property to show its current value. However, you are not obliged to use both of them and you can achieve most effects with just one.

Note that when the StatusField is used to display hints it is its Text property that is used.

A StatusField may be used to monitor the status of the keyboard and this is controlled by its Style property. The default value for Style is an empty vector. However, you can set it to monitor various keyboard states as follows :

CapsLock | Monitors state of Caps Lock key
ScrollLock | Monitors state of Scroll Lock key
NumLock | Monitors state of Num Lock key
KeyMode | Monitors the keyboard mode (APL/ASCII)
InsRep | Monitors the state of the Insert key

In each case, the Text property of the StatusField is used to display the keyboard status. If Style is CapsLock, ScrollLock or NumLock, the field displays "Caps", "Num" or "Scroll" if the corresponding mode is selected and is blank if not.

If Style is InsRep, the StatusField displays either "Ins" or "Rep". Initially it always displays "Ins" and then toggles between "Rep" and "Ins" each time the Insert key is pressed.

If Style is KeyMode, the StatusField displays the name for the current keyboard mode which is defined in the input table being used. For the 2-mode tables APL_US.DIN, APL_UK.DIN etc., the mode name displayed is either "Apl" or "Asc". The unified tables have no modes so a StatusField with this Style does nothing.

If Style is set to one of the above, you may still use the Caption property to give the StatusField a title. You may even set the value of the Text property, but be aware that this value will be reset when the user next presses the key the StatusField is monitoring.


SubForm Object
Parents Children Properties Methods Events
Purpose: This object represents a window that is owned by and constrained within another Form or an MDIClient.

Description

If the SubForm is the child of a Form, it is by default a simple featureless window that occupies the entire client area (excluding standard ToolBars, StatusBars and TabBars) of its parent. The properties that control its appearance, including Sizeable, Moveable, SysMenu, Border, MaxButton and MinButton, all default to 0. The EdgeStyle property also defaults to 'None', so the background of the SubForm defaults to the Window Background colour.

If the SubForm is the child of an MDIClient, its default appearance is the same as for a top-level Form. By default its size is 25% of its parent client area and it is positioned in the centre of its parent object.

The Posn property specifies the location of the internal top-left corner of the SubForm relative to its parent. If the SubForm has a title bar, border, or a 3-dimensional shadow, you must allow sufficient space for these components. Similarly, the Size property specifies the internal size of the SubForm excluding the title bar and border.

A SubForm is constrained so that it cannot be moved outside its parent. In all other respects it behaves in a similar manner to a Form object. See Form object and the descriptions of its properties for further details.


SysTrayItem Object
Parents Children Properties Methods Events
Purpose: The SysTrayItem object represents an item that you can create in the Windows System Tray.

Description

The SysTrayItem object appears as an icon in the Windows System Tray and allows the user to interact with your application even if it is minimised or has no other visible presence.

Interaction is provided through a pop-up menu that is displayed when the user clicks on the SysTrayItem. The SysTrayItem does not support mouse or keyboard events directly.

The IconObj property specifies the name of an Icon object used to display the SysTrayItem. If not specified, the default is the standard Dyalog APL icon.

The Popup property specifies the name of a Menu object (which may be a child of the SysTrayItem). The Menu object is displayed automatically when the user clicks on the SysTrayItem icon. The Menu should contain one or more MenuItem objects with suitable callback functions attached.

Unlike other popup menus, the SysTrayItem menu is not activated by an explicit (modal) ⎕DQ but is posted automatically for you. The MenuItem callbacks will be executed by the current ⎕DQ, with the exception of modal ⎕DQs on MsgBox, FileBox, Locator and other popup Menu objects. For example, if your application is in a modal ⎕DQ on a Form, that ⎕DQ will react to and action events on the SysTrayItem menu, even though it is not explicitly included in the list of objects being ⎕DQ'ed.

The Tip property specifies a character string to be displayed when the user hovers the mouse over the SysTrayItem. This is displayed using the user's current setting for Tip text and it is not possible to change this appearance.


TabBar Object
Parents Children Properties Methods Events
Purpose: To manage a set of TabBtn objects.

Description

The TabBar object manages a group of TabBtn objects. These are associated with a set of SubForm objects which are positioned on top of one another. When the user clicks on a TabBtn, the corresponding SubForm is brought to the top and given the focus.

TabBar and TabBtn objects were implemented before Windows provided direct support for tabbed dialogs, and have been superceded by TabControl and TabButton objects. Please use these instead.

By default, a TabBar is a flat bar stretched across the bottom of its parent form. You can alter its appearance using its EdgeStyle property and you can control its alignment with its Align property. Align can be set to Top, Bottom (the default), Left or Right and causes the TabBar to be attached to the corresponding edge of the Form. A TabBar aligned Top or Bottom will automatically stretch or shrink horizontally when its parent Form is resized, but it will remain fixed vertically. A TabBar aligned Left or Right will stretch vertically but will remain fixed horizontally. By default a TabBar occupies the entire width or length of the side of the Form to which it is attached. Both the Posn and Size properties can be altered.

The alignment of a TabBar also determines the orientation of its TabBtns. TabBars aligned Top or Bottom cause their TabBtns to be drawn left to right with the free edge of the TabBtns facing downwards or upwards respectively. TabBar aligned Left or Right draw their TabBtns downwards with their free edges facing left or right respectively.

By default, TabBtn objects are positioned along the inner edge of the TabBar. This is the edge closest to the SubForm s they will tab. They are also positioned so that they overlap one another horizontally or vertically according to the Align property.

The HScroll and VScroll properties determine what happens when the end of the TabBar is reached. If HScroll or VScroll is 0 (the default) a TabBtn that would otherwise extend beyond the TabBar is instead positioned immediately above, below or alongside the first TabBtn in the TabBar, thereby starting a new row or column. Note however that the TabBar is not automatically resized vertically to accommodate a second row or column. If you want a multi-flight TabBar you have to set its height or width explicitly. If HScroll or VScroll is ¯1 or ¯2, TabBtns continue to be added along the TabBar even though they extend beyond its boundary and may be scrolled into view using a mini scrollbar. If HScroll is ¯1, the scrollbar is shown whether or not any controls extend beyond the TabBar. If HScroll is ¯2, the scrollbar appears only if required and may appear or disappear when the user resizes the parent Form.

VScroll and HScroll may only be set when the object is created and may not subsequently be changed.

If you specify a value for its Posn property, a TabBtn will be placed at the requested position regardless of the value of Style, HScroll or VScroll. However, the next control added will take its default position from the previous one according to the value of these properties. Thus if you wish to group your controls together with spaces between the groups, you need only specify the position of the first one in each group.

If you specify a value for its Posn property, a TabBtn will be placed at the requested position regardless of the value of Align. However, the next TabBtn added will take its default position from the previous one. Thus if you wish to group your TabBtns together with spaces between the groups, you need only specify the position of the first one in each group.


TabBtn Object
Parents Children Properties Methods Events
Purpose: To tab a SubForm.

Description

TabBtn objects are associated with SubForms which are positioned on top of one another. When the user clicks on a TabBtn, the corresponding SubForm is brought to the top and given the focus.

TabBar and TabBtn objects were implemented before Windows provided direct support for tabbed dialogs, and have been superceded by TabControl and TabButton objects. Please use these instead.

The appearance of a TabBtn is determined by its EdgeStyle, Border and Caption properties. These take their defaults from the SubForm with which the TabBtn is associated. Thus there is generally no need to specify them. BCol also defaults to that of its associated SubForm.

The position of a TabBtn is normally determined by its parent TabBar and its default size is fixed (22 x 80 pixels), and not related to the size of its Caption. These defaults can be overridden using the Posn and Size properties.

A SubForm is associated with a TabBtn by setting the TabObj property of the SubForm to the name of, or ref to, the TabBtn. The TabObj property of the TabBtn is a read-only property that contains the name of, or ref to, the associated SubForm.


TabButton Object
Parents Children Properties Methods Events
Purpose: The TabButton object represents an individual tab or button in a TabControl

Description

The TabButton object represents an individual tab or button in a TabControl

The position and size of a TabButton object are entirely determined by its parent TabControl and may not be altered. For this reason, the Posn and Size properties are read-only.

The Caption property specifies the text that appears on the button or tab.

A picture is specified by setting the ImageIndex property of the TabButton. This is a number that points to a particular icon or bitmap defined in an ImageList object whose name is specified by the ImageListObj property of the parent TabControl.

Note that all TabButton objects share the same font which is defined by the FontObj property of the TabControl.

The foreground and background colours of the TabButton object are fixed.

When used as a tab, a TabButton is normally attached to a SubForm by the TabObj property of the SubForm. The TabObj property of the TabButton itself, is a read-only property that specifies the name of, or ref to, the SubForm to which the TabButton is attached.

The State property reports the (selected) state of a TabButton.


TabControl Object
Parents Children Properties Methods Events
Purpose: The TabControl object provides access to the native Windows tab control.

Description

The standard tab control is analogous to a set of dividers in a notebook and allows you to define a set of pages that occupy the same area of a window or dialog box. Each page consists of a set of information or a group of controls that the application displays when the user selects the corresponding tab.

A special type of tab control displays tabs that look like buttons. For example, the Windows taskbar is such a tab control.

The overall appearance of the TabControl is determined by the Style property which may be 'Tabs' (the default), 'Buttons' or 'FlatButtons'.

Individual tabs or buttons are represented by TabButton objects which should be created as children of the TabControl object. Optional captions and pictures are specified by the Caption and ImageIndex properties of the individual TabButton objects themselves. Otherwise, the appearance of the tabs or buttons is determined by properties of the TabControl itself.

To implement a multiple page tabbed dialog (see Example 1), you should create a Form, then a TabControl with Style 'Tabs' as a child of the Form. Next, create one or more pairs of TabButton and SubForm objects as children of the TabControl. You associate each SubForm with a particular tab by setting its TabObj property to the name of, or ref to, the associated TabButton object. Making the SubForms children of the TabControl ensures that, by default, they will automatically be resized correctly. You may alternatively create your SubForms as children of the main Form and establish appropriate resize behaviour using their Attach property.

A TabControl object with Style 'Buttons' (Example 2) or 'FlatButtons' (Example 3) may be used in a similar way (i.e. to display a set of alternative pages), although buttons in this type of TabControl are more normally used to execute commands. For this reason, these styles of TabControl are without borders.

If Style is 'FlatButtons', the FlatSeparators property specifies whether or not separators are drawn between the buttons. The default value of FlatSeparators is 0 (no separators).

Example 3a shows the effect of setting FlatSeparators to 1.

The Align property specifies along which of the 4 edges of the TabControl the tabs or buttons are arranged. Align also controls the relative positioning of the picture and Caption within each TabButton. Align may be Top (the default), Bottom, Left or Right.

If Align is 'Top' or 'Bottom' (Example 4), the tabs or buttons are arranged along the top or bottom edge of the TabControl and picture is drawn to the left of the Caption.

If Align is 'Left' (Example 5), the tabs or buttons are arranged top-to-bottom along the left edge of the TabControl, and the pictures are drawn below the Captions.

In recent versions of Windows, 'Align' 'Right' fails to show the tabs or buttons on the right hand edge of the TabControl; this appears to be a limitation of Windows.

The Attach property specifies how the TabControl responds when its parent is resized. Its default value, which is independent of the Align property, is 'None' 'None' 'None' 'None'. This causes the TabControl to maintain its original proportions when its parent is resized.

The MultiLine property determines whether or not your tabs or buttons will be arranged in multiple flights or multiple rows/columns.

The default value of MultiLine is 0, in which case, if you have more tabs or buttons than will fit in the space provided, the TabControl displays an UpDown control to permit the user to scroll them. See Example 7.

If MultiLine is set to 1, the tabs are displayed in multiple flights (Example 8) or the buttons are displayed in multiple rows (Example 9).

The ScrollOpposite property specifies that unneeded tabs scroll to the opposite side of a TabControl, when a tab is selected. Setting ScrollOpposite to 1 forces MultiLine to 1 also.

Example 10 illustrates a TabControl with ScrollOpposite set to 1, after the user has clicked Third Tab. Notice that, in this example, the SubForms have been created as children of the TabControl. This is necessary to ensure that they are managed correctly in this case.

If MultiLine is 1, the way that multiple flights of tabs or rows/columns of buttons are displayed is further defined by the Justify property which may be 'Right' (the default) or 'None'.

If Justify is 'Right'(which is the default), the TabControl increases the width of each tab, if necessary, so that each row of tabs fills the entire width of the tab control. Otherwise, if Justify is empty or 'None', the rows are ragged.

See Example 11 (for tabs) and Example 12 (for buttons).

By default, the size of the tabs may vary from one to another. Fixed size tabs may be obtained by setting the TabSize property.

To obtain fixed sized tabs with MultiLine set to 1, you must however also set Justify to 'None'.

If fixed size tabs are in effect, the positions at which the picture and Caption are drawn within each TabButton is controlled by the TabJustify property which may be 'Centre', 'Edge', or 'IconEdge'.

Example 13 illustrates these different settings.

The font used to draw the captions in the TabButton objects is determined by the FontObj property of the TabControl.

You cannot specify the foreground or background colours of the tabs/buttons, nor can you use different fonts in different tabs/buttons. The orientation of the Caption text is always determined by the value of the Align property of the TabControl.

The TabObj property is read-only and reports the name of, or ref to, the TabButton that is currently selected.

The MultiSelect property specifies whether or not the user can select more than one button in a TabControl at the same time, by holding down the Ctrl key when clicking. The default is 0 (only one button may be selected). MultiSelect is ignored if Style is 'Tabs'.

The TabFocus property specifies the focus behaviour for the TabControl object and may be 'Normal' (the default), 'Never' or 'ButtonDown'.

The HotTrack property specifies whether or not the tabs or buttons are automatically highlighted by the mouse pointer. The default is 0 (no highlighting).


TCPSocket Object
Parents Children Properties Methods Events
Purpose: The TCPSocket object provides an interface to TCP/IP.

Description

The TCPSocket object provides an event-driven mechanism to communicate with other programs (including Dyalog APL) via TCP sockets. Dyalog recommends that Conga is used in preference to TCPSockets in new applications.

The SocketType property is a character vector that specifies the type of the TCP/IP socket. This is either 'Stream' (the default), or 'UDP'. SocketType must be defined when the object is created and cannot be set or changed using ⎕WS.

The Style property is a character vector that specifies the type of data transmitted or received by the socket; it may be 'Char', 'Raw', or 'APL'. The value 'APL' is valid only if the SocketType is 'Stream'.

The Encoding property is a character vector that specifies how character data are encoded or translated. The possible values are 'None', 'UTF-8', 'Classic' or 'Unicode', depending upon the value of the Style property.

LocalAddr and LocalPort properties identify your end of the connection; RemoteAddr and RemotePort identify the other end of the connection. The values of the two sets of properties are clearly symmetrical; your LocalAddr is your partner's RemoteAddr, and there are strict rules concerning which of them you and your partner may set. See the individual descriptions of these properties for details.

The SocketNumber property is the Window handle of the socket attached to the TCPSocket object and is generally a read-only property. The only time that SocketNumber may be specified is when a server replicates (clones) a listening socket to which a client has just connected.


Text Object
Parents Children Properties Methods Events
Purpose: Writes text.

Description

The Text object is used to write arbitrary text. It can be used in a Form, SubForm or Group instead of a Label. The main difference is that a Label is implemented as a true window object (thus consuming Windows resources). A Text object is not a window and consumes no MS-Windows resources. However, a Label supports DragDrop events and has various useful properties that are not shared by the Text object.

The contents of the Text object are defined by its Text property. This is a character array containing one of the following :

  • a simple scalar
  • an enclosed vector or matrix (also a scalar)
  • a simple vector
  • a simple matrix
  • a vector of enclosed vectors or matrices

Points is either a simple 2-column matrix of (y,x) co-ordinates, or a 2-element vector of y-coordinates and x-coordinates respectively.

There are two distinct cases:

  1. Points specifies a single point. In this case, Text may be a single scalar character, a simple vector, or a matrix containing a block of text. The result is that the character, string, or matrix is written at the specified point.
  2. Points specifies more than one point. There are three possibilities:
    1. If Text is a scalar, its contents are written at each of the points in Points. This means that by enclosing a vector or matrix, you can draw a string or block of text at several locations.
    2. If Text is a vector, each element of Text is written at the corresponding position in Points.
    3. If Text is a matrix, each row of Text is written at the corresponding position in Points.

FontObj specifies a single font to be used to write the Text. See a description of the FontObj property for details.

FCol specifies the colour of the Text. For a single text item, FCol may be a single number which specifies one of the standard MS-Windows colours, or a simple 3-element numeric vector of RGB colour intensities. If more than one text item is involved, FCol may be a vector which specifies the colour for each item separately. If so, its length must be the same as the number of points specified by Points.

BCol specifies the background colour of the text, i.e. the colour for the part of the character cell that is blank. It is defined in the same way as FCol.

HAlign and VAlign specify the horizontal and vertical alignment of the text respectively. They may each be numeric scalars or vectors with the same length as the number of points specified in Points. See HAlign and VAlign for details.

When one or more of FCol, BCol, HAlign and VAlign are vectors, the different components of Text are drawn using the corresponding colours and alignments.

The value of the Dragable property specifies whether or not the Text object can be dragged by the user. The value of the AutoConf property determines whether or not the Text object is repositioned when its parent is resized.

Examples:

Write 'A' at (10,20)

      'g.t1' ⎕WC 'Text' 'A' (10 20)

Write 'h' at (10,20) in red

      'g.t1' ⎕WC 'Text' 'h' (10 20) ('FCol' 255 0 0)

Write 'Hello' at (10,20)

      'g.t1' ⎕WC 'Text' 'Hello' (10 20)
Write 'THIS IS A
       BLOCK OF
       TEXT     '   at (20,30)
      BLK←3 9⍴'THIS IS A BLOCK OF TEXT     '
      'g.t1' ⎕WC 'Text' BLK (10 20)

Write 'A' at (10,20) and at (30,40)

      'g.t1' ⎕WC 'Text' 'A' ((10 30)(20 40))

Write a red '+' at (10,20) and a green '+' at (20 40)

      'g.t1' ⎕WC 'Text' '+' ((10 30)(20 40))('FCol' (255 0 0)(0 255 0))

Write 'Hello' at (10,20) and at (30,40)

      'g.t1' ⎕WC 'Text' (⊂'Hello') ((10 30)(20 40))

Write 'A' at (10,20) and 'B' at (30,40)

      'g.t1' ⎕WC 'Text' 'AB' ((10 30)(20 40))

Write 'Hello' at (10,20) and 'World' at (30,40)

      'g.t1' ⎕WC 'Text' ('Hello' 'World')((10 30)(20 40))


Timer Object
Parents Properties Methods Events
Purpose: To generate an action at regular intervals.

Description

The Timer object is used to generate an event at regular intervals. It can be used to produce animation and to implement "repeaters" such as spin buttons.

The Interval property specifies how often the Timer generates events and is defined in milliseconds. Its default value is 1000.

The Active property determines whether or not the Timer generates events and can be used to switch the Timer off and on as required.

Note that if you create a Timer object whose Timer event generates an error (for example by attaching it to a non-existent callback) it may be very difficult or even impossible to type into the Session, because the error will be displayed over and over again. Care is therefore recommended.


TipField Object
Parents Children Properties Methods Events
Purpose: To display pop-up help.

Description

The TipField is used to display pop-up help when the user moves the mouse pointer over an object.

Most of the GUI objects supported by Dyalog APL/W have a Tip and a TipObj property. TipObj specifies the name of, or ref to, a TipField object, and Tip specifies a "help" message. The TipField automatically pops-up to display the Tip when the user moves the mouse pointer over the object. It disappears when the user moves the mouse pointer away.

The TipField is a simple box with a 1-pixel black border in which the text specified by Tip is displayed. FCol, BCol and FontObj can be used to customise the appearance of the text within the box. FCol specifies the colour of the text; BCol specifies the background colour with which the box is filled. The default is black on yellow.

If you wish to display Tips for particular objects in different fonts and colours, you must create a separate TipField for each combination of colour and font you need.


ToolBar Object
Parents Children Properties Methods Events
Purpose: To manage a group of controls such as Buttons.

Description

The ToolBar object is used to display and manage a set of controls. It is typically used to present a set of Buttons which the user can press to perform various actions. However, the ToolBar has the ability to manage other controls too.

By default, the ToolBar is a raised bar stretched across the top of its parent form. You can alter its appearance using its EdgeStyle property and you can control its alignment with its Align property. Align can be set to Top (the default), Bottom, Left or Right and causes the ToolBar to be attached to the corresponding edge of the Form. A ToolBar aligned Top or Bottom will automatically stretch or shrink horizontally when its parent Form is resized, but it will remain fixed vertically. A ToolBar aligned Left or Right will stretch vertically but will remain fixed horizontally. By default a ToolBar occupies the entire width or length of the side of the Form to which it is attached and is 30 pixels high or wide. You can change these defaults using the Posn and Size properties.

A ToolBar organises its child controls in the order they are created. The way this is done is governed by the value of the Align property. If Align is Top or Bottom, the ToolBar arranges its controls in rows across the screen. If Align is Left or Right, the ToolBar arranges controls in columns.

The first control added to a ToolBar is automatically positioned 2 pixels down and 2 pixels across from its top left corner. The rule for positioning subsequent controls depends upon the value of the Align property.

If Align is 'Top' or 'Bottom', controls are positioned so as to be horizontally adjacent to one another. Whenever a control is added it is positioned relative to the one that immediately preceded it so that its top left corner meets the top right corner of the previous one. The HScroll property determines what happens when the end of the ToolBar is reached. If HScroll is 0 (the default) a control that would otherwise extend beyond the width of the ToolBar is instead positioned immediately below the first control in the ToolBar, thereby starting a new row. Note however that the ToolBar is not automatically resized vertically to accommodate a second row. If you want a multi-row ToolBar you have to set its height explicitly. If HScroll is ¯1 or ¯2, controls continue to be added along the ToolBar even though they extend beyond its right edge and may be scrolled into view using a mini scrollbar. If HScroll is ¯1, the scrollbar is shown whether or not any controls extend beyond the width of the ToolBar. If HScroll is ¯2, the scrollbar appears only if required and may appear or disappear when the user resizes the parent Form.

If Align is 'Left' or 'Right', controls are positioned so as to be vertically adjacent to one another. Whenever a control is added, its top left corner is positioned against the bottom left corner of the previous control. The VScroll property determines what happens when the bottom of the ToolBar is reached. If VScroll is 0 (the default) a control that would otherwise extend beyond the bottom of the ToolBar is instead positioned immediately to the right of the first one; thereby starting a new column. Note however that the ToolBar is not automatically resized horizontally to accommodate a second column. You must set the width of the ToolBar explicitly.

If VScroll is ¯1 or ¯2, controls continue to be added down the ToolBar even though they extend beyond its bottom edge and may be scrolled into view using a mini scrollbar. If VScroll is ¯1, the scrollbar is shown whether or not any controls extend beyond the bottom of the ToolBar. If VScroll is ¯2, the scrollbar appears only if required and may appear or disappear when the user resizes the parent Form.

VScroll and HScroll may only be set when the object is created and may not subsequently be changed.

If you specify a value for its Posn property, a control will be placed at the requested position regardless of the value of Style, VScroll or HScroll. However, the next control added will take its default position from the previous one according to the value of these properties. Thus if you wish to group your controls together with spaces between the groups, you need only specify the position of the first one in each group.

The ToolBar object was introduced in Dyalog APL before an appropriate standard Windows control existed. The ToolBar object should be considered as a legacy object and used only in old GUI applications. The ToolControl object should be used instead.


ToolButton Object
Parents Children Properties Methods Events
Purpose: The ToolButton object represents a button in a ToolControl.

Description

The ToolButton object represents a selectable button in a ToolControl object.

A ToolButton displays a text string, defined by its Caption property, and an image defined by its ImageIndex property. Apart from these characteristics, the appearance of a ToolButton is controlled by its parent ToolControl object.

ImageIndex is an index into an ImageList which contains a set of icons or bitmaps. The ImageList itself is named by the ImageListObj property of the parent ToolControl.

Typically, you will create up to three ImageLists as children of the ToolControl. These will be used to specify the pictures of the ToolButton objects in their normal, highlighted (sometimes termed hot) and inactive states respectively. The set of images in each ImageList is then defined by creating unnamed Bitmap or Icon objects as children. Finally, when you create each ToolButton you specify ImageIndex, selecting the three pictures which represent the three possible states of the button.

If you specify only a single ImageList, the picture on the ToolButton will be the same in all three states.

The behaviour and appearance of a ToolButton is further defined by its Style property, which may be 'Push', 'Check', 'Radio', 'Separator' or 'DropDown'.

Push buttons are used to generate actions and pop in and out when clicked. Radio and Check buttons are used to select options and have two states, normal (out) and selected (in). Their State property is 0 when the button is in its normal (unselected state) or 1 when it is selected.

A group of adjacent ToolButtons with Style 'Radio' defines a set in which only one of the ToolButtons may be selected at any one time. The act of selecting one will automatically deselect any other. Note that a group of Radio buttons must be separated from Check buttons or other groups of Radio buttons by ToolButtons of another Style.

A ToolButton with Style 'Separator 'has no Caption or picture, but appears as a vertical line and is used to separate groups of buttons.

A ToolButton with Style 'DropDown' has an associated popup Menu object which is named by its Popup property. There are two cases to consider.

If the ShowDropDown property of the parent ToolControl is 0, clicking the ToolButton causes the popup menu to appear. In this case, the ToolButton itself does not itself generate a Select event; you must rely on the user selecting a MenuItem to specify a particular action.

If the ShowDropDown property of the parent ToolControl is 1, clicking the dropdown button causes the popup menu to appear; clicking the ToolButton itself generates a Select event, but does not display the popup menu.

The following example illustrates the use of DropDown buttons:

'F'⎕WC'Form' 'ToolControl: Dropdown Buttons'('Size' 20 40)
'F.TB'⎕WC'ToolControl'('ShowDropDown' 1)

:With 'F.FMENU'⎕WC'Menu' ⍝ Popup File menu
    'NEW'⎕WC'MenuItem' '&New'
    'OPEN'⎕WC'MenuItem' '&Open'
    'CLOSE'⎕WC'MenuItem' '&Close'
:EndWith

:With 'F.EMENU'⎕WC'Menu' ⍝ Popup File menu
    'CUT'⎕WC'MenuItem' 'Cu&t'
    'COPY'⎕WC'MenuItem' '&Copy'
    'PASTE'⎕WC'MenuItem' '&Paste'
:EndWith

'F.TB.B1'⎕WC'ToolButton' 'File'('Style' 'DropDown')('Popup' 'F.FMENU')
'F.TB.B2'⎕WC'ToolButton' 'Edit'('Style' 'DropDown')('Popup' 'F.EMENU')


ToolControl Object
Parents Children Properties Methods Events
Purpose: The ToolControl object provides a standard Windows ToolBar.

Description

The ToolControl object provides an interface to the native Windows ToolBar control and supersedes the Dyalog APL ToolBar object.

The tools on a ToolControl are normally represented by ToolButton objects, but the ToolControl may also act as a parent for other objects, including a MenuBar (see below).

Unlike the ToolBar, the ToolControl fully determines the positioning of its children automatically and this is governed by their order of creation. The Posn property of any child of a ToolControl is therefore read-only. Furthermore, the height of objects in a ToolControl may be no greater than that of a ToolButton in the same ToolControl. This in turn is governed by the sizes of the FontObj and ImageList in use in that ToolControl. ToolControl objects should be used in preference to ToolBar objects.

If a ToolControl is the child of a Form, its position and orientation is defined by its Align property. This property is ignored if the ToolControl is the child of a CoolBand.

The overall appearance of the ToolButton objects displayed by the ToolControl is defined by the Style property of the ToolControl itself, rather than by individual ToolButtons. This may be 'Buttons', 'FlatButtons', 'List' or 'FlatList'.

'F'⎕WC'Form' 'ToolControl: FlatButtons Style (default)'('Size' 10 40)
'F.TB'⎕WC'ToolControl'

'F.TB.IL'⎕WC'ImageList'('Masked' 0)
'F.TB.IL.'⎕WC'Bitmap'('Comctl32' 120)
'F.TB'⎕WS'ImageListObj' 'F.TB.IL'

'F.TB.B1'⎕WC'ToolButton' 'New'('ImageIndex' 7)
'F.TB.B2'⎕WC'ToolButton' 'Open'('ImageIndex' 8)
'F.TB.B3'⎕WC'ToolButton' 'Save'('ImageIndex' 9)

'F.TB'⎕WC'ToolControl'('Style' 'Buttons')

'F.TB'⎕WC'ToolControl'('Style' 'FlatList')

'F.TB'⎕WC'ToolControl'('Style' 'List')

The presence or absence of a recessed line drawn above, below, to the left of, or to the right of the ToolControl is controlled by the Divider property whose default is 1 (show divider).

The MultiLine property specifies whether or not ToolButtons (and other controls) are arranged in several rows (or columns) when there are more than will otherwise fit. If MultiLine is 0 (the default), the ToolControl object clips its children and the user must resize it to bring more objects into view.

'F'⎕WC'Form' 'ToolControl: MultiLine 0'('Size' 20 36)
'F.TB'⎕WC'ToolControl'('Style' 'List')

'F.TB.IL'⎕WC'ImageList'('Masked' 0)('Size' 24 24)
'F.TB.IL.'⎕WC'Bitmap'('ComCtl32' 121)⍝ STD_LARGE
'F.TB'⎕WS'ImageListObj' 'F.TB.IL'

'F.TB.B1'⎕WC'ToolButton' 'Cut'('ImageIndex' 1)
'F.TB.B2'⎕WC'ToolButton' 'Copy'('ImageIndex' 2)
'F.TB.B3'⎕WC'ToolButton' 'Paste'('ImageIndex' 3)
'F.TB.B4'⎕WC'ToolButton' 'Undo'('ImageIndex' 4)
'F.TB.B5'⎕WC'ToolButton' 'Redo'('ImageIndex' 5)
'F.TB.B6'⎕WC'ToolButton' 'Delete'('ImageIndex' 6)

'F.TB'⎕WC'ToolControl'('MultiLine' 1)('Style' 'List')

The Transparent property specifies whether or not the ToolControl is transparent. If so, the visual effect is as if the ToolButtons (and other controls) were drawn directly on the parent Form as illustrated below:

'F'⎕WC'Form' 'ToolControl: Transparent 1)'('Size' 10 40)
'F.BM'⎕WC'Bitmap' 'C:\WINDOWS\WINLOGO'
'F'⎕WS'Picture' 'F.BM' 1

'F.TB'⎕WC'ToolControl'('Transparent' 1)('Style' 'FlatList')
'F.TB.IL'⎕WC'ImageList'('Masked' 0)('Size' 24 24)
'F.TB.IL.'⎕WC'Bitmap'('ComCtl32' 121)⍝ STD_LARGE
'F.TB'⎕WS'ImageListObj' 'F.TB.IL'

'F.TB.B1'⎕WC'ToolButton' 'New'('ImageIndex' 7)
'F.TB.B2'⎕WC'ToolButton' 'Open'('ImageIndex' 8)
'F.TB.B3'⎕WC'ToolButton' 'Save'('ImageIndex' 9)

The ShowCaptions property specifies whether or not the captions of ToolButton objects are drawn. Its default value is 1 (draw captions). ToolButtons drawn without captions occupy much less space and ShowCaptions provides a quick way to turn captions on/off for user customisation.

The ShowDropDown property specifies whether or not a drop-down menu symbol is drawn alongside ToolButtons which have Style 'DropDown'. ShowDropDown also affects the behaviour of such ToolButton objects when clicked.

The ButtonsAcceptFocus property determines how the ToolControl responds to the Tab and cursor movement keys.

As a special case, the ToolControl may contain a MenuBar as its only child. In this case, Dyalog APL causes the menu items to be drawn as buttons as shown below.

Although nothing is done to prevent it, the use of other objects in a ToolControl containing a MenuBar, is not supported.

'F'⎕WC'Form' 'ToolControl with MenuBar'('Size' 20 40)
'F.TB'⎕WC'ToolControl'

:With 'F.TB.MB'⎕WC'MenuBar'
    :With 'File'⎕WC'Menu' 'File'
        'New'⎕WC'MenuItem' 'New'
        'Open'⎕WC'MenuItem' 'Open'
        'Close'⎕WC'MenuItem' 'Close'
    :EndWith

    :With 'Edit'⎕WC'Menu' 'Edit'
        'Cut'⎕WC'MenuItem' 'Cut'
        'Copy'⎕WC'MenuItem' 'Copy'
        'Paste'⎕WC'MenuItem' 'Paste'
    :EndWith

:EndWith


TrackBar Object
Parents Children Properties Methods Events
Purpose: The TrackBar object is a slider control that allows the user to enter a value by positioning a pointer (thumb) on a scale.

Description

The TrackBar object consists of a window which contains a slider bar, a thumb, and a set of tick marks. The slider in a TrackBar moves in increments that you specify when you create it. For example, if you specify that the TrackBar should have a range of five, the slider can only occupy six positions: a position at the left side of the TrackBar and one position for each increment in the range. Typically, each of these positions is identified by a tick mark. TrackBars can have either a vertical or horizontal orientation. They can have tick marks on either side, both sides, or neither. A selection of different TrackBars is illustrated below.

The position and size of the container window are defined by the Posn and Size properties. Its appearance is defined by the EdgeStyle, Border and BCol properties. The defaults are ('EdgeStyle' 'None'), ('Border' 0) and ('BCol' 0). The default background colour ('BCol' 0) obtains either the standard Window Background colour, or grey to match the colour of the parent object if it has a 3-dimensional appearance.

The orientation of a TrackBar is determined by the HScroll and VScroll properties. A horizontal TrackBar is obtained by setting HScroll to ¯1 and VScroll to 0. This is the default. A vertical TrackBar is obtained by setting VScroll to ¯1 and HScroll to 0.

VScroll and HScroll may only be set when the object is created and may not subsequently be changed.

The ShowThumb property determines whether or not the thumb is visible. Its default value is 1. You may toggle this property dynamically using ⎕WS.

The TrackBar optionally displays tick marks at the two ends of the slider bar and spaced out along it. This behaviour is determined by the HasTicks property which may be 1 (the default) or 0 and may be set only when the object is created by ⎕WC.

If HasTicks is 1, the position and frequency of the tick marks is determined by the TickAlign and TickSpacing properties. Note that TickAlign may only be set when the TrackBar is created with ⎕WC and may not be altered using ⎕WS.

The slider and tick marks in a horizontal TrackBar are drawn along the top of the enclosing window. The slider and tick marks in a vertical TrackBar are drawn along the left edge of the window. The position and size of the slider and the thumb may be obtained from the TrackRect and ThumbRect properties which report these values in pixels. These are read-only properties and cannot not be set with ⎕WC or ⎕WS.

The value of the TrackBar is determined by its Thumb property which is an integer that may be set with ⎕WS or retrieved with ⎕WG. The Limits property specifies the minimum and maximum values of Thumb corresponding to its position at the two ends of the slider bar. The Step property is a 2-element integer vector defining the small and large increments by which the Thumb moves. A small step is obtained by pressing a cursor movement key; a large step is achieved by clicking the left mouse button either side of the thumb or by pressing Page Up and Page Down. The user may also drag the thumb to a new position or move it directly to either end of the slider by pressing Home or End.

An alternative form of the TrackBar is obtained by setting the Style property to 'Selection'. This may only be done when the object is created using ⎕WC. This style of TrackBar has a slider that is represented by a recessed thick white rectangle instead of a solid black line. Furthermore, you can select a range of values within the TrackBar by setting the SelRange property. This causes the TrackBar to display a solid blue bar within the white slider and to show the corresponding tick marks as small triangles. Note that there is no way for the user to change SelRange directly; you can only do this using ⎕WS.

In addition to the normal mouse events, the TrackBar generates a Scroll and ThumbDrag event. The Scroll event is the same event that is generated by a Scroll object and is reported when the user repositions the thumb. If enabled, the ThumbDrag event is reported continuously as the user drags the thumb with the mouse and may be used to synchronise the display of a corresponding value in another object.


TreeView Object
Parents Children Properties Methods Events
Purpose: The TreeView object displays a hierarchical list of items.

Description

A TreeView object displays a hierarchical list of items, such as the headings in a document, the entries in an index, or the files and directories on a disk. Each item consists of a label and an optional bitmapped image, and each item can have a list of sub-items associated with it. By clicking an item, the user can expand and collapse the associated list of sub-items.

The contents of a TreeView object are defined by the Items property; a vector of character vectors that specifies the item labels.

The ImageListObj, ImageIndex and SelImageIndex properties define bitmapped images corresponding to each item. The bitmapped images are drawn to the left of the item labels.

ImageListObj specifies the name of a single ImageList object that contains one or more bitmaps

ImageIndex and SelImageIndex are ⎕IO sensitive scalars, or vectors with the same length as the number of items in the object. The value in the ith element specifies the image for the ith item and is an index into the corresponding ImageList object. ImageIndex specifies the image displayed when an item is not selected, SelImageIndex specifies the image displayed when an item is selected.

If ImageListObj is specified, but ImageIndex is empty or not specified, the first bitmap in the ImageList is drawn alongside every item. If an element of ImageIndex or SelImageIndex specifies a value that does not correspond to a bitmap in the ImageList, no picture is drawn.

The structure of the items (i.e. the parent/child relationships of the items) is defined by the Depth property. This is either a scalar 0 (the default) which means that all items are root items, or it is a numeric vector of the same length as Items. Non-zero values in Depth indicate child items.

The HasLines property is 0, 1 or 2 and determines whether or not lines are drawn that link child items to their corresponding parent item. If HasLines is 0, no lines are drawn. If HasLines is 1, lines are drawn at all except the top level, i.e. the object does not link items at the root of the hierarchy. The default value for HasLines is 2 which provides lines at all levels including the root.

The HasButtons property determines whether or not the TreeView object has a button to the left side of each parent item. It is Boolean with a default value of 1. The user can click the button to expand or collapse the child items as an alternative to double-clicking the parent item. Note that by itself, setting HasButtons to 1 does not add buttons to items at the root of the hierarchy. To achieve this you must also set HasLines to 2.

The CheckBoxes property specifies whether or not check boxes are displayed alongside items in a TreeView.

The FullRowSelect property specifies whether just the item itself, or the entire row of the TreeView, is highlighted when an item is selected. FullRowSelect should not be used if HasLines is 1 or 2

When the user presses the left mouse button over an item, the object generates an ItemDown event. This is followed by an ItemUp event when the mouse button is released. The object also generates an ItemDblClick event when the left mouse is double-clicked over an item. If all three events are enabled, they are reported in the order ItemDown, ItemDblClick, ItemUp.

When a parent item is in its retracted state (its children are not visible) it can be expanded to show its children by the user double-clicking its label or by clicking over its button or tree lines. An Expanding event is reported immediately before the children are shown. Similarly, when a parent item is in its expanded state, it can be retracted to hide its children when a Retracting event is reported. You can use the Expanding event to define new children for the object just before they are shown. You can also control the actions of these events using callback functions.

The EditLabels is a Boolean property (default 0) that determines whether or not the user may edit the labels which are specified by the Items property.

The SelItems property is a Boolean vector that indicates which of the items is currently selected and has the focus. If more items are visible than can fit within the object, a scrollbar is automatically provided. The Index property is a ⎕IO sensitive integer that reports the index number of the first item displayed in the object and changes as the items are scrolled.

Warning: Due to the limitations of the Win32 TreeView object, it is necessary to query the state of each item in a TreeView in order to obtain the value of the SelItems property, making it a comparatively slow operation if there are a lot of Items.


UpDown Object
Parents Children Properties Methods Events
Purpose: The UpDown object is a pair of arrow buttons used to increment or decrement a value.

Description

An UpDown object is a pair of arrow buttons that the user can click to increment or decrement a value, such as a scroll position or a number displayed in a companion control. The Spinner object is actually a composite object consisting of an UpDown and a companion Edit.


APLVersion Property
Applies To: Root

Description

This is a read-only property that provides information about the Version of Dyalog APL that you are using. It is a 4-element vector of character vectors as described in the table below.

Note: In future releases these values may change, be removed, or new ones added.

Index | Description | Possible Values
[1] Target Environment Windows
Windows-64
Windows Mobile
Linux
Linux-64
AIX
AIX-64
Mac-64
Solaris
Solaris-64
[2] | Version Number
[3] Version Type
W | Windows
S | Server (terminal) version
M | Motif
P | PocketAPL
[4] Program Type Development
Runtime
DLL
DLLRT

Example

      ]display '.'⎕WG 'APLVersion'
┌──────┬────────────┬─┬───────────┐
│Mac-64│16.0.29941.0│S│Development│
└──────┴────────────┴─┴───────────┘


Accelerator Property

Applies To

Description

This property specifies a keystroke that, when pressed by the user, will generate a Select event on an object. It applies to all objects whether or not they possess a "natural" Select event. You can therefore associate a keystroke with an arbitrary action on any object you desire.

The Accelerator property is a 2-element integer vector. The first element is a key number which is the number by which Windows knows the key. The second element is the shift state which is the sum of 1 (Shift key), 2 (Control key) and 4 (Alt key).

For example, to attach the keystroke Ctrl+A to an object, you would set its Accelerator to (65 2). To attach the keystroke Shift+Ctrl+F1 (key number 112), you would set its Accelerator to (112 3). Key numbers may be obtained by displaying the messages generated by the KeyPress event.

Note that a keystroke used as an Accelerator will not generate a KeyPress event.


AcceptFiles Property

Applies To

Description

The AcceptFiles property is Boolean and specifies whether or not an object will accept a file drag/drop operation. Its default value is 0. If set to 1, the object will report a DropFiles event when file icons are dropped on it.


Active Property

Applies To

Description

This property specifies whether or not an object is currently responsive to user actions. It is a single number with the value 0 (object is inactive and does not generate events) or 1 (object is active and capable of generating events). The default is 1.

Setting Active to 0 disables the object (and all its children), even though the object may be referenced in the argument to ⎕DQ. It is therefore possible to deactivate an object from a callback function.

In general, the text associated with an object whose Active property is 0 is displayed in grey.


Align Property

Applies To

Description

For an Animation, the Align property may be 'None' or 'Centre' ('Center'). If Align is 'None', the Animation window is automatically resized to fit the AVI being played. If Align is 'Centre', the AVI is centred in the Animation window. If the window is too small, the AVI is clipped.

For a Button, Menu, or MenuItem the Align property may be 'None', 'Left' or 'Right'. If the Button Style is 'Radio' or 'Check' this property specifies the position of the text relative to the button symbol. The default is 'Right'. For a Button with Style 'Push', the value of Align is 'None'.

For a Button with Style 'Radio' or 'Check' that is created as a child of a Grid the value of the Align property may also be 'Centre' or 'Center'. Either of these values causes the symbol part of the Button (the circle or checkbox) to be centred within the corresponding Grid cell(s).

For a DateTimePicker, the Align property specifies the horizontal alignment of the drop-down Calendar which may be 'Left' (the default) or 'Right'. This applies only if the Style of the DateTimePicker is 'Combo'.

For a Menu, MenuItem, or StatusField, Align 'Right' is used to position the object at the right end of its parent MenuBar or StatusBar. 'None' is equivalent to 'Left' which is the default.

For objects of type CoolBar, Splitter, Scroll, StatusBar, TabBar, ToolBar and ToolControl, Align may be 'None', 'Top', 'Bottom', 'Left' or 'Right'. It specifies to which (if any) of the four sides of the parent the object is anchored and also the default position and size of the object. Specifying Align typically causes the Attach property to be set to appropriate values as follows :

Align | Attach
'Top' | 'Top' 'Left' 'Top' 'Right'
'Bottom' | 'Bottom' 'Left' 'Bottom' 'Right'
'Left' | 'Top' 'Left' 'Bottom' 'Left'
'Right' | 'Top' 'Right' 'Bottom' 'Right'

These settings cause the object to remain at a fixed distance (in pixels) from the corresponding edge of the parent. Furthermore, the object will have a fixed height or width, but its length will stretch and shrink as the Form is resized.

Note that this does not apply to a TabControl for which the default value of Attach is 'None' 'None' 'None' 'None', regardless of the value of Align.

The default value of Align is 'Right' for a vertical Scroll, 'Bottom' for a horizontal Scroll, and 'Top' for a CoolBar, TabBar, TabControl, ToolBar and ToolControl. Furthermore, unless Posn and Size are specified explicitly, the object is placed along the corresponding edge of its parent.

For a Scroll object, Align also determines the direction of a Scroll object unless it is overridden by setting HScroll or VScroll directly. If neither HScroll or VScroll is defined and Align is 'Top' or 'Bottom', a horizontal scrollbar is provided. If neither HScroll or VScroll is defined and Align is 'None', 'Left' or 'Right', a vertical scrollbar is provided.

Note

The value of the Align property may only be assigned by ⎕WC and may not be changed using ⎕WS.


AlignChar Property
Applies To: Grid

Description

The AlignChar property specifies a character on which the data displayed in a column of a Grid is to be aligned vertically. It is useful to align columns of numbers that are formatted by the FormatString property. AlignChar may be a scalar or singleton that applies to all columns of the Grid, or a vector with one element per column.

If the data in the column is left-justified, it is aligned using the first occurrence of the alignment character in each cell counting from the left. If the data is right-justified, it is aligned using the first occurrence of the alignment character from the right-hand end of the text.

If the text in a cell does not contain an alignment character, it is aligned as if the alignment character were placed following the last digit.


AlphaBlend Property
Applies To: Form

Description

The AlphaBlend property specifies a level of translucency which allows the area behind a Form to show through.

AlphaBlend is a scalar integer value in the range 0 to 255.

A value of 255 (the default) specifies no translucency, and the Form is entirely opaque obliterating anything behind it.

A value of 0 specifies total translucency and the Form itself is not visible. Furthermore, mouse events over the Form will not be reported by the Form itself but will be passed to any other windows underneath the Form.

Values in between specify varying levels of translucency.


AlwaysShowBorder Property
Applies To: Grid

Description

The AlwaysShowBorder property specifies whether or not the border around the current cell in a Grid is displayed when the Grid loses the focus.

It is a Boolean value with a default value of 1.


AlwaysShowSelection Property
Applies To: Grid ListView TreeView

Description

The AlwaysShowSelection property specifies whether or not the selection remains highlighted when the object loses the focus.

It is a Boolean value with a default value of 1.

If AlwaysShowSelection is 1, the highlight is dimmed. If AlwaysShowSelection is 0, the highlight disappears.


ArcMode Property
Applies To: Circle Ellipse

Description

This property determines how arcs are drawn. Its value is 0, 1 or 2.

0 | only the arc is drawn
1 | arcs define "arc segments", with a single straight line joining the two ends of the arc together
2 | arcs define "pie segments", with lines drawn from the start and end points of the arc to the centre

Note that the segments defined by ArcMode 1 and 2 may be filled (by setting FStyle).


Array Property
Applies To: Clipboard

Description

This property may be used to set or retrieve the contents of the Windows clipboard as a Dyalog APL array.


Attach Property

Applies To

Description

This property specifies how an object responds to its parent being resized. It is a 4-element vector of character vectors which defines how each of the four edges of the object moves in response to a resize request made by the parent. Note that this property is only effective if the value of AutoConf on the parent is 2 or 3 and AutoConf for the object itself is 1 or 3.

The 4 elements of Attach refer to the Top, Left, Bottom and Right edges of the object respectively. Their values may be defined as follows :

Element | Value | Meaning
[1] | 'Top' | top edge of object attached to top edge of parent.
 | 'Bottom' | top edge of object attached to bottom edge of parent.
 | 'None' | top edge of object is not attached to its parent
[2] | 'Left' | left edge of object is attached to left edge of parent
 | 'Right' | left edge of object is attached to right edge of parent
 | 'None' | left edge of object is not attached to its parent
[3] | 'Top' | bottom edge of object is attached to top edge of parent.
 | 'Bottom' | bottom edge of object is attached to bottom edge of parent.
 | 'None' | bottom edge of object is not attached to its parent
[4] | 'Left' | right edge of object is attached to left edge of parent
 | 'Right' | right edge of object is attached to right edge of its parent
 | 'None' | right edge of object is not attached to its parent

If an edge of the object is attached to an edge of its parent, its position in absolute (pixel) terms remains fixed relative to that edge when its parent is resized. Thus if Coord is 'Pixel', the corresponding Posn or Size property of the object remains unaffected by the resize. If Coord has any other value, the value of Posn or Size will change.

If an edge of the object is not attached to its parent, its absolute position (in pixels) will change in proportion to the size change (in the corresponding direction) of its parent. Thus if Coord is 'Pixel', the corresponding Posn or Size property of the object will change as a result of the resize. If Coord has any other value, the value of Posn or Size will be unaffected.

The default value of Attach is ('None' 'None' 'None' 'None'). This causes the object to reposition and resize itself in proportion to its parent.

Some objects have an Align property which, among other things, provides a quick way to set their Attach property. Examining this mechanism may help to further explain how the Attach property works. Setting Align to 'Top' has the effect of setting Attach to ('Top' 'Left' 'Top' 'Right'). Attaching the top edge of the object to the top edge of its parent causes the object to remain at a fixed distance from the top edge of its parent. The additional measure of attaching its bottom edge to the top edge of its parent causes the height of the object to remain fixed. Attaching the left and right edges of the object to the corresponding edges of its parent causes the object to shrink and expand as the parent is resized horizontally. If you position the object at (0 0) and set its width to be the same as the width of its parent, you have an object that always occupies the entire length of its parent, yet remains of fixed height. This is precisely the behaviour required for a ToolBar or a top Scroll Bar. For further details, see Align property.


AutoArrange Property
Applies To: ListView

Description

The AutoArrange property is Boolean and specifies whether or not the items in a ListView object are automatically re-arranged when a single item is repositioned. Its default value is 0.


AutoBrowse Property
Applies To: OLEClient

Description

This property is retained for backwards compatibility with previous versions of Dyalog APL, but is no longer relevant. Setting it has no effect.


AutoConf Property

Applies To

Description

This property determines what happens to an object when its parent is resized, and how resizing an object affects its children. It may take one of the following values; the default is 3.

0 | Ignore resize by parent. Do not propagate resize to children.
1 | Accept resize by parent. Do not propagate resize to children.
2 | Ignore resize by parent. Propagate resize to children.
3 | Accept resize by parent. Propagate resize to children.

If AutoConf is 0 or 2, the object's physical size (in pixels) and position (in pixels) relative to the top left corner of its parent remains unchanged when its parent is resized. If the object has 'Prop' or 'User' co-ordinates, the values of its Posn and Size properties will change as a result.

If AutoConf is 1 or 3, by default, the object is physically reconfigured when its parent is resized such that its relative size and position within its parent remain unchanged. If the object has 'Pixel' co-ordinates, the values of its Posn and Size properties will change as a result. Note that this default processing can be prevented by inhibiting the Configure (31) Event.

If AutoConf is 0 or 1 and the object is resized, either by its parent or directly by the user, it does not attempt to physically reconfigure its children. This means that if the children have 'Prop' or 'User' co-ordinates, the values of their Posn and Size co-ordinates will change as a result.

If AutoConf is 2 or 3 and the object is resized, either by its parent or directly by the user, it propagates a Configure (31) Event to each of its children. By default this means that the object's children will be physically reconfigured so that they maintain their relative positions and sizes within it. If their co-ordinate system is 'Pixel', the values of their Posn and Size properties will change as a result.

Note

Additional or alternative control may be imposed by inhibiting the Configure (31) Event. This can be done either by setting the event's "action" code to ¯1 or by returning a 0 from a callback function attached to it.


AutoExpand Property
Applies To: Grid

Description

This property is a 2-element Boolean value that specifies whether or not rows and columns may be added to a Grid object by the user.

If the first element of AutoExpand is 1, a row is added when the current cell is within the last row of the Grid and the user presses Cursor Down

Similarly, if the second element is 1, a column is added when the current cell is within the last column of the Grid and the user presses Cursor Right.

Note that when a row or column is added, the appropriate properties (including Values and CellTypes) are expanded accordingly.

The default value for AutoExpand is (0 0).

If AutoExpand is enabled, the Grid generates AddRow and AddCol events. You can return a zero from a callback function to selectively prevent the addition of rows and columns if appropriate.


AutoPlay Property
Applies To: Animation

Description

Specifies whether or not an AVI clip is played immediately when loaded in an Animation object.

AutoPlay is a single number with the value 0 (the default) or 1. If AutoPlay is 1, the AVI clip is automatically played through once from beginning to end when loaded from a file by the AnimOpen method.


BCol Property

Applies To

Description

This property defines the background colour(s) of an object. For objects with more than one constituent part, it may specify a set of background colours, one for each part. A single colour is represented by a single number which refers to a standard colour, or by a 3-element vector which defines a colour explicitly in terms of its red, green and blue intensities.

If BCol is set to 0 (which is the default) the background colour is defined by your current colour scheme for the object in question. For example, if you select yellow as your MS-Windows "Menu Bar" colour, you will by default get a yellow background in Menu and MenuItem objects, simply by not specifying BCol or by setting it to 0.

If BCol is set to ⍬ (Zilde), Dyalog APL will never paint the background of the object. If therefore the object is overlaid by another window and then exposed, its background will not be redrawn and it will simply contain whatever was previously shown on that area of the screen.

A negative value of BCol refers to a standard MS-Windows colour as described below. Positive values are reserved for a possible future extension.

BCol | Colour Element | BCol | Colour Element
0 | Default | ¯11 | Active Border
¯1 | Scroll Bars | ¯12 | Inactive Border
¯2 | Desktop | ¯13 | Application Workspace
¯3 | Active Title Bar | ¯14 | Highlight
¯4 | Inactive Title Bar | ¯15 | Highlighted Text
¯5 | Menu Bar | ¯16 | Button Face
¯6 | Window Background | ¯17 | Button Shadow
¯7 | Window Frame | ¯18 | Disabled Text
¯8 | Menu Text | ¯19 | Button Text
¯9 | Window Text | ¯20 | Inactive Title Bar Text
¯10 | Active Title Bar Text | ¯21 | Button Highlight

If BCol contains a 3-element vector, it specifies the intensity of the red, green and blue components of the colour as values in the range 0-255. For example, (255 0 0) is red and (255 255 0) is yellow.

Note that the colour realised depends upon the capabilities of the display adapter and driver, and the current Windows colour map.

For a Button, BCol is only effective if the Style is 'Radio' or 'Check' and is ignored if the Style is 'Push'.

It is recommended that you only use pure background colours in Combo and Edit objects. This is because the text written in these objects cannot itself have a dithered background.

For the Ellipse, Poly and Rect objects, BCol specifies the background colour of the line drawn around the perimeter of the object and is effective only when a non-solid line (LStyle 1-4) is used. It also specifies the colour used to fill the spaces between hatch lines if a hatch fill (FStyle 1-6) is used.


BandBorders Property
Applies To: CoolBar

Description

The BandBorders property specifies whether or not narrow lines are drawn to separate adjacent bands in a CoolBar.

BandBorders is a single number with the value 0 (no lines) or 1 (lines are displayed); the default is 0.

The effect of BandBorders is illustrated below.


BaseClass Property
Applies To: NetType

Description

This property specifies the name of the .NET class upon which the NetType is based. The newly created NetType inherits the properties, methods and events of this class.


Bits Property
Applies To: Bitmap Clipboard Cursor Icon

Description

This property defines the pattern in a Bitmap, Cursor, or Icon object, or the pattern of a bitmap stored in the Windows clipboard.

For a Bitmap, Clipboard or Icon, Bits is an integer matrix each of whose elements represents the colour of the corresponding pixel in the bitmap. The colours are specified as 0-origin indices into the CMap property, which itself defines the complete set of different colours (the colour map) used by the object.

Please note that Bits and CMap may only be used to represent an image with a colour palette of 256 colours or less. If the colour palette is larger, the values of Bits and CMap reported by ⎕WG will be (0 0). For a high-colour image, use CBits instead.

For a Cursor, Bits is a Boolean matrix which specifies the shape of the cursor. For a Cursor and Icon, Bits is used in conjunction with the Mask property.

See CMap for further details.


Border Property

Applies To

Description

This property specifies whether or not an object is displayed with a border around it. It is a single number with the value 0 (no border)1 (Border), or 2. The value 2 applies only to a Form and is used in combination with ('EdgeStyle' 'Dialog') to obtain standard dialog box appearance

For a Form or SubForm, the value of the Border property is only relevant if Sizeable, Moveable, SysMenu, MaxButton and MinButton are all 0.

Note

The value of the Border property may only be assigned by ⎕WC and may not be changed using ⎕WS.


BrowseFor Property
Applies To: BrowseBox

Description

The BrowseFor property is a character vector that specifies the type of resource to be the target of an object.

BrowseFor may be 'Directory' (the default), 'File', 'Computer' or 'Printer'.


BtnPix Property
Applies To: Button Menu MenuItem

Description

This property is used to customise the appearance of a Button, Menu or MenuItem. It specifies the names of or refs to up to 3 Bitmap objects to be used to display the object under different circumstances. In general, BtnPix is a 3-element vector of character vectors or refs. However, if it defines a single Bitmap, it may be a single ref, a simple character scalar or vector, or an enclosed character vector.

The first Bitmap is displayed when the object is shown in its normal state. For a Button, this is when its State is 0. The second Bitmap is used for a Menu or MenuItem, when the object is selected (highlighted), or for a Button when its State is 1. The third Bitmap is used when the object is disabled by having its Active property set to 0.

For a Button with Style 'Push', this means that when the user clicks the Button, its appearance switches from the first to the second Bitmap, and then back again. To maintain the standard 3-D appearance, the Bitmaps should contain the correct shadow lines around their edges. For Buttons with Style 'Radio' or 'Check', the Button will display one or other of the two Bitmaps according to its current State.

For example, to have a Button that displays a "Tick" or a "Cross" according to its State:

      'YES' ⎕WC 'Bitmap' 'C:\WDYALOG\YES.BMP'
      'NO'  ⎕WC 'Bitmap' 'C:\WDYALOG\NO.BMP'
      'f1.r1' ⎕WC 'Button'('Style' 'Check')
                          ('BtnPix' 'YES' 'NO')


Btns Property
Applies To: MsgBox

Description

The Btns property determines the set of buttons to be displayed in a MsgBox. It is a simple vector (one button) or a matrix with up to 3 rows, or a vector of up to 3 character vectors specifying the captions for up to 3 buttons. The buttons are arranged along the bottom of the dialog box in the order specified.

Under Windows, there are restrictions on these buttons. However the property has been designed more generally to be useful under different GUIs and perhaps later revisions of Windows.

Under Windows, the Btns property may specify one of six sets of buttons as follows.

  • 'OK'
  • 'OK' 'CANCEL'
  • 'RETRY' 'CANCEL'
  • 'YES' 'NO'
  • 'YES' 'NO' 'CANCEL'
  • 'ABORT 'RETRY' 'IGNORE'

If any other combination is specified, ⎕WC and ⎕WS will report a DOMAIN ERROR. The names of the buttons are however case-insensitive, so the system will accept 'ok', 'Ok', 'oK' or 'OK'.

If the Btns property is not specified, it assumes a default according to Style as follows :

Style | Btns
'Msg' or 'Info' | 'OK'
'Warn' or 'Error' | 'OK' 'CANCEL'
'Query' | 'YES' 'NO'

If Style is not specified, Btns defaults to 'OK'.


ButtonsAcceptFocus Property
Applies To: ToolControl

Description

This is a Boolean property that determines how the Tab key and other cursor movement keys are handled by a ToolControl object.

If ButtonsAcceptFocus is 0 (the default), when the user presses Tab or Shift+Tab to switch the input focus from another object to the ToolControl, the first ToolButton in the ToolControl receives the input focus and is highlighted. Pressing Tab or Shift+Tab again causes the input focus to move to another control. The cursor movement keys have no effect.

If ButtonsAcceptFocus is 1, when the user presses Tab or Shift+Tab to switch the input focus from another object to the ToolControl, the first or last ToolButton in the ToolControl receives the input focus and is highlighted. Note that the behaviour of Shift+Tab in this case is different. Pressing Tab or Shift+Tab again causes the input focus to move to another control, although if there is no other control to accept the input focus, it moves to the first or last ToolButton as appropriate. Pressing the cursor movement keys causes the input focus to move from one ToolButton to the next.


CBits Property
Applies To: Bitmap Clipboard Icon

Description

The CBits property represents the pixels that make up a picture..

CBits provides an alternative representation to that provided by the Bits and CMap properties which apply only to images with 256 colours or under. CBits may be used to represent both low-colour and high-colour images.

CBits is a rank-2 numeric array whose dimensions represent the rows and columns of pixels in the image. The values in CBits represent the colour of each pixel and (for an Icon) its transparency.

For a Bitmap, the colour value of each pixel is obtained by encoding the red, green and blue components, i.e.

      PIXEL←256⊥RED GREEN BLUE

where RED, GREEN and BLUE are numbers in the range 0-255.


CMap Property
Applies To: Bitmap Clipboard Cursor Icon

Description

This property defines the table of colours (the colour map) used by a Bitmap or Icon object or by a bitmap stored in the Windows clipboard. Its value is a 3-column integer matrix of numbers in the range 0-255. Each row represents a separate colour which is indexed (0-origin) by values in the Bits property. The 3 columns refer to the intensities of the red, green and blue components of colour respectively.

Please note that Bits and CMap may only be used to represent an image with a colour palette of 256 colours or less. If the colour palette is larger, the values of Bits and CMap reported by ⎕WG will be (0 0). For a high-colour image, use CBits instead.

When you create a Bitmap or Icon by specifying Bits and CMap, the actual colours you obtain are not necessarily those that you specified. This is partly due to hardware restrictions and partly due to the way in which Windows manages colours. Firstly, your display adapter and driver limit the number of pure colours that can be displayed at any one time and therefore define a maximum size for the colour map. For example, on a standard VGA you are limited to 16 different pure colours (additional ones are provided by dithering).

Secondly, Windows reserves a certain number of colours in the colour map for its own use. When an application requests a new colour (i.e. one that is not already installed in the colour map), MS-Windows either assigns it to a spare entry, or allocates the closest match if the colour map is full. The value of Bits and CMap after ⎕WC reflect the actual colours allocated and may bear little resemblance to the values you assigned to these properties initially.

Note that if you are running 16 colours, MS-Windows reserves all 16 entries in the colour map for its own use. This means that on a 16-colour system, you cannot use any colours other than the default ones reserved by MS-Windows. In practice, the "standard" 16-colour CMap is shown in the following table.

Bits[] | CMap |  |  | Colour
1 | 0 | 0 | 0 | Black
2 | 128 | 0 | 0 | Dark red
3 | 0 | 128 | 0 | Dark Green
4 | 128 | 128 | 0 | Olive Green
5 | 0 | 0 | 128 | Dark Blue
6 | 128 | 0 | 128 | Dark Magenta
7 | 0 | 128 | 128 | Dark Cyan
8 | 128 | 128 | 128 | Dark Grey
9 | 192 | 192 | 192 | Light Grey
10 | 255 | 0 | 0 | Red
11 | 0 | 255 | 0 | Green
12 | 255 | 255 | 0 | Yellow
13 | 0 | 0 | 255 | Blue
14 | 255 | 0 | 255 | Magenta
15 | 0 | 255 | 255 | Cyan
16 | 255 | 255 | 255 | White

Table 29: The default 16-colour CMap

If you are using a 256-colour set-up, the first 9 and the last 7 entries of the 256-colour CMap are the same as the first 9 and last 7 entries of the 16-colour CMap shown above. The intervening entries represent additional colours or are initially unused (0 0 0). New colours that you specify will be allocated to unused entries until the table is full.


CalendarCols Property
Applies To: Calendar DateTimePicker

Description

The CalendarCols property specifies the colours used for various elements in the Calendar object.

CalendarCols is a 6-element integer vector whose elements specify the colours as follows:

[1] | Background colour displayed between months
[2] | Background colour displayed within the month.
[3] | Text colour within a month
[4] | Background colour displayed in the calendar's title
[5] | Colour used to display text within the calendar's title
[6] | Colour used to display header day and trailing day text. Header and trailing days are the days from the previous and following months that appear on the current month calendar.

Each element of CalendarCols may be 0 (which means default colour), a negative singleton that specifies a particular Windows colour, or a 3-element integer vector of RGB values.

Note: At the time of writing, setting the first element of CalendarCols has no effect. Dyalog believes this to be a Windows problem that may be corrected in due course.


Cancel Property
Applies To: Button

Description

This property determines which (if any) Push button in a Form or SubForm is to be associated with the Escape key. It has the value 1 or 0.

Pressing the Escape key will generate a Select event on the Button whose Cancel property is 1, regardless of which object has the keyboard focus.

As only one button in a Form or SubForm can be the Cancel button, setting Cancel to 1 for a particular button automatically sets Cancel to 0 for all others in the same Form.


Caption Property

Applies To

Description

The Caption property is a character vector specifying fixed text associated with the object. For example, Caption defines the label on a Button, the title of a Form, SubForm or MsgBox, the heading in a Group, and the text of a Menu or a MenuItem.

For the Root object, Caption specifies the text displayed when Alt+Tab is used to switch to the Dyalog APL/W application. It may be used in conjunction with the IconObj property which specifies the name of an Icon object to be displayed alongside this text.

Its default value is an empty vector.

For a Button or Label, if the Caption property contains one or more linefeed characters (⎕UCS 10) the text is top-left justified or, for a Button with Style 'Push', centre-justifed ; and automatically wraps on white-space characters (such as space and tab) to fit in the width provided.

For controls that support this feature, a single ampersand (&) is used to designate that the following character (if present) is an access key or an accelerator key and that character is underlined. The ampersand is not itself displayed. To negate this feature and cause an ampersand to be displayed, it is necessary to specify "&&".


CaseSensitive Property
Applies To: ComboEx

Description

Specifies whether or not string searches in the items displayed by a ComboEx object will be case sensitive. Searching occurs when text is being typed into the edit box portion of the ComboEx


CellFonts Property
Applies To: Grid

Description

This property specifies the font objects to be used to display the Values in a Grid object.

CellFonts is either a single ref or a simple character vector, or a vector of refs or character vectors. If it specifies a single font object this will be used to draw the text in all of the cells in the Grid. If it specifies more than one font object, these are mapped to individual cells through the CellTypes property.


CellHeights Property
Applies To: Grid

Description

This property specifies the height of each row in a Grid object in the units specified by its Coord property. It may be a scalar or a vector whose length is the same as the number of rows implied by the Values property. If it is a scalar, it specifies a constant row height. If it is a vector it specifies the height of each row individually.


CellSelect Property
Applies To: Grid

Description

The Grid supports the selection of a contiguous block of cells by the user, using the mouse and/or the keyboard. The ability to select a range of cells is determined by the CellSelect property. This may be a character vector or a vector of character vectors comprising the following:

'Rows' | User may select an entire row by clicking on a row title and may select multiple rows by dragging the mouse over contiguous row titles.
'MultiRows' | Same as 'Rows', but user may additionally select several non-contiguous rows and blocks of rows using the Ctrl key.
'Columns' | User may select an entire column by clicking on a column title and may select multiple columns by dragging the mouse over contiguous column titles.
'MultiColumns' | Same as 'Columns', but user may additionally select several non-contiguous columns and blocks of columns using the Ctrl key.
'Partial' | User may select any rectangular block of cells by either dragging the mouse or using Shift+cursor keys.
'MultiPartial' | Same as 'Partial', but user may additionally select multiple rectangular blocks of cells using the Ctrl key.
'Whole' | User may select the entire Grid by clicking in the space to the left of the column titles and above the row titles.
'Any' | Same as ('Rows' 'Columns' 'Partial' 'Whole'). This is the default.
'Multi' | Same as ('MultiRows' 'MultiColumns' 'MultiPartial' 'Whole').
'None' | User may not select any cells in the Grid.

For example, the following expression would allow the user to select only whole rows and columns:

      gridname ⎕WS 'CellSelect' ('Rows' 'Columns')

Setting CellSelect to ('Rows' 'Columns' 'Whole' 'Partial') is equivalent to setting it to 'Any'.

When the user performs a selection, the Grid generates a GridSelect event.

The range of cells currently selected is given by the SelItems property. You can obtain the current selection by querying this property with ⎕WG and you can set it with ⎕WS.

Note that the user may delete the contents of the selected range, or cut and copy them to the clipboard by pressing Delete, Shift+Delete or Ctrl+Insert respectively. The user may also replace the current selection with the contents of the clipboard by pressing Shift+Insert. These operations generate GridDelete, GridCut, GridCopy and GridPaste events which you may disable (by setting the event action code to ¯1 or to which you may attach a callback function.

If more than one block of cells has been selected, these operations are honoured only if the blocks begin and end on the same rows or begin and end on the same columns. If so, the data placed in the clipboard is the result of joining the blocks horizontally or vertically as appropriate.

You can also invoke these events as methods. This allows you to attach these actions to MenuItems and Buttons. For example, the following expression could be used to implement Cut as a MenuItem:

      name ⎕WC 'MenuItem' 'Cu&t'('Event' 'Select' '⍎gridname.GridCut')

In addition to the ability to copy blocks of cells through the clipboard, the user may also drag a block of cells from one part of the Grid to another.

When the user places the mouse pointer over any of the four edges of a selected block of cells, the cursor changes from a cross to an arrow pointer. The user may now drag the border of the selected block to a new location. If the Ctrl key is pressed at the same time, the contents of the selected cells are copied to the new location. If not, the operation is a move and the original block of cells is cleared (emptied). In either case, the contents of the original block replace the contents of the target block (marked by the dragging rectangle) and the target block becomes selected. You may only move or copy a single block of cells in this way.

These operations generate a GridDropSel event. You may prevent the user from moving and copying blocks of cells by disabling this event (by setting its event action code to ¯1) or you may control these operations selectively with a callback function. Note that although the operation of inserting cells (using Ctrl+Shift) has not been implemented, you may provide this facility yourself with the information provided by the event message.

You may also move or copy a block of cells (which need not necessarily be selected) under program control by calling GridDropSel event as a method.


CellSet Property
Applies To: Grid

Description

This property identifies which cells in a Grid are set (i.e. have values) and which are empty. Its purpose is to allow large numeric matrices containing blank cells to be displayed and edited efficiently.

The CellSet property is a Boolean matrix with the same shape as the Values property. If an element of CellSet is 0, the cell is defined to be empty. Empty cells are displayed as blank and the cell contents by the Values property are ignored.

A more direct way to handle empty cells is to set the corresponding elements of Values to empty vectors. However, if Values is otherwise entirely numeric, this makes the array nested when it would otherwise be simple. For large numeric matrices, this penalty can be severe. For example, a 100x100 array of 2-byte integer values occupies about 20Kb of workspace. Setting one or more elements of the array to an empty vector increases its size to 200Kb. However, because it is Boolean, the size of the CellSet property for a 100x100 array is only 1.27Kb and represents a significant space saving.

Note that if the Values property contains text and is therefore nested anyway, the CellSet property is not helpful in conserving workspace, although it may still be useful to separate empty cells from real data.

You can dynamically change a single element of CellSet using the SetCellSet method.


CellTypes Property
Applies To: Grid

Description

This property specifies the type of each cell in a Grid object. It is a matrix whose elements are origin-1 indices into other property arrays (FCol, BCol, CellFonts and Input).

For example, if CellTypes[1;1] is 3, the first cell in the Grid is displayed using the foreground colour specified by the 3rd element of FCol, the background colour specified by the 3rd element of BCol, and so forth. Note however that scalar property arrays are extended if necessary. Therefore if you require 5 different foreground colours but only one background colour, BCol need specify only a single colour.

You can dynamically change a single element of CellTypes using the SetCellType method.


CellWidths Property
Applies To: Grid

Description

This property specifies the width of each column in a Grid object in the units specified by its Coord property. It may be a scalar or a vector whose length is the same as the number of columns implied by the Values property. If it is a scalar, it specifies a constant column width. If it is a vector it specifies the width of each column individually.


Changed Property
Applies To: ButtonEdit Edit PropertyPage RichEdit Spinner

Description

The Changed property, in conjunction with the Change event, provides the means to control the validation of an object after the user has finished interacting with it.

Initially, the value of the Changed property of an object is set to 0. When the user gives the focus to the object and causes either the Text or (in the case of a Spinner) the Thumb property to be altered, the Changed property is immediately set to 1. When the object loses the input focus and the value of the Changed property is 1, the object generates a Change event. The value of the Changed property is then determined as follows:

If there is no callback function attached to the Change event, or if the Change event is disabled, the Changed property is reset to 0.

If an attached callback returns no result or returns 1, the Change property is reset to 0.

If an attached callback function returns 0, the Changed property is not altered and remains set to 1. The object will therefore generate another Change event when the user next tries to leave it, even if the text and/or Thumb are not altered this time.

Note that the object generates a Change event when it loses the focus only if the value of the Changed property is 1 at the time.


CharFormat Property
Applies To: RichEdit

Description

The CharFormat property describes or applies formatting to the currently selected text in a RichEdit object. If the selection is empty, it reports or specifies the default character formatting for the object. It is a 5-element nested array structured as follows:

[1] A vector of character vectors which describes the text attributes and is comprised of the following keywords:
'Autocolour' | default colour (Windows text colour)
'Bold' | bold text
'Italic' | bold text
'Underline' | underlined
'StrikeOut' | line through text
'Protected' | protected (read-only) text
[2] | A character vector that specifies the face name of the font used to draw the text
[3] | Character height in Twips.
[4] | Text colour. A single integer or an enclosed vector of 3 RGB values. The default is 0 which implies the standard Windows text colour.
[5] | Integer specifying the vertical offset of the character from the base line in Twips. This is used to specify superscript (positive offset) and subscript (negative offset) symbols. The default value is 0.

When you set the character format using ⎕WC or ⎕WS the following rules apply:

If you just want to set a single text attribute (element 1) you may specify a simple vector, for example (⎕WS 'CharFormat' 'Protected') is valid and will add the protected text attribute to the current set of text attributes.

To unset a text attribute (element 1) you must insert the tilde (~) character before the name of the attribute. For example, the expression (⎕WS 'CharFormat' '~Bold') will turn the bold text attribute off.

You need only specify the number of elements required, but you must insert proper values for the elements you wish to remain unaltered. However, you may use '' in the first element to leave the text attributes unchanged.

If there is no text selected, CharFormat specifies the default character format, i.e. the format that will be used to draw the next (and subsequent) characters that the user enters. If there is text selected it specifies the format of the selected block of text. If the format is not strictly homogeneous, ⎕WG may report the format of the first character in the selected block, or, if the block contains characters which use completely different fonts, the result of (⎕WG 'CharFormat') will be empty.

(⎕WS 'CharFormat' ...) will set the format of the currently selected block of text. To set the format of an arbitrary block of text you must select it first using (⎕WS 'SelText' ...).


CharSet Property
Applies To: Font

Description

This property applies to the Classic Edition only. In the Unicode Edition, its value typically has no effect.

CharSet is an integer that specifies the character encoding of the Font object.

The following table illustrates some of the character set encodings supported by Windows. Note that this set may vary according to the edition of Windows that is installed.

Language | CharSet
Western (ANSI) | 0
Hebrew | 177
Arabic | 178
Greek | 161
Turkish | 162
Baltic | 186
Central European | 238
Cyrillic | 204
Vietnamese | 163

Windows fonts typically contain glyphs for the ASCII character set in their first 128 positions, and glyphs for the Western European character set in positions 129-256. Additional sets of character glyphs are stored in positions 257 onwards in what are sometimes referred to as codepages.

When you change the character set encoding, to (say) Greek (161), the set of Greek characters are mapped into the top 128 positions of the font.

For example, if the CharSet is 0 (ANSI), the character code Hex EC is displayed as ì (i-grave). However, if you change CharSet to 161 (Greek), the same character code is displayed as the Greek µ.

The following example illustrates how the character string 'ôï üíïìá ìïõ Ýéíáé Ðåôå' appears differently according to the value of CharSet.

      'F'⎕WC'FORM' 'CharSet Property'('Size' 300 400)('Coord' 'Pixel')
      F.Coord←'Prop'

      'F.F1'⎕WC'Font' ('Size' 32) ('CharSet' 0)
      'F.F2'⎕WC'Font' ('Size' 32) ('CharSet' 161)
      'F.F3'⎕WC'Font' ('Size' 32) ('CharSet' 178)

      STRING←'ôï üíïìá ìïõ Ýéíáé Ðåôå'

      'F.E1'⎕WC'Edit'STRING(10 10)(⍬ 80)('Font' 'F.F1')
      'F.E2'⎕WC'Edit'STRING(40 10)(⍬ 80)('Font' 'F.F2')('Translate' 'ANSI')
      'F.E3'⎕WC'Edit'STRING(70 10)(⍬ 80)('Font' 'F.F3')('Translate' 'ANSI')

Note that setting Translate to 'ANSI' means that characters entered into the Edit fields using a corresponding National Language keyboard (Greek and Arabic) will appear in that language as intended


CheckBoxes Property
Applies To: ListView TreeView

Description

The CheckBoxes property specifies whether or not check boxes are displayed alongside items in a ListView or TreeView object.

CheckBoxes is a single number with the value 0 (check boxes are not displayed) or 1 (check boxes are displayed); the default is 0.

For a TreeView, CheckBoxes will only be honoured if the items have pictures associated with them (via the ImageListObj and ImageIndex properties).

For a ListView, CheckBoxes applies to all settings of the View property.

The GetItemState method can be used to determine if a specific item in a ListView or TreeView is checked. The result of the method will have the 13th bit set if the item is checked.

      STATE←Form.ListView.GetItemState 11
      13⊃⌽(32⍴2)⊤STATE
1

The picture below illustrates the effect on the appearance of a ListView object, of setting CheckBoxes to 1.


Checked Property
Applies To: MenuItem

Description

This property determines whether or not a check mark is displayed alongside the text in a MenuItem. It is a single number with the value 0 (not checked) or 1 (checked). The default is 0.


ChildEdge Property
Applies To: CoolBand

Description

The ChildEdge property specifies whether or not the CoolBand leaves space above and below its child window.

ChildEdge is a single number with the value 0 (no space) or 1 (space is provided); the default is 0.

The following pictures illustrate the effect of the ChildEdge property.


ChildList Property

Applies To

Description

This is a read-only property that reports the names of those objects that may be created as children of the object in question. It is a vector of character vectors in which the order of the items is not significant.


CircleToday Property
Applies To: Calendar DateTimePicker

Description

The CircleToday property specifies whether or not a circle is drawn around the Today date in a Calendar object or in the drop down calendar in a DateTimePicker, when the month containing that date is visible.

CircleToday is a single number with the value 0 (a circle is not drawn) or 1 (a circle is drawn); the default is 1.

See also HasToday property.


ClassID Property
Applies To: ActiveXControl OCXClass OLEClient OLEServer

Description

The ClassID property specifies the class identifier (usually abbreviated to CLSID) of an APL object that is used to represent a COM object. The CLSID is a globally unique identifier (GUID) that uniquely identifies the object.

When you create or recreate an ActiveXControl or OLEServer using ⎕WC, you may specify ClassID. This allows you to re-use a value that was previously allocated to that control by the system. However, you should not specify any other value because that value could be allocated now or in the future to another object on any other computer in the world. Otherwise, a new ClassID is automatically allocated by the system.

Note that the CLSID is not actually recorded on your computer (in the registry) until you register it using )SAVE or Make OCX, or by executing the OLERegister method.


ClassName Property
Applies To: ActiveXControl OCXClass OLEClient OLEServer

Description

For an OLEClient, the ClassName property specifies the name of the OLE object to which an OLEClient object named by the left argument of ⎕WC is to be connected. Similarly, for a NetControl the ClassName property specifies the name of the .NET class to be instantiated. Note that ClassName is mandatory for ⎕WC and may not subsequently be changed using ⎕WS.

For an ActiveXControl or OLEServer, ClassName specifies the external name with which the object is registered, and by which it is referenced by other applications.

For an ActiveXControl, the external name is "Dyalog xxx Control, where xxx is the value of the ClassName property, or, if ClassName is not specified, the name of the ActiveXControl namespace.

For an OLEServer, the external name is "Dyalog.xxx" where xxx is derived in the same way.

For a NetControl, the external name is the name of the .NET class which must be expressed relative to a corresponding element of ⎕USING. For example, to load one of the standard .NET controls:

      ⎕USING,←⊂'System.Windows.Forms,system.windows.forms.dll'


ClipCells Property
Applies To: Grid

Description

This property determines whether or not the Grid displays partial cells. The default is 1. If you set ClipCells to 0, the Grid displays only complete cells and automatically fills the space between the last visible cell and the edge of the Grid with the GridBCol colour.

The first picture below shows a default Grid (ClipCells is 1) in which the third column of data is in fact incomplete (clipped), although this is by no means apparent to the user. The second picture shows the effect on the Grid of setting ClipCells to 0 which prevents such potential confusion.


ColLineTypes Property
Applies To: Grid

Description

This property specifies the appearance of the vertical grid lines in a Grid object.

ColLineTypes is an integer vector, whose length is normally equal to the number of columns in the Grid. Each element in ColLineTypes specifies an index into the GridLineFCol and GridLineWidth properties, thus selecting the colour and width of the vertical grid lines.

For example, if ColLineTypes[1] is 3, the first vertical grid line in the Grid is displayed using the colour specified by the 3rd element of GridLineFCol, and the width specified by the 3rd element of GridLineWidth.

Note that ColLineTypes is not ⎕IO dependant, and the value 0 is treated the same as the value 1; both selecting the first colour and line width specified by GridLineFCol and GridLineWidth respectively.

The default value of ColLineTypes is an empty numeric vector (⍬). If so, all vertical grid lines are drawn using the first element of GridLineFCol and GridLineWidth.

A vertical grid line is drawn down the right edge of its associated column. One pixel is drawn inside the column of cells; additional pixels (if any) are drawn between that column of cells and the next one to its right.


ColSortImages Property
Applies To: Grid

Description

The ColSortImages property identifies the names of, or refs to, up to three Bitmap objects that are used to specify the sort images for a Grid object.

If ColSortImages is not specified, default images are used.

The Bitmap specified by the 1st element of ColSortImages is used to display columns that are sorted down.

The Bitmap specified by the 2nd element of ColSortImages is used to display columns that are unsorted.

The Bitmap specified by the 3rd element of ColSortImages is used to display columns that are sorted up.

 'F'⎕WC'Form' 'Grid: ColSortImages Property'
 F.(Coord Size)←'Pixel'(313 341)
 'F.fnt'⎕WC'Font' 'APL385 Unicode' 16
 F.FontObj←F.fnt
 BK←16 16⍴256⊥White←255 255 255

 'F.gu'⎕WC'Bitmap'('CBits'BK)('MaskCol'White)
 'F.gu.'⎕WC'Text' '⍋'(0 3)
 'F.gd'⎕WC'Bitmap'('CBits'BK)('MaskCol'White)
 'F.gd.'⎕WC'Text' '⍒'(0 3)

 'F.G'⎕WC'Grid'('Posn' 0 0)F.Size
 F.G.Values←#.(COUNTRIES,POPULATION,[1.5]AREA)
 F.G.ColTitles←'Country' 'Population' 'Area'
 F.G.CellWidths←140 100 100
 F.G.TitleWidth←0

 F.G.ColSortImages←'F.gd' '' 'F.gu'
 F.G.(Values←Values[⍋Values[;3];])

 F.G.ColSorted 3 1


ColTitle3D Property
Applies To: ListView

Description

The ColTitle3D property is a Boolean value that specifies whether or not the column titles in a ListView object are displayed with a 3-dimensional effect. Its default value is 1. A column heading with a 3-dimensional button appearance may be used to imply that the user may click on it to sort by the values in that column.

ColTitle3D is only relevant if View is 'Report' and Header is 1. Note that this property may only be set by ⎕WC and may not subsequently be changed using ⎕WS.


ColTitleAlign Property
Applies To: Grid ListView

Description

The ColTitleAlign property specifies the alignment of column titles. For a ListView object this is only relevant only when the View property is set to 'Report'. ColTitleAlign is either a simple character vector, or a vector of character vectors with one element per column.

For a Grid, ColTitleAlign may be:'Top', 'Bottom', 'Left', 'Right', 'Centre', 'TopLeft', 'TopRight', 'BottomLeft', or 'BottomRight'.

For a ListView object, ColTitleAlign may be 'Left', 'Right' or 'Centre'. Also, for a ListView the column data itself is aligned likewise. Note that the first column in a ListView is always left-aligned regardless of the setting of ColTitleAlign. This is a Windows restriction.

Note that both spellings 'Centre' and 'Center' are accepted.


ColTitleBCol Property
Applies To: Grid

Description

The ColTitleBCol property specifies the background colour of the column titles in a Grid object

ColTitleBCol may be a scalar that specifies a single background colour to be used for all of the column titles, or a vector that specifies the background colour of each of the column titles individually. An element of ColTitleBCol may be an enclosed 3-element vector of integer values in the range 0-255 which refer to the red, green and blue components of the colour respectively, or it may be a scalar that defines a standard Windows colour element (see BCol for details). Its default value is 0 which obtains the colour defined for Button Face.


ColTitleDepth Property
Applies To: Grid

Description

ColTitleDepth specifies the structure of a set of hierarchical column titles. It is an integer vector with the same length as the ColTitles property. A value of 0 indicates that the corresponding element of ColTitles is a top-level title. A value of 1 indicates that the corresponding title is a sub-title of the most recent title whose ColTitleDepth is 0; a value of 2 indicates that the corresponding title is a sub-title of the most recent title whose ColTitleDepth is 1, and so forth. For example:

      'F'⎕WC'Form'('Coord' 'Pixel')('Size' 200 498)
      'F'⎕WS'Caption' 'Hierarchical Column Titles'
      'F.G'⎕WC'Grid'(?10 12⍴100)(0 0)(200 498)
      'F.G'⎕WS('TitleWidth' 0)('TitleHeight' 60)
      'F.G'⎕WS'CellWidths' 40

      Q1←'First Quarter' 'Jan' 'Feb' 'Mar'
      Q2←'Second Quarter' 'Apr' 'May' 'Jun'
      Q3←'Third Quarter' 'Jul' 'Aug' 'Sep'
      Q4←'Fourth Quarter' 'Oct' 'Nov' 'Dec'

      CT←(⊂'1995'),Q1,Q2,Q3,Q4
      CD←0,16⍴1 2 2 2

      'F.G'⎕WS('ColTitles'CT)('ColTitleDepth'CD)

Note that the LockColumns method is not supported in combination with hierarchical column titles.


ColTitleFCol Property
Applies To: Grid

Description

The ColTitleFCol property specifies the colour of the column titles in a Grid object

ColTitleFCol may be a scalar that specifies a single colour to be used for all of the column titles, or a vector that specifies the colour of each of the column titles individually. An element of ColTitleFCol may be an enclosed 3-element vector of integer values in the range 0-255 which refer to the red, green and blue components of the colour respectively, or it may be a scalar that defines a standard Windows colour element (see BCol for details). Its default value is 0 which obtains the colour defined for Button text.


ColTitles Property
Applies To: Grid ListView

Description

This property specifies the headings that are displayed above the columns in a Grid object. If specified, it must be a vector of character vectors or matrices whose length is the same as the number of columns implied by the Values property. The default value of ColTitles is an empty character vector. In this case, the system displays "standard" spreadsheet column titles A-Z, AA-AZ, BA-BZ and so forth.

To disable the display of column titles in a Grid, you should set the TitleHeight property to 0.


Collate Property
Applies To: Printer

Description

Specifies whether or not multiple copies of printer output are collated.

Collate is a single number with the value 0 or 1. If Collate is 1, multiple copies of output are collated separately. If Collate is 0, copies are uncollated on output.

Collate is ignored unless Copies is >1.

The default value for Collate is derived from the current printer setting and Collate is only effective if the printer supports this capability.


ColorMode Property
Applies To: Printer

Description

Specifies whether or not printing is done in colour.

ColorMode is a single number with the value 0 or 1. If ColorMode is 1, printing is done in colour. If ColorMode is 0, printing is done using black ink only.

This property only applies to colour printers.


ColumnWidth Property
Applies To: List

Description

This property specifies the column width in pixels of a multi-column List object. See MultiColumn property for details.


Container Property
Applies To: ActiveXControl

Description

The Container property is a read-only property whose value is the ⎕OR of an ActiveXContainer object that represents the ActiveX Site object of the application that is hosting the ActiveXControl.

The value of Container may be converted to a namespace using ⎕NS or ⎕WC.

The resulting object may then be used to obtain the values of ambient properties, or to access methods exposed by the host application via OLE interfaces. See OLEQueryInterface.


Coord Property

Applies To

Description

This property defines an object's co-ordinate system. It is a character string with one of the following values; 'Inherit', 'Prop', 'Pixel', 'RealPixel', 'ScaledPixel', 'User' or 'Cell' (graphics children of a Grid only).

If Coord is 'Inherit', the co-ordinate system for the object is inherited from its parent. Note that the default value of Coord for the system object '.' is 'Prop', so by default all objects created by ⎕WC inherit 'Prop'.

If Coord is 'Prop', the origin of the object's parent is deemed to be at its top left interior corner, and the scale along its x- and y-axes is 100. The object's position and size (Posn and Size properties) are therefore specified and reported as a percentage of the dimensions of the parent object, or, for a Form, of the screen.

If Coord is 'RealPixel', the origin of the object's parent is deemed to be at its top left interior corner, and the scale along its x- and y-axes is measured in physical pixel units. The object's position and size (Posn and Size properties) are therefore reported and set in physical pixel units. If you set Coord on the system object to 'Pixel', the value of its Size property gives you the resolution of your screen. Note that pixels are numbered from 0 to (Size -1).

If Coord is 'ScaledPixel' the number of pixels specified for Posn, Size, and other such properties will be automatically scaled by Dyalog APL according to the user's chosen display scaling factor. So if you specify an Edit object to be 80 pixels wide and 20 pixels high, and the user's scaling factor is 150%, Dyalog will automatically draw it 120 pixels wide and 30 pixels high. Dyalog will also de-scale coordinate values reported by ⎕WG and event messages.

If Coord is 'Pixel', it is interpreted as either 'RealPixel' or 'ScaledPixel' according to the value of the DYALOG_PIXEL_TYPE parameter, which is either ScaledPixel or RealPixel. See DYALOG_PIXEL_TYPE.

If this parameter is not specified, the default is RealPixel. So by default, when you set Coord to Pixel, it will be treated as RealPixel.

If Coord is 'User', the origin and scale of the co-ordinate system are defined by the values of the YRange and XRange properties of the parent object. Each of these is a 2-element numeric vector whose elements define the co-ordinates of top left and bottom right interior corners of the (parent) object respectively.

Note that if Coord is 'User' and you change the values of YRange and/or XRange of the parent, the object (and all its siblings with Coord 'User') are redrawn (and clipped) according to the new origin and scale defined for the parent. The values of their Posn, Size and Points properties are unaffected. Changing YRange and/or XRange therefore provides a convenient and efficient means to "pan and zoom".

The Coord property for graphic objects created as children of a Grid may also be set to Cell. Apart from being easier to compute, a graphic drawn using cell coordinates will expand and contract when the grid rows and columns are resized.

Example:

This statement creates a button 10 pixels high, 20 pixels wide, and 5 pixels down and along from the top-left corner of the parent Form T.

      'T.B1'⎕WC'Button' 'OK'(5 5)(10 20)('Coord' 'Pixel')

If you set Coord to 'RealPixel' in the Root object '.', then query its Size, you get the dimensions of the screen in pixels, i.e.

      '.' ⎕WS 'Coord' 'RealPixel'
      '.' ⎕WG 'Size'
480 640

If you set Coord to 'ScaledPixel' in the Root object '.', then query its Size, you get the virtual resolution of the screen, i.e.

      '.'⎕WS 'Coord' 'ScaledPixel'
      '.'⎕WG'Size'
1080 1920


Copies Property
Applies To: Printer

Description

Specifies the number of copies to be printed.

Copies is a non-zero scalar integer value whose default is defined by the current printer settings.


Cue Property
Applies To: ButtonEdit Edit

Description

This property specifies optional text to be displayed when a ButtonEdit or an Edit object is empty. For an Edit object it applies only if the Style of the Edit object is 'Single'.

Note that this feature only applies if Native Look and Feel is enabled.

The Boolean property ShowCueWhenFocused determines whether or not the cue should also be displayed once the user has tabbed into or clicked on the input field (and thus given it the focus).

Example

      'F' ⎕WC 'Form' 'Cue Property'
      'F.E' ⎕WC 'Edit'
       F.E.Cue←'Enter Password'


CurCell Property
Applies To: Grid

Description

This property specifies or reports the current cell in a Grid object. The current cell is the one that is currently addressed by the user. The current cell is identified visibly if it has an associated object, other than an external. Label object.


CurrentColor Property
Applies To: ColorButton

Description

The CurrentColor property is a 3-element integer vector that specifies and reports the RGB value of the currently selected colour in a ColorButton object. Its default value is (0 0 0) which is black.


CurrentState Property
Applies To: TCPSocket

Description

The CurrentState property is a read-only property that reports the current state of a TCPSocket object. Its possible values and their means are as follows:

CurrentState | Description
'Open' | a client socket that is not yet connected or a UDP socket
'Bound' | a server socket that has been bound
'Listening' | a server socket to which a client has not yet connected
'Connected' | a client or server socket that is connected
'IHaveClosed' | a temporary state on the way to Closed
'PartnerHasClosed' | a temporary state on the way to Closed
'Closed' | a socket that has been closed by both client and server


CursorObj Property

Applies To

Description

This property is used to associate a particular cursor with an object. Its value is either a simple scalar number which specifies a standard Windows cursor, or the name of, or ref to, a Cursor object. The standard Windows cursors are :

0 | arrow (Windows default)
1 | hourglass
2 | crosshair
3 | I-Beam
4 | crossing vertical/horizontal double-headed arrows
5 | diagonal double-headed arrows (left-to-right)
6 | vertical double-headed arrows
7 | diagonal double-headed arrows (right-to-left)
8 | horizontal double-headed arrows
9 | upward pointing arrow
10 | box
11 | crossing vertical/horizontal double-headed arrows
12 | no-entry sign
13 | arrow with hourglass
14 | pointing hand

If CursorObj is set to anything other than an empty vector (which is the default) it defines the appearance of the cursor when the mouse pointer is moved into the object. If CursorObj is an empty vector, the shape of the cursor remains unchanged when the mouse pointer enters the object. In effect, the cursor is "inherited" from its parent. Exceptions to this rule are certain objects which have special cursors by default.

If the value of CursorObj for the Root object is set to anything other than an empty vector, it applies to all Forms and their children, irrespective of their own CursorObj values. Therefore, if you want to indicate that your application is "working" and is not responsive to input, you can simply do:

      '.' ⎕WS 'CursorObj' 1 ⍝ Hourglass cursor

Then to reset the application you do:

      '.' ⎕WS 'CursorObj' ''


CustomColors Property
Applies To: ColorButton

Description

The CustomColors property is a 1-row, 16-column nested matrix which specifies the RGB values of the colours displayed in the Custom colors section of the Windows colour selection dialog box when displayed by a ColorButton object.

Each element of CustomColors is a 3-element integer vector specifying an RGB colour value.

By default, each element of CustomColors is (0 0 0). If the user selects a new custom colour from the Windows colour selection dialog box, its value will be reported by CustomColors. CustomColors must always have shape (1 16).

Note that CustomColors is maintained separately for each separate ColorButton, and CustomColors defaults to (1 16⍴⊂0 0 0) for each new ColorButton that you create. If you want to maintain a global custom colour table for your application, you must do this yourself.

Note that the Pocket PC 2002 colour selection dialog box does not provide the facility to select custom colours, so this functionality is not available in PocketAPL.


CustomFormat Property
Applies To: DateTimePicker

Description

Specifies a custom format for the date/time display in a DateTimePicker.

CustomFormat is a character vector that may contain a mixture of date/time format elements and body text. The date/time elements are replaced by the actual date/time values when the object is displayed. The body text is displayed as-is. Note that CustomFormat may only be specified when the DateTimePicker object is created.

The date/time elements are defined by the following groups of characters, notice that they are case-sensitive:

Element | Description
d | The one- or two-digit day.
dd | The two-digit day. Single-digit day values are preceded by a zero.
ddd | The three-character weekday abbreviation.
dddd | The full weekday name.
h | The one- or two-digit hour in 12-hour format.
hh | The two-digit hour in 12-hour format. Single-digit values are preceded by a zero.
H | The one- or two-digit hour in 24-hour format.
HH | The two-digit hour in 24-hour format. Single-digit values are preceded by a zero.
m | The one- or two-digit minute.
mm | The two-digit minute. Single-digit values are preceded by a zero.
M | The one- or two-digit month number.
MM | The two-digit month number. Single-digit values are preceded by a zero.
MMM | The three-character month abbreviation.
MMMM | The full month name.
t | The one-letter AM/PM abbreviation (that is, AM is displayed as "A").
tt | The two-letter AM/PM abbreviation (that is, AM is displayed as "AM").
yy | The last two digits of the year (that is, 1996 would be displayed as "96").
yyyy | The full year (that is, 1996 would be displayed as "1996").

The body text is defined by sub-strings contained within single quotes. For example, to display the current date with the format "Today is: 04:22:31 Tuesday Mar 23, 1996", the format string is defined as follows:

      CustomFormat
'Today is: 'hh':'m':'s dddd MMM dd', 'yyyy

To include a single quote in your body text, use two consecutive single quotes. For example, to produce output that looks like: "Don't forget Mar 23, 1996", CustomFormat should be specified as follows:

        CustomFormat
'Don''t forget' MMM dd',' yyyy

Note: Non format characters that are not delimited by single quotes will result in unpredictable display by the DateTimePicker object.


Data Property

Applies To

Description

This property allows you to associate arbitrary data with an object. The value of the Data property may be any APL array.


DateTime Property
Applies To: DateTimePicker

Description

Specifies the value of date/time in a DateTimePicker.

The DateTime property represents the date and time value that is currently displayed in a DateTimePicker object.

It is normally a 4-element integer vector containing the date (as an IDN), hour, minutes and seconds respectively.

However, if the checkbox shown in the object is unset (see HasCheckBox), the value of DateTime will be ⍬ (zilde).


DblClickToggle Property
Applies To: CoolBar

Description

The DblClickToggle property specifies whether or not the user must single-click or double-click to toggle a child CoolBand between its maximised or minimised state.

DblClickToggle is a single number with the value 0 (single-click toggles state) or 1 (double-click toggles state); the default is 0.


Decimals Property
Applies To: ButtonEdit Edit Label Spinner

Description

This property specifies the number of decimal places to which a number is to be displayed in an Edit or Label object with FieldType 'Numeric'. For an Edit object, Decimals also specifies the maximum number of digits that the user may enter after a decimal point.

The default value of decimals is ¯1 which allows any number of decimal places to be entered.


Default Property
Applies To: Button MsgBox

Description

This property determines which of a set of push buttons in a Form, SubForm or MsgBox is the default button.

In a Form or SubForm, the Default Button will generate a Select event (30) when the user presses the Enter key, even though the Default Button may not have the focus at the time.

If however, the user explicitly shifts the focus to another Push Button, the automatic selection of the Default Button is disabled and the Enter key applies to the Button with the focus.

For a Button, the Default property has the value 1 or 0. As only one Button can be the Default Button, setting Default to 1 for a particular Button automatically sets Default to 0 for all others with the same parent.

In a MsgBox, Default specifies which button initially has the focus. It has the value 1, 2 or 3 corresponding to the three buttons that can be defined. See Btns property for further details.


DefaultColors Property
Applies To: ColorButton

Description

The DefaultColors property is a nested matrix which specifies the RGB values of the colours shown in the colour selection drop-down displayed by a ColorButton object.

The shape of DefaultColors determines the number of rows and columns in the colour selection drop-down.

Each element of DefaultColors is a 3-element integer vector specifying an RGB colour value.


Depth Property
Applies To: TreeView

Description

The Depth property specifies the structure of the items in a TreeView object. It is either a scalar 0 or an integer vector of the same length as the Items property.

A value of 0 indicates that the corresponding item is a top-level item. A value of 1 indicates that the corresponding item is a child of the most recent item whose Depth is 0; a value of 2 indicates that the corresponding item is a child of the most recent item whose Depth is 1, and so forth. For example:

AIRPORTS | DEPTH | Description
Europe | 0 | Top-level (root) item
UK | 1 | 1st sub-item of Europe
London Heathrow | 2 | 1st sub-item of UK
London Gatwick | 2 | 2nd sub-item of UK
Manchester | 2 | 3rd sub-item of UK
France | 1 | 2nd sub-item of Europe
Paris CDG | 2 | 1st sub-item of France
Americas | 0 | Top-level (root) item
USA | 1 | 1st sub-item of N.America
California | 2 | 1st sub-item of USA
Los Angeles | 3 | 1st sub-item of California
San Francisco | 3 | 2nd sub-item of California
East Coast | 2 | 2nd sub-item of USA
New York | 3 | 1st sub-item of East Coast
Kennedy | 4 | 1st sub-item of NY
La Guardia | 4 | 2nd sub-item of NY
      'F'⎕WC'FORM' 'International Airports'
      'F.TV'⎕WC'TreeView'AIRPORTS(0 0)(100 100)('Depth'DEPTH)


DevCaps Property
Applies To: Printer Root

Description

This property reports the device capabilities of the screen or printer. It is a 4-element nested vector as follows:

[1] | Height and Width:2-element numeric vector of device in pixels
[2] | Height and Width:2-element numeric vector of device in mm
[3] | Number of colours or ¯1
[4] | Windows scaling factor as a percentage (100=no scaling). This value is the same as reported in the Display section of the Windows Control Panel

This property is useful if you want to make objects of a specific physical size. For example, to draw a 10mm square in a Form 'F' at (5,5):

      Size ← 10× ⊃÷/2↑'.' ⎕WG 'DevCaps'
      'F.R' ⎕WC 'Rect' (5 5) Size ('Coord' 'Pixel')

Notes

  • the physical size reported for the screen is typically only a nominal size, because, if you use a generic video driver, Windows has no way to tell what size of screen is attached to your computer.
  • The number of colours is reported only if the device has a colour depth of no more than 8 bits per pixel. For devices with greater colour depths, ¯1 is returned.
  • new elements may be added to DevCaps in future releases.


Directory Property
Applies To: FileBox

Description

The Directory property contains a simple character vector which specifies the initial directory from which a list of suitable files is displayed.

If, whilst interacting with the FileBox, the user changes directory and exits by pressing "OK" or by closing the FileBox, the value of the Directory property is updated accordingly.


Divider Property
Applies To: ToolControl

Description

The Divider property controls the presence or absence of a recessed line drawn above, below, to the left of, or to the right of a ToolControl object.

Divider is a single number with the value 0 (dividing line is not drawn) or 1 (a dividing line is drawn); the default is 1.

The pictures below illustrates a ToolControl drawn with and without a divider.


DockChildren Property
Applies To: CoolBar Form SubForm

Description

The DockChildren property specifies the names of client objects that may be docked in a host object.

DockChildren may be a single ref or simple character scalar or vector, or a vector of refs or character vectors. Each item represents an object that may be docked. Notice that if you use a name, you must specify the simple name of the object, excluding any part of its full pathname that refers to a parent; i.e. the specified names must not contain any leading pathname information.

If the name of, or ref to, a dockable object occurs in the DockChildren property, the host object will generate DockMove events when the client is dragged over it, and will generate a DockAccept event when a docking operation takes place.

If the name of, or ref to, the client object is not present in its DockChildren property, the object will not respond in any way as the client is dragged over it.

The following example shows the creation of 3 dockable forms, all of which are dockable in a host form called h1.

The first, c1, is a totally independent Form. When docked in h1, it will become a SubForm h1.c1. When undocked, it will revert to an independent Form c1.

The second, c2, is created initially as a child of h1 and will therefore be displayed above it in the window stacking order. When docked it will become a SubForm h1.c2. When undocked, it will revert back to a dependant Form h1.c2. In all cases, it appears on top of h1.

The third, c3, is created initially as a child of another Form, h2. When docked (in h1) it will become a SubForm h1.c3. When undocked, it will become a dependant Form h1.c3, and will therefore appear above h1 in the stacking order.

      'h1'⎕WC'Form' 'Host1'
      'h2'⎕WC'Form' 'Host2'

      'c1' ⎕WC 'Form' 'Client 1' ('Dockable' 'Always')
      'h1.c2' ⎕WC 'Form' 'Client 2' ('Dockable' 'Always')
      'h2.c3' ⎕WC 'Form' 'Client 3' ('Dockable' 'Always')
      h1.DockChildren←'c1' 'c2' 'c3'


DockShowCaption Property
Applies To: Form SubForm

Description

The DockShowCaption property specifies whether or not a Form displays a title bar when it is docked as a SubForm.

DockShowCaption is a single number with the value 0 or 1 (the default).

The DockShowCaption property may be toggled on and off by the user from the object's context menu.

The first picture below illustrates a Form, docked as a SubForm, whose DockShowCaption property is 1, but is about to be set to 0.

The next picture shows the same docked Form with DockShowCaption set to 0.


Dockable Property
Applies To: CoolBand Form SubForm ToolControl

Description

The Dockable property specifies whether or not an object may be docked or undocked.

Dockable is a character vector containing 'Never' (the default), 'Always' or 'Disabled'.

If Dockable is 'Never', the object may not be docked or undocked by the user, and the docking menu items are not present in the object's context menu. This is the default.

If Dockable is 'Always', the object may be docked or undocked by the user, and the docking menu items are present in the object's context menu.

If Dockable is 'Disabled', the object may not currently be docked or undocked by the user, but the docking menu items are present in the object's context menu.

Note that by default, the user may switch between Dockable 'Always' and 'Disabled' by toggling the Dockable menu item. If you want to exercise full control over this property, you may implement your own context menu (see ContextMenu Event)


Docked Property
Applies To: Form SubForm

Description

The Docked property is a read-only property that indicates whether or not an object is currently docked.

Docked is a single number with the value 0 (is not docked) or 1 (is docked).


DragItems Property
Applies To: ListView

Description

The DragItems property is Boolean and specifies whether or not the items in a ListView object may be drag/dropped by the user. Its default value is 1.


Dragable Property

Applies To

Description

This property determines whether or not an object may be the subject of a "drag and drop" operation. It is a single number with the value 0, 1 or 2. A value of 0 (which is the default) means that the object may not be drag/dropped. A value of 1 means that the object may be drag/dropped and that during the "drag" operation, a box representing the bounding rectangle around the object is displayed on the screen. A value of 2 means that the outline of the object is displayed as the object is dragged, or, if the object is an Image with a Picture property containing the name of an Icon object, the icon itself is displayed as it is dragged. For rectangular non-graphical objects, values of 1 and 2 are equivalent.

If an object is Dragable, the user may drag it by positioning the mouse pointer within the object, depressing the left mouse button, then moving the mouse with the button held down. During the drag operation, the mouse pointer is automatically changed to a "drag" symbol. The object is "dropped" by releasing the left mouse button. The effect depends upon where it is dropped, and on the action associated with the DragDrop event for the object under the mouse pointer (if any).

If there is no object under the mouse pointer, the "drag and drop" operation is ignored. Otherwise, the object under the mouse pointer generates a DragDrop event.

If the object under the mouse pointer is the parent of the object that has been "dragged and dropped", the default action is for the system to move that object to the new location within its parent. If you wish to allow your user to freely move an object within its parent Form or Group, simply set its Dragable property to 1; the system will take care of the rest. If you want to allow the user to move an object, but you want to know about it when it happens, you can associate a callback function to the DragDrop event that queries the new position. To permit the operation to complete, the callback function should either not return a result or it should return something other than a scalar 0. To selectively disable movement, your callback function should return a scalar 0 in circumstances when the "drop" is not to be permitted.

If the object under the mouse pointer is not the parent of the object being dragged, the default action is for the system to ignore the operation. However, by enabling the DragDrop event, your application can of course take whatever action is appropriate, including perhaps moving the dragged object to a new parent.

Note that a Dragable object does not generate a Configure (31) event when it is dragged and dropped.


DrawMode Property
Applies To: Circle Ellipse Marker Poly Rect Text

Description

The DrawMode property provides direct control over the low-level drawing operation performed by graphical objects.

The DrawMode property specifies the current foreground mix mode. The Windows GDI uses the foreground mix mode to combine pens and interiors of filled objects with the colours already on the screen. The foreground mix mode defines how colours from the brush or pen and the colours in the existing image are to be combined.

DrawMode affects every drawing operation performed by Dyalog APL and not just the initial drawing operation when the object is created. Many of the drawing modes are additive (the result depends not just on what is being drawn, but on what is already there) and the effects may therefore vary. For this reason, DrawMode should normally be used only with un-named graphical objects.

You could use DrawMode to move or animate graphical objects in circumstances where the standard Dyalog APL behaviour was not ideal.

DrawMode is an integer with one of the following values:

Value | Name | Resulting Pixel Colour
1 | R2_BLACK | Pixel is always 0.
2 | R2_NOTMERGEPEN | Pixel is the inverse of the R2_MERGEPEN colour.
3 | R2_MASKNOTPEN | Pixel is a combination of the colours common to both the screen and the inverse of the pen.
4 | R2_NOTCOPYPEN | Pixel is the inverse of the pen colour.
5 | R2_MASKPENNOT | Pixel is a combination of the colours common to both the pen and the inverse of the screen.
6 | R2_NOT | Pixel is the inverse of the screen colour.
7 | R2_XORPEN | Pixel is a combination of the colours in the pen and in the screen, but not in both.
8 | R2_NOTMASKPEN | Pixel is the inverse of the R2_MASKPEN colour.
9 | R2_MASKPEN | Pixel is a combination of the colours common to both the pen and the screen.
10 | R2_NOTXORPEN | Pixel is the inverse of the R2_XORPEN colour.
11 | R2_NOP | Pixel remains unchanged.
12 | R2_MERGENOTPEN | Pixel is a combination of the screen colour and the inverse of the pen colour.
13 | R2_COPYPEN | Pixel is the pen colour.
14 | R2_MERGEPENNOT | Pixel is a combination of the pen colour and the inverse of the screen colour.
15 | R2_MERGEPEN | Pixel is a combination of the pen colour and the screen colour.
16 | R2_WHITE | Pixel is always 1.


Duplex Property
Applies To: Printer

Description

Specifies whether pages are printed on separate sheets or back-to-back.

Duplex is a character vector which is either empty or contains 'Simplex', 'Vertical', or 'Horizontal'.

The default value for Duplex is derived from the current printer setting and 'Vertical' and 'Horizontal' are only effective if the printer supports a duplex capability.


EdgeStyle Property

Applies To

Description

Note that EdgeStyle is not honoured for objects which have a natural built-in 3-dimensional appearance.

This property is used to give a 3-dimensional appearance to screen objects. This is achieved by drawing the object with a grey or white background colour and by drawing a border around it using various combinations of black, white and dark grey lines. Note that this border is drawn outside a control but inside a Form or SubForm.

The value of the EdgeStyle property is a character vector chosen from the following :

'None' | Object is drawn with no 3-dimensional effects and the EdgeStyle properties of its children are ignored (treated as None).
'Plinth' | Object is drawn with a light shadow along its top and left edges and a dark shadow along its bottom and right edges. This gives the illusion of a raised effect.
'Recess' | Object is drawn with a dark shadow along its top and left edges and a light shadow along its bottom and right edges. This gives the illusion of a sunken effect.
'Groove' | Object is drawn with a border that has the appearance of a groove.
'Ridge' | Object is drawn with a border that has the appearance of a ridge.
'Shadow' | Object is drawn with a dark border line along its top and left edges.
'Default' | Object itself is drawn with no 3-dimensional border, but the values of the EdgeStyle properties of its children are observed.
'Dialog' | Used in conjunction with ('Border' 2), this gives a Form the appearance of a standard 3-dimensional dialog box. This setting applies only to a Form or a SubForm

For the Root object, the EdgeStyle property may be 'None' or 'Default'. If EdgeStyle is 'None', screen objects are drawn without 3-dimensional effects of any kind and the value of their EdgeStyle property is ignored. If EdgeStyle is 'Default', all controls are drawn using their default EdgeStyle properties.

Note that MsgBox, FileBox and the set-up dialog box associated with the Printer object are all drawn with 3-dimensional effects regardless of the value of EdgeStyle on Root. These objects do not have their own EdgeStyle properties.

If you set EdgeStyle to 'None' on the Root object, all your objects will (by default) be drawn without 3-dimensional effects.


EditImage Property
Applies To: ComboEx

Description

Specifies whether or not the edit control portion of the ComboEx displays an image for selected items.

EditImage is a single number with the value 0 or 1 (the default). If EditImage is 1, the image associated with the selected item is displayed in the edit control, portion of the ComboEx object, to the left of the text. If EditImage is 0, only the item text is displayed in the edit control.


EditImageIndent Property
Applies To: ComboEx

Description

Specifies whether or not the indents associated with items in a ComboEx object are honoured in the edit control portion of the ComboEx.

EditImageIndent is a single number with the value 0 or 1 (the default).

If EditImageIndent is 1, the selected item which is displayed in the edit control portion of the ComboEx object is indented in the same way as when it is displayed in the dropdown portion of the object. The amount of indentation is specified by the Indents property.

If EditImageIndent is 0, the item displayed in the edit control portion of the ComboEx is not indented.


EditLabels Property
Applies To: ListView TreeView

Description

The EditLabels property is Boolean and specifies whether or not the labels (specified by the Items property) in a ListView or TreeView object may be edited by the user. Its default value is 0 (editing is not allowed).

If EditLabels is 1, the user begins editing by clicking the label of the item that has the focus. This causes a pop-up edit box to appear around the item and allows the use to change it. A BeginEditLabel event is reported at the start of the edit operation and an EndLabelEdit event is reported on its completion. You may control the edit of a particular label using callback functions attached to these events.


Elevated Property
Applies To: Button

Description

The Elevated property applies only to a Button whose Style is 'CommandLink'.

Elevated is a Boolean scalar with a default value of 0. When set to 1, the icon on the CommandLink button changes from a "green arrow" to a "shield". This is intended to convey to the user that the action associated with the Button requires Elevation. This is a feature of User Account Control in Windows 7. See your Windows documentation for further information. Note that APL does not take any action (other than to cause the icon to change) when Elevated is set to 1. This is the responsibility of the programmer.


Encoding Property
Applies To: TCPSocket

Description

The Encoding property is a character vector that specifies how character data are encoded or translated. The possible values are 'None', 'UTF-8', 'Classic', or 'Unicode', depending upon the value of the Style property.

Table 30: Unicode Edition

Style | Encoding | Description
'Raw' | 'None' | Not applicable. Only integer data may be transmitted/received.
'Char' | 'None' | Transmission is limited to characters with Unicode code points in the range 0-255. Attempting to transmit (or receive) a character outside this range will cause DOMAIN ERROR.
 | 'UTF-8' | Characters are transmitted/received using the UTF-8 encoding scheme.
'APL' | 'Classic' | Characters are transmitted/received as indices of ⎕AV, and translated according to the current value of ⎕AVU. An attempt to transmit or receive a characters not present in ⎕AVU will cause TRANSLATION ERROR
 | 'Unicode' | Characters are transmitted/received as is (as Unicode code points).

Table 31: Classic Edition

Style | Encoding | Description
'Raw' | 'None' | Not applicable. Only integer data may be transmitted/received.
'Char' | 'None' | Characters (which are represented internally as indices of ⎕AV) are translated to and from ASCII using the Output Translate Table win.dot.
 | 'UTF-8' | Characters are converted to/from Unicode using ⎕AVU and transmitted/received using the UTF-8 encoding scheme. An attempt to transmit or receive a characters not present in ⎕AVU will cause TRANSLATION ERROR.
'Raw' | 'Classic' | Characters are transmitted/received as indices of ⎕AV.
 | 'Unicode' | Characters are converted to/from Unicode using ⎕AVU and transmitted/received as Unicode code points. An attempt to transmit or receive a characters not present in ⎕AVU will cause TRANSLATION ERROR.

The default value of Encoding depends upon the value of Style as indicated. Default values are highlighted thus. in the above tables.

An attempt to set the value of Encoding to a value not valid for the current Style, as implied by the above tables, will cause DOMAIN ERROR.

If you change the value of the Style property, the value of Encoding will remain unchanged if it is valid for the new Style. Otherwise it will revert to the default value for the new value of Style.

      's0'⎕WC'TCPSocket' ('LocalPort' 2001)
      s0.(Style Encoding)
Char  None

      s0.Style←'APL'
      s0.(Style Encoding)
Apl  Classic


End Property
Applies To: Circle Ellipse

Description

This property specifies one or more end-angles for an arc, pie-slice, or chord of a circle or ellipse. It may be used in conjunction with Start which specifies start angles. Angles are measured counter-clockwise from the x-axis at the centre of the object.

If a single arc is being drawn, End is a single number that specifies the end angle of the arc in radians (0 ⍎> ○2). If multiple arcs are being drawn, End is either a single number as before (the end angle for several concentric arcs) or a numeric vector with one element per arc.

If Start is not specified, the default value of End is ○2. Otherwise, the default value of End is ((¯1↓+\Start),○2).


EnterReadOnlyCells Property
Applies To: Grid

Description

This is a Boolean property that specifies whether or not the user may visit read-only cells in a Grid object. Its default value is 1.

In this context, a read-only cell is one that satisfies one or more of the following conditions:

  • it has no associated Input object
  • its associated Input object is a Label
  • its associated Input object is an Edit object with ReadOnly set to 1
  • its associated Input object is inactive (Active 0)

If EnterReadOnlyCells is set to 0 and the user clicks the mouse on a read-only cell, the current cell does not change although CellDown, CellUp and CellDblClick events are reported if enabled. If the user presses a cursor movement key that would otherwise cause the cursor to move into a read-only cell, the cursor moves instead to the nearest editable cell in the appropriate direction.


EvaluationDays Property
Applies To: Root

Description

This is a read-only property that reports the number of days remaining before an evaluation version of a Dyalog APL run-time application expires.

It is provided so that you can display an appropriate message box to notify your end-user when your application is started.

PocketAPL only


Event Property

Applies To

Description

This property defines how an object responds to user actions. Unlike other properties which only have a single value, this property has a value corresponding to each of the different types of event that may be generated by a particular object. Consequently the syntax for setting the Event property differs from the general syntax that applies to other properties.

Two syntactic forms are allowed:

  • A 3 or 4-item vector containing the property name 'Event', followed by the Event Type(s), a value which determines the action to be taken, and an optional array that will be supplied as a left argument to the callback function
  • A composite vector whose first element contains the property name 'Event', followed by a series of 2 or 3-element vectors, each defining the action to be taken for a different Event Type (or types).

Examples

     'Event' 'MouseUp' 'foo' 88
     'Event' ('MouseUp' 'MouseDown') 'foo' 88
     'Event' ('MouseUp' 'foo' 88)('MouseDown' 'goo')

Like any other property, the Event property can be set using assignment. However, certain special considerations apply which are discussed later.

When you specify the Event property using ⎕WC or ⎕WS, the action to be taken for an event type or types is specified by a 2 or 3-element vector containing:

Element | Item | Description
[1] | Type(s) | see below
[2] Action numeric scalar or character vector
¯1 | inhibit (ignore) event
0 | handle event, do not report to APL
1 | handle event, then report to APL
fn | name of callback function
fn& | name of callback function to be executed asynchronously
⍎expr | expression to be executed
[3] | Arg | any array (optional)

Event Types

The first element, Type(s) may be one of the following:

  • A character vector containing an event name (for example 'MouseUp')
  • A numeric scalar containing an event number (for example 2). If the number is not one of the built-in event numbers generated by the object, it is assumed to be a user-defined event which can (only) be generated anagrammatically using ⎕NQ
  • A vector of character vectors containing a list of event names, for example ('MouseDown' 'MouseUp'). This may be used as a shortcut to associate several different types of events with the same action
  • An Event name preceded by the string 'on' (for example'onMouseUp')
  • An event number preceded by the string 'on' (for example 'on99'). This syntax is intended for user-defined events although it can be used with regular events too.

The onEvent syntax causes all objects reported in the event message (see below) to be identified by a ref. Otherwise, objects reported in the event message are identified by name.

Action

Inhibit (¯1)

If Action is set to ¯1, the event is inhibited (if possible) by APL. If, for example, you set the action on a KeyPress event to ¯1, all keystrokes for the object in question will be ignored. Similarly, if you set the action on a Close event for a Form to ¯1, the user will be unable to close the Form. This is possible because APL intercepts most events before Windows itself takes any action. However, certain events (e.g. focus change events) are not notified to APL until after the event has occurred and after Windows has itself responded in some way. In these circumstances it is not always practical for APL to undo what Windows has already done, and an action code of ¯1 is treated as if it were 0. For further details, see the individual entries for each event type in this chapter.

Default Processing (0)

If Action is set to 0 (the default), the event is processed by APL and Windows in the normal way (this is referred to herein as the default processing) but your program is not notified in any way that the event has occurred. For example, the default processing for a keystroke is to action it and either echo a character in the object or perform some other appropriate function.

Terminate ⎕DQ (1)

If Action is set to 1, the event is first processed by APL (and Windows) in the normal way, then ⎕DQ terminates, returning an event message as its result. The format of the event message is given under the description of each event type.

Callback (function name)

If Action is set to a character vector that specifies the name of a function, this function (termed a callback) will be executed automatically by ⎕DQ every time the event occurs. The function may be a traditional defined function or a dfn.

A traditional defined function may be monadic, dyadic, or niladic. If dyadic, the left argument may be optional. A niladic callback may be appropriate if the function can perform its task without needing to interrogate the event message.

Unless the callback function is niladic, it will be supplied a right argument (⍵ for a dfn) containing the event message and a left argument (⍺ for a dfn) of the value of the array Arg (if specified).

The function may be defined to return no result, a result, or a shy result. The result determines how the event is handled.

The default processing of the event is deferred until after the callback has been run, and may be inhibited or modified by its result. If the callback function returns no result, or returns a scalar 1, normal processing of the event is allowed to continue as soon as the callback completes. If the callback returns a scalar 0, normal processing of the event is inhibited and the effect is identical to setting Action to ¯1. A callback function may also return an event message as its result. If so, ⎕DQ will action this event rather than the original one that fired the callback.

If a callback function does not exist at the instant it is invoked, ⎕DQ terminates with a VALUE ERROR. However, the name of the missing function is reported in the Status Window.

Asynchronous Callback (function name followed by &)

If Action is set to a character vector that specifies the name of a callback function, followed by the character &, the callback function will be executed asynchronously in a new thread when the event occurs.

For example, the event specification:

      'Event' 'onSelect' 'DoIt&'

tells ⎕DQ to execute the callback function DoIt asynchronously as a thread when a Select event occurs on the object. Note that a callback function executed in this way should not return a result (because ⎕DQ does not wait for it) and any result will be displayed in the Session window.

Execute

If action code is set to a character vector whose first element is the execute symbol (⍎) the remaining string will be executed automatically whenever the event occurs. The default processing for the event is performed first and may not be changed or inhibited in any way.

Notice that when you specify the action to be taken on the occurrence of an event there is a great difference between 'FOO' and '⍎FOO'. The former causes APL to invoke the function FOO as a callback function. If the function takes an argument, APL will supply it with the event message. Secondly, the result (if any) of the function FOO will be used by APL and may cause the event to be disabled or changed in some way. In the second case, APL will perform the default processing for the event and then execute FOO without supplying an argument. If the function returns a result, it will be displayed in the Session.

Optional Left Argument (Arg)

If specified, Arg is an array whose value will be passed as the left argument to a callback function when that particular event (or events) is generated. Note that this is a constant defined when the value is assigned to the Event property.

If the callback function is defined to take an explicit left argument and Arg was not specified, the call will fail with the error message:

 SYNTAX ERROR: The function requires a left argument

If the callback function is defined to take an optional left argument and Arg was not specified, a reference to the left argument (⍺ for a dfn) will generate VALUE ERROR.

Event Message

When a callback function is invoked by ⎕DQ, the corresponding event message is supplied as its right argument. The event message is a vector whose first 2 elements identify the object that generated the event and the type of the event. Additional elements may be provided, depending upon the type of the event.

The same event message is returned as a (shy) result by ⎕DQ when it is terminated by an event whose Action is set to 1.

Object(s)

The first element of the event message always identifies the object that generated the event. Other elements may identify other objects associated with the event. For example, a DragDrop event reports both the object being dropped, and the object on which it is being dropped.

Objects are identified by names or refs. If the Event property was set using the onEvent syntax (whereby the event name or number is prefixed by the string 'on'), for example, 'onSelect' or 'on99', objects are identified by refs. This is also true if the object which generated the event has no name (i.e. was created by ⎕NEW). Otherwise, objects are identified by their names.

Event Type

If, when the event type was specified it was identified by its name, the second element of the event message will be a character vector containing that name. If it was identified by its number, the second element of the event message will be an integer containing that number. If the event type was identified using the onEvent syntax, the second element of the event message will be a character vector containing the prefix 'on' followed by the event name, even if it had been specified by number. The exception is that if the event is a user-defined event, the second element of the event message will be a character vector containing the prefix 'on' followed by the character representation of the user-defined event number.

Specifying the Event property using Assignment

There are two ways to specify the Event property using assignment; you can specify the entire set of events, or you can set events one by one (see below).

To specify the entire set of events, you assign an array to the Event property. The array must contain one or more nested vectors, each containing 2 or 3 elements (Type, Action and optionally Arg) as described above.

Example (F1 is a Form)

      F1.Event ← 'onMouseDown' 'FOO'

Means: invoke callback function FOO on MouseDown, the first element of the right argument to FOO will contain a namespace reference to F1. All other events perform their default actions.

Example

      F1.Event ← 'MouseDown' 'FOO'

Means: invoke callback function FOO on MouseDown, the first element of the right argument to FOO will contain the character vector'F1'. All other events perform their default actions.

Example

      F1.Event ← ('onMouseDown' 'FOO')('onMouseUp' 'FOO')

Means: invoke callback function FOO on MouseDown and MouseUp. All other events perform their default actions.

Example

      F1.Event, ← ⊂ 'onMouseMove' 'FOO' ('THIS' 1)

Means: add a callback function FOO on the MouseMove event. The function will receive the array('THIS' 1) as its left argument. All other events perform their default actions.

Specifying Individual Event types using Assignment

To define the action to be taken for individual events, one by one, you use the onEvent syntax and make the assignment to the event name prefixed by the string 'on'.

Example

      F1.onMouseDown ← 'FOO'

Means: invoke callback function FOO on MouseDown.

Example

      F1.onMouseUp ← 'FOO'

Means: add the same callback for MouseUp.

Example

      F1.onMouseMove ← 'FOO' ('THIS' 1)

Means: add the same callback function FOO for the MouseMove event. The function will receive the array ('THIS' 1) as its left-argument.

Notice that you must use the 'on' prefix; you cannot assign to the Event name itself. This would cause an error:

      F1.MouseUp←'foo'
SYNTAX ERROR: Invalid modified assignment, or an attempt was made to change nameclass on assignment
      F1.MouseUp←'foo'
     ∧

Specifying the Event property using ⎕WC and ⎕WS

When you set the Event property using ⎕WC and ⎕WS you define the actions for the event types that you specify in the argument, leaving the actions for all other event types unchanged. When you create an object with ⎕WC, all unspecified event types will be unhandled; i.e. those events will perform the default processing. However, when you specify the action for a new event type using ⎕WS, any actions previously defined for other event types will remain as they were.

Examples using Event Names

Ignore MouseDown (1) event (APL will perform the default processing for you)

      'F1' ⎕WS 'Event' 'MouseDown' 0

Terminate ⎕DQ on MouseDown

      'F1' ⎕WS 'Event' 'MouseDown' 1

Invoke callback function FOO on MouseDown, the first element of the right argument to FOO will contain a namespace reference to F1

      'F1' ⎕WS 'Event' 'onMouseDown' 'FOO'

Invoke callback function FOO on MouseDown, the first element of the right argument to FOO will contain the character vector 'F1'

      'F1' ⎕WS 'Event' 'MouseDown' 'FOO'

Invoke callback function FOO on MouseDown and MouseUp

      'F1' ⎕WS 'Event' ('onMouseDown' 'onMouseUp') 'FOO'

Invoke callback function FOO with ('THIS' 1) as its left-argument on MouseDown

      'F1' ⎕WS 'Event' 'onMouseDown' 'FOO' ('THIS' 1)

Invoke callback function FOO with ('THIS' 1) as its left-argument on MouseDown, MouseUp and MouseMove

      EV ← 'onMouseDown' 'onMouseUp' 'onMouseMove'
      'F1' ⎕WS 'Event' EV 'FOO' ('THIS' 1)

Execute the expression COUNT+←1 on MouseDown

      'F1' ⎕WS 'Event' 'MouseDown' '⍎COUNT+←1'

Execute the expression COUNT+←1 on MouseDown, MouseUp and MouseMove

      EV ← 'MouseDown' 'MouseUp' 'MouseMove'
      'F1' ⎕WS 'Event' EV '⍎COUNT+←1'

Examples using Event Numbers

Ignore MouseDown (1) event (APL will perform the default processing for you)

      'F1' ⎕WS 'Event' (1 0)
      'F1' ⎕WS 'Event' 1 0     ⍝  Ditto

Terminate ⎕DQ on MouseDown

      'F1' ⎕WS 'Event' (1 1)
      'F1' ⎕WS 'Event' 1 1     ⍝ Ditto

Call function FOO on MouseDown

      'F1' ⎕WS 'Event' (1 'FOO')
      'F1' ⎕WS 'Event' 1 'FOO'    ⍝ Ditto

Call function FOO on MouseDown and MouseUp

      'F1' ⎕WS 'Event' ((1 2) 'FOO')
      'F1' ⎕WS 'Event' (1 2) 'FOO'              ⍝ Ditto
      'F1' ⎕WS 'Event' 1 2 'FOO'                ⍝ Ditto
      'F1' ⎕WS 'Event' (1 'FOO')(2 'FOO')       ⍝ Ditto

Call function FOO with ('THIS' 1) as its left-argument on MouseDown

      'F1' ⎕WS 'Event' (1 'FOO' ('THIS' 1))
      'F1' ⎕WS 'Event' 1 'FOO' ('THIS' 1)       ⍝ Ditto

Call function FOO with ('THIS' 1) as its left-argument on MouseDown and MouseUp

      'F1' ⎕WS 'Event' ((1 2) 'FOO' ('THIS' 1))
      'F1' ⎕WS 'Event' (1 2) 'FOO' ('THIS' 1)   ⍝ Ditto
      'F1' ⎕WS 'Event' 1 2 'FOO' ('THIS' 1)     ⍝ Ditto
      'F1' ⎕WS 'Event' 1 2 'FOO' ('THIS' 1)     ⍝ Ditto

Execute the expression COUNT+←1 on MouseDown

      'F1' ⎕WS 'Event' 1 '⍎COUNT+←1'

Execute the expression COUNT+←1 on MouseDown, MouseUp and MouseMove

      'F1' ⎕WS 'Event' (1 2 3) '⍎COUNT+←1'
      'F1' ⎕WS 'Event' 1 2 3 '⍎COUNT+←1'     ⍝ Ditto

User defined Events

In addition to the standard events supported directly by Dyalog APL, you may specify your own events. For these, you must use event numbers; user-defined event names are not allowed.

You may use any numbers not already defined, but it is strongly recommended that you choose numbers greater than 1000 to avoid potential conflict with future releases of Dyalog APL.

You can only generate user-defined events under program control with ⎕NQ.

Examples

     ∇ foo m
[1]    ⎕SE.UCMD'display m'
     ∇

      'f'⎕WC'Form' ('Event' 1001 'foo')
      f.Event
 1001  #.foo
      ⎕NQ 'f' 1001
┌→─────────┐
│ ┌→┐      │
│ │f│ 1001 │
│ └─┘      │
└∊─────────┘
      'f' ⎕WS 'Event' 1002 'foo'
       f.Event
 1001  #.foo   1002  #.foo
       ⎕NQ 'f' 1002
┌→─────────┐
│ ┌→┐      │
│ │f│ 1002 │
│ └─┘      │
└∊─────────┘

Notice that if you use the onEvent syntax, the event property reports the event type as you specified, but the callback function receives just the number as before.

      f.on1003←'foo'
      f.Event
 1001  #.foo   1002  #.foo    on1003  #.foo
      ⎕NQ 'f' 1003
┌→─────────┐
│ #.f  1003│
└+─────────┘

Notes

Resetting (clearing) the Event Property

If no events are set, the result obtained by ⎕WG and the result obtained by referencing Event directly are different:

      'F'⎕WC'Form'
      DISPLAY 'F'⎕WG'Event'
┌→──┐
│0 0│
└~──┘
      DISPLAY F.Event
┌⊖────────────┐
│ ┌→────────┐ │
│ │ ┌⊖┐ ┌⊖┐ │ │
│ │ │ │ │ │ │ │
│ │ └─┘ └─┘ │ │
│ └∊────────┘ │
└∊────────────

To reset the Event property, the same (different) values must be used accordingly:

      f.Event←0⍴⊂'' ''

or

      'f'⎕ws'Event' 0 0

onEvent Syntax with Event Numbers

If you use the onEvent syntax with built-in event numbers, the effect is the same as if you had used the event name. This does not apply to user-defined events.

Example

      'f'⎕WC'Form'
      f.on2←'foo'
      f.Event
  onMouseUp  #.foo
       ∇foo∇
     ∇ foo m
[1]    ⎕SE.UCMD'display m'
     ∇
┌→──────────────────────────────────────────┐
│     ┌→──────┐                             │
│ #.f │MouseUp│ 24.81481552 73.33333588 1 0 │
│     └───────┘                             │
└∊──────────────────────────────────────────┘

This differs from the behaviour when you use event number normally:

Example

      'f'⎕WC'Form'
      'f' ⎕ws 'Event' 2 'foo'
      f.Event
 2  #.foo
┌→──────────────────────────────────┐
│ ┌→┐                               │
│ │f│ 2 52.77777863 13.22916698 1 0 │
│ └─┘                               │
└∊──────────────────────────────────┘

Callback Names

When you query the Event property using ⎕WG, names of callbacks associated with events are reported exactly as they were set. When you reference the Event property, the names are reported as absolute pathnames.

      )ns x
#.x
      )cs x
#.x
     'f'⎕WC'form'
      f.onMouseUp←'foo'
      f.Event
┌───────────────────┐
│┌─────────┬───────┐│
││onMouseUp│#.x.foo││
│└─────────┴───────┘│
└───────────────────┘
      'f'⎕wg'event'
┌───────────────┐
│┌─────────┬───┐│
││onMouseUp│foo││
│└─────────┴───┘│
└───────────────┘
      )cs
#
      #.x.f.Event
┌───────────────────┐
│┌─────────┬───────┐│
││onMouseUp│#.x.foo││
│└─────────┴───────┘│
└───────────────────┘
      '#.x.f'⎕wg'Event'
┌─────────────────┐
│┌─────────┬─────┐│
││onMouseUp│x.foo││
│└─────────┴─────┘│
└─────────────────┘

Spelling Event Names

When using regular event names, case is unimportant. For example, the system will accept 'MouseUp', 'MOUSEUP' or even 'mOuSeUp'. When using the onEvent syntax, case is critical. The 'on' must be in lower-case and the case of the event name must be spelled exactly as documented. In all cases, the event name will be reported using the documented spelling.

Special Case for All events

The event number 0 and the event name 'All', are convenient shorthands to associate a particular action (such as a callback) with all the built-in events supported by an object.

Example

      'f'⎕WC'Form' ('Event' 'All' 1)
      f.Event
  All  1
      ⎕←⎕DQ 'f'
 f  Create  1


EventList Property

Applies To

Description

This is a read-only property that reports the names of all the events supported by an object.


ExportedFns Property
Applies To: OLEServer

Description

This property specifies the functions to be exposed as methods by an OLEServer object.

ExportedFns may be set to 0 (none), 1 (all), or a vector of character vectors containing the names of the functions to be exported.

There are certain important restrictions concerning the type of function that you can export as a method.

Firstly, only top-level defined functions within the OLEServer may be exported; you cannot export functions in other namespaces including sub-namespaces.

Furthermore, you may not export defined operators, dfns, external functions, or functions created by function assignment.

Finally, OLE does not support the concept of a dyadic function, so your exported functions must be niladic, monadic, or take an optional left argument; they may not be explicitly dyadic.

If you wish to export a new function from your OLEServer, and ExportedFns is not 1, you must explicitly reset the value of the ExportedFns property before you re-save the workspace.


ExportedVars Property
Applies To: OLEServer

Description

This property specifies the variables to be exposed as properties by an OLEServer object.

ExportedVars may be set to 0 (none), 1 (all), or a vector of character vectors containing the names of the variables to be exported.

Note that you may not export external variables or shared variables, or variables in other namespaces.

If you wish to export a new variable from your OLEServer, and ExportedVars is not 1, you must explicitly reset the value of the ExportedVars property before you re-save the workspace.


FCol Property

Applies To

Description

This property defines the foreground colour(s) of an object. For non-graphical objects, FCol specifies a single colour. For graphical objects with more than one constituent part, it may specify a set of background colours, one for each part. A single colour is represented by a single number which refers to a standard colour, or by a 3-element vector which defines a colour explicitly in terms of its red, green and blue intensities.

If FCol is 0 (which is the default) the foreground colour is defined by your current colour scheme for the object in question. For example, if you select red as your MS-Windows "Button Text" colour, you will by default get red writing on all your Button objects, simply by not specifying FCol or by setting it to 0.

FCol | Colour Element | FCol | Colour Element
0 | Default | ¯11 | Active Border
¯1 | Scroll Bars | ¯12 | Inactive Border
¯2 | Desktop | ¯13 | Application Workspace
¯3 | Active Title Bar | ¯14 | Highlight
¯4 | Inactive Title Bar | ¯15 | Highlighted Text
¯5 | Menu Bar | ¯16 | Button Face
¯6 | Window Background | ¯17 | Button Shadow
¯7 | Window Frame | ¯18 | Disabled Text
¯8 | Menu Text | ¯19 | Button Text
¯9 | Window Text | ¯20 | Inactive Title Bar Text
¯10 | Active Title Bar Text | ¯21 | Button Highlight

A negative value of FCol refers to a standard MS-Windows colour as described below. Positive values are reserved for a possible future extension.

If instead, FCol contains a 3-element vector, it specifies the intensity of the red, green and blue components of the colour as values in the range 0-255. For example, (255 0 0) is red and (255 255 0) is yellow.

Note that if the colour specified by FCol would normally be rendered as a dithered colour, it is instead converted to the nearest pure colour available on the device. The actual colour realised also depends upon the capabilities of the display adapter and driver, and the current Windows colour map.

For a Button, Combo, Edit, Label, List, Menu and MenuItem, FCol refers to the colour of the text in the object. Borders around these objects (where applicable) are drawn using the standard Windows colour. For a Static object however, FCol specifies the colour of its border.

For the Ellipse, Poly and Rect objects, FCol specifies the colour of the line drawn around the perimeter of the object. If a dashed or dotted line is used (LStyle 1-4) the "gaps" in the line are drawn using the colour specified by BCol, or are left undrawn if BCol is not specified. For the Marker object, FCol specifies the colour in which the markers are drawn. For the graphics objects Ellipse, Poly, Rect and Text, FCol may be a vector of 3-element vectors specifying a set of colours for the constituent parts of the object. For example, a Poly object consisting of four polygons, may have a FCol property of four 3-element vectors. In addition, for graphics objects, FCol is used in place of FillCol if the latter is not specified.


FStyle Property
Applies To: Circle Ellipse Poly Rect

Description

This property determines how a graphics object is filled. It takes one of the following values, or, if the object has more than one component, a vector of such values.

FStyle | Effect
¯1 | hollow (no fill). This is the default.
0 | solid fill
1 | hatch fill with horizontal lines
2 | hatch fill with vertical lines
3 | hatch fill with diagonal lines at 135 degrees
4 | hatch fill with diagonal lines at 45 degrees
5 | hatch fill with horizontal and vertical lines
6 | hatch fill with criss-crossing diagonal lines
str | the name of. or a ref to, a Bitmap object which is used to fill the object.

For example, to fill an object with criss-crossing diagonal lines you would specify ('FStyle' 6). If the object contained two components, you could fill the first one with criss-crossing diagonal lines, and the second one with a Bitmap called 'YES', with the specification ('FStyle' 6 'YES')

If the size of the Bitmap is 8x8 APL uses a Windows "brush" to fill the object. If not, it uses "tiling". Filling with a brush is faster.


FieldType Property
Applies To: ButtonEdit DateTimePicker Edit Label Spinner

Description

The FieldType property controls data conversion, formatting and validation. For Edit, Label and Spinner objects, FieldType controls how the Value property of these objects is interpreted.

FieldType is a character vector. If it is empty (the default), the Text or Label object is a standard text object with no special formatting or, in the case of an Edit, no input validation. For a DateTimePicker, an empty FieldType implies the default which is 'Date'.

For a DateTimePicker, FieldType may be one of the following:

'Date' | Uses Windows "short date" format
'DateCentury' | Uses Windows "short date" format but with a 4-digit year regardless of user preference
'LongDate' | Uses Windows "long date" format
'Time' | Uses Windows time format
'Custom' | Uses a special format defined by the CustomFormat property

The value of the date or time is represented by the DateTime property. Note that all validation is performed by the object itself, and it is impossible to enter an invalid value.

For an Edit, Label and Spinner, if FieldType is defined, the contents of the object are defined by its Value property, which is a number, rather than by its Text property, and special formatting and validation rules are applied. FieldType may be one of the following :

'Numeric' | Simple numeric formatting and validation
'LongNumeric' | Uses Windows number format
'Date' | Uses Windows "short date" format
'LongDate' | Uses Windows "long date" format
'Currency' | Uses Windows currency format
'Time' | Uses Windows time format
'Char' | No validation, forces Value to be a character vector

FieldType 'Char' only affects an Edit object. When the user enters data into a standard single-line Edit object, the Value property is set to a number if the contents are numeric, or to a character vector if the contents do not represent a valid number. If FieldType is 'Char', the Value property is always set to a character vector, regardless of the type of the field contents.

If FieldType is 'Numeric', the object displays the number defined by its Value property rounded to the number of decimal places specified by its Decimals property. The decimal separator character used will be as specified by the Number format in the user's International Control Panel settings. If the object is an Edit object, the user is prevented from entering anything but a valid number. The number of decimal digits is also restricted to Decimals. When the user "leaves" the object, the number is re-formatted.

If FieldType is 'LongNumeric', the object displays the number specified by its Value property according to the Number format in the user's International Control Panel settings. This format specifies the 1000 separator, decimal separator, decimal digits and whether or not a leading zero is inserted. If the object is an Edit object, the user is prevented from entering anything but a valid number. However, the character specified for the 1000 separator is ignored and may be entered anywhere in the number. When the user "leaves" the object, the number is re-formatted correctly.

If the FieldType is 'Currency', the object displays the number specified by its Value property according to the Currency format in the user's International Control Panel settings. This specifies the currency symbol and placement, the way in which a negative value is displayed, and the number of decimal places. If the object is an Edit object, the user is restricted to entering a "reasonable" value. When the user leaves the object, the number is reformatted correctly.

If the FieldType is 'Date', the Value property represents the number of days since January 1st 1900 and is displayed using the "short date" format specified by the user's International Control Panel settings. If the object is an Edit object, the user is restricted to entering a "reasonable" date. The object will accept any numeric triplet separated by slash(/), colon (:) or space characters but checks that the day number and month number lie in the range 1-31 and 1-12 respectively and will not allow the user to enter a digit that would invalidate this. (Note that the position within the triplet of the day, month and year are as specified by the Windows short date format). However, the user is not prevented from entering an invalid date such as 31st September.

If the FieldType is 'LongDate', the Value property represents the number of days since January 1st 1900 and is displayed using the "long date" format specified by the user's International Control Panel settings. If the object is an Edit object, its appearance and behaviour automatically switches to FieldType 'Date' when it has the input focus and back again when it loses the focus. This allows the user to edit or input a date in a more convenient form.

If the FieldType is 'Time', the Value property represents the number of seconds since midnight and is displayed using the time format specified by the user's International Control Panel settings.

When the user attempts to move the input focus away from the object, the contents are validated. If they cannot be converted to a valid number, date, or time, the object generates a BadValue event, or, if the object is associated with a Grid, the Grid (and not the Edit object) generates a CellError event. See the descriptions of these events for further details.

Note that for Edit, Label and Spinner objects, FieldType may only be specified when you create an object using ⎕WC.


File Property

Applies To

Description

For an Animation, Bitmap, Cursor or Icon object, this property is either a simple character vector or a 2-element nested vector.

If it is simple, File specifies the name of the associated bitmap (.BMP), icon (.ICO) or cursor (.CUR) file.

If it is nested, the first element specifies the name of a DLL or (Icon only) EXE and the second element identifies the particular bitmap, icon or cursor in that file. The identifier may be its name (a character string), its resource id (a non-zero positive integer) or (Icon only), its index (0 or negative integer) within the file. As a special case, if the name of the file is an empty vector, the object is loaded from DYALOG.EXE or the Dyalog resource DLL. The name of the latter varies according to the version installed but begins DYARES. In this case, the identifier must be a name or resource id; indexes are not supported.

For a Metafile object, File must be simple and specifies the name of a metafile (.WMF) file. For a RichEdit object, File must be simple and specifies the name of a Rich text Format (.RTF) file.

When applied to a FileBox object, File contains the name (or names) of the selected file (or files) depending upon the value of its Style ('Single' or 'Multi').


FileMode Property
Applies To: FileBox

Description

The FileMode property applies only to a FileBox object. It indicates the mode in which the selected file is going to be opened. It is a character vector containing 'Read' (the default) or 'Write'. If FileMode is 'Write', files listed in the File Selection Box are greyed, although they may still be selected.


FillCol Property
Applies To: Circle Ellipse Poly Rect

Description

This property defines the fill colour in a graphics object.

If FStyle is 0 (solid fill) FillCol defines the colour with which the object is filled. If FStyle is in the range 1-6 (pattern fill) it defines the colour of the lines that make up the pattern. The areas between the lines are filled using the colour specified by BCol, or are left undrawn (transparent) if BCol is not specified. If FStyle contains the name of a Bitmap object, the value of FillCol is ignored.

A single colour is represented by a single number which refers to a standard colour, or by a 3-element vector which defines a colour explicitly in terms of its red, green and blue intensities. A negative value of FillCol refers to a standard MS-Windows colour as described below. Positive values are reserved for a possible future extension.

FillCol | Colour Element | FillCol | Colour Element
0 | Default | ¯11 | Active Border
¯1 | Scroll Bars | ¯12 | Inactive Border
¯2 | Desktop | ¯13 | Application Workspace
¯3 | Active Title Bar | ¯14 | Highlight
¯4 | Inactive Title Bar | ¯15 | Highlighted Text
¯5 | Menu Bar | ¯16 | Button Face
¯6 | Window Background | ¯17 | Button Shadow
¯7 | Window Frame | ¯18 | Disabled Text
¯8 | Menu Text | ¯19 | Button Text
¯9 | Window Text | ¯20 | Inactive Title Bar Text
¯10 | Active Title Bar Text | ¯21 | Button Highlight

If instead, FillCol contains a 3-element vector, it specifies the intensity of the red, green and blue components of the colour as values in the range 0-255. For example, (255 0 0) is red and (255 255 0) is yellow. Note that the colour realised depends upon the capabilities of the display adapter and driver, and the current Windows colour map.

FillCol may also be a vector of 3-element vectors specifying a set of colours for the constituent parts of the object. For example, a Poly object consisting of four polygons, may have a FillCol property of four 3-element vectors.


Filters Property
Applies To: FileBox

Description

The Filters property is a nested scalar or vector containing a list of filters. Each filter is a 2-element vector of character vectors which contain a file type mask and a file type description respectively. The file type descriptions appear in a drop-down combo box labelled "List Files of Type". When the user selects one of these, the currently selected directory is searched for files which match the corresponding mask. The default value of Filters is an empty vector. This gives a file type mask of "*.*" and a file type description of "All Files (*.*)". Hence an empty vector is equivalent to (⊂'*.*' 'All Files (*.*)').


FirstDay Property
Applies To: Calendar

Description

The FirstDay property specifies the day that is considered to be the first day of the week and which appears first in the Calendar.

FirstDay is an integer whose value is in the range 0-6. The default value for FirstDay depends upon your International Settings, but in most countries is 0 meaning Monday.


Fixed Property
Applies To: Font

Description

This property specifies whether or not a font represented by a Font object is fixed-width or proportional. It is either 0 (fixed-width) or 1 (proportional). There is no default; the value of this property reflects the characteristic of the selected font.


FixedOrder Property
Applies To: CoolBar

Description

The FixedOrder property specifies whether or not the CoolBar displays CoolBands in the same order.

FixedOrder is a single number with the value 0 (user may re-order bands) or 1 (user may not re-order bands); the default is 0.

If FixedOrder is 1, the user may move bands to different rows, but the band order is static.


FlatSeparators Property
Applies To: TabControl

Description

The FlatSeparators property specifies whether or not separators are drawn between buttons in a TabControl object. FlatSeparators only affects a TabControl if Style is 'FlatButtons' and is otherwise ignored.

FlatSeparators is a single number with the value 0 (no separators) or 1 (separators); the default is 0.

The pictures below illustrate the effect of FlatSeparators on the appearance of a TabControl object.


FontList Property
Applies To: Printer Root

Description

The FontList property is a read-only property (you cannot set its value) that provides a list of available fonts.

Its value is a vector (1 per font) of 8-element character vectors, each of which is as follows :

[1] | Face name (character vector)
[2] | Character height in "points" (integer)
[3] | Fixed width or not (Boolean)
[4] | Italic or not (Boolean)
[5] | Underline or not (Boolean)
[6] | Weight (integer)
[7] | Angle of rotation (integer)
[8] | Character set (see CharSet)

Example:

       ↑'.'⎕WG'FontList'
 System                         16 0 0 0 700 0   0
 Terminal                       12 1 0 0 400 0 255
 Fixedsys                       15 1 0 0 400 0   0
 Roman                          37 0 0 0 400 0 255
 Script                         36 0 0 0 400 0 255
 Modern                         37 0 0 0 400 0 255
 Small Fonts                     3 0 0 0 400 0   0
 Courier                        13 1 0 0 400 0   0
 Serif                          13 0 0 0 400 0   0
 Dyalog Alt                     16 1 0 0 400 0   0
 Dyalog Std                     16 1 0 0 400 0   0

Note that the list of fonts obtained from FontList for a Printer object will include TrueType fonts and printer fonts but will exclude screen fonts. FontList for Root will include TrueType fonts and screen fonts, but exclude printer-only fonts. The two lists will therefore (typically) be different.


FontObj Property

Applies To

Description

The FontObj property associates a font with an object. It specifies either the name of or a ref to a Font object

If unspecified, the default value for FontObj is an empty character vector. For most objects, this setting implies that the font used in the object is inherited from its parent object. However, CoolBar, Menu, MenuBar, StatusBar, TipField, ToolBar, and ToolControl objects do not inherit their font.

Note that the default value of FontObj for Root is also an empty character vector and that this implies the Windows default GUI font, which is a Windows user preference setting.

Note however that it is not currently possible to specify the font for Menu and MenuItem objects which are the direct descendants of a MenuBar. Nor is it possible to specify the font used for the Caption in a Form.


FormatString Property
Applies To: ButtonEdit Edit Grid Label Spinner

Description

The FormatString property specifies one or more ⎕FMT format specifications to be used to format data in an Grid or single-line Edit. When applied to a Grid, it is either a simple character vector that specifies the format specification for the entire Grid, or a vector of character vectors. If it is a vector, its elements are mapped to individual cells via the CellTypes property. When applied to an Edit object, FormatString must be a simple character vector.

APL derives the text to be displayed in a cell by calling ⎕FMT with a left argument of the corresponding element of FormatString and a right argument of the cell value. If the format specification is invalid, the text displayed is blank.

When a formatted Edit object receives the focus, it redisplays the contents in its raw (unformatted) form. When the Edit loses the focus, its contents are reformatted. When the user moves to a formatted Grid cell, the text remains formatted until the user presses a non-movement key or enters in-cell mode. The data is then redisplayed in its raw form for editing. Data in the cell is reformatted when the user moves away.

In a Grid, formatted data may be aligned vertically using the AlignChar property as illustrated in the following example.

      'F'⎕WC'Form'
      'F.G'⎕WC'Grid'(¯50+?10 10⍴100)(0 0)(100 100)
      'F.G'⎕WS'FormatString' 'M<(>N<)>F12.3'
      'F.G'⎕WS'AlignChar' '.'


Formats Property
Applies To: Clipboard

Description

This is a "read-only" property that identifies the formats in which data is currently available in the clipboard. It is a vector of character vectors containing the names of the corresponding Clipboard properties for which data may be obtained using ⎕WG. In the following example data was copied to the Windows clipboard from Microsoft Excel. This product stores data in CF_Text and the older device-dependent CF_Bitmap formats. The latter excludes colour map information, so CMap is not available.

      'CL' ⎕WC 'Clipboard'
      'CL' ⎕WG 'Formats'
 Bits  CMap  Text


FullRowSelect Property
Applies To: ListView TreeView

Description

The FullRowSelect property specifies whether or not the entire row is highlighted when an item in a ListView or a TreeView is selected.

FullRowSelect is a single number with the value 0 (only the item name is highlighted) or 1 (the whole row is highlighted); the default is 0.

For a ListView, FullRowSelect only applies if its View property is set to 'Report'.

The picture below illustrates the effect on the appearance of a ListView object, of setting FullRowSelect to 1.


GridBCol Property
Applies To: Grid

Description

This property specifies the colour used to fill the area between the end of the last column of data and the right edge of the Grid and between the bottom row of data and the bottom edge of the Grid.

GridBCol may be a 3-element vector of integer values in the range 0-255 which refer to the red, green and blue components of the colour respectively, or it may be a scalar that defines a standard Windows colour element (see BCol for details). Its default value is 0 which obtains the colour defined for Window Background.


GridFCol Property
Applies To: Grid

Description

The GridFCol property specifies the colour of the grid lines in a Grid object.

GridFCol may be a 3-element vector of integer values in the range 0-255 which refer to the red, green and blue components of the colour respectively, or it may be a scalar that defines a standard Windows colour element (see BCol for details). Its default value is 0 which obtains the colour defined for Window text.

The grid lines may be removed by setting GridFCol to the same colour as the background colour of the cells, which is defined by BCol.

Finer control of the colour of the grid lines can be achieved by using GridLineFCol instead.

Unlike GridLineFCol, the value of GridFCol is ignored when Native Look and Feel is enabled; the colour is taken from the current theme.


GridLineFCol Property
Applies To: Grid

Description

The GridLineFCol property specifies the colours of the grid lines in a Grid object. GridLineFCol should be used if different coloured grid lines are required. If all the grid lines are the same colour, use GridFCol.

GridLineFCol may be a scalar or a vector. Each item may be a 3-element vector of integer values in the range 0-255 which refer to the red, green and blue components of the colour respectively, or a scalar that defines a standard Windows colour element (see BCol for details). Note that a single RGB triplet must be enclosed.

The default value of GridLineFCol is an empty numeric vector (⍬). If so, all the grid lines are drawn using the single colour specified by GridFCol.

Unlike GridFCol, setting GridLineFCol overrides the colour which would be used if Native Look and Feel was enabled.

Elements of GridLineFCol are allocated to individual grid lines via the RowLineTypes and ColLineTypes properties.

See also: GridLineWidth.


GridLineWidth Property
Applies To: Grid

Description

The GridLineWidth property specifies the widths in pixels of the grid lines in a Grid object.

GridLineWidth may be an integer scalar or a vector. Its default value is an empty numeric vector (⍬). If so, grid lines are drawn 1-pixel wide.

Grid lines are always displayed so that 1 pixel is drawn within the cell. If the width is greater than 1 pixel, the additional pixels are drawn between the cells.

If an element of GridLineWidth is 0, the corresponding grid lines are not drawn.

Elements of GridLineWidth are allocated to individual grid lines via the RowLineTypes and ColLineTypes properties.

See also: GridLineFCol.


GridLines Property
Applies To: ListView

Description

The GridLines property specifies whether or not lines are displayed between items in a ListView object. GridLines applies only if the value of the View property is 'Report'.

GridLines is a single number with the value 0 (no lines are displayed) or 1 (lines are displayed); the default is 0.

The picture below illustrate the effect on the appearance of a ListView object, of setting GridLines to 1.


GripperMode Property
Applies To: CoolBand

Description

The GripperMode property specifies whether or not the CoolBand has a gripper bar which is used to reposition and resize the CoolBand within its parent CoolBar.

GripperMode is a character vector with the value 'Always' (the default), 'Never' or 'Auto'.

If GripperMode is 'Always', the CoolBand displays a gripper bar even if it is the only CoolBand in the CoolBar.

If GripperMode is 'Never', the CoolBand does not have a gripper bar and may not be directly repositioned or resized by the user.

If GripperMode is 'Auto', the CoolBand displays a gripper bar only if there are other CoolBands in the same CoolBar.


HAlign Property
Applies To: Text

Description

This property determines the horizontal alignment of text in a Text object. It is either a single integer value, or, if the Text object contains several components, a corresponding vector of such values.

These may be:

0 | left aligned | the left edge of the bounding box of the text is aligned on the x-coordinate specified by the Points property.
1 | centre aligned | the centre of the bounding box of the text is aligned on the x-coordinate specified by the Points property.
2 | right aligned | the right edge of the bounding box of the text is aligned on the x-coordinate specified by the Points property.


HScroll Property

Applies To

Description

For most objects to which it applies, this property determines whether or not a horizontal scrollbar is provided.

HScroll may only be set when the object is created with ⎕WC and may not subsequently be changed with ⎕WS or assignment.

When applied to a Combo, or to an Edit object with Style 'Single' (i.e. a single-line edit field), the value 0 inhibits scrolling, and prevents the user from entering more data when the field is full. If instead it has the value ¯2, the field is scrollable, and the length of data that may be entered is not limited by the length of the field.

When applied to an Edit object with Style 'Multi' (i.e. a multi-line text box), the value 0 inhibits scrolling, and causes individual lines to be "word-wrapped". The values ¯2 and ¯1 enable sideways scrolling, and permit individual lines to exceed the width of the object. The value ¯1 means that a horizontal scrollbar is provided.

For a Scroll object, the scrollbar is horizontal if HScroll is ¯1 and vertical if HScroll is 0. For a Form, a horizontal scrollbar is provided if HScroll is set to ¯1. The default value is 0 (no scrollbar).

For a StatusBar, TabBar or ToolBar with Align set to Top or Bottom, HScroll determines whether or not a horizontal scrollbar is provided and how the object positions its children. If HScroll is 0 (the default) the object organises its children in multiple rows and does not provide a scrollbar. If HScroll is ¯1 or ¯2, the object organises its children in a single row and provides a mini scrollbar to allow those positioned beyond the right edge of the object to be scrolled into view. If HScroll is ¯1, the scrollbar is always shown. If HScroll is ¯2, it is only shown when needed.

For a Grid, HScroll may be 0 (no horizontal scrollbar), ¯1 (scrollbar is displayed when required), ¯2 (same as ¯1) or ¯3 (scrollbar is always displayed).


Handle Property

Applies To

Description

This is a read-only property that reports the handle associated with an object. For a visual object, such as a Form or a Button, this is the window handle. For a Printer, it is the printer device context.

This handle allows you to access the corresponding object directly with Windows API functions via ⎕NA. This facility must be used with care and the responsibility for its behaviour is entirely yours. Do NOT use it to delete an object. This will cause APL to crash.

An example of the use of the Handle property is to set tab stops in a List object. This is illustrated by the following function:

     ∇ obj TABSTOPS stops;I;LB_SETTABSTOPS;SetTabStops;sink;args
[1]   ⍝ Sets the tabstops in the List Box OBJ to be at
[2]   ⍝ stops Horizontal Dialog units.
[3]   ⍝ Sends LB_SETTABSTOPS (402) to the List Box
[4]   ⍝ See Windows SDK for Details.
[5]
[6]    I←obj ⎕WG'Items'
[7]
[8]    LB_SETTABSTOPS←402
[9]    'SetTabStops'⎕NA'U4 USER32|SendMessageA U4 U4 U4 <U4[]'
[10]
[11]   args←(obj ⎕WG'Handle') LB_SETTABSTOPS (⍴,stops)(,stops)
[12]   sink←SetTabStops args
[13]
[14]   obj ⎕WS'Items'I
     ∇


HasApply Property
Applies To: PropertySheet

Description

The HasApply property is a Boolean value that specifies whether or not a PropertySheet has an Apply button. Its default value is 1. Note that an Apply button is only actually used if Style is 'Standard'.


HasButtons Property
Applies To: TreeView

Description

The HasButtons property is a Boolean value and specifies whether or not buttons are shown in a TreeView object. If HasButtons is 1 (the default) a square button is displayed to the left of each parent item label. If the item is expanded (i.e. is children are visible) the button contains a minus sign. If the item is not expanded, (i.e. its children are hidden) the button contains a plus sign. The user can cause a parent item to expand or collapse by clicking this button.


HasCheckBox Property
Applies To: DateTimePicker

Description

Specifies whether or not a checkbox is displayed alongside the value in a DateTimePicker.

HasCheckBox is a single number with the value 0 (the default) or 1. If HasCheckBox is 1, the user may set or clear the checkbox to indicate whether or not the date/time displayed in the object is to apply.

If the checkbox is not set, the DateTimePicker is considered to be empty (the contents will be grayed out) and the value returned by the DateTime property is zilde. Note that HasCheckBox may only be set when the object is created.


HasClearButton Property
Applies To: ButtonEdit Combo ComboEx Edit

Description

Specifies whether or not an [image] button is displayed in the right-hand end of an edit box. Clicking this button clears the text from the field.

Note that this feature only applies if Native Look and Feel is enabled.

HasClearButton is Boolean. 1 means that an [image] button will be displayed; 0 (the default) means that the button will not be shown. It may only be specified when the object is created. If you subsequently attempt to change the value of HasClearButton, the operation will fail with NONCE ERROR.

HasClearButton is only effective for Edit objects with Style Single; it is silently ignored for other Styles of Edit objects.


HasEdit Property
Applies To: BrowseBox

Description

Specifies whether or not a BrowseBox has an edit field.

HasEdit is a single number with the value 0 (the default) or 1. If HasEdit is 1, the user may type in the name of a folder or other resource that is the target of the BrowseBox. If HasEdit is 0, the user must browse to it.


HasHelp Property
Applies To: PropertyPage PropertySheet

Description

The HasHelp property is a Boolean value For a PropertySheet, it determines whether or not the PropertySheet has a Help button. for a PropertyPage, HasHelp determines whether or not the Help button is active when the PropertyPage is the current page. If the HasHelp property of a PropertyPage is 0, the Help button on the parent PropertySheet will be temporarily disabled when that PropertyPage is displayed.


HasLines Property
Applies To: TreeView

Description

The HasLines property specifies whether or not tree lines are drawn in a TreeView object. It is a single integer with the value 0, 1 or 2:

0 | No tree lines
1 | Tree lines are drawn at all levels except the top level
2 | Tree lines are drawn at all levels

The user can cause a parent item to expand or collapse by clicking on its corresponding tree line.


HasTicks Property
Applies To: TrackBar

Description

The HasTicks property specifies whether or not tick marks are drawn in a TrackBar object. It is Boolean value with a default value of 0.

The position of the tick marks in the TrackBar is determined by the TickAlign property.


HasToday Property
Applies To: Calendar DateTimePicker

Description

The HasToday property specifies whether or not the Today date is displayed in the bottom left corner of a Calendar object or in the drop-down calendar of a DateTimePicker.

HasToday is a single number with the value 0 (the date is not shown) or 1 (the date is shown); the default is 1.

See also CircleToday property.


Header Property
Applies To: ListView

Description

The Header property is Boolean and specifies whether or not a ListView object displays column titles. Its default value is 1. Header applies only if the View property is 'Report'. The column titles are defined by the ColTitles property and their alignment by the ColTitleAlign property.

Note that Header may only be set by ⎕WC and may not subsequently be changed.


HeaderImageIndex Property
Applies To: ListView

Description

The HeaderImageIndex property is an integer vector that specifies the images to be displayed alongside each column heading in a ListView object in Report View. Each positive element of HeaderImageIndex specifies an index into the ImageList object specified by the HeaderImageList property. The special values ¯1 and ¯2 specify the standard Sort Up and Sort Down images respectively.


HeaderImageList Property
Applies To: ListView

Description

The HeaderImageList property specifies the name of or ref to an ImageList object that contains images to be displayed alongside each column heading in a ListView object in Report View.


HelpButton Property
Applies To: Form PropertySheet SubForm

Description

This is a Boolean property that specifies whether or not a Question (?) button appears in the title bar of a Form or SubForm. However, this does not apply if the Form has a maximise or minimise button which both take precedence. The user may obtain help by clicking on the Question (?) button and then on a control in the Form. It is up to you to provide the help by responding to the Help event on the control. The default value of HelpButton is 0.


HelpFile Property
Applies To: ActiveXControl OCXClass OLEClient

Description

The HelpFile property is a read-only property that reports the pathname of a Windows help file associated with a particular COM object.

For an OCXClass or OLEClient object, the HelpFile property is read-only.


HighlightHeaders Property
Applies To: Grid

Description

The HighlightHeaders property is a Boolean value (default 1) that specifies whether or not the appropriate row and column titles in a Grid are highlighted corresponding to the currently selected block of cells.


Hint Property

Applies To

Description

The Hint property is a character vector that specifies a help message that is to be displayed when the user positions the mouse pointer over the object. The Hint is displayed in the object specified by its HintObj property. A StatusField is often used for this purpose.


HintObj Property

Applies To

Description

The HintObj property is a character vector or ref that specifies the name of, or a ref to, an object in which the "help" message defined by the Hint property is to be displayed. This message is displayed when the user positions the mouse pointer over the object. The Hint is displayed by automatically setting the Caption or Text property of the object named by HintObj.

The following types of object can therefore be used to display Hints: Button, Edit, Combo, Group, Form, Label, Menu, MenuItem, StatusField, SubForm and Text. For a StatusField that has both Caption and Text properties, the text property is used for displaying hints.

When the user moves the mouse pointer away from the object, the Caption or Text property of the object specified by HintObj is reset to an empty vector.

Note that if HintObj is empty, its value is inherited from its parent. Thus setting HintObj on a Form defines the default location for displaying Hints for all the controls in that Form. Setting HintObj on Root defines the default location for hints for the entire application.


HotSpot Property
Applies To: Cursor

Description

This property specifies the point within a Cursor object that registers the cursor's position over another object. The mouse position, which is reported by various events, is actually the position of the cursor's HotSpot over the object in question.

HotSpot is a 2-element numeric vector that specifies the y-position and x-position of the hotspot within the cursor. A value of (0 0) specifies the top-left corner of the cursor; (31 31) specifies the bottom right corner of the cursor. The default value of HotSpot is (15 15).


HotTrack Property
Applies To: TabControl

Description

The HotTrack property specifies whether or not the tabs or buttons in a TabControl object ( which are represented by TabButton objects), are automatically highlighted by the mouse pointer.

HotTrack is a single number with the value 0 (no highlighting) or 1. The default is 0.

If HotTrack is 1 and the Style property of the TabControl is 'Tabs' or 'Buttons', the text defined by the Caption property of the TabButton is highlighted when the mouse pointer is placed over the tab or button. If Style is 'FlatButtons', the button is highlighted by being raised.

The value of HotTrack is effective only when the object is created with ⎕WC.


IconObj Property

Applies To

Description

This property is used to specify a large and small icon for a Form or SubForm, or for the Root object which represents your application as a whole. Its value is either a single ref or character scalar or vector containing the name of, or ref to, an Icon object, or a 2-element vector of character vectors or refs that specifies 2 Icon objects.

If empty (the default value), the standard "Dyalog APL GUI" icon is used.

The large and small icons are supplied to the Operating System which uses them as and when is appropriate. Normally, the large icon is of size 32x32 and the small icon is 16x16. If you specify an icon of a different size, the Operating System will scale it as appropriate.

The icon associated with a Form is displayed when the Form is minimised. The icon associated with '.' is displayed when the user presses Alt+Tab to toggle between applications. In both cases, the text shown underneath or alongside the icon is defined by the Caption property.


ImageCount Property
Applies To: ImageList

Description

The ImageCount property is a read-only property that reports the number of images in an ImageList object. It is an integer scalar.


ImageIndex Property

Applies To

Description

For a ComboEx, ListView or TreeView, the ImageIndex property maps bitmapped images in an ImageList to items. ImageIndex is an integer vector whose length is the same as the number of items in the object. See also SelImageIndex

For a CoolBand, MenuItem, TabButton or ToolButton, ImageIndex specifies the picture to be displayed in the object. In these cases, ImageIndex is a single integer value.

ImageIndex is ⎕IO dependent.


ImageListObj Property

Applies To

Description

The ImageListObj property is a simple character vector or a ref, or a vector of character vectors or refs that specifies ImageList objects that are associated with an object.

For a ComboEx or TreeView object, the ImageListObj property specifies the name of, or ref to, a single ImageList object that contains a set of images to be displayed alongside its Items. The image(s) displayed by a particular item in its normal (unselected) and selected states are specified by the corresponding element of the ImageIndex and SelImageIndex properties respectively.

For CoolBar, Menu, and TabControl objects, the ImageListObj property specifies the name of, or ref to, a single ImageList object that contains a set of images for its CoolBand, MenuItem, and TabButton children respectively.

For a ToolControl, ImageListObj may specify up to three ImageList objects that correspond to the three different states, normal, highlighted (hot) and inactive, of its ToolButton children.

In all these cases, individual images are mapped to the child objects by their ImageIndex property.

For a ListView either one or two ImageList objects may be specified. The first ImageList contains the large icon set of images. the second contains the small icon set. The set that is used is determined by the value of the View property. The mapping between the set of images in the ImageList and items in the object is determined by the ImageIndex property.


Indents Property
Applies To: ComboEx

Description

Specifies the amount by which items in a ComboEx object are indented.

Indents may be an integer scalar or a vector with the same number of elements as there are items in the ComboEx. Its default value is 0.

The unit of indenting is 10 pixels. For example, if there are 3 items and Indents is (0 1 2), the items will be indented by 0, 10 and 20 pixels respectively.


Index Property

Applies To

Description

For a List and a Combo with Style 'Simple', this property specifies the position of the data in the list box as a positive integer value. If Index has the value "n", it means that the "nth" item in Items is displayed on the top line in the list box. The value of Index is dependent upon the value of ⎕IO. Note that Index for a Combo or List cannot be set using ⎕WC. The value of Index in a Combo with a drop-down list box (Style 'Drop' or 'DropEdit') is always equal to ⎕IO.

For a Grid, Index is a 2-element vector that specifies the row and column number of the cell that is currently in the top left corner of the Grid.

For a TreeView, Index is a positive integer value that specifies which item appears at the top of the TreeView window.

For a FileBox, the Index property determines which of the Filters is initially selected.

For a CoolBand, the Index property specifies the position of the CoolBand within its parent CoolBar, relative to the other CoolBands in the CoolBar.

The value of Index is dependent on ⎕IO, and its default value is equal to ⎕IO.


Input Property
Applies To: Grid

Description

This property specifies objects to be associated with cells in a Grid. These objects may be of type Button, ColorButton, Combo, Edit, Label, Spinner or TrackBar. In addition, the Input property may specify instances of OCXClass objects (ActiveX controls) and NetType objects (.NET classes).

The Input property is either a single ref or a simple character scalar or vector, or a vector of character vectors or refs. If it specifies a single object, this will be associated with all of the cells in the Grid. If it specifies a set of objects, these are mapped to individual cells through the CellTypes property.

When a cell becomes the current cell, its value (defined by the appropriate element of the Values property) defines the value of a corresponding property of the associated object The property that corresponds to the value in the cell, depends upon the Type of the associated object as shown in the following table:

Associate Object Type | Corresponding Property
Label | Text
Edit | Value
Combo | Text
Button (Style Push) | Caption
Button (Style Radio or Check) | State
ColorButton | CurrentColor
Spinner | Value
TrackBar | Thumb
OCXClass | Specified by InputProperties
NetType | Specified by InputProperties

In effect, the user inputs a new value into the current cell by changing the corresponding property of its associated object. An associated object may be a fixed object that is external to the Grid or a floating object that moves automatically from cell to cell. The latter is achieved by creating the associated object as a child of the Grid.

If the associated object is an Edit or Combo, the user may change the Text property of the object by typing, or, in the case of a Combo, by selecting an item from a list. The new value of the Text property is then used to update the value in the cell (defined by the Values property of the Grid) when the user moves on. If the associated object is a radio button, the value in the cell (0 or 1) is reflected by the State property of the Button. The user may click the Button on and off, changing its State and thereby the corresponding value in the cell.

If the associated object is a ColorButton, the corresponding elements of the Values property contain 3-element integer vectors which specify the RGB colour values.

If the associated object is an instance of an OCXClass object (ActiveX control) or a NetType object (.NET class), the Grid uses the default property of the external object if it has one. Alternatively, the InputProperties property is used to specify which property (or properties) of the external object are to be mapped to elements of Values. If more than one property is specified, elements of Values are vectors.

If there is no object associated with a cell, or if its associated object is a Label or a Button with Style Push, the cell is protected and may not be changed by the user. When the current cell is thus protected, the corresponding row and column titles are not indented as they are when the cell may be edited.

If the associated object is a numeric Edit or Label (FieldType Numeric, LongNumeric, Currency, Date, LongDate or Time) the contents of the cell are formatted accordingly, even when it is not the current cell. Thus a cell associated with a Label with FieldType Date, always displays as a date.

If the associated object is a Combo or Button, the appearance of a non-current cell is defined by the corresponding element of the ShowInput property.

The following example illustrates the use of different types of object specified by the Input and ShowInput properties:


InputMode Property
Applies To: Grid

Description

This property determines editing behaviour and the action of the cursor movement keys when the user changes the contents of a Grid using a floating Edit or DropEdit Combo control.

InputMode is a character vector with one of the following values:

'Scroll' | The cursor keys move around the Grid; the user may switch to InCell mode
'InCell' | The cursor keys move within the Input object; the mode reverts to Scroll when the user selects a new cell
'AlwaysScroll' | The cursor keys move around the Grid; the user may not switch to InCell mode
'AlwaysInCell' | The cursor keys move within the Input object, even when the user moves to a new cell
'AutoEdit' | See below

By default, the input mode is Scroll. In this mode, cursor movement keys are actioned by the Grid itself and used to move from cell to cell. The user may switch to InCell mode by double-clicking or by pressing the key defined by InputModeKey (the default is "F2").

In InCell mode, all cursor movement keys are actioned by the Input object and typically move the cursor around within the Input object and do not switch between cells. When the user switches to a different cell, InputMode reverts to Scroll mode

If InputMode is AlwaysScroll or AlwaysInCell, the user remains permanently in either Scroll or InCell mode respectively.

If InputMode is 'AutoEdit', the behaviour of a cell that contains a floating Input field is as follows:

When the user enters the cell, the contents are selected (and highlighted).At this stage, the cursor movement keys move to an adjacent cell. If the user presses a (valid) data key, that character replaces the current contents of the cell.

If the user presses F2 (or the key defined by the InputModeKey property), the data is de-selected and unhighlighted and the cursor is placed at the rightmost end of the data.

In either case, the left and right cursor keys now move the cursor within the current data string, but skip to the adjacent cell from the beginning or end of the data. This behaviour differs from InCell mode in which the cursor movement keys stick at the end of the data.


InputModeKey Property
Applies To: Grid

Description

This property defines the keystroke used to switch from Scroll mode to InCell mode in a Grid. It applies only where the Grid has a floating Edit control. See the description of the InputMode property for further details.

The InputModeKey property is specified (in the same way as the Accelerator property) as a 2-element vector of integer values containing the key number and shift state respectively. Its default is (113 0) which is "F2".

As an example, if you wanted to use Ctrl+Shift+a to switch modes, you would set InputModeKey to (65 3). 65 is the keynumber for "a" and 3 means Shift (1) + Ctrl (2).


InputProperties Property
Applies To: Grid

Description

The InputProperties property is a vector of character vectors that specifies the names of properties of an OCXClass (ActiveX Control) or .NET Class that are to be mapped to the Values property in a Grid.

When an ActiveX Control or .NET Class is used as a child of the Grid, InputProperties is used to specify how the value in each Grid cell corresponds to the value of one or more properties of the child object.

For example, suppose there is a third-party ActiveX Control that displays a playing card. The control has two properties named Suit and Value that specify the suit (1=clubs, 2=diamonds, 3=hearts, 4=spades) and card value (1="Ace", 2="2", …11="Jack",…) respectively. To display these cards in a Grid, the InputProperties property may be set to ('Suit' 'Value') and each element of the Values property must be a 2-element integer vector specifying the suit and value of the corresponding card.

     'CARDS'⎕WC'OCXClass' '...'
     'F'⎕WC'Form'
     'F.G'⎕WC'Grid'
     'F.G.card'⎕WC'CARDS'
     F.G.Input←'F.G.card'
     F.G.InputProperties←'Suit' 'Value'
     F.G.Values←⍳4 13

If InputProperties is not specified, the default property of the ActiveX Control or .NET Class is used.


InstanceMode Property
Applies To: OLEClient

Description

The InstanceMode property specifies how APL attempts to connect the OLEClient to an OLE Server.

InstanceMode is a character vector that may be 'ExistingFirst' (the default), 'ExistingOnly' or 'New'. Its value is effective only when the object is created with ⎕WC. Changing InstanceMode with ⎕WS has no effect.

If InstanceMode is 'ExistingFirst', APL attempts first to connect to a running instance of the OLE Server. If there is no running instance, it starts the OLE server to obtain a new object.

If InstanceMode is 'ExistingOnly', APL attempts to connect to a running instance of the object. If there is no running instance, it fails with a DOMAIN ERROR.

Note that in either case, if there is more than one instance running, there is no way to predict to which instance APL will be connected.

If InstanceMode is 'New', APL attempts to start the OLE Server to obtain a new object, whether or not the OLE Server is already running. However, if the OLE Server has registered itself as a single instance object and is already running, APL will be connected to it, and a second instance of the Server will not in fact be started.


Interval Property
Applies To: ProgressBar Timer

Description

Interval is an integer value specified in milliseconds and has a default of 1000.

For a Timer object, the Interval property specifies the frequency with which it generates Timer events. Setting Interval to 0 disables Timer events.

For a ProgressBar with ProgressStyle 'Marquee', Interval specifies the frequency with which the animated bar is updated. Setting Interval to ¯1 stops the animation.


Italic Property
Applies To: Font

Description

This property specifies whether or not a font represented by a Font object is italicised or not. It is either 0 (normal) or 1 (italic). There is no default; the value of this property reflects the characteristic of the selected font.


ItemGroupMetrics Property
Applies To: ListView

Description

This property is used to specify colours and spacing elements for a ListView that is displaying its Items in groupings (see ItemGroups).

Note that this feature only applies if Native Look and Feel is enabled.

ItemGroupMetrics is a 3-item nested vector as follows:

[1] | Text Colours | 2-element vector of 3 element RGB values that specifies the colour of the group caption and group footer respectively.
[2] | Spacing | 4-element integer vector that specifies the top, left, bottom and right spacing around each grouping in pixels
[3] | Border | Colours4-element vector of 3 element RGB values that specifies the colours for the top, left, bottom and right borders (not yet implemented).

The following expression, coupled with the code shown in the SetGroups example, causes the items to be displayed as shown below.

      F.L.ItemGroupMetrics[1 2]←(2⍴⊂255 0 0)(10 100 0 10)


ItemGroups Property
Applies To: ListView

Description

This property specifies item groupings for a ListView object.

Note that this feature only applies if Native Look and Feel is enabled.

ItemGroups is a nested scalar or nested vector each of whose elements specifies a grouping. Each grouping is a 5-element vector as follows:

[1] | Group caption | character vector
[2] | Item index | Vector of indices to the Items property that specifies which Items are in this grouping.
[3] | Caption alignment | an integer: 1 = left aligned caption (the default) 2 = centre aligned caption 4 = right-aligned caption
[4] | State | Integer (not yet implemented)
[5] | Footer text | character vector (not yet implemented)

Note that State and Footer text are not yet implemented by Windows.

For example, the following expressions executed in the WTUTOR95 workspace will result in the display shown below.

      'F'⎕WC'Form' 'ListView Object'
      II←⍳⍴COUNTRIES
      'F.L'⎕WC'ListView'COUNTRIES(0 0)(100 100)
                       ('ImageList' 'F.I1')
                       ('ImageIndex' (⍳⍴COUNTRIES))
      'F.I1'⎕WC'ImageList'('Size' 32 32)
      (⊂'F.I1.')⎕WC¨(⊂'Icon' ''),¨↓⍉↑FLAGBITS FLAGCMAP FLAGMASK
      GROUPS←⊂'Europe'(11 4 5 6 7 8 9)
      GROUPS,←⊂'Americas'(12 3 2)
      GROUPS,←⊂'Rest of the World'(1 10)
      F.L.ItemGroups←GROUPS

You can control the appearance of the groupings using the ItemGroupMetrics property.


Items Property
Applies To: Combo ComboEx List ListView Spinner TreeView

Description

This property specifies the list of items from which the user may choose.

The value of Items is a text array. It is normally specified as a vector of character vectors each of which represents an item. For a Combo, ComboEx, or List or Spinner, Items may also be a matrix whose rows specify items. If a character scalar or simple vector is specified, it is treated as a single item.

An empty character vector is treated the same as a vector of blanks, and represents one item.

A zero-length vector of vectors or an empty matrix represents 0 items. The default value for Items is an empty matrix.

⎕WG 'Items' returns an array of the same structure as was assigned by ⎕WC or ⎕WS.


Justify Property
Applies To: Button ButtonEdit Edit Label Spinner TabControl

Description

This property determines the manner in which text is justified within the object. It is a character vector that may take the value 'Left' (the default), 'Centre' or 'Right'. The keyword 'Centre' may also be spelled 'Center'.

When applied to an Edit object with Style 'Multi', a value of 'Centre' or 'Right' forces word-wrapping and disables horizontal scrolling. Note that Justify only applies to a multi-line edit field. If you specify a value for Justify in a 1-line edit field (Style 'Single'), it will be ignored.

For a TabControl, Justify may be 'Right' (which is the default) or 'None' or empty.

If Justify is 'Right', the TabControl increases the width of each tab, if necessary, so that each row of tabs fills the entire width of the tab control. Otherwise, if Justify is empty or 'None', the rows are ragged.

With the exception of Label and TabControl objects, Justify may only be specified when the object is created using ⎕WC.


KeepBits Property
Applies To: Bitmap Cursor Icon

Description

This property is be used to control the way that Bitmap, Cursor and Icon objects are stored in the workspace.

When you create a Bitmap, Icon or Cursor using ⎕WC, APL asks Windows to allocate a corresponding bitmap, icon or cursor resource. This resource is allocated in Windows memory. If APL were to hold the values of the image properties (CBits, Bits and CMap for a Bitmap; Bits, CMap and Mask for Cursor and Icon objects) internally in the workspace, this data would be duplicated. For large bitmaps this would have a serious impact on memory utilisation and may affect performance. The KeepBits property is provided to allow you to control whether or not APL retains the values of the image properties in the workspace, so that you can choose a strategy to suit your configuration and requirements. KeepBits may take the value 0 or 1.

If KeepBits is 0 the values of the image properties are not stored internally in your workspace. If you save a workspace containing a Bitmap, Cursor or Icon object, the corresponding Windows resource is automatically re-allocated when the workspace is loaded by referring to the associated file. This is the file whose full pathname is defined by the value of the object's File property. It follows that if you adopt this strategy, you must ensure that the File property is set correctly. If APL cannot find the file when the workspace is )LOADed, it cannot re-create the object, and you will get a VALUE ERROR when you subsequently refer to it. A further consideration is the effect on ⎕WG. If KeepBits is 0, and you execute ⎕WG 'CBits' or 'Bits' or 'CMap' or 'Mask', APL obtains these values by requesting the data from Windows.

If KeepBits is set to 1, the contents of the image properties are stored in the workspace, thus duplicating the information which is held by Windows itself. If you save a workspace containing a Bitmap, Cursor or Icon the corresponding Windows resource is automatically re-allocated from the image properties when the workspace is loaded. The value of the File property is ignored. When you execute ⎕WG 'CBits' or 'Bits' or 'CMap' or 'Mask', APL generates the result directly from the stored values held (internally) in the workspace.


KeepOnClose Property

Applies To

Description

This property is either 0 or 1 and determines how the object is treated when its parent Form (or, in the case of a Form, the Form itself) is closed by the user, receives a Close event from ⎕NQ, or when Close is called as a method.

If KeepOnClose is 1 (for the object itself and for all its parents) when its parent Form is closed, the object changes from being a GUI object to a pure namespace. For example, the Type of a Button will change from 'Button' to 'Namespace'. Effectively, the GUI component of the object is discarded but its Namespace component (and any variables, functions, operators and other namespaces that it contains) remains intact. Monadic ⎕WC may subsequently be used to re-attach the GUI component to the object.

Note that the default value of KeepOnClose depends upon the way in which a GUI object was created with ⎕WC. If a GUI object is created by dyadic ⎕WC, KeepOnClose defaults to 0. If a GUI object is attached by monadic ⎕WC, its KeepOnClose property defaults to 1.


LStyle Property
Applies To: Circle Ellipse Locator Poly Rect

Description

This property determines the type of line used to draw a graphics object. It takes one of the following integer values, or, if the object contains more than one component, a vector of such values.

0 | solid line
1 | dashed line
2 | dotted line
3 | dash dotted line
4 | dash dot dotted line
5 | null line (invisible)

If LStyle is in the range 1-4, the gaps between the dashes and dots are drawn using the colour specified by BCol, or are left undrawn (i.e. transparent) if BCol is not defined.

In versions of Dyalog APL prior to 13.2 revision 19489, if LWidth specified a line width greater than 1 pixel, a solid line was drawn in the colour specified by the FCol Property, regardless of the value of LStyle. From that revision onwards, if the value of LWidth is greater than 1 then the value of LStyle is honoured, but only the FCol of the line is honoured - the BCol is still ignored.


LWidth Property
Applies To: Circle Ellipse Poly Rect

Description

This property determines the width of line used to draw a graphics object. A positive value specifies the line width in pixels. A negative value specifies line width in units of the co-ordinate system defined for the object in the x direction. If the object contains more than one component, LWidth may be a vector.

In versions of Dyalog APL prior to 13.2 revision 19489, if LWidth specified a line width greater than 1 pixel, a solid line was drawn in the colour specified by the FCol Property, regardless of the value of LStyle. From that revision onwards, if the value of LWidth is greater than 1 then the value of LStyle is honoured, but only the FCol of the line is honoured - the BCol is still ignored.


LastError Property
Applies To: ActiveXControl OLEClient OLEServer Root

Description

The LastError property provides information about the most recent error reported by OLE. You may use this property to report an error from an OLEServer or ActiveXControl to a host application.


LateBind Property
Applies To: OLEClient OLEServer

Description

LateBind is a Boolean property that determines whether or not the Type Information is read when an OLEClient object is instantiated, or when an OLEServer references a COM object. It must be set when the OLEClient or OLEServer object is created and cannot subsequently be changed.

If LateBind is 0 (the default) the Type information is obtained, in its entirety, when the OLEClient object is instantiated or when an OLEServer processes a reference to an external COM object.

If LateBind is 1, APL postpones the calls to obtain Type Information until a particular property, method or event of the COM object is referenced; and then only for that particular member.


LicenseKey Property
Applies To: OCXClass

Description

The LicenseKey property is a character string that contains the license key for an ActiveX control.

If an ActiveX control requires a license key, it must be specified by an application when it creates an instance of the control. Typically, the license key is required only by the run-time version of an ActiveX control, and is made available to an application by the development version of the control.


Limits Property
Applies To: ProgressBar Scroll Spinner TrackBar UpDown

Description

This property is a 2-element vector that specifies the minimum and maximum values of an object. The values must be in the range (-2*31) to (¯1+2*31) inclusive.


LocalAddr Property
Applies To: TCPSocket

Description

The LocalAddr property is a character vector that specifies the IP address of your computer. Its default value is '0.0.0.0'.

Unless your computer has more than one network adapter each identified by a different IP address, you do not need to specify LocalAddr. However, in this case you may use either LocalAddr or LocalAddrName to identify the adapter. If you specify both properties, the value of LocalAddrName will be ignored.

Note that you may also set the value of LocalAddr to an empty character vector. In this case, the value returned by ⎕WG will be '0.0.0.0'.

LocalAddr may only be specified in the ⎕WC statement that creates the TCPSocket and may not subsequently be changed using ⎕WS.


LocalAddrName Property
Applies To: TCPSocket

Description

The LocalAddrName property is a character vector that specifies the host name of your computer. It may be useful when you have more than one network adapter (perhaps an Ethernet adapter and a token ring adapter) and you wish to avoid hard-coding the IP address.

Note that you may use either LocalAddr or LocalAddrName to identify the local computer. If you specify both properties, the value of LocalAddrName will be ignored.

LocalAddrName may only be specified by a server TCPSocket. Furthermore, it must be specified in the ⎕WC statement that creates the TCPSocket object and it may not subsequently be changed using ⎕WS.

When the specified host name has been resolved to an IP address, the TCPSocket will generate a TCPGotAddr event and update the value of LocalAddr accordingly.

For a client TCPSocket, you may not specify LocalAddrName and ⎕WG returns an empty character vector.


LocalPort Property
Applies To: TCPSocket

Description

The LocalPort property is a scalar integer in the range 1-65536 that identifies the port number associated with a TCPSocket object.

Note that you may use either LocalPort or LocalPortName to identify the service. The use of LocalPortName is slightly slower but it avoids hard-coding the port number in your program and is generally more flexible. If you specify both properties, the value of LocalPortName will be ignored.

LocalPort may be specified only by the process that is initiating the connection (the server) and must be set by the ⎕WC statement that creates the TCPSocket. LocalPort may not subsequently be changed using ⎕WS

If you specify a value of 0, the system will assign an available port number. For example:

      'S1' ⎕wc'TCPSocket' ('LocalPort' 0)
      S1.LocalPort
4047

For a process that is completing a connection, LocalPort is allocated by the system and is effectively read-only.


LocalPortName Property
Applies To: TCPSocket

Description

The LocalPortName property is a character vector that specifies the port name of the local service that you wish to offer as a server.

Note that you may use either LocalPort or LocalPortName to identify the service. The use of LocalPortName is slightly slower but it avoids hard-coding the port number in your program and is generally more flexible. If you specify both properties, the value of LocalPortName will be ignored.

LocalPortName may be specified only by the process that is initiating the connection (the server) and must be set by the ⎕WC statement that creates the TCPSocket. LocalPortName may not subsequently be changed using ⎕WS.

When the specified port name has been resolved to a port number, the TCPSocket will generate a TCPGotPort event and update the value of LocalPort accordingly.

For a client TCPSocket, you may not specify LocalPortName and ⎕WG returns an empty character vector.


Locale Property
Applies To: OLEClient

Description

The Locale property specifies the language in which the OLE server, attached to an OLEClient, exposes its methods (functions) and properties (variables).

When you create an OLEClient object, Dyalog APL/W requests the default Type Library associated with the OLE server that you specify. Many OLE servers, such as Excel.Application, provide different names for the methods and properties they expose for different languages. Without Locale, it would be difficult to write an OLE client application that could run in different countries, as the names of the functions and variables may be unpredictable.

Locale is an integer; for example, the value 9 specifies English and the value 12 specifies French.

Locale may only be specified by the ⎕WC statement that is used to create the OLEClient; it may not subsequently be changed using ⎕WS. A table of commonly used Locale values is given below.

Note that Dyalog cannot guarantee that you will actually be given the Locale you specify. This is a function of your specific installation and the OLE server in question. However, Dyalog believes that for Microsoft products, it is a fairly safe bet that the US/English interface will be available in most countries.

Language | Locale
Neutral | 0
Danish | 6
Dutch | 19
English | 9
Finnish | 11
French | 12
German | 7
Italian | 16
Norwegian | 20
Portuguese | 22
Russian | 25
Spanish | 10
Swedish | 29


MDIActive Property
Applies To: MDIClient

Description

This property contains the name of the SubForm owned by the MDIClient that is currently active. Only one SubForm may be active at a time. You can switch between SubForms in an MDI application under program control by setting this property with ⎕WS. You can also do this by generating an MDIActivate event.

See also MDIActiveObject property.


MDIActiveObject Property
Applies To: MDIClient

Description

This property contains a ref to the SubForm owned by the MDIClient that is currently active.

See also MDIActive property.


MDIMenu Property
Applies To: MenuBar

Description

This property specifies the name of, or ref to, the Menu object that is nominated as the "Window" menu in an MDI application. If such a menu is defined, the Captions of all the child Forms are automatically added to it below any other Menu or MenuItem objects that the application has created directly. This list is separated from the preceding items by a separator. The entry for the currently active SubForm is checked and the user may switch between SubForms by selecting from this list.

Note that the additional separator and the items representing the list of child forms are not Dyalog APL/W objects and may not be accessed by the application. If you prefer to maintain your own "window list" you should not use this property.


MapCols Property
Applies To: ImageList

Description

The MapCols property specifies whether or not the button colours in bitmaps and icons in an ImageList are re-mapped to reflect the users colour preferences. If your bitmaps and icons represent buttons using the standard windows button colours, this property causes those colours to be changed to suit the user's own colour scheme.

MapCols is a single number with the value 0 (no colour mapping) or 1 (colours are automatically re-mapped. The default is 0.

If MapCols is 1, the following colour mappings are performed:

Colour | Description | Mapped to
0 0 0 | Black | Button Text
128 128 128 | Dark grey | Button Shadow
191 191 191 | Light grey | Button Face
192 192 192 | Light grey | Button Face
255 255 255 | White | Button Highlight


Mask Property
Applies To: Cursor Icon

Description

This property is used to specify how the bitmap for a Cursor or Icon interacts with the pixels of the screen when it is displayed.

When a Cursor or Icon is displayed, the colour of each pixel occupied by the object on the screen is determined by :

  • The colour specified by Bits via CMap
  • The value of Mask
  • The existing colour of the screen pixel

Mask is a Boolean matrix with the same shape as the Bits property. See Cursor and Icon objects for further details.


MaskCol Property
Applies To: Bitmap Form

Description

Specifies the transparent colour for a Bitmap or Form.

MaskCol may be an integer scalar or a 3-element integer vector.

If MaskCol is 0 (the default), no transparent colour is defined.

If MaskCol is a negative scalar, it specifies a standard Windows colour. See BCol for details.

Otherwise, MaskCol is a 3-element vector of integers in the range 0-255 that specifies the transparent colour in terms of RGB values (the intensity of the red, green and blue components of colour).

For a Bitmap, if MaskCol is non-zero, any pixels specified with the same colour will instead be displayed in whatever colour is underneath the Bitmap. This achieves similar behaviour to that of an Icon.

For a Form, if MaskCol is non-zero, any of the contents of the Form that are specified to be the same colour as MaskCol will be transparent. For example, if MaskCol is 255 0 0 (red), any red items contained in the Form will instead be transparent areas, displaying whatever is behind them on the screen. Mouse events generated over such transparent areas will be passed to any other windows behind them, and will not be reported on the Form itself.


Masked Property
Applies To: ImageList

Description

The Masked property specifies whether or not the ImageList will contain opaque or transparent images. It may be 0, 1(the default), 2, or 3.

Masked must be established when the ImageList is created by ⎕WC and may not subsequently be altered. An inappropriate value of Masked will cause the images to be drawn incorrectly.

If Masked is 0, the ImageList expects opaque Bitmap objects.

If Masked is 1, the ImageList expects low-colour (4-bit or 8-bit) Icon objects whose transparency is defined by their Mask property.

If Masked is 2, the ImageList expects Bitmap or Icon objects whose alpha channel (the degree of transparency of each pixel) is encoded in its source file along with the colours.

If Masked is 3 and Native Look and Feel is enabled, the behaviour is the same as if Masked were 2. If Native Look and Feel is not enabled, it behaves as if Masked were 1. This setting provides the greatest degree of portability for applications whose users may or may not have Native Look and Feel enabled. This value is used for the ImageLists on the Dyalog Session CoolBars.


MaxButton Property
Applies To: Form SubForm

Description

This property determines whether or not a Form or a SubForm has a "maximise" button. Pressing this button will cause a Form to be resized to occupy the entire screen, or a SubForm to occupy the entire area of its parent. Pressing it again will restore the Form or SubForm to its original size. MaxButton is a single number with the value 0 (no maximise button) or 1 (maximise button is provided). The default is 1.

Note that MaxButton is independent of Sizeable, i.e. you can define a Form that can be maximised but not resized. If any of the properties MaxButton, MinButton, SysMenu and Sizeable are set to 1, the Form or SubForm will have a title bar.


MaxDate Property
Applies To: Calendar DateTimePicker

Description

The MaxDate property specifies the largest date that the user may select in a Calendar object or in the calendar drop-down of a DateTimePicker.

MaxDate is an IDN value. Its default value is 11249470 which is the maximum date that the Calendar can display.


MaxLength Property
Applies To: ButtonEdit Edit Spinner

Description

This property specifies the maximum number of characters that the user may enter in a single-line Edit object ( Style 'Single') or in the edit field associated with a Spinner. It does not apply to a multi-line Edit object (Style 'Multi'). MaxLength does not limit the length of the vector that you may assign to the Text property using ⎕WC or ⎕WS. However, if you overfill the field in this way, the user must delete excess characters before the object will accept further input.


MaxSelCount Property
Applies To: Calendar

Description

The MaxSelCount property specifies the maximum number of contiguous days that the user may select in a Calendar object.

MaxSelCount is an integer whose default value is 7.

MaxSelCount is ignored unless the Style property of the Calendar object is set to 'Multi'.


MetafileObj Property
Applies To: Clipboard

Description

This property is used to copy graphical data to and from the Windows clipboard using the Windows Metafile format.

When you set the MetafileObj property of a Clipboard object to the name of the Metafile object using ⎕WS its contents are copied to the Windows clipboard in Windows Metafile format.

To import a picture that has been stored in the Windows clipboard in Metafile format you use ⎕WG. This returns a nested array whose elements correspond to the graphical components of the picture. Each of the elements of the array may be used as the arguments of ⎕WC to draw the corresponding component of the picture. For example, if the picture stored in C:\MSOFFICE\CLIPART\BIRD.WMF is copied to the Windows clipboard, it may be imported into Dyalog APL/W as follows :

      BIRD ← 'CL' ⎕WG 'MetafileObj'
      ⍴BIRD
4

Each of the items in BIRD is a 2-element vector. The first element is a "dummy" object name which you may use or ignore as you wish. The second element is an array that defines a graphical object and is suitable as the right argument of ⎕WC. For example :

      2⊃4⊃BIRD
POLY  191 397   FSTYLE  0   FILLCOL  0 0 0    ...

190 402
187 406
182 409
176 410
172 409
168 406
165 402
164 397
165 391
168 387
172 384
176 383
182 384
187 387
190 391
191 397
189 395
191 397

From this array, you can rebuild the imported picture component by component, either as a Metafile object or directly onto a Form, Static or another object. The following example draws the picture in a Form using the dummy names supplied.

      'TEST' ⎕WC 'FORM' ('Coord' 'User')
      'TEST' ⎕WS ('YRange' 0 1024)('XRange' 0 2048)
      TEST.⎕WC/¨BIRD

Notice that the co-ordinates of each of the graphical components are typically integers in a co-ordinate system that extends from 0 to 1024 in the y-direction and 0 to 2048 in the x-direction. The simplest way to draw the picture is therefore to set up the same co-ordinate system on a Form as in the example above.


MethodList Property

Applies To

Description

This property reports the names of all the methods supported by a particular COM object or instance of an OLE control. It is a vector of character vectors returned by ⎕WG. It may not be set using ⎕WC or ⎕WS.


MinButton Property
Applies To: Form SubForm

Description

This property determines whether or not a Form or SubForm has a "minimise" button. Pressing this button will cause the Form or SubForm to be iconified. Pressing it again will restore the Form to its original size. MinButton is a single number with the value 0 (no minimise button) or 1 (minimise button is provided). The default is 1.

Note that MinButton is independent of Sizeable, i.e. you can define a Form that can be minimised but not resized.

If any of the properties MinButton, MaxButton, SysMenu, and Moveable are set to 1, the Form or SubForm will have a title bar.


MinDate Property
Applies To: Calendar DateTimePicker

Description

The MinDate property specifies the smallest date that the user may select in a Calendar or DateTimePicker object.

MinDate is an IDN value. Its default value is -109206 which is the minimum date that the Calendar can display.


MonthDelta Property
Applies To: Calendar DateTimePicker

Description

The MonthDelta property specifies the number of months by which a Calendar object scrolls when the user clicks its scroll buttons.

MonthDelta is an integer or an empty vector (zilde). The latter means that the Calendar object scrolls by the number of months that are currently displayed in its window. This is the default.


Moveable Property
Applies To: Form SubForm

Description

This property determines whether or not a Form or SubForm can be moved by the user. It is a single number with the value 0 (Form cannot be moved) or 1 (Form is moveable). If any of the properties MinButton, MaxButton, SysMenu, and Moveable are set to 1, the Form or SubForm will have a title bar. However, a Form or SubForm with a title bar is not necessarily moveable.


MultiColumn Property
Applies To: List

Description

MultiColumn is Boolean and specifies whether or not a List object displays its items in a single column (0, the default) or in multiple columns (1). MultiColumn may only be set by ⎕WC and cannot be changed using ⎕WS after the object has been created. Note that a MultiColumn List will use the minimum number of columns that are required to make the items fit within it and will reconfigure itself automatically when resized.

The following example illustrates its use.

      'F'⎕WC'Form' 'MultiColumn List'('Size' 23 32)
      'F.L'⎕WC'LIST' AIRPORTS (0 0)(100 100)('MultiColumn' 1)


MultiLine Property
Applies To: TabControl ToolControl

Description

The MultiLine property determines whether or not the tabs or buttons will be arranged in multiple flights or multiple rows/columns in a TabControl or ToolControl object.

MultiLine is a single number with the value 0 (single flight of tabs, or single row/column of buttons) or 1 (multiple flights of tabs or multiple rows/columns of buttons); the default is 0.

If MultiLine is 0 and there are more tabs or buttons than will fit in the space provided, the TabControl displays an UpDown which allows the user to scroll.

However, If MultiLine is 0 in a ToolControl, the buttons are clipped, and the user may have to resize the object to see them all.

See also: Justify, TabSize.


MultiSelect Property
Applies To: TabControl

Description

The TabControl property specifies whether or not the user can select more than one button in a TabControl at the same time, by holding down the Ctrl key when clicking.

MultiSelect is a single number with the value 0 (only 1 button may be selected) or 1 (more than one button may be selected); the default is 0.

MultiSelect apples only if the Style of the TabControl is 'Buttons' or 'FlatButtons', and is ignored if Style is 'Tabs'.

Note that the State property of the associated TabButton object reports whether or not the button is selected.


NewLine Property
Applies To: CoolBand

Description

The NewLine property specifies whether or not a CoolBand occupies the same row as an existing CoolBand, or is displayed on a new line within its CoolBar parent.

NewLine is a single number with the value 0 (same row) or 1 (new row); the default is 1.

The value of NewLine in the first CoolBand in a CoolBar is always 1, even if you specify it to be 0.

When the user drags a CoolBand to another row, the value of its NewLine property, and that of any other CoolBand affected by the move, will change.

You may move a CoolBand to the previous or next row by changing its NewLine property (using ⎕WS )from 1 to 0, or from 0 to 1 respectively.


Note Property
Applies To: Button

Description

The Note property applies only to a Button whose Style is 'CommandLink'.

It is a character vector (by default empty) that specifies text to be displayed below the Caption.

Example:

'F'⎕WC'Form' 'CommandLink Button'
'F.clb'⎕WC'Button' 'Visit Us'('Style' 'CommandLink')
F.clb.Size←80 200
F.clb.Note←'www.dyalog.com'


OKButton Property
Applies To: Form

Description

OKButton applies only to PocketAPL. In versions of Dyalog APL for other platforms, it has no effect.

This is a Boolean property that specifies whether or not an [OK] button appears in the title bar of a Form. Its default value is 0.

OKButton may only be specified when the Form is created using ⎕WC; you cannot subsequently change its value.

If OKButton is 1, the Form displays an [OK] button in its title bar in place of the standard [X] button.

When the user clicks the [OK] button, the system will press the default button, which is specified by the Default property of a Button on the Form.

If there is no default button, the Form will generate a Close event.


OLEControls Property
Applies To: Root

Description

The OLEControls property reports a list of the OLE Controls installed on your computer. This information is obtained from the Windows registry. Its value is a nested vector with one element per OLE Control. Each element is a vector of 2-element character vectors. The first is the name of the OLE Control; the second is its class identifier.


OLEServers Property
Applies To: Root

Description

The OLEServers property is a read-only property that reports the names and CLSIDs of all the OLE Automation servers installed on your computer. This information comes from the Windows registry.

Its value is a nested vector with one element per OLE Server.

Each element is a vector of 2-element character vectors. The first is the name of the OLE Server; the second is its class identifier or CLSID which is a type of GUID.


OnTop Property

Applies To

Description

This property may be used to cause a Form or SubForm to be displayed on top of all other windows, even those owned by other applications.

Normally, Forms are brought to the front when they receive the input focus. Forms that do not have the input focus may be partially obscured by the one that does. If OnTop is set to 1, the Form or SubForm remains at the front even if it doesn't have the input focus. Indeed, it may partially obscure the Form that does have the focus. The default value is 0 (normal).

More than one Form may have OnTop set to 1. If so, these Forms appear on top of all others, but may overlap one another. Other applications may also have windows with this property.

For a graphical object, the OnTop property controls how it is drawn in a Grid relative to the grid lines and cell text. OnTop is applicable only if the graphic is the child of a Grid and is otherwise ignored.

0 | Graphical object is drawn behind grid lines and cell text
1 | Graphical object is drawn on top of grid lines but behind cell text
2 | Graphical object is drawn on top of grid lines and cell text


Orientation Property
Applies To: Printer

Description

The Orientation property specifies the orientation of the paper on a Printer object. It is a simple character vector which is either 'Portrait' or 'Landscape'. When you create a Printer object, the default value of the Orientation property is determined by the current setting for the corresponding printer device.

The effect of changing Orientation using ⎕WS is to spool the current page (effectively the same as sending a NewPage event) and then to change the orientation of the paper. Note that the values of the first 2 elements of the DevCaps property change accordingly. You may also set Orientation when you create the Printer object with ⎕WC. In neither case does the global setting for the printer device change.


OtherButton Property
Applies To: ColorButton

Description

The OtherButton property is Boolean and specifies whether or not the user can select a colour from a ColorButton object using the Windows colour selection dialog box.

If OtherButton is 1 (the default), the final row of the colour selection drop-down contains a button labelled "Other…". If the user clicks this button, the standard Windows colour selection dialog box is displayed, allowing the user to select any colour that the computer can render.

If OtherButton is 0, the button labelled "Other…" is not present and the user is restricted to the choice of colours provided by the DefaultColors property.


OverflowChar Property
Applies To: Grid

Description

The OverflowChar property specifies the character to be displayed in place of the digits when a numeric value cannot be displayed in its entirety in a Grid cell. If the value of OverflowChar is an empty vector (the default) the data in a numeric cell is simply clipped if it is too wide to fit in the cell. For example:

   'F'⎕WC'Form'('Coord' 'Pixel')('Size' 101 296)
   'F'⎕WS'Caption' 'OverflowChar Property'
   DATA←3 3⍴12 123456789 13 9876543 99 456 10 99 1236.893
   'F.G'⎕WC'Grid'DATA(0 0)(101 296)
   'F.G'⎕WS'CellWidths' 65
   'F.G'⎕WS'OverflowChar' '#'

The same Grid without OverflowChar being defined appears as follows. Notice how the numbers have been truncated


PName Property
Applies To: Font Printer

Description

This property is a character vector that specifies the face name for a Font object, or the printing device associated with a Printer. It is case-independent.

For a Printer, PName contains the description of the printer followed by a comma (,) and then the device to which it is attached.

Example:

      'PR1' ⎕WC 'Printer'
      'PR1' ⎕WG 'PName'
HP Universal Printing PS,hp4200


PageActive Property
Applies To: PropertySheet

Description

The PageActive property specifies the name of the current PropertyPage in a PropertySheet. You may select a particular page by setting this property or by generating a PageActivate event.

See also or PageActiveObject.


PageActiveObject Property
Applies To: PropertySheet

Description

The PageActiveObject property specifies a ref to the current PropertyPage in a PropertySheet. You may select a particular page by setting this property or by generating a PageActivate event.

See also or PageActive.


PageSize Property
Applies To: Form Scroll SubForm

Description

For a Form and SubForm, the PageSize property is a 2-element integer vector which specifies the size of the thumb in the vertical and horizontal scrollbars respectively.

For a Scroll object it is a single integer.

If PageSize is 0 (the default) it specifies the default thumb. Otherwise, PageSize is expressed in proportion to the corresponding value of Range. For example, if Range is 1000, setting PageSize to 100 will obtain a thumb which is approximately 10% of the height or length of the scrollbar.


PageWidth Property
Applies To: RichEdit

Description

The PageWidth property specifies the width of the page in a RichEdit object and is the dimension that is used to apply text wrapping and paragraph formatting to the text in the object. PageWidth is a single integer value specified in Twips.

The default value of PageWidth is 0 which disables text wrapping. You may find it convenient to set PageWidth to the width of the RichEdit window or to a value that is appropriate for your printer.


PaperSize Property
Applies To: Printer

Description

The PaperSize property specifies the size of paper to be used for printing

PaperSize may be a character vector containing the name of the paper size (eg. 'Legal 8 1/2 x 14 in' or 'A4 210 x 297 mm') or a 2-element integer vector that specifies the desired height and width of the paper in tenths of a millimetre (e.g. 3556 2159 or 2970 2099).

The default value of PaperSize is the name of the paper size associated with the current printer settings.

You can obtain a list of supported paper sizes from the PaperSizes property.


PaperSizes Property
Applies To: Printer

Description

The PaperSizes property is a read-only property that provides the names and dimensions of the various different paper sizes supported by the printer associated with the Printer object.

PaperSizes is a nested vector of 2-element vectors which contain the name, and height and width of each paper size respectively. Dimensions are reported in tenths of a millimetre.

You may set or query the current paper size using the PaperSize property.


PaperSource Property
Applies To: Printer

Description

The PaperSource property is a character vector that specifies the name of the paper bin to be used as the paper source for printing.

An empty character vector (the default) means the default bin, Otherwise, PaperSource must be a member of the PaperSources property.


PaperSources Property
Applies To: Printer

Description

The PaperSources property is a read-only property that provides the names of the paper bins installed on the printer associated with the Printer object. It is a vector of character vectors.

You may select which of the bins is to be used by specifying the PaperSource property.


ParaFormat Property
Applies To: RichEdit

Description

The ParaFormat property describes the current paragraph format or the paragraph format of the currently selected text in a RichEdit object. It is a 6-element nested array structured as follows:

[1] | A character vector that specifies the text alignment. This may be 'Left' (the default), 'Right' or 'Centre'
[2] | The size of the indentation of the first line in the paragraph measured from the left margin in Twips.
[3] | The size of the horizontal offset of the start of the second and subsequent lines. This is measured in Twips relative to the first line indentation specified in element [2].
[4] | The size of the right indentation measured in Twips from the right margin.
[5] | An integer value specifying the bullet/numbering option. 0 mean no numbering, 1 means bullets.
[6] | An integer vector specifying the size of any tab stops measured in Twips from the left margin and specified in ascending order.

If there is no text selected, ParaFormat specifies the current paragraph formatting format, i.e. that which will be used to format the current (and subsequent) lines of characters that the user enters. If there is text selected ParaFormat specifies the paragraph formatting of the selected block of text. If the format is not strictly homogeneous, ⎕WG will report the format of the first paragraph in the selected block

(⎕WS 'ParaFormat' ...) will set the format of the currently selected block of text. To set the format of an arbitrary block of text you must select it first using (⎕WS 'SelText' ...).


Password Property
Applies To: ButtonEdit Edit Spinner

Description

This property specifies the character that is echoed when a user enters data into a single-line Edit object ( Style 'Single'). It does not apply to a multi-line object (Style 'Multi'). If Password is empty (the default) the character echoed is the same as the character the user entered. If Password is set to (say) the asterisk character (*), the object will display asterisks as the user types into it.


PathWordBreak Property
Applies To: ComboEx

Description

If set, the edit control portion of the ComboEx will use the forward slash (/), back slash (\), and period (.) characters as word delimiters. This makes keyboard shortcuts for word-by-word cursor movement (Ctrl + arrow keys) effective in path names and URLs.


Picture Property

Applies To

Description

The Picture property specifies a bitmap, icon, or other image for an object.

For Button, Form, Group, MDIClient, Static, StatusBar, StatusField, SubForm, SM, TabBar or ToolBar, this property specifies the name of, or ref to, a Bitmap, Icon, or Metafile which is drawn as a background on the object. Other controls and graphical objects are drawn on top of this background.

When it refers to a Metafile, the Picture property specifies the name of, or ref to, the Metafile to be drawn in the object. When it refers to a Bitmap or Icon, the value of the Picture property is a 2-element vector whose elements specify the name of, or ref to, the Bitmap, or Icon, and the manner in which it is displayed. This is specified as an integer as follows:

0 | The Bitmap or Icon is drawn in the top left corner of the object.
1 | The Bitmap or Icon is tiled (replicated) to fill the object.
2 | The Bitmap is scaled (up or down) to fit exactly in the object. This setting does not apply to an Icon whose size is fixed.
3 | The Bitmap or Icon is drawn in the centre of the object. This is the default. Note that the centre of the Bitmap is positioned over the centre of the object, so that you see the middle portion of a Bitmap that is larger than the object in which it is displayed.

For example, the following statements produce a Form filled with the CARS bitmap.

      'CARS' ⎕WC 'Bitmap' 'C:\WINDOWS\CARS'
      'f1' ⎕WC 'Form' ('Picture' 'CARS' 1)

An easy way to provide a customised pushbutton is to create a Button whose Picture property specifies the name of, or ref to, a Bitmap or Icon, using drawmode 3 (the default). This causes the corresponding bitmap or icon to be drawn in the centre of the Button. So long as the Button is larger than the bitmap or icon, its borders (which give it its 3-dimensional appearance and "pushbutton" behaviour) will be unaffected.

Note that if Picture is set on a Button whose Style is 'Radio' or 'Check', the Button assumes pushbutton appearance, although its radio/check behaviour is preserved.

For an Image object, the Picture property specifies the name of, or ref to, a Bitmap, Icon or Metafile object to be drawn, or a vector of names or refs. The Image is a graphical object and is drawn on top of the background. It does not support the drawmode options provided by the objects in which Picture specifies the background.

For the Clipboard object, Picture is a "set-only" property that allows you to place a specified Bitmap object into the Windows clipboard. To place a Metafile object into the clipboard, use its Metafile property.


Points Property

Applies To

Description

This property specifies the co-ordinates for a graphics object. It may define a single set of co-ordinates, or be a nested scalar or a nested vector each element of which contains a set of co-ordinates.

Each set of co-ordinates may be:

  • a 2-column numeric matrix containing y-values in column 1 and x-values in column 2. or
  • a 2-element numeric vector whose first element specifies y-values and whose second element specifies x-values. The two elements must be of equal length unless one or both is a scalar in which case scalar extension applies.

For further details, see the specifications for the relevant objects.


Popup Property
Applies To: SysTrayItem ToolButton

Description

The Popup property specifies the name of, or ref to, a (popup) Menu object that is associated with a SysTrayItem or ToolButton.

Note that Popup is ignored unless Style is set to 'DropDown'.


Posn Property

Applies To

Description

With the exception of Menu, MenuItem and Separator objects, Posn is a 2-element numeric vector specifying the y-position and x-position respectively of the top-left corner of the object relative to its parent. For a Form, Posn specifies its position on the screen. The units are defined by the Coord property.

When specifying Posn for ⎕WC, you can allow the y-position or x-position to assume a default value by giving the corresponding element a value of ⍬.

Using ⎕WS, if you want to set the y-position, but not the x-position, or vice-versa, you should specify ⍬ for the item you don't want to change.

For Menu, MenuItem and Separator objects, Posn is a single integer that specifies the position at which the object is to be inserted in its parent. For example, to add a new MenuItem between the third and fourth items in an existing Menu, you would specify its Posn as 4. For these objects, the value of Posn returned by ⎕WG is the current index of the object within its parent.


PrintList Property
Applies To: Root

Description

This property provides a list of the printers that are installed on your computer system, i.e. those listed when you select "printers" from the MS-Windows Control Panel. It is a "read-only" property of the Root object '.'.

PrintList is a vector of character vectors. Each item in PrintList contains the name of an installed printer followed by a comma (,) and then the name of the device to which it is attached. The first item in PrintList is the default system printer.

Example:

      ⍴'.'⎕WG'PrintList'
6
      ]display ⊃'.'⎕WG'PrintList'
┌→─────────────────────┐
│KODAK ESP-3 AiO,USB001│
└──────────────────────┘
      ↑'.'⎕WG'PrintList'
KODAK ESP-3 AiO,USB001
Send To OneNote 2007,Send To Microsoft OneNote Port:
Microsoft XPS Document Writer,XPSPort:
Microsoft Office Document Image Writer,Microsoft Document Imaging Writer Port:
Fax,SHRFAX:
Auto Canon MP600 Printer on DIMENSION5150,\\DIMENSION5150\Canon


PrintRange Property
Applies To: Printer

Description

The PrintRange property specifies the range of pages to be printed.

PrintRange may be an empty character vector (the default), or 'All', either of which will cause all pages to be printed.

Alternatively, PrintRange may be a 3 or 4-element nested array whose items are:

[1] | 'Pages'
[2] | Start page (integer)
[3] | End page (integer)
[4] | Maximum number of pages (integer)

In this case, printing starts at the page specified to be the Start page, and ends at the page specified by End page or after the Maximum number of pages has been reached, whichever is sooner.


ProgressStyle Property
Applies To: ProgressBar

Description

The ProgressStyle property specifies the appearance of a ProgressBar control.

ProgressStyle is a character vector that may be 'Normal', 'Smooth' or 'Marquee'. Its value is effective only when the object is created with ⎕WC. Changing ProgressStyle with ⎕WS has no effect on the appearance or behaviour of the ProgressBar.

If ProgressStyle is 'Normal', the highlight in the centre of the ProgressBar is displayed as a broken bar. This is the default.

If ProgressStyle is 'Smooth', the highlight in the centre of the ProgressBar is displayed as a solid block of colour. This style only applies if Windows Classic Theme is in use. If not, it will be as if 'Normal' were specified.

If ProgressStyle is 'Marquee', the highlight in the centre of the ProgressBar is displayed as a broken bar that moves continuously from left to right. The speed is controlled by the Interval Property which determines the frequency in milliseconds with which the highlight is redrawn, each time further along the ProgressBar. The special value of ¯1 causes the animation to stop.

Note that this feature only applies if Native Look and Feel is enabled. If not, 'Marquee' will produce the same behaviour as 'Normal'.

The pictures below illustrate the appearance of the different values of ProgressStyle.

ProgressStyle Normal (the default)

ProgressStyle Smooth (Windows Classic Theme only)

ProgressStyle Marquee (requires Native Look and Feel)


PropList Property

Applies To

Description

This is a "read-only" property that supplies a list of all other properties which are applicable to the object in question. The list is returned as a vector of character vectors in the order in which the corresponding properties are expected by ⎕WC and ⎕WS.

Example:

      'F'    ⎕WC 'Form'
      'F.MB' ⎕WC 'MenuBar'
      'F.MB' ⎕WG 'PropList'
 Type  Visible  FontObj  Data  EdgeStyle  MDIMenu  PropList


QueueEvents Property
Applies To: OCXClass OLEClient

Description

The QueueEvents property specifies whether or not incoming events generated by an COM object are queued. It is a Boolean value where the (default) value 1 specifies that events are queued, and 0 that they are not.

If QueueEvents is 1, the result (if any) of your callback function is not passed back to the COM object but is discarded. Thus you cannot, for example, inhibit or modify the default processing of the event by the COM object.

If QueueEvents is 0, the following applies.

  • The callback function attached to the event is executed immediately, even if there are other APL events before it in the internal event queue. This immediate execution means that your callback can fire during the execution of any other function, including a callback function on an APL event. You must therefore take care that the callback makes no references to objects that may be shadowed.
  • The result of your callback function is then passed back to the COM object. In this situation, it is essential that the callback is not interrupted by other events from the same, or another instance, of an COM object.
  • To prevent APL itself from yielding to Windows, the Yield property is temporarily set to 0 while the callback is run. For the same reason, the tracing of a callback function, that is run immediately in this way, is disabled.

However, you must yourself also ensure that your own code does not yield. This means that you may not perform any operation in your callback that would yield to Windows; these include:

  • ⎕DL
  • certain uses of ⎕NA
  • external function calls to Auxiliary Processors

If your callback does yield to Windows, thereby allowing another COM object event to arrive, this second event and any subsequent events that arrive during the execution of the callback are queued and will be processed later. These events may therefore not be modified by their callback functions.


RTFText Property
Applies To: Clipboard RichEdit

Description

The RTFText property is used to set or retrieve the contents of a Clipboard or a RichEdit object in rich text format (RTF). It is always a character vector.


Radius Property
Applies To: Circle Rect

Description

For a Circle object, this property is a single number that specifies the radius of the circle/arc or a numeric vector that specifies the radii of a set of circles/arcs.

For a Rect object, Radius is a 2-element vector that specifies the curvature of the corners of the rectangle or set of rectangles to be drawn. The curvature is defined in terms of the vertical and horizontal radii of an ellipse. The first element of Radius defines the radius vertically, the second horizontally. If more than one rectangle is involved, either or both of the elements of Radius may be vectors. The default value is (0,0) which gives square corners.


RadiusMode Property
Applies To: Circle Root

Description

A perfectly round circle can only be drawn if the diameter is an odd number of pixels. The RadiusMode property specifies whether or not a circle is adjusted by a single pixel, if necessary, so as to appear perfectly round.

If RadiusMode is 1 or ¯1, and the diameter is an even number of pixels, the circle is actually drawn with a diameter of 1 pixel more or less than specified. If RadiusMode is 0 (the default), no such adjustment is made.

RadiusMode may be set on the Root object to be inherited by all Circle objects.


Range Property
Applies To: Form Scroll SubForm

Description

This property determines the maximum value of the thumb in a scrollbar (the minimum value is always 1). This may be any positive integer value that is greater than 1.

For a Scroll object Range is a single number. For a Form or SubForm object, Range is a 2-element vector which specifies the maxima for the Form's vertical and horizontal scrollbars respectively.


ReadOnly Property
Applies To: Button ButtonEdit Edit Spinner

Description

This property specifies whether or not the user may alter the text in an object. The default value of ReadOnly is 0 which allows the user to alter text.

If you set ReadOnly to 1, a cursor is displayed in the object, the user may navigate around the text in the usual manner with the mouse and/or the keyboard and select text and copy it to the clipboard. However, all input that would otherwise change the data is ignored.

For a Button object with Style 'Radio' or 'Check', setting ReadOnly to 1 prevents the user from changing the state of the Button, although mouse and other events will still be reported.


RealSize Property
Applies To: Metafile

Description

There are several distinct types of Windows metafiles. A placeable metafile is one that carries with it its suggested size. Certain programs (such as Word for Windows) only support placeable metafiles.

The RealSize property specifies the suggested size of a Metafile in units of 0.01mm. Thus to make a placeable Metafile with a suggested size of 20 x 10 cm, you would set RealSize to (20000 10000).

The RealSize property is not used or required by Dyalog APL/W and is provided only to enable you to make and save a new metafile that is placeable. If you create a Metafile object from a file, the value of RealSize will be obtained from the value recorded in the file (if it is placeable). Otherwise, RealSize will be (0 0). If so, you must set RealSize to make it placeable. Each element of RealSize must be an integer in the range 0-144745.


Redraw Property

Applies To

Description

The Redraw property specifies whether or not APL automatically redraws an object when it is exposed or when any of its properties change in a way that would affect its appearance.

The value reported by the Redraw property is a Boolean value; 1 means that APL automatically redraws the object when necessary (the default); 0 means that APL does not redraw the object.

Setting Redraw to 0 or 1 affects only whether or not APL will redraw the object from then on.

Setting Redraw to 2 has the same effect as setting it to 1, but the object is also redrawn immediately. Note that no child object is redrawn.

Setting Redraw to 3 has the same effect as setting it to 1, but the object and its children are redrawn immediately.


RemoteAddr Property
Applies To: TCPSocket

Description

The RemoteAddr property is a character vector that specifies the IP address of the remote computer.

RemoteAddr may only be specified by a client TCPSocket that is intended to make a connection with a server. Furthermore, it must be specified in the ⎕WC statement that creates the TCPSocket object and it may not subsequently be changed using ⎕WS.

You may use either RemoteAddr or RemoteAddrName to identify the remote computer. If you know its IP address, it is normally quicker to specify RemoteAddr. If you specify both properties, the value of RemoteAddrName will be ignored.

For a server TCPSocket, RemoteAddr is determined by the IP address of the connecting process and is a read-only property.


RemoteAddrName Property
Applies To: TCPSocket

Description

The RemoteAddrName property is a character vector that specifies the host name of the remote computer to which you wish to make a connection.

RemoteAddrName may only be specified by a client TCPSocket that is intended to make a connection with a server. Furthermore, it must be specified in the ⎕WC statement that creates the TCPSocket object and it may not subsequently be changed using ⎕WS.

When the specified host name has been resolved to an IP address, the TCPSocket will generate a TCPGotAddr event and update the value of RemoteAddr accordingly.

Note that you may use either RemoteAddr or RemoteAddrName to identify the remote computer. If you know its IP address, it is normally quicker to specify RemoteAddr. If you specify both properties, the value of RemoteAddrName will be ignored.

For a server TCPSocket, you may not specify RemoteAddrName and ⎕WG returns an empty character vector.


RemotePort Property
Applies To: TCPSocket

Description

The RemotePort property is a scalar integer in the range 1-65536 that identifies the port number associated with a service on a remote computer.

RemotePort may only be specified by a client TCPSocket that is intended to make a connection with a server. Furthermore, it must be specified in the ⎕WC statement that creates the TCPSocket object and it may not subsequently be changed using ⎕WS.

Note that you may use either RemotePort or RemotePortName to identify the remote service. If you know the port number, it is normally quicker to specify RemotePort. However unless it is a well known port number, the use of a port name is generally more flexible. If you specify both properties, the value of RemotePortName will be ignored.

For a server TCPSocket, RemotePort is determined by the port number of the connecting process and is a read-only property.


RemotePortName Property
Applies To: TCPSocket

Description

The RemotePortName property is a character vector that specifies the port name of the remote service to which you wish to make a connection.

RemotePortName may only be specified by a client TCPSocket that is intended to make a connection with a server. Furthermore, it must be specified in the ⎕WC statement that creates the TCPSocket object and it may not subsequently be changed using ⎕WS.

When the specified port name has been resolved to a port number, the TCPSocket will generate a TCPGotPort event and update the value of RemotePort accordingly.

Note that you may use either RemotePort or RemotePortName to identify the remote service. If you know the port number, it is normally quicker to specify RemotePort. However unless it is a well known port number, the use of a port name is generally more flexible. If you specify both properties, the value of RemotePortName will be ignored.

For a server TCPSocket, you may not specify RemotePortName and ⎕WG returns an empty character vector.


ReportBCol Property
Applies To: ListView

Description

In Report View, the ReportBCol property is either a scalar or a matrix that specifies the background colours for each item displayed in a ListView object .

Its first column refers to the Items themselves, and subsequent columns to the elements of ReportInfo.

i.e. if non-scalar, (⍴ReportBCol)←→(0 1+⍴ReportInfo)

Each element of ReportBCol is either an integer colour value or a 3-element of RGB colour indices.

For further information, see BCol.


ReportImageIndex Property
Applies To: ListView

Description

The ReportImageIndex property is an integer scalar or matrix that specifies the images to be displayed alongside each item in a ListView object in Report View.

If it is a matrix, its first column specifies the indices of the icons to be displayed against the Items of the ListView, overriding the icons specified by ImageIndex, and its subsequent columns specify the indices of the icons to be displayed against the elements of ReportInfo.

i.e. if non-scalar, (⍴ReportImageIndex)←→(0 1+⍴ReportInfo)

Each element of ReportImageIndex specifies an index into the ImageList object specified by the ImageListObj property.


ReportInfo Property
Applies To: ListView

Description

The ReportInfo property is a matrix that is displayed alongside each item in a ListView object when its View property is 'Report'. Each element of the matrix may be a character vector or a number.

The information is displayed in a grid format, the first column of which contains the item labels and their icons. Subsequent columns of the grid are defined by the corresponding columns of ReportInfo. The alignment of the columns is specified by the ColTitleAlign property.


ResizeColTitles Property
Applies To: Grid

Description

This property determines whether or not the user may alter the height of the column titles in the Grid. It is either 1, which indicates that the height of the column titles is adjustable by the user, or 0 which means that it is not.

If the height of the column titles is adjustable, the cursor changes to a double headed arrow when the mouse pointer is placed over the top border of the first row title The user may resize the column titles by dragging this border. The user may also resize the column titles by double-clicking over this border. This causes the column titles to be resized to fit the data and the height of the column titles is automatically adjusted to display the tallest heading in any of its columns. Either operation generates a SetRowSize event. The value of the row number reported by the event is ¯1.

Note that the user may cause the column titles to disappear altogether by dragging them to a zero height. Once this has been done, the row titles cannot be restored.


ResizeCols Property
Applies To: Grid

Description

This property determines whether or not the user may resize columns in the Grid. It is a Boolean scalar or vector with one element per column. A value of 1 indicates that the corresponding column is resizable by the user. A value of 0 means that the corresponding column may not be resized by the user.

If a column is resizable, the cursor changes to a double headed arrow when the mouse pointer is placed over the right-hand border of the column title. The user may resize the column by dragging this border. The user may also resize a column by double-clicking over its right-hand border. This causes the column to be resized to fit the data and the width of the column is automatically adjusted to display the widest value in any of its cells. Either operation generates a SetColSize event.

Note that the user may cause the column to disappear altogether by dragging it to a zero width. Once this has been done, this column may only be restored if the column to its left is itself not resizable.


ResizeRowTitles Property
Applies To: Grid

Description

This property determines whether or not the user may alter the width of the row titles in the Grid. It is either 1, which indicates that the width of the row titles is adjustable by the user, or 0 which means that it is not.

If the width of the row titles is adjustable, the cursor changes to a double headed arrow when the mouse pointer is placed over the left-hand border of the first column title. The user may resize the row titles by dragging this border. The user may also resize the row titles by double-clicking over this border. This causes the row titles to be resized to fit the data and the width of the row titles is automatically adjusted to display the longest string in any of its rows. Either operation generates a SetColSize event. The value of the column number reported by the event is ¯1.

Note that the user may cause the row titles to disappear altogether by dragging them to a zero width. Once this has been done, the row titles cannot be restored.


ResizeRows Property
Applies To: Grid

Description

This property determines whether or not the user may resize rows in the Grid. It is a Boolean scalar or vector with one element per column. A value of 1 indicates that the corresponding row is resizable by the user. A value of 0 means that the corresponding row may not be resized by the user.

If a row is resizable, the cursor changes to a double headed arrow when the mouse pointer is placed over the lower border of the row title. The user may change the height of the row by dragging this border up and down. The user may also resize a row by double-clicking over its bottom border. This causes the row to be resized to fit the data and the height of the row is automatically adjusted to display the tallest value in any of its cells. Either operation generates a SetRowSize event.

Note that the user may cause the row to disappear altogether by dragging it to a zero height. Once this has been done, this row may only be restored if the row above it is itself not resizable.


Resolution Property
Applies To: Printer

Description

The Resolution property determines the print resolution.

You may set Resolution to 'Draft', 'Low', 'Medium' or 'High'.

Alternatively, you can set Resolution to a 2-element integer vector that specifies the desired number of dots per inch in the x (horizontal) and y (vertical) direction respectively.

The initial value reported by Resolution may be reported in either form (character vector or 2-element numeric vector) according to the current printer settings.


Resolutions Property
Applies To: Printer

Description

The Resolutions property is a read-only property that reports the available printer resolutions.

Resolutions is a vector of 2-element integer vectors each of which specifies the number of dots per inch in the x (horizontal) and y (vertical) directions respectively.


Rotate Property
Applies To: Font

Description

This property specifies the angle of rotation of the font measured in radians (0 → ○2) from the x-axis in a counter-clockwise direction. Note that only TrueType fonts can be rotated. Rotated fonts are supported only for use with the Text object.


RowHiddenDepth Property
Applies To: Grid

Description

The RowHiddenDepth property is read-only and identifies which rows of a Grid are currently hidden.

RowHiddenDepth is an integer vector with the same number of elements as there are rows in the Grid. The values in RowHiddenDepth indicate the current depth of the row in the visible hierarchy; i.e. number of nodes that must be opened to display it. The value 0 means that the corresponding row is visible. The value 1 means that 1 node must be opened to display it; 2 means 2 nodes, and so forth.

Example

      'F'⎕WC'Form' 'Grid: RowHiddenDepth'
       F.(Coord Size)←'Pixel'(163 306)
       'F.G'⎕WC'Grid'(10 2⍴2/⍳10)('Size'F.Size)
       ⎕←F.G.RowTreeDepth←10⍴0 1 2 3
0 1 2 3 0 1 2 3 0 1

With all nodes closed, RowHiddenDepth is the same as RowTreeDepth.

      F.G.RowHiddenDepth
0 1 2 3 0 1 2 3 0 1

The next picture shows the Grid after the user has opened nodes 5,6 and 9.

      F.G.RowHiddenDepth
0 1 2 3 0 0 0 1 0 0


RowLineTypes Property
Applies To: Grid

Description

This property specifies the appearance of the horizontal grid lines in a Grid object.

RowLineTypes is an integer vector, whose length is normally equal to the number of rows in the Grid. Each element in RowLineTypes specifies an index into the GridLineFCol and GridLineWidth properties, thus selecting the colour and width of the horizontal grid lines.

For example, if RowLineTypes[1] is 3, the first horizontal grid line in the Grid is displayed using the colour specified by the 3rd element of GridLineFCol, and the width specified by the 3rd element of GridLineWidth.

Note that RowLineTypes is not ⎕IO dependant, and the value 0 is treated the same as the value 1; both selecting the first colour and line width specified by GridLineFCol and GridLineWidth respectively.

The default value of RowLineTypes is an empty numeric vector (⍬). If so, all horizontal grid lines are drawn using the first element of GridLineFCol and GridLineWidth.

A horizontal grid line is drawn along the bottom edge of its associated row. One pixel is drawn inside the row of cells; additional pixels (if any) are drawn between that row of cells and the next one below.


RowTitleAlign Property
Applies To: Grid

Description

The RowTitleAlign property specifies the alignment of row titles in a Grid. It is either a simple character vector, or a vector of character vectors with one element per row.

An element of RowTitleAlign may be: 'Top', 'Bottom', 'Left', 'Right', 'Centre', 'TopLeft', 'TopRight', 'BottomLeft', or 'BottomRight'.

Note that both spellings 'Centre' and 'Center' are accepted.


RowTitleBCol Property
Applies To: Grid

Description

The RowTitleBCol property specifies the background colour of the row titles in a Grid object

RowTitleBCol may be a scalar that specifies a single background colour to be used for all of the row titles, or a vector that specifies the background colour of each of the row titles individually. An element of RowTitleBCol may be an enclosed 3-element vector of integer values in the range 0-255 which refer to the red, green and blue components of the colour respectively, or it may be a scalar that defines a standard Windows colour element (see BCol for details). Its default value is 0 which obtains the colour defined for Button Face.


RowTitleDepth Property
Applies To: Grid

Description

RolTitleDepth specifies the structure of a set of hierarchical row titles. It is an integer vector with the same length as the RowTitles property. A value of 0 indicates that the corresponding element of RowTitles is a top-level title. A value of 1 indicates that the corresponding title is a sub-title of the most recent title whose RowTitleDepth is 0; a value of 2 indicates that the corresponding title is a sub-title of the most recent title whose RowTitleDepth is 1, and so forth. For example:

      'F'⎕WC'Form'('Coord' 'Pixel')('Size' 318 310)
      'F'⎕WS'Caption' 'Hierarchical Column Titles'
      'F.G'⎕WC'Grid'(?12 4⍴100)(0 0)(318 310)
      'F.G'⎕WS('TitleWidth' 150)('TitleHeight' 0)
      'F.G'⎕WS'CellWidths' 40

      Q1←'Q1' 'Jan' 'Feb' 'Mar'
      Q2←'Q2' 'Apr' 'May' 'Jun'
      Q3←'Q3' 'Jul' 'Aug' 'Sep'
      Q4←'Q4' 'Oct' 'Nov' 'Dec'
      RT←(⊂'1995'),Q1,Q2,Q3,Q4
      RD←0,16⍴1 2 2 2

      'F.G'⎕WS('RowTitles'RT)('RowTitleDepth'RD)

      'F.G'⎕WS'RowTitleAlign' 'Centre'

Note that the LockRows method is not supported in combination with hierarchical row titles.


RowTitleFCol Property
Applies To: Grid

Description

The RowTitleFCol property specifies the colour of the row titles in a Grid object

RowTitleFCol may be a scalar that specifies a single colour to be used for all of the row titles, or a vector that specifies the colour of each of the row titles individually. An element of RowTitleFCol may be an enclosed 3-element vector of integer values in the range 0-255 which refer to the red, green and blue components of the colour respectively, or it may be a scalar that defines a standard Windows colour element (see BCol for details). Its default value is 0 which obtains the colour defined for Button text.


RowTitles Property
Applies To: Grid

Description

This property specifies the headings that are displayed to the left of the rows in a Grid object. If specified, it must be a vector of character vectors or matrices whose length is the same as the number of rows implied by the Values property. The default value of RowTitles is an empty character vector. In this case, the system displays the row numbers.

To disable the display of row titles in a Grid, you should set the TitleWidth property to 0.


RowTreeDepth Property
Applies To: Grid

Description

The RowTreeDepth property specifies the structure of the rows in a Grid object. It is either a scalar 0 or an integer vector of the same length as the number of rows in the Grid. RowTreeDepth is similar to the Depth property of the TreeView object.

A value of 0 indicates that the corresponding row is a top-level row. A value of 1 indicates that the corresponding row is a child of the most recent row whose RowTreeDepth is 0; a value of 2 indicates that the corresponding row is a child of the most recent row whose RowTreeDepth is 1, and so forth.

When you set RowTreeDepth, the Grid is redrawn so that only rows with a RowTreeDepth of 0 are visible.

The RowSetVisibleDepth method can be used to make data visible to a specific depth.

Example:

      'F'⎕WC'Form' 'Grid: TreeView Feature'
      'F.G'⎕WC'Grid'(30 2⍴2/⍳30)
      F.G.RowTreeDepth←30⍴0 1 2 2

The user can interact with the tree images to expand and contract rows of the Grid.


RowTreeImages Property
Applies To: Grid

Description

The RowTreeImages property is a simple character vector or ref, or a vector of character vectors or refs, that specifies the names(s) of, or ref(s) to, Bitmap objects that are used to display the tree nodes for a Grid object.

Note that images in tree nodes are only displayed if RowTreeStyle is set to 'ImagesOnly', 'ImagesAndLines', or 'AllImagesAndLines'.

If RowTreeImages is not specified default images are used.

The Bitmap specified by the 1st element of RowTreeImages is used to display unopened nodes.

The Bitmap specified by the 2nd element of RowTreeImages is used to display opened nodes.

The Bitmap specified by the 3rd element of RowTreeImages is used to display nodes without children.

Example:

      'Closed'⎕WC'Bitmap' 'Folder.bmp'
      'Open'⎕WC'Bitmap' 'FolderOpen.bmp'
      'Item'⎕WC'Bitmap' 'Ideas'
      F.G.RowTreeStyle←'AllImagesAndLines'
      F.G.RowTreeImages←'Closed' 'Open' 'Item'


RowTreeStyle Property
Applies To: Grid

Description

RowTreeStyle specifies the visible attributes of the tree displayed in the Row titles of a Grid.

The value of the RowTreeStyle property is a character vector chosen from the following :

'LinesOnly' | Only the lines of the tree structure are drawn.
'ImagesOnly' | Only the images of nodes with children are drawn.
'ImagesAndLines' | Both lines and images for nodes with children are drawn.
'AllImagesOnly' | Images for all nodes are drawn.
'AllImagesAndLines' | Both lines and images for all nodes are drawn.

The default value, 'ImagesAndLines', is illustrated in the first picture below. Other values are displayed in subsequent pictures.

F.G.RowTreeStyle←'LinesOnly'

f.g.RowTreeStyle←'ImagesOnly'

f.g.RowTreeStyle←'AllImagesOnly'

f.g.RowTreeStyle←'AllImagesAndLines'


Rows Property
Applies To: Combo ComboEx

Description

For Combo objects with Style 'Drop' or 'DropEdit' this property determines the number of rows displayed in the drop-down listbox when it is displayed. Note that the height of the edit field of a Combo of this type is dependent only upon the size of the font in use, and cannot otherwise be changed.

Rows is a "read-only" property for a Combo with Style 'Simple' and an attempt to set it in a Combo of this type with ⎕WC or ⎕WS will generate a NONCE ERROR. Instead, the overall height of a Simple Combo is determined by the first element of the Size property.


RunMode Property
Applies To: OLEServer

Description

This property specifies the way in which an OLEServer object serves multiple clients.

RunMode is a character vector and may be 'MultiUse' (the default), 'SingleUse' or 'RunningObject'.

If RunMode is 'MultiUse', OLE will load a single copy of Dyalog APL and the appropriate workspace into memory. All OLE client processes will communicate with the same Dyalog APL session.

Note that in this case, each OLE client is actually connected to a separate instance of the corresponding APL namespace. That is to say, each client will appear to have its own private copy of the namespace. However, the individual functions and variables in the namespace are not physically copied until they are changed. This means that, in general, OLE clients will share APL functions but have private copies of the namespace variables. However, please remember that global objects in the workspace or in other namespaces are not instanced and will effectively be shared by all clients although they are not directly accessible to them.

If RunMode is 'SingleUse', OLE will load a separate copy of Dyalog APL and a separate copy of the appropriate workspace into memory for each OLE client. Each OLE client operates directly on the namespace associated with the object and not an instance of it.

If RunMode is 'RunningObject', OLE will load a single copy of Dyalog APL and the appropriate workspace into memory. All OLE client processes will communicate with the same Dyalog APL session and indeed with the same namespace. The namespace is not instanced and all objects, including exported variables, are shared by all clients.


SIPMode Property
Applies To: Form

Description

SIPMode applies only to PocketAPL. In versions of Dyalog APL for other platforms, it has no effect.

This is a Boolean property that specifies the behaviour of the Input Panel with respect to the Pocket APL GUI.

If SIPMode is 1, the Input Panel is automatically displayed when a GUI control that may receive character input (e.g. an Edit object) receives the input focus. The Input Panel is automatically hidden when the input focus moves to a control that does not receive character input.

If SIPMode is 0 (the default), the display of the Input Panel is not handled automatically, but may be controlled using the ShowSIP method.

Note that the user may display and hide the Input Panel manually, regardless of the value of SIPMode.


SIPResize Property
Applies To: Form

Description

SIPResize applies only to PocketAPL. In versions of Dyalog APL for other platforms, it has no effect.

This is a Boolean property that specifies the behaviour of a Form when the Input Panel is raised or lowered.

If SIPResize is 1 (the default), the Form generates a Configure event when the Input Panel is raised or lowered. Unless disabled or modified by a callback function, the Form is automatically resized to occupy the entire space above the Input Panel.

If SIPResize is 0, the Form does not generate a Configure event when the Input Panel is raised or lowered. This means that, at times, the lower part of the Form may be obscured by the Input Panel.


ScrollOpposite Property
Applies To: TabControl

Description

The ScrollOpposite property specifies that unneeded tabs scroll to the opposite side of a TabControl, when a tab is selected.

ScrollOpposite is a single number with the value 0 (normal scrolling) or 1 (scrolling to the opposite side); the default is 0.

The picture below illustrates a TabControl with ScrollOpposite set to 1, after the user has clicked Third Tab.

Setting ScrollOpposite to 1 implies that MultiLine is also 1. If you set ScrollOpposite to 1 in a ⎕WC statement, the MultiLine property will automatically be set to 1, even if you try to set MultiLine to 0 in the same statement. If you subsequently change MultiLine back to 0 using ⎕WS, this will work, but the effect is not useful and it is not supported.


SelDate Property
Applies To: Calendar

Description

The SelDate property identifies the range of dates that is currently selected in a Calendar object.

SelDate is a 2-element integer vector of IDN values that identifies the first and last dates that are currently selected.


SelImageIndex Property
Applies To: ComboEx TreeView

Description

The SelImageIndex property determines which bitmapped images in an ImageList correspond to items in a TreeView object when the item is selected. It is an integer vector whose length is the same as the number of items in the object and is ⎕IO dependent.

See also ImageIndex


SelItems Property
Applies To: Combo ComboEx Grid List ListView TreeView

Description

This property determines which (if any) of the items in an object are currently selected and highlighted. Except in a Grid, it is a Boolean vector with one element per item in the list. A value of 1 means "selected"; 0 means "not selected".

This property is used after a Select event to identify which item has been chosen. In a Combo or a List with Style 'Single' it will contain only a single 1.

SelItems should also be used to pre-set the contents of the edit field in a Combo box with Style 'Drop'. In Combo boxes with Style 'Simple' or 'DropEdit', the contents of the edit field may also be specified by the Text property. If you specify both, the value of Text takes precedence.

In a Grid, SelItems is a 2-element integer vector. The first element identifies the row and column coordinates respectively of the first cell(s) in the selected block(s) and the second, the row and column coordinates of the last cell(s) in the selected block(s). If the CellSelect property allows only a single block of cells to be selected, each set of coordinates is a 2-element vector. If the CellSelect property permits more than one block of cells to be selected, each set of coordinates is a 2-column matrix with one row per selected block, whose columns identify the first row and column, and the last row and column respectively of each selected block.


SelRange Property
Applies To: TrackBar

Description

The SelRange property specifies the selected range in a TrackBar which has Style 'Selection'. It is a 2-element numeric vector.


SelText Property
Applies To: ButtonEdit Combo ComboEx Edit RichEdit

Description

This property determines or identifies the portion of text in an object that is currently selected and highlighted. It can be used to pre-select all or part of the text to be replaced or deleted when the user starts typing. It can also be used to query the area of text that the user has highlighted. This can be useful if you want to implement your own cut/paste/replace features.

SelText is always a 2-element integer vector. If the field contents (defined by the Text property) is a vector, SelText is simple. Its first element is the index of the first selected character and its second element is 1 + the index of the last selected character. The length of the selected string is therefore obtained by subtracting the first element from the second.

If there are no characters selected, the two elements are equal and specify the current position of the input cursor.

If the contents is a vector of vectors or a matrix, each element of SelText is a 2-element vector. The first item in each of the elements indexes the vector (in a vector of vectors) or row (in a matrix). The second item in each element indexes the position of the character in the vector or along the row. Again, the value reported for the last character in the selected string is 1 + its index.


SelectionBorderWidth Property
Applies To: Grid

Description

The SelectionBorderWidth property specifies the width of the border that is drawn around the currently selected block of cells. It is expressed in pixels.


SelectionColor Property
Applies To: Grid

Description

The SelectionColor property specifies the colour used to highlight the currently selected block of cells and, if HighlightHeaders is 1, the corresponding row and column headings. See also SelectionColorAlpha.


SelectionColorAlpha Property
Applies To: Grid

Description

The SelectionColorAlpha property is a 2-element integer vector that specifies the degree of transparency or shade of the colour that is used to highlight the currently selected block of cells in a Grid. See SelectionColor.

The first element refers to the shade to be used when the Grid has the input focus; the second to when it doesn't. Each element is an integer in the range 0 (invisibly light) to 255 (fully dark).


ServerVersion Property
Applies To: OLEServer

Description

This property specifies the version number of an OLEServer object.

It is a 2-element integer vector that specifies the major and minor version numbers respectively.

The default value of ServerVersion is (1 0).


ShowCaptions Property
Applies To: ToolControl

Description

The ShowCaptions property specifies whether or not the captions of individual ToolButton objects are drawn. ShowCaptions is a property of the parent ToolControl object.

ShowCaptions is a single number with the value 0 (ToolButton captions are not shown) or 1 (ToolButton captions are shown); the default is 1

ShowCaptions allows you to toggle end-user preferences for the display of ToolButton captions, without having to set/clear individual captions one by one.


ShowCueWhenFocused Property
Applies To: ButtonEdit Edit

Description

This Boolean property specifies whether or not the text specified by the Cue property should be displayed once the user has tabbed into or clicked on the empty input field (and thus given it the focus). For an Edit object it applies only if the Style of the Edit object is 'Single'.


ShowDropDown Property
Applies To: ColorButton ToolControl

Description

The ShowDropDown property specifies whether or not a drop-down menu symbol is drawn in a ColorButton or alongside ToolButton objects which have Style 'DropDown'.

ShowDropDown is a single number with the value 0 (drop-downs captions are not shown) or 1 (drop-downs are shown); the default is 1.

ShowDropDown also affects the behaviour of ToolButton objects which have Style 'DropDown'.

If the ShowDropDown property of the parent ToolControl is 0, clicking the ToolButton causes the popup menu to appear. In this case, the ToolButton itself does not itself generate a Select event; you must rely on the user selecting a MenuItem to specify a particular action.

If the ShowDropDown property of the parent ToolControl is 1, clicking the dropdown button causes the popup menu to appear; clicking the ToolButton itself generates a Select event, but does not display the popup menu.

The following picture illustrates a ToolControl with ShowDropDown set to 1:


ShowInput Property
Applies To: Grid

Description

This property specifies whether or not the cells in a Grid are displayed using their associated input objects.

The ShowInput property is either a single Boolean value that applies to all the cells in a Grid, or it is a vector whose elements are mapped to individual cells via the CellTypes property. A value of 0 means that the corresponding cell is displayed normally. A value of 1 indicates that the cell is displayed using its associated input object, as it is when it is the current cell. ShowInput is relevant to cells displayed using Combo and Button objects.

The example below illustrates the appearance of a Grid in which ShowInput is set to 0 for the Job Title column and 1 for the Region and Permanent columns.

The appearance of the same Grid but with ShowInput set to 0 throughout is illustrated below:


ShowSession Property
Applies To: OLEServer

Description

This property specifies whether or not the APL Session window is displayed when an OLEServer object is started by an OLE client.

Its default value is 0 (hide Session).

Note that if RunMode is 'MultiUse', you may not in any way access the instances of the object that are being controlled by the client applications, even if only a single client is connected.


ShowThumb Property
Applies To: TrackBar

Description

The ShowThumb property specifies whether or not the thumb in a TrackBar object is visible. It is Boolean with a default value of 1 and it may be toggled on and off using ⎕WS.


SingleClickExpand Property
Applies To: TreeView

Description

The SingleClickExpand property specifies whether or not an item in a TreeView control is expanded when the user selects the item.

SingleClickExpand is a single number with the value 0 (the user must select the expand icon to cause the item to expand) or 1 (the item is expanded when the text of the item is selected); the default is 0.


Size Property

Applies To

Description

This is a 2-element numeric vector specifying the height and width of the object.

For the Bitmap object, Size is set and reported in pixels. Setting the Size of a Bitmap causes it to be scaled (up or down).

For all other objects, Size is reported and set in units defined by the Coord property and, if Coord is 'User', the XRange and YRange properties of the object's parent.

For the Root object, if Coord is 'Prop' the value of Size is (100,100). If Coord is 'Pixel' the value of Size reports the number of pixels on the screen.

For a Form or SubForm, the Size property defines the area within the object, and excludes its title bar, menu bar and border if these are present.

For a Combo object with a "drop-down" list, the first element of Size (height) is ignored. The height of the edit field is determined by the height of the font, while the size of the list box is determined by the Rows property.

Otherwise the Size property defines the total size of the object, including borders, edges etc.

When specifying Size, you can set the height or width to a default value (⎕WC) or leave it unchanged (⎕WS) by giving the corresponding element a value of ⍬.


Sizeable Property

Applies To

Description

This property determines whether or not an object can be directly resized by the user once it has been created by ⎕WC.

It is a single number with the value 0 (the object cannot be resized by the user) or 1 (the object may be resized by the user). The default is 1.

For a Form or SubForm, the Sizeable property may only be set by ⎕WC and cannot subsequently be altered using ⎕WS. An attempt to do so generates a NONCE ERROR. For a Form, the default value is 1 and the Form occupies a standard resizeable window with a border. Note that the value of Sizeable is independent of the values of the MaxButton and MinButton properties, so that a Form with MaxButton 1 can be maximised even though its Sizeable property is 0.

For other objects, the default value of the Sizeable property is 0. However, setting it to 1 (which may be done dynamically using ⎕WS) allows the user to resize it with the mouse.

In all these cases, when the user resizes an object, the object will generate a Configure (31) event.

Sizeable also applies to the Locator object. In this case, a value of 1 implies "rubberbanding" and a value of 0 means "no rubberbanding". See Locator object for further details.


SocketNumber Property
Applies To: TCPSocket

Description

The SocketNumber property is an integer whose value is the Window handle of the socket attached to the TCPSocket object and is generally a read-only property.

The only time that SocketNumber may be specified is when a server replicates (clones) a listening socket to which a client has just connected.


SocketType Property
Applies To: TCPSocket

Description

The SocketType property is a character vector that specifies the type of the TCP/IP socket. This is either Stream (which is the default), or UDP.

SocketType must be defined when the object is created and may not be set or changed using ⎕WS.

For two Dyalog APL applications to communicate, their TCPSocket objects must have the same SocketType.


SortItems Property
Applies To: List

Description

The SortItems property specifies whether or not the items in a List object are sorted.

It is Boolean with a default value of 0. If SortItems is 1, the items are automatically sorted in alphabetical order and the object provides word recognition capabilities for selecting an item from the keyboard.

Note that the value of the Items property reflects the order of the items displayed in the List object rather than the order in the array that was used to assign it.

This property may only be initialised when the object is created and cannot subsequently be changed.


SplitObj1 Property
Applies To: Splitter

Description

The SplitObj1 property specifies the name of, or ref to, one of up to two objects managed by a Splitter object. The object must be one of the following types:

Button | Calendar | Combo | Edit | Grid | Group
Label | List | ListView | MDIClient | ProgressBar | RichEdit
Scroll | Spinner | Static | StatusBar | SubForm | TabBar
TabControl | ToolBar | TrackBar | TreeView | UpDown |

If the Style property of the Splitter is 'Vert', the object specified by SplitObj1 is positioned at (0 0) and sized to occupy the space in its parent to the left of the Splitter, with the Splitter itself attached to its right edge.

If the Style property of the Splitter is 'Horz', the object specified by SplitObj1 is positioned at (0 0) and sized to occupy the space in its parent above the Splitter, with the Splitter itself attached to its bottom edge.

If SplitObj1 is empty, the Splitter manages the single object specified by SplitObj2 and the space to the left or above the Splitter is empty or controlled by another Splitter.


SplitObj2 Property
Applies To: Splitter

Description

The SplitObj2 property specifies the name of, or ref to, one of up to two objects managed by a Splitter object. The object must be one of the following types:

Button | Calendar | Combo | Edit | Grid | Group
Label | List | ListView | MDIClient | ProgressBar | RichEdit
Scroll | Spinner | Static | StatusBar | SubForm | TabBar
TabControl | ToolBar | TrackBar | TreeView | UpDown |

If the Style property of the Splitter is 'Vert', the object specified by SplitObj2 is initially positioned at (0 x), where x is half the width of the parent plus the Size of the Splitter, and sized to occupy the space in its parent to the right of the Splitter, with the Splitter itself attached to its left edge.

If the Style property of the Splitter is 'Horz', the object specified by SplitObj2 is initially positioned at (y 0), where y is half the height of the parent plus the Size of the Splitter, and sized to occupy the space in its parent below the Splitter, with the Splitter itself attached to its top edge.

If SplitObj2 is empty, the Splitter manages the single object specified by SplitObj1 and the space to the right or below the Splitter is empty or controlled by a second Splitter.


Start Property
Applies To: Circle Ellipse

Description

This property specifies one or more start-angles for an arc, pie-slice, or chord of a circle or ellipse. It may be used in conjunction with End which specifies end angles. Angles are measured counter-clockwise from the x-axis at the centre of the object.

If a single arc is being drawn, Start is a single number that specifies the start angle of the arc in radians (0 ⍎> ○2). If multiple arcs are being drawn, Start is either a single number as before (the start angle for several concentric arcs) or a numeric vector with one element per arc.

If End is not specified, the default value of Start is 0. Otherwise, the default value of Start is (0,¯1↓+\End).


StartIn Property
Applies To: BrowseBox

Description

The StartIn property is a character string that specifies the start point and root for a BrowseBox object.

Only the specified folder and its subfolders appear in the dialog box. The user cannot browse higher in the folder architecture than this folder.

The default value for StartIn is an empty vector which means that the root of the browse dialog is the desktop.


State Property
Applies To: Button Form SubForm TabButton ToolButton

Description

This property determines the state of a Button, TabButton, ToolButton, Form, or SubForm. It is a single number with the value 0 (the default), 1, or 2 (Form and SubForm).

If the Style property is 'Push', a State of 0 means that the pushbutton is displayed normally (out). If its State is 1, the pushbutton is displayed depressed (in).

If the Style property is 'Radio' or 'Check', 0 means "not selected" and 1 means "selected". Note that only one of a group of buttons with Style 'Radio' that share the same parent may have State 1. Setting State to 1 automatically deselects all the others in the group.

For a Form or SubForm, a value of State of 0 means that the Form is currently displayed in its "normal" state. 1 means that the Form is currently minimised (displayed as an icon). The value 2 indicates that the Form is maximised and displayed full-screen. The State of a Form can be changed using ⎕WS.


Step Property

Applies To

Description

This property determines the size of changes reported when the user clicks a scroll arrow (small change) or clicks on the body of the scrollbar (large change). The object's Thumb property increases or decreases by this amount.

For a Scroll object, Step is a 2-element numeric vector whose first element specifies the value of the "small change" and whose second element specifies the value of the "large change".

For a Form or SubForm, Step is a 4-element numeric vector. The first two elements refer to the Form's vertical scrollbar and the second two elements refer to the Form's horizontal scrollbar.

For the above objects, values of Step must be between 1 and the value of the Range property.

For a Locator object, Step is a 2-element integer vector (default value 1 1) that specifies the increments (in pixels) by which the size or position of the Locator changes in the Y and X directions respectively as the user moves the Locator.


Style Property

Applies To

Description

This property determines a particular style of object within the general category of Type. It is a character vector whose value depends upon the type of object.

For a Button, Style may be 'Push', 'Radio', 'Check', 'Toggle', 'CommandLink' or 'Split'.

'Push' specifies that the button appears and behaves like a pushbutton (sometimes also called a command button).

'Radio' means that the button is displayed as a small circle accompanied by a description. When the button is selected, the circle is filled in. In a group of buttons with Style 'Radio' that share the same parent, only one of them may be selected. This style of button is generally known as a "radio-button" or an "option button".

'Check' or 'Toggle' means that the button is displayed as a small box accompanied by a description. When the button is selected a cross appears in the box. This style of button is known as a "check-box".

'CommandLink' means that the button has an icon displayed to the left of its Caption, the appearance of which is controlled by the Elevated property. Note that this feature only applies if Native Look and Feel is enabled.

'Split' specifies a 'Push' button with an additional drop-down button, similar to that provided by a Combo object. Note that this feature only applies if Native Look and Feel is enabled.

For a Calendar object, The Style property may be either 'Single' (the default) or 'Multi'. If Style is 'Single', the user may select a single date. If Style is 'Multi', the user may select a contiguous range of dates.

For a Combo or ComboEx object, Style may be 'Simple' 'DropEdit' or 'Drop' (the default). 'Simple' specifies a simple combo box in which the associated list box is displayed at all times. The other two styles provide list boxes which "drop down" when the user clicks on a symbol displayed to the right of the Combo's edit field. A 'DropEdit' Style allows the user to type (anything) in the edit field. A 'Drop' Style forces the contents of the edit field to be either empty or one of the choices specified by Items.

For a DateTimePicker, Style may be either 'Combo' (the default) or 'UpDown'.

For an Edit object, Style may be 'Single' or 'Multi'. If Style is 'Single' the object displays only a single line of text and the user may not enter any more lines. If the Style is 'Multi' the number of lines displayed is governed by the Rows or Size property and the user may insert, add or delete lines as desired.

For FileBox, List, and ListView objects, Style may be 'Single' or 'Multi'. If the Style is 'Single'only one file or item can be selected. If Style is 'Multi', several files or items can be selected.

For an Icon, Style may be 'Large' (the default) or 'Small' and specifies the size of the icon (32x32 or 16x16) to be loaded from a file.

For a Locator, Style may be 'Point', 'Rect' (the default), 'Line' or 'Ellipse'. It specifies the shape that is drawn as the user moves the mouse.

For a MenuItem, Style may be 'Check' (the default) or 'Radio'. The latter specifies that within a contiguous block of such MenuItems, only one may have Checked set to 1. Setting Checked to 1 on any item in that group automatically sets Checked to 0 on the others. A radio style MenuItem that is checked has a small radio dot drawn to the left of its Caption.

For a MsgBox, the Style property determines the type of icon which is displayed in it. This is a character vector with one of the following values:

'Msg' | no icon (the default)
'Info' | information message icon
'Query' | query (question) icon
'Warn' | warning icon
'Error' | critical error icon

For a Static object, Style defines its appearance, and may be one of:

'BlackFrame' | 'BlackBox'
'GreyFrame' or 'GrayFrame' | 'GreyBox' or 'GrayBox'
'WhiteFrame' | 'WhiteBox'

A StatusField may be used to monitor the state of a key on the keyboard. If so, its Style property determines the key it monitors and may be one of the following:

CapsLock | Monitors state of Caps Lock key
ScrollLock | Monitors state of Scroll Lock key
NumLock | Monitors state of Num Lock key
KeyMode | Monitors the keyboard mode (APL/ASCII)
InsRep | Monitors the state of the Insert key

For a Splitter, the Style property specifies the orientation of the Splitter and may be 'Vert' (the default) or 'Horz'.

For a TabControl, the Style property determines the appearance of its TabButton children, and may be 'Tabs' (the default), 'Buttons' or 'FlatButtons'.

For a TCPSocket, Style is a character vector that specifies the type of data transmitted or received by the socket; it may be 'Char', 'Raw', or 'APL'. The value APL is valid only if the SocketType is 'Stream'.

For a ToolButton, the Style property specifies the behaviour of the button and may be 'Push' (the default), 'Check', 'Radio', 'DropDown', or 'Separator'.

For a ToolControl, the Style property determines the appearance of its ToolButton children and may be 'Buttons', 'FlatButtons' (the default), 'List' or 'FlatList'.

For a TrackBar, the Style property determines the appearance and behaviour of the TrackBar and may be 'Standard' (the default) or 'Selection'.


SysMenu Property
Applies To: Form SubForm

Description

This property determines whether or not a Form or SubForm has a "System Menu " box in the top-left corner of its border. Pressing the left mouse button in this box brings up the standard window control menu for the Form. Double clicking the box closes the Form.

SysMenu is a single number with the value 0 (no System menu box) or 1 (System Menu box is provided). The default is 1.

If any of the SysMenu, MaxButton, MinButton and Moveable properties are set to 1, the Form or SubForm has a title bar.


TabFocus Property
Applies To: TabControl

Description

The TabFocus property specifies the focus behaviour for the TabControl object and may

TabFocus is a character vector that may be 'Normal' (the default), 'Never' or 'ButtonDown'.

If TabFocus is 'Normal', the tabs or buttons in a TabControl do not immediately receive the input focus when clicked, but only when clicked a second time. This means that, normally, when the user circulates through the tabs, the input focus will be given to the appropriate control in the associated SubForm. However, if the user clicks twice in succession on the same tab or button, the TabControl itself will receive the input focus.

If TabFocus is 'ButtonDown', the tabs or buttons in a TabControl receive the input focus when clicked.

If TabFocus is 'Never', the tabs or buttons in a TabControl never receive the input focus. This allows the user to circulate through a set of tabbed SubForms without ever losing the input focus to the TabControl itself.


TabIndex Property

Applies To

Description

The TabIndex property reports the ⎕IO-dependent relative position of a child object within the list of child objects owned by its parent. If N is the number of children owned by an object, TabIndex is an integer between ⎕IO and (N-~⎕IO). The sequence of objects in this list is also used as the tabbing sequence, i.e. if the input focus is on the first child in the list, pressing Tab moves the input focus to the next child in the list.

When you create a child object, it is inserted in the list at the position specified by its TabIndex property. If TabIndex is omitted, it is appended to the end of the list.

If you subsequently change TabIndex, the object is moved to the corresponding position in the list.

Naturally, if you specify a value of TabIndex that is greater than the number of existing children, the object is inserted at or moved to the end of the list.


TabJustify Property
Applies To: TabControl

Description

The TabJustify property specifies, the positions at which the picture and caption are drawn within each tab or button implemented by a TabButton in a TabControl object.

TabJustify is a character vector that may be 'Centre', 'Edge', or 'IconEdge'. Its default value is 'Centre'.

If TabJustify is 'Centre', the picture and caption are arranged in the centre of the TabButton.

If TabJustify is 'Edge', the picture and caption are together aligned to the appropriate edge of the TabButton according to the value of Align.

If TabJustify is set to 'IconEdge', the caption is drawn centrally and only picture is aligned to the edge.

TabJustify is only honoured if fixed size tabs are in effect.


TabObj Property
Applies To: SubForm TabBar TabBtn TabButton TabControl

Description

TabObj is a ref or a character vector.

TabObj associates a SubForm with a TabBtn or a TabButton object. Selecting the associated TabBtn or TabButton causes the SubForm to be given the input focus.

For a SubForm, it specifies the name of, or ref to, a TabBtn or TabButton object that is to be associated with the SubForm. When referenced or queried using ⎕WG, TabObj returns a name if it was specified by a name, or a ref if it was specified by a ref.

For TabBtn and TabButton objects, TabObj is a read-only property that contains a ref to the associated SubForm.

For a TabBar or TabControl, TabObj is a read-only property that contains a ref to the currently selected TabBtn or TabButton.


TabSize Property
Applies To: TabControl

Description

The TabSize property specifies the size of fixed size tabs or buttons in a TabControl object.

By default, the size of the tabs may vary from one to another. Fixed size tabs may be obtained by setting the TabSize property.

TabSize is a 2-element numeric vector that specifies the height and width of the tab. The first element of TabSize may be set to ⍬ which means "default height".

To obtain fixed sized tabs with MultiLine set to 1, you must however also set the Justify property to 'None'.

If MultiLine is 1 and Justify is 'Right', TabSize is ignored.


Target Property
Applies To: BrowseBox

Description

The Target property is a read-only character string that specifies the chosen folder or other resource selected by the user in a BrowseBox object.

If the BrowseFor is 'Directory', Target will contain a directory name followed by the character "\". Otherwise, Target just contains the name.


TargetState Property
Applies To: TCPSocket

Description

The TargetState property reflects the intended final state of a TCPSocket object. Its possible values are as follows:

Stream | UDP
Client | Open
Server | Bound
Closed | Closed

Setting TargetState to Closed is the recommended way to close a socket. It informs APL that you want the socket to be closed, but only when it is safe to do so. When all the data has been sent, the TCPSocket will generate a TCPClose event which, unless a callback function decides otherwise, will cause the TCPSocket object to disappear.

To control socket closure, you may execute the following steps:

  1. Set TargetState to Closed
  2. Either:
    1. continue processing or
    2. wait (using ⎕DQ) for the TCPSocket to disappear or
    3. wait (using ⎕DQ) for the TCPClose event


Text Property

Applies To

Description

This property is associated with the text contents of an object and is a character array.

In a ButtonEdit, Combo, StatusField, Spinner, or a single-line Edit object, Text may be a simple scalar or a simple vector.

In a RichEdit, a multi-line Edit field or in a MsgBox, the value of Text may also be a simple matrix, or a vector of vectors. If so, "new-line" characters are appended to each row of the matrix, or to each vector in a vector of vectors, before being displayed. The user may insert or add a "new-line" character in a multi-line Edit by pressing Ctrl-Enter (Enter itself is used to press Buttons).

Note that if word-wrapping is in effect in a multi-line Edit object, the structure of Text does not correspond to the lines displayed.

In a Text object, the value of the Text property may be a simple scalar, an enclosed vector or matrix, a simple vector, a simple matrix, or a vector of enclosed vectors or matrices.

In general, the value of Text returned by ⎕WG has the same structure that was assigned to it by ⎕WC or by the most recent call to ⎕WS. New-Line characters entered by the users are removed.

You can copy text into the Windows Clipboard by using ⎕WS to set Text for a Clipboard object. In this case you may specify a simple character scalar, vector or matrix, or a vector of character vectors. If you are retrieving data from the clipboard that has been stored by another application, Text will be either a character vector or a vector of character vectors.

The Text property of a StatusField is updated automatically if its Style property is set to monitor the status of a key.


TextSize Property

Applies To

Description

This property has been replaced by the GetTextSize method, which should be used instead. TextSize is retained only for compatibility with previous versions of Dyalog APL.

TextSize is a "read-only" property that reports the size of the bounding rectangle of a text item in a given font. The result is given in the co-ordinate system of the object in question. This property is useful for positioning Text objects.

When you query TextSize you give the text item in whose size you are interested and, optionally, the name of a Font object. The text item may be a simple scalar, a vector or a matrix. If the Font is omitted, the result is given using the current font for the object in question. When you query TextSize on its own, you must enclose the argument to ⎕WG. This is because APL would otherwise not be able to distinguish between the text string and font name associated with 'TextSize' and other properties with the same name as these items.

Examples:

      '.' ⎕WG ⊂'TextSize' 'Hello World'
2.666666746 9.625

      'FNT1' ⎕WC 'FontObj' 'Arial' 72
      '.' ⎕WG ⊂'TextSize' 'Hello World' 'FNT1'
12 41.875

      '.' ⎕WS 'Coord' 'Pixel'
      '.' ⎕WG ('TextSize' (3 11⍴'Hello World')) 'Coord'
39 55  Pixel


Thumb Property

Applies To

Description

This property determines and reports the position of the thumb in an object.

For a Scroll object, the value of Thumb is a single integer whose minimum value is 1 and whose maximum value is defined by the Range property.

For ProgressBar, Spinner, UpDown and TrackBar objects, Thumb is a single numeric value in the range specified by the Limits property.

For a Form or SubForm object, Thumb is a 2-element vector whose elements refer to the position of the thumb in the object's own built-in vertical and horizontal scrollbars respectively.

For other objects, Thumb is a single numeric value in the range defined by the Limits property.


ThumbRect Property
Applies To: TrackBar

Description

ThumbRect is a read-only property that reports the position and size of the bounding rectangle of the thumb in a TrackBar object. It is a 4-element integer vector containing:

[1] | Vertical position of the top-left corner of the bounding rectangle
[2] | Horizontal position of the top-left corner of the bounding rectangle
[3] | Height of the bounding rectangle
[4] | Width of the bounding rectangle


TickAlign Property
Applies To: TrackBar

Description

TickAlign determines the position of the tick marks in a TrackBar object. For a horizontal TrackBar, TickAlign may be either 'Bottom' (the default), 'Top' or 'Both'. If TickAlign is 'Bottom', the ticks are drawn below the slider. If TickAlign is 'Top', the ticks are drawn above it. If TickAlign is 'Both', the ticks are drawn above and below.

For a vertical TrackBar, TickAlign may be either 'Right' (the default), 'Left', or 'Both' and similarly specifies to which side of the slider bar the ticks are drawn. Note that TickAlign may only be set when the TrackBar is created with ⎕WC and may not subsequently be altered using ⎕WS.

Note that ticks are not drawn if the value of HasTicks is 0


TickSpacing Property
Applies To: TrackBar

Description

The TickSpacing property specifies the spacing between each tick mark in a TrackBar object. It is an integer between 1 and the maximum value of the TrackBar which is defined by the 2nd element of the Limits property.

For example, if you set ('Limits' 10 50) and you specify ('TickSpacing' 10) you will obtain 5 ticks corresponding to the values 10, 20, 30, 40 and 50 along the slider bar.


Tip Property

Applies To

Description

The Tip property is a character vector or character matrix that specifies a "help" message which is to be displayed when the user positions the mouse pointer over the object. The Tip is displayed in a pop-up TipField object specified by the TipObj property.


TipObj Property

Applies To

Description

The TipObj property is a character vector or ref that specifies the name of, or ref to, a TipField object in which the "help" message defined by the Tip property is to be displayed. This message is displayed when the user positions the mouse pointer over the object.

Note that if TipObj is empty, its value is inherited from its parent. Thus setting TipObj on a Form defines the default TipField (and thus the default appearance of all Tips) for all the controls in that Form. Setting TipObj on Root defines the default TipField for the entire application.


TitleHeight Property
Applies To: Grid

Description

This property is a single number that specifies the height of the column titles displayed in a Grid object. It is expressed in the units specified by the Coord property of the Grid.


TitleWidth Property
Applies To: Grid

Description

This property is a single number that specifies the width of the row titles displayed in a Grid object. It is expressed in the units specified by the Coord property of the Grid.


Today Property
Applies To: Calendar DateTimePicker

Description

The Today property is an IDN that specifies today's date in a Calendar or DateTimePicker object. Its default value is the current date that is set on your computer.

See also CircleToday and HasToday properties.


ToolboxBitmap Property
Applies To: ActiveXControl OCXClass

Description

For an ActiveXControl, the ToolboxBitmap property is a character vector or ref that specifies the name of, or ref to, a Bitmap object that may be used by a host application to represent the ActiveXControl when its complete visual appearance is not required. For example, if you add an ActiveX control to the Microsoft Visual Basic development environment, its bitmap is added to the toolbox. The Bitmap should therefore be of an appropriate size, usually 24 x 24 pixels.

For an OCXClass, The ToolboxBitmap is a read-only property that reports a bitmap image associated with an OLE Control. This is intended for use by a GUI design tool. Its value is a 2-element vector. The first element is an integer matrix of pixel colours corresponding to the Bits property of a Bitmap object. The second element is a 3-column integer matrix specifying the colour map and corresponds to the CMap property of a Bitmap object.

Thus you can construct a Bitmap object directly from this property with an expression such as:

      'BM'⎕WC'Bitmap' '','GAUGE' ⎕WG'ToolboxBitmap'

where GAUGE is the name of an OCXClass.


TrackRect Property
Applies To: TrackBar

Description

TrackRect is a read-only property that reports the position and size of the bounding rectangle of the slider in a TrackBar object. It is a 4-element integer vector containing:

[1] | Vertical position of the top-left corner of the bounding rectangle
[2] | Horizontal position of the top-left corner of the bounding rectangle
[3] | Height of the bounding rectangle
[4] | Width of the bounding rectangle


Translate Property

Applies To

Description

This property applies to the Classic Edition only. In the Unicode Edition, its value is ignored.

This property specifies whether or not character data is to be translated. Translate is a character vector whose values may be 'Inherit', 'Translate', 'ANSI' or 'None'.

A value of 'Translate' means that all character property values and event parameters are translated to and from ⎕AV using the current output translation table (WIN.DOT).

'None' means that character data is passed between APL and the object with no translation.

If you set the value of the Translate property to 'ANSI', APL does not attempt to resolve characters as they are typed by the user via the Input Translate Table. Using Translate 'ANSI' in combination with the appropriate value of CharSet and the corresponding National Language keyboard will permit users to enter strings in non-western languages.

'Inherit' means that the object inherits its translation from its parent.

The default value for the Root and Printer objects is 'Translate', and for most other objects it is 'Inherit'.


Transparent Property
Applies To: Animation ButtonEdit ToolControl

Description

The Transparent property specifies whether or not a ToolControl is transparent.

Transparent is a single number with the value 0 (the default) or 1.

If Transparent is 1, the visual effect is as if the ToolButtons (and other controls owned by the ToolControl) were drawn directly on the parent Form as illustrated below.


Type Property

Applies To

Description

This property determines the type of an object. Its value is a character vector containing a valid object type. The Type property is set by ⎕WC and reported by ⎕WG, but may not be altered using ⎕WS.


TypeLibFile Property
Applies To: ActiveXControl OLEServer

Description

The TypeLibFile property is a read-only property that reports the name of the file in which the Type Library associated with a COM object is stored.


TypeLibID Property
Applies To: ActiveXControl OLEServer

Description

The TypeLibID property is a read-only property that reports the value of the globally unique identifier (GUID) of the Type Library associated with a COM object.


TypeList Property
Applies To: OCXClass OLEClient

Description

This property reports the names of all the special data types defined for a particular COM object. It is a vector of character vectors returned by ⎕WG. It may not be set using ⎕WC or ⎕WS. Further information about each data type may be obtained using GetTypeInfo.

Note that TypeList reports all of the data type names recorded in the .OCX file associated with the COM object. If several COM objects are provided within a single .OCX file, the entire set of data types reported may not necessarily be applicable to the Control in question.


Underline Property
Applies To: Font

Description

This property specifies whether or not the characters in the font associated with a Font object are underlined or not. It is either 0 (normal) or 1 (underlined). There is no default; the value of this property reflects the underline characteristic of the font allocated by Windows.


UndocksToRoot Property
Applies To: CoolBand Form SubForm ToolControl

Description

Specifies the parent adopted by an object when its Type changes to a Form as a result of an undocking operation.

UndocksToRoot is a single number with the value 0 or 1.

If UndocksToRoot is 1, the object becomes a Form that is a child of Root and therefore becomes completely independent of the Form in which it was previously docked.

If UndocksToRoot is 0, the object becomes a Form that is a child of the Form in which it was previously docked and is therefore always displayed on top of it. This setting is appropriate for a dockable toolbar.

The default value of UndocksToRoot is 1 if the object was originally created as a child of Root; otherwise it is 0.


VAlign Property
Applies To: Text

Description

This property determines the vertical alignment of text in the Text object. It is either a single integer value, or, if the Text object has several components, a corresponding vector of such values.

These may be :

0 | base aligned | the base line of the character is aligned on the y-coordinate specified by the Points property.
1 | half aligned | the centre of the character is aligned on the y-coordinate specified by the Points property.
2 | cap aligned | the top of the character is aligned on the y-coordinate specified by the Points property.
3 | bottom aligned | the bottom of the character cell is aligned on the y-coordinate specified by the Points property.
4 | top aligned | the top of the character cell is aligned on the y-coordinate specified by the Points property. This is the default.


VScroll Property

Applies To

Description

This property determines whether or not an object has a vertical scrollbar. It is a single integer with the value ¯2, ¯1, or 0.

VScroll may only be set when the object is created with ⎕WC and may not subsequently be changed with ⎕WS or assignment.

For a Form object, the value ¯1 specifies that the Form has a vertical scrollbar. A value of 0 (which is the default) means that it does not.

When applied to an Edit object, the value ¯2 specifies that the data is scrollable vertically, but only by using the cursor keys; a scrollbar is not provided. A value of ¯1 causes a scrollbar to be displayed (whether or not one is needed).

When applied to a List object, the value ¯2 specifies that the data is scrollable vertically, but only by using the cursor keys; a scrollbar is not provided. A value of ¯1 causes a scrollbar to be displayed if required (when the list of items exceeds the height of the object).

When applied to a Combo or ComboEx object, a value of ¯1 or ¯2 causes a scrollbar to be displayed, whether or not one is required.

For all these objects, a value of 0 inhibits scrolling altogether.

For a Scroll object, VScroll may be ¯1 or 0. If it is ¯1 the direction of the scrollbar is vertical. If both HScroll and VScroll are set to ¯1, HScroll takes precedence and forces VScroll back to 0.

For a StatusBar, TabBar or ToolBar with Align set to Left or Right, VScroll determines whether or not a vertical scrollbar is provided and how the object positions its children. If VScroll is 0 (the default) the object organises its children in multiple columns and does not provide a scrollbar. If VScroll is ¯1 or ¯2, the object organises its children in a single column and provides a mini scrollbar to allow those positioned beyond the bottom edge of the object to be scrolled into view. If VScroll is ¯1, the scrollbar is always shown. If VScroll is ¯2, it is only shown when needed.

For a Grid, VScroll may be 0 (no vertical scrollbar), ¯1 (scrollbar is displayed when required), ¯2 (same as ¯1) or ¯3 (scrollbar is always displayed).


ValidIfEmpty Property
Applies To: ButtonEdit Edit Spinner

Description

This property applies to an Edit object with Style Single and specifies whether or not an empty field is considered to be valid. It also applies to a Spinner. Its value is either 0 (an empty field is not valid) or 1 (an empty field is valid. If the FieldType is Numeric, LongNumeric, Currency, Date or Time, the default value for ValidIfEmpty is 0. Otherwise, its default value is 1.

If ValidIfEmpty is 0 and the user attempts to leave the Edit object by shifting the input focus to another control, or by selecting a Button or MenuItem, the Edit object will generate a BadValue event. The Text property will reflect the appearance of the field and be empty, but the Value property will not be changed.

If ValidIfEmpty is 1 and the FieldType is Numeric, LongNumeric, Currency, date or Time, the Value property will be set to ⍬ when the user clears the field and leaves it.


Value Property
Applies To: ButtonEdit Edit Label Spinner

Description

This property specifies or reports the numeric value associated with an Edit or Label object whose FieldType property is set to Numeric, LongNumeric, Date, LongDate or Time.

If the FieldType is Numeric or LongNumeric, the Value property contains a scalar number. If the FieldType is Date or LongDate, the Value property is an integer representing the date as the number of days since 1st January 1900. If the FieldType is Time, the Value property is an integer that contains the number of seconds since midnight.


Values Property
Applies To: Grid

Description

This property specifies the data values for the cells in a Grid object. Values must be a matrix whose elements are either single numbers, character scalars, character vectors or character matrices. This property is updated as the user moves around the Grid changing data.


VariableHeight Property
Applies To: CoolBar

Description

The VariableHeight property specifies whether or not a CoolBar displays bands at the minimum required height, or all the same height (that of the largest).

VariableHeight is a single number with the value 0 (same height) or 1 (variable height). The default is 1.


View Property
Applies To: ListView

Description

The View property specifies how the items in a ListView object are displayed. It is a character vector which may have one of the following values; 'Icon' (the default), 'SmallIcon', 'List' or 'Report'.

When View is 'Icon' or 'SmallIcon', the items are arranged row-wise with large or small icons as appropriate. When View is set to 'List', the items are arranged column-wise using small icons. When View is set to 'Report', the items are displayed in a single column using small icons but with the matrix specified by ReportInfo displayed alongside. In this format, the ListView also provides column headings which are specified by the ColTitles property. The alignment of these titles (and of the data in the columns beneath them) is defined by the ColTitleAlign property. Examples of different views are illustrated below.


Visible Property

Applies To

Description

This property specifies whether or not an object is currently visible. It is a single number with the value 0 (object is invisible) or 1 (object is visible). The default is 1. Setting Visible on and off is a way to pop a dialog box up and down as required.

Note that an invisible object is not necessarily inactive, and is capable of generating events. For example, a Button with a Cancel property of 1 will generate a Select (30) event (if enabled) whether or not it is visible. An invisible object will also respond to methods and events sent to it by ⎕NQ.


WantsReturn Property
Applies To: Edit RichEdit

Description

This Boolean property specifies the behaviour of the Enter key for a multi-line Edit (Style 'Multi') and a RichEdit object.

A value of 0 means that the Enter key is ignored by the Edit or RichEdit. Instead, the Enter key will (if appropriate) cause a Select event on a Button in the same Form. The user must press Ctrl+Enter to input a new line.

A value of 1 means that pressing the Enter key will introduce a new line into the object.

WantsReturn must be established when the object is created by ⎕WC and may not subsequently be altered using ⎕WS. Its default value is 0 in an Edit and 1 in a RichEdit.


WeekNumbers Property
Applies To: Calendar DateTimePicker

Description

The WeekNumbers property specifies whether or not a Calendar object displays week numbers.

WeekNumbers is a single number with the value 0 (week numbers are not shown) or 1 (week numbers are shown); the default is 0.


Weight Property
Applies To: Font

Description

This property specifies the degree of boldness of a font associated with a Font object. It is a number in the range 0 to 1000, where 0 represents very faint and 1000 represents very bold. There is no default; the value of this property reflects the degree of boldness of the font allocated by Windows.

In general, 400 means normal and 700 means bold.


WordFormat Property
Applies To: RichEdit

Description

The WordFormat property is identical to the CharFormat property except that it is used to apply formatting to the selected word or words in a RichEdit object. If the selection is empty but the insertion point is inside a word, the formatting is applied to the word. See CharFormat for further details.


Wrap Property
Applies To: ListView ProgressBar Spinner UpDown

Description

The Wrap property is Boolean and has a default value of 1.

For a ListView it specifies whether or not long labels (specified by the Items property) may be wrapped or not.

For a ProgressBar object it determines whether or not the object starts over again when it reaches its upper limit. In particular, if Wrap is 1, the value obtained when you set the Thumb property is given by the expression: LIMITS[1]+THUMB|LIMITS[2] where THUMB is the value to which you set the Thumb property and LIMITS is the value of the Limits property.

For a Spinner, Wrap determines what happens when the value in the Spinner reaches its upper or lower limit. If Wrap is 1 the Spinner will wrap around to its opposite limit. Otherwise it will stick.


XRange Property

Applies To

Description

XRange and YRange together determine a user-defined co-ordinate system. These properties are effective on the object's children which have Coord set to 'User'.

XRange is a 2-element numeric vector containing the x-coordinate of the top left and bottom right interior corners of the object respectively. See Coord for further details.


YRange Property

Applies To

Description

XRange and YRange together determine a user-defined co-ordinate system. These properties are effective on the object's children which have Coord set to 'User'.

YRange is a 2-element numeric vector containing the y-coordinate of the top left and bottom right interior corners of the object respectively. See Coord for further details.


Yield Property
Applies To: Root

Description

This property determines how frequently Dyalog checks the windows message queue. The message queue contains the underlying Windows messages for User interface events, such as mouse clicks, timers, and so on. Dyalog needs to check for the existence of these messages in order to pass them on to any GUI windows that may exist. In addition the windows message queue is used to handle interrupts and to implement the session window.

The value of Yield is an integer expressed in 1/1000's of a second. Its default value is 200. Yield defines the period of time allowed to elapse between the execution of successive lines of APL code before APL yields to Windows by requesting a message from the Windows queue. If Yield is set to zero APL does not explicitly yield.

Note that the value of this property only controls the yield frequency when APL is executing user-defined code. APL may also yield implicitly during ⎕DQ, ⎕NQ, ⎕WC, ⎕SR, ⎕WS and ⎕WG and in communicating with Auxiliary processors. Note that setting Yield to 0 (or to a very high value) during the execution of code that does not implicitly yield will effectively de-activate all other applications (including Program manager) and disable APL interrupts (Ctrl+Break). It should therefore be used with extreme caution.


ActivateApp Event

ActivateApp Event 139
Applies To: Root

Description

If enabled, this event is reported when the user switches to or from a Dyalog APL/W application.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ActivateApp' or 139
[3] | Activation flag | 0 or 1

The Activation flag is 0 when the user switches from Dyalog APL to another application.

The Activation flag is 1 when the user switches to Dyalog APL from another application.


AddCol Event

AddCol Event 153
Applies To: Grid

Description

If enabled, this event is reported by the Grid object if the user presses the Cursor Right key, and the current cell (CurCell) is within the last column on the Grid. The default action is to append a new column to the contents of the Grid. If you attach a callback function to this event and have it return a value of 0, a new column will not be appended to the Grid. Note that the event will not be generated unless the second element of the AutoExpand property is set to 1.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'AddCol' or 153
[3] | Column number | number of the new column (integer)

An application may insert a new column into a Grid by calling AddCol as a method. The argument is a 1 to 7-element array as follows:

[1] | Column number | number of the new column (integer)
[2] | Column title | character vector or matrix
[3] | Column width | integer
[4] | Undo flag | 0 or 1
[5] | Resize flag | 0 or 1
[6] | Title colour | negative integer or 3-element RGB vector
[7] | Line type | integer

If you are using default column headings, Column title will be ignored and the columns will be re-labelled with the default titles. If you have set ColTitles, the title you specify will be inserted. If you omit Column title, a blank title will be inserted.

Similarly, if you have not previously set CellWidths, ResizeCols, ColTitleFCol or ColLineTypes, or if you have given them a scalar value, the corresponding parameter will be ignored. However, if you have specified CellWidths, ResizeCols, ColTitleFCol or ColLineTypes to be a vector, the number you specify in the corresponding parameter will be inserted into the appropriate property vector.

If you omit to specify Column width for the new column, it will be assigned a default value; new values for the other properties default to 0.

Undo flag (default 1) specifies whether or not the addition of the new column may subsequently be undone by an Undo event.

To insert a new column before the first one, you must specify the Column number as 1 (or 0 if ⎕IO is 0). To add a new column after the last one, you may specify any number greater than the current number of columns. The data in the new column will be set to 0 if the Values property is numeric, or to an empty character vector otherwise.


AddRow Event

AddRow Event 152
Applies To: Grid

Description

If enabled, this event is reported by the Grid object if the user presses the Cursor Down key, and the current cell (CurCell) is within the last row on the Grid. The default action is to append a new row to the contents of the Grid. If you attach a callback function to this event and have it return a value of 0, a new row will not be appended to the Grid.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3 element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'AddRow' or 152
[3] | Row number | number of the new row (integer)

An application may insert a new row into a Grid by calling AddRow as a method. The argument is a 1 to 7-element array as follows:

[1] | Row number | integer
[2] | Row title | character vector or matrix
[3] | Row height | integer
[4] | Undo flag | 0 or 1
[5] | Resize flag | 0 or 1
[6] | Title colour | negative integer or 3-element RGB vector
[7] | Line type | integer

If you are using default row titles, Row title will be ignored and the rows will be re-labelled with default titles. If you have set RowTitles, the title you specify will be inserted. If you omit Row title, a blank title will be inserted.

Similarly, if you have not previously set CellHeights, ResizeRows, RowTitleFCol or RowLineTypes, or if you have given them a scalar value, the corresponding parameter will be ignored. However, if you have specified CellHeights, ResizeRows, RowTitleFCol or RowLineTypes to be a vector, the number you specify in the corresponding parameter will be inserted into the appropriate property vector. If you omit Row height, it will be assigned a default value; new values for the other properties default to 0.

Undo flag (default 1) specifies whether or not the addition of the new row may subsequently be undone by an Undo event.

To insert a new row before the first one, you must specify the Row number as 1 (or 0 if ⎕IO is 0). To add a new row after the last one, you may specify any number greater than the current number of rows. The data in the new row will be set to 0 if the Values property is numeric, or to an empty character vector otherwise.


AmbientChanged Event

AmbientChanged Event 533
Applies To: ActiveXContainer ActiveXControl

Description

If enabled, this event is reported when any of the ambient properties change in an application hosting an ActiveXControl object. The new values of the ambient properties are available from the FontObj, BCol and FCol properties of the ActiveXContainer.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'AmbientChanged' or 533
[3] | Property code | integer
[4] | Description | character vector

For properties supported by Dyalog APL, Property code and Description may be one of the following:

Property code | Description | Meaning
¯701 | DISPID_AMBIENT_BACKCOLOR | BCol has changed
¯703 | DISPID_AMBIENT_FORECOLOR | FCol has changed
¯705 | DISPID_AMBIENT_FONT | Font has changed
¯1 | DISPID_AMBIENT_UNKNOWN | Unknown

Note that other ambient properties may be reported, although these have no corresponding Dyalog APL property.


AnimStarted Event

AnimStarted Event 294
Applies To: Animation

Description

If enabled, this event is reported by an Animation object just before an AVI clip starts playing

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'AnimStarted' or 294

This event is reported for information only and cannot be disabled or modified in any way.


AnimStopped Event

AnimStopped Event 295
Applies To: Animation

Description

If enabled, this event is reported by an Animation object just after an AVI clip has stopped playing

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'AnimStopped' or 295

This event is reported for information only and cannot be disabled or modified in any way.


BadValue Event

BadValue Event 180
Applies To: ButtonEdit Edit Spinner

Description

If enabled, this event is reported by an Edit or Spinner object when the user enters invalid data into the object and then switches focus to another control or to another application. Data is invalid if it conflicts with the FieldType property, or for a Spinner if it is outside the range specified by the Limits property.

The default action of the event is to sound the bell (beep). You can disable this action by returning 0 from a callback function or by setting its action code to ¯1. Note that in neither case is the Value property of the object updated. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'BadValue' or 180
[3] | Object name | character vector

The third element of the event message is either the name of the control to which the user has switched the focus, or is an empty vector if the focus has gone to another application.


BalloonHide Event

BalloonHide Event 862
Applies To: SysTrayItem

Description

If enabled, this event is reported by an SysTrayItem object when a BalloonTip disappears for any reason other than it is dismissed by a timeout or because the user clicked the mouse.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'BalloonHide' or 862

This event is reported for information only and cannot be disabled or modified in any way


BalloonShow Event

BalloonShow Event 861
Applies To: SysTrayItem

Description

If enabled, this event is reported by an SysTrayItem object when a BalloonTip is displayed using the ShowBalloonTip method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'BalloonShow' or 861

This event is reported for information only and cannot be disabled or modified in any way


BalloonTimeout Event

BalloonTimeout Event 863
Applies To: SysTrayItem

Description

If enabled, this event is reported by an SysTrayItem object when a BalloonTip is dismissed by a timeout or because the user clicked the close (X) button..

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'BalloonTimeout' or 863

This event is reported for information only and cannot be disabled or modified in any way


BalloonUserClick Event

BalloonUserClick Event 864
Applies To: SysTrayItem

Description

If enabled, this event is reported by an SysTrayItem object when a BalloonTip is dismissed because the user clicked the mouse in the body of the BalloonTip. It is not reported when the user clicks the close (X) button.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'BalloonUserClick' or 864

This event is reported for information only and cannot be disabled or modified in any way


BeginEditLabel Event

BeginEditLabel Event 300
Applies To: ListView TreeView

Description

If enabled, this event is reported when the user clicks on an item in a ListView or TreeView object that has the focus, and signals the start of an edit operation. The default processing for the event is to display a pop-up edit box around the item and to permit the user to change its text.

You may disable the operation by setting the action code for the event to ¯1. You may prevent a particular item from being edited by returning 0 from a callback function. You may also initiate the edit operation by calling BeginEditLabel as a method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'BeginEditLabel' or 300
[3] | Item number | Integer. The index of the item.


CalendarDblClick Event

CalendarDblClick Event 273
Applies To: Calendar

Description

If enabled, this event is reported when the user double-clicks the left mouse button over a Calendar object.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CalendarDblClick' or 273
[3] | Item Number | integer
[4] | Mouse Button | integer
[5] | Shift State | integer. Sum of 1=shift key, 2=ctrl key, 4=Alt key
[6] | Element Type | integer

For the meaning of elements 3 and 6, see CalendarDown.


CalendarDown Event

CalendarDown Event 271
Applies To: Calendar

Description

If enabled, this event is reported when the user depresses the left mouse button over a Calendar object.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CalendarDown' or 271
[3] | Item Number | integer (see below)
[4] | Mouse Button | integer
[5] | Shift State | integer. Sum of 1=shift key, 2=ctrl key, 4=Alt key
[6] | Element Type | integer (see below)

The 6th element of the event message is one of the following values:

If the value of the 6th element of the event message is 2 (CALENDARDATE), the 3rd element is the corresponding date reported as an IDN.

If the value of the 6th element of the event message is 5 (CALENDARDAY), the 3rd element is the index of the corresponding weekday (0-6).

If the value of the 6th element of the event message is 6 (CALENDARWEEKNUM), the 3rd element is the date of the first (leftmost) day in the corresponding week, reported as an IDN.

Otherwise, the 3rd element of the event message is 0.


CalendarMove Event

CalendarMove Event 274
Applies To: Calendar

Description

If enabled, this event is reported when the user moves the left mouse button over a Calendar object.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CalendarMove' or 274
[3] | Item Number | integer
[4] | Mouse Button | integer
[5] | Shift State | integer. Sum of 1=shift key, 2=ctrl key, 4=Alt key
[6] | Element Type | integer

For the meaning of elements 3 and 6, see CalendarDown.


CalendarUp Event

CalendarUp Event 272
Applies To: Calendar

Description

If enabled, this event is reported when the user releases the left mouse button over a Calendar object.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CalendarUp' or 272
[3] | Item Number | integer
[4] | Mouse Button | integer
[5] | Shift State | integer. Sum of 1=shift key, 2=ctrl key, 4=Alt key
[6] | Element Type | integer

For the meaning of elements 3 and 6, see CalendarDown.


CellChange Event

CellChange Event 150
Applies To: Grid

Description

If enabled, this event is reported when the user changes the contents of a cell in a Grid object and then attempts to move to another cell or to another control outside the Grid.

The purpose of this event is to give the application the opportunity to perform additional validation before the update occurs (and to prevent it if necessary) or to update other cells in the Grid as a result of the change.

The default action for the CellChange event is to update the appropriate element of the Values property with the new data. This action can be disabled by returning 0 from the attached callback function. Notice however, that the user is not prevented from moving away from the cell. If you are using this event to perform additional validation and you require the user to correct the data before moving away, you may force the user back to the cell in question using the CellMove method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is an 8-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'CellChange' or 150
[3] | Cell row | integer
[4] | Cell column | integer
[5] | New data | number or character array
[6] | Object name | character vector (name of object to which the user has transferred focus)
[7] | New cell (row) | integer
[8] | New cell (column) | integer

If the user moves to another cell in the Grid, the 6th element of the event message is the name of the Grid object and elements 7 and 8 specify the new cell address (⎕IO dependent).

If the user switches the input focus to another control or selects a MenuItem, the 6th element of the event message contains the name of that control or MenuItem. If the user switches to another application, the 6th element of the event message is an empty character vector. In all these cases, the 7th and 8th elements are 0.

The 5th element of the event message contains the data value that will be used to update the Values property. This will be numeric if the FieldType of the associated Edit object is Numeric, LongNumeric, Date, LongDate or Time. Otherwise, it will be a character array.

An application can update an individual cell in the Grid under program control by calling CellChange as a method. If so, the New object, New cell row and New cell column parameters may be omitted.


CellChanged Event

CellChanged Event 164
Applies To: Grid

Description

If enabled, this event is reported after the user has changed the contents of a cell in a Grid object and then moved to another cell or to another control outside the Grid. The purpose of this event is to give the application the opportunity to perform calculations, and perhaps to update other cells in the Grid as a result of the change.

Note that this event is reported after the change has taken place, and after the Values property has been updated. Furthermore, neither setting the event action code to ¯1 nor returning 0 from a callback function has any effect. If you wish to validate the new data you should use the CellChange (150) event instead.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is an 5-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'CellChanged' or 164
[3] | Cell row | integer
[4] | Cell column | integer
[5] | New data | number or character array

The 5th element of the event message contains the data value that has been used to update the Values property. This will be numeric if the FieldType of the associated Edit object is Numeric, LongNumeric, Date, LongDate or Time. Otherwise, it will be a character array.

If you want to update an individual cell under program control, you may call CellChange, but not CellChanged, as a method.


CellDblClick Event

CellDblClick Event 163
Applies To: Grid

Description

If enabled, this event is reported when the user double-clicks a mouse button whilst over a cell in a Grid. The purpose of this event is to allow an application to enable some special action on double-click. This event may not be disabled.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 9 element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CellDblClick' or 163
[3] | Y | y-position of mouse (number)
[4] | X | x-position of mouse (number)
[5] | Button | button pressed (number) 1 = left button 2 = right button 4 = middle button
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down 4 = Alt key is down
[7] | Cell row | integer
[8] | Cell column | integer
[9] | Title index | integer

The y and x position of the mouse are reported relative to the top-left corner of the Grid.

The cell row and column are ⎕IO dependent

If the user clicks over a row title, the value reported for the column is ¯1, and the value reported for Title index is the index of that row title in RowTitles, or, if RowTitles is not defined, the row number. Column titles are handled in a similar fashion.


CellDown Event

CellDown Event 161
Applies To: Grid

Description

If enabled, this event is reported when the user presses a mouse button down whilst over a cell in a Grid. The purpose of this event is to allow an application to display a pop-up Menu or a Locator over a cell in a Grid or to take some other special action.

The default action is to generate a CellMove event which will then position the user on the new cell. This action can be prevented by returning 0 from the callback function, in which case the normally ensuing CellMove event will not occur.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is an 9 element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CellDown' or 161
[3] | Y | y-position of mouse (number)
[4] | X | x-position of mouse (number)
[5] | Button | button pressed (number) 1 = left button 2 = right button 4 = middle button
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down 4 = Alt key is down
[7] | Cell row | integer
[8] | Cell column | integer
[9] | Title index | integer

The y and x position of the mouse are reported relative to the top-left corner of the Grid.

The cell row and column are ⎕IO dependent

If the user clicks over a row title, the value reported for the column is ¯1, and the value reported for Title index is the index of that row title in RowTitles, or, if RowTitles is not defined, the row number. Column titles are handled in a similar fashion.

An application can position the user on a particular cell in a Grid by calling CellDown as a method, but it is recommended that a CellMove event is used instead.


CellError Event

CellError Event 157
Applies To: Grid

Description

If enabled, this event is reported when the user inserts invalid data into the Edit object associated with a cell in a Grid object and then attempts to move to another cell or to another control outside the Grid. It is also reported if the user selects a MenuItem.

The default action for the CellError event is to sound the bell (beep). This action can be disabled by returning 0 from the attached callback function. Whatever the result of the callback, the user will be prevented from moving to another cell in the Grid and the CurCell and Values properties will remain unchanged. The user is not prevented from switching to any other control or to another application. However, if and when the user returns to the Grid, the current cell (CurCell) remains the invalid one and the user may not select a different one until the invalid data in the cell has been corrected. If you wish to allow the user to move to another cell without correcting the data, you may do so by generating a CellMove event explicitly. However, the Values property will remain unchanged and the invalid contents of the Edit object will simply be discarded.

The event message reported as the result of ⎕DQ or supplied as the right argument to your callback function, is an 8-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'CellError' or 157
[3] | Cell row | integer
[4] | Cell column | integer
[5] | Invalid data | character vector
[6] | Object name | character vector (name of object to which the user has transferred focus)
[7] | New cell (row) | integer
[8] | New cell (column) | integer

If the user moves to another cell in the Grid, the 6th element of the event message is the name of the Grid object and elements 7 and 8 specify the cell address (⎕IO dependent).

If the user switches the input focus to another control or selects a MenuItem, the 6th element of the event message contains the name of that control or MenuItem. If the user switches to another application, the 6th element of the event message is an empty character vector. In all these cases, the 7th and 8th elements are 0.

The 5th element of the event message contains the character vector in the Text property of the associated Edit object which is inconsistent with its FieldType.


CellOver Event

CellOver Event 160
Applies To: Grid

Description

If enabled, this event is reported when the user moves the mouse pointer whilst over a cell in a Grid.

There is no default action for this event.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is an 9 element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CellOver' or 160
[3] | Y | y-position of mouse (number)
[4] | X | x-position of mouse (number)
[5] | Button | button pressed (number) 1 = left button 2 = right button 4 = middle button
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down 4 = Alt key is down
[7] | Cell row | integer
[8] | Cell column | integer
[9] | Title index | integer

The y and x position of the mouse are reported relative to the top-left corner of the Grid.

The cell row and column are ⎕IO dependent

If the user moves the mouse pointer over a row title, the value reported for the column is ¯1, and the value reported for Title index is the index of that row title in RowTitles, or, if RowTitles is not defined, the row number. Column titles are handled in a similar fashion.


CellUp Event

CellUp Event 162
Applies To: Grid

Description

If enabled, this event is reported when the user releases a mouse button down whilst over a cell in a Grid. This event is a companion to the CellDown event and could be used to hide a pop-up which was displayed in response to the CellDown. The CellUp event performs no default action and may not be disabled.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 9 element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CellUp' or 162
[3] | Y | y-position of mouse (number)
[4] | X | x-position of mouse (number)
[5] | Button | button released (number) 1 = left button 2 = right button 4 = middle button
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down 4 = Alt key is down
[7] | Cell row | integer
[8] | Cell column | integer
[9] | Title index | integer

The y and x position of the mouse are reported relative to the top-left corner of the Grid.

The cell row and column are ⎕IO dependent.

If the user clicks over a row title, the value reported for the column is ¯1, and the value reported for Title index is the index of that row title in RowTitles, or, if RowTitles is not defined, the row number. Column titles are handled in a similar fashion.

An application can position the user on a particular cell in a Grid by calling CellDown event as a method, but it is recommended that a CellMove event is used instead.


Change Event

Change Event 36
Applies To: ButtonEdit Combo Edit RichEdit Spinner

Description

If enabled, this event is reported when the user alters the text in a Combo or Edit object (by typing). The event is not applicable for a Combo with Style 'Drop' because this Style does not allow the user to alter data. The Change event is not reported repeatedly as the user edits the data. Instead, it is reported when the user indicates that he has finished with the field by :

  1. clicking on another object, or
  2. causing an event on another object (without altering the input focus) which will fire a callback function or cause ⎕DQ to terminate. This can occur if the user chooses a MenuItem, or fires a Button with the Default or Cancel property by pressing Enter or Esc, or selects an object using an accelerator key.

The purpose of the Change event is to allow the application to validate data which has been newly entered to the field, before proceeding with another action. It is for this reason that the event is fired not just when the input focus changes, but also when the user takes some action that could cause the application to do something else.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Change' or 36
[3] | Object name | character vector (name of object that is to receive the focus or generate an event)

If the focus is transferred to an external application, the third element is an empty vector.

The default processing for this event is to allow the focus to change (if applicable) and to reset the internal flag that indicates that the data in the field has changed.

If you disable the event by setting the "action" code to ¯1, or inhibit it by returning 0 from a callback, the focus change (if applicable) is allowed to proceed, but the internal flag is not reset. If you wish to prevent the focus change you must explicitly reset the focus back onto the object that generated the event.

If the event was generated because the user switched to another application, and you return a 0 from your callback (because the data was not valid), the flag marking the Combo or Edit as having been changed remains set. If the user returns to your application by re-focusing on the same Combo or Edit, nothing happens immediately, but because the field is marked as changed (the flag was not reset) you will get another Change event when he leaves it. However, if the user returns to your application in some other way, e.g. by focusing on another object or by selecting a MenuItem, a second Change event will be generated immediately.

The following function illustrates how Change events can be processed. The Check function referred to in line[4] is assumed to return 1 if the data is valid and 0 if not.

[0]   R←VALIDATE Msg
[1]  ⍝ Validates field contents after Change event
[2]
[3]  ⍝ Normal exit (R←1) if data is valid
[4]    →(R←Check⊃Msg)/Exit
[5]
[6]  ⍝ R now 0, so field remains marked as "changed"
[7]
[8]  ⍝ If user has switched to another application,
[9]  ⍝ we need take no further action because we will
[10] ⍝ get a second Change event when he returns.
[11]  →(''≡3⊃Msg)/Exit
[12]
[13] ⍝ Display error box (prepared earlier)
[14]   'ERR' ⎕WS 'Text' 'Data is invalid'
[15]   ⎕DQ'ERR'
[16]
[17] ⍝ Restore focus to bad field
[18]   ⎕NQ(⊃Msg)40
[19]
[20] Exit:


ClickComment Event

ClickComment Method 225
Applies To: Grid

Description

If enabled, a ClickComment event is generated when the user clicks the mouse in a comment window of a Grid.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ClickComment' or 225
[3] | Row | integer
[4] | Column | integer

The event message reports the co-ordinates of the cell. The default action is to raise the comment window so that it appears above all other, potentially overlapping, comment windows.

Note that if the comment window relates to a row or column title, the value reported in element [3] or [4] of the event message is ¯1.


ClipChange Event

ClipChange Event 120
Applies To: Clipboard

Description

If enabled, this event is reported when another application changes the contents of the Windows clipboard.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ClipChange' or 120


Close Event

Close Event 33

Applies To

Description

A Close event is generated when an object is destroyed. For a Form or SubForm, the event may be generated by the user selecting "Close" from its System Menu. In this case, the event is reported before the window is destroyed, and you may prevent it from going ahead by associating a callback function which returns a result of 0.

By trapping this event you can control termination of your application in many different ways. For example, you could:

  • automatically close all Forms in your application when the master Form is closed.
  • prevent the user from terminating the application if it is inappropriate at that time.
  • display an "Are you sure ?" MsgBox.

Note that although all the object's child GUI objects will also be destroyed, none of the child objects will generate a Close event.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Close' or 33


CloseUp Event

CloseUp Event 46
Applies To: DateTimePicker

Description

If enabled, this event is reported by a DateTimePicker object just before the drop-down calendar is hidden. It applies only if the Style of the DateTimePicker is 'Combo'.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'CloseUp' or 46

This event is reported for information only and cannot be disabled or modified in any way.


ColorChange Event

ColorChange Event 430
Applies To: ColorButton

Description

If enabled, this event is reported by a ColorButton object when the user chooses a colour from the colour selection drop-down.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ColorChange' or 430
[3] | New Colour | 3-element integer vector

The 3rd element of the event message contains the RGB value for the selected colour.

Note that the event is reported when the user chooses a colour, whether or not the newly selected colour differs from the one that was previously selected.

This event is reported for information only and cannot be disabled or modified in any way.


ColumnClick Event

ColumnClick Event 320
Applies To: ListView

Description

If enabled, this event is reported when the user clicks on the column heading in a ListView object. This event may not be disabled or affected by a callback function in any way.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ColumnClick' or 320
[3] | Column number | Integer
[4] | Button | button pressed (number) 1 = left button 2 = right button 4 = middle button
[5] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down


Configure Event

Configure Event 31

Applies To

Description

If enabled, this event is generated when the configuration of an object (position and/or size) is about to change.

For a Form, the event is generated when the Form is resized or moved by the user.

For any object other than a Form, it can occur in one of two ways. Firstly, whenever a Form is resized, the system (by default) re-arranges its children so as to maintain their relative position and size. This generates a Configure event (if enabled) for each one of them.

Secondly, it can occur as a result of the user resizing the object directly. This facility is enabled by setting the object's Sizeable property to 1.

Note that a Configure event is not reported when an object is moved using "drag & drop". See Dragable (property) and DragDrop (event) for details of this operation.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Configure' or 31
[3] | Y | y-position of top left corner
[4] | X | x-position of top left corner
[5] | H | height of object
[6] | W | width of object

For any object, the operation can be prevented by returning a scalar 0 from the callback function associated with the Configure event.

Full-Drag Considerations

The user may choose a system option, described here as full-drag, whereby the contents of the window are re-arranged during a resize operation.

If you manage the geometry of your controls using the Attach property, APL honours full drag during resize, changing the size and position of your controls dynamically for you.

However, if you manage the geometry of controls using Configure event callbacks, you should consider the following.

  1. If full drag is in enabled, APL generates Configure events during the resize operation, allowing you to dynamically alter the geometry of controls as you wish. However, the following restrictions apply:

  2. Configure callbacks will only be executed when the interpreter is idle. For example during a ⎕DQ or during Session input (6-space prompt). If the user attempts to move/resize a window that has Configure callbacks attached when the interpreter is busy, the move/resize is not started. This is similar to the operation in non full drag mode, where the move/resize is allowed but the callback does not execute until the interpreter again becomes idle.

  3. The callback cannot be traced. It is necessary to debug the callback code with full drag disabled.

  4. Any untrapped errors in the Configure callback will not halt execution in the normal way, but will instead be reported in the Status Window. Note that it is also not possible to trap such errors higher up the SI stack than the Configure Callback.

  5. There are some programming styles to be avoided if full drag Configure callbacks are to be processed correctly. For example events generated by monadic ⎕NQ within a Configure callback will not be processed until the entire resize operation has been completed.

  6. It is not possible to save a workspace from within a Configure Callback in full drag mode.

The above restrictions apply to Configure events when full drag is enabled, but only when full drag is enabled. The behaviour of Configure callbacks with full drag disabled is the same as for other events.


ContextMenu Event

ContextMenu Event 410

Applies To

Description

If enabled, this event is reported when the user performs the standard Windows action to display a ContextMenu. These include clicking/releasing the right mouse button and pressing F10.

If the object has its own standard context menu, for example an Edit object, the default action is to display this menu. If the object is dockable (see Docking Property), the default action is to display the standard (English) Dyalog APL docking menu.

You may use this event to display your own pop-up context menu, by ⎕DQ'ing it within a callback function. In this case, your callback function should return 0 to disable the standard context menu.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ContextMenu' or 410
[3] | (reserved) | Empty character vector
[4] | Y | y-position of the mouse (number)
[5] | X | x-position of the mouse (number)


Create Event

Create Event 34

Applies To

Description

If enabled, this event is reported after an object has been created. You may not nullify or modify the event with a 0-returning callback, nor may you generate the event using ⎕NQ, or call it as a method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Create' or 34
[3] | Flag | 1 = object was created by ⎕WC 0 = object was created by )LOAD, )COPY or ⎕OR

This event also applies to the Session object ⎕SE and may be used to fire a start-up function (in the ⎕SE namespace) when APL initialises.


DDE Event

DDE Event 50
Applies To: Root

Description

If enabled, a DDE event is generated whenever a DDE message is received by Dyalog APL. This will occur whenever a server notifies APL that the value of a shared variable has changed, and whenever a client application requests data from APL. If you have several shared variables, you can determine which of them has changed or whose value has been requested using ⎕SVS.

This event only applies to the Root object ".", so to enable it you must execute one of the following statements :

      '.' ⎕WS 'Event' 50 1
      '.' ⎕WS 'Event' 50 fn
      '.' ⎕WS 'Event' 50 fn larg

The first statement would cause ⎕DQ to terminate on receipt of a DDE event. The second would cause it to call "fn" each time. The third would do likewise but the value in "larg" would be supplied as its left argument.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DDE' or 50

Note: Due to the nature of DDE "conversations" messages may be received when in fact no change in the value of any shared variables has occurred. Your application code must therefore be prepared to cater for this situation.


DateTimeChange Event

DateTimeChange Event 267
Applies To: DateTimePicker

Description

If enabled, this event is reported by a DateTimePicker object when the user changes the DateTime value. This occurs when the user selects a new date from the drop-down calendar, or increments or decrements a date time element using the spinner buttons, or edits a datetime element using the keyboard. In the latter case, the event may not be generated until the input focus leaves the corresponding date time element.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DateTimeChange' or 267
[3] | IDN | integer
[4] | Hour | integer
[5] | Minute | integer
[6] | Second | integer

This event is reported for information only and cannot be disabled or modified in any way. It is not possible to enqueue this event; set the DateTime value instead.

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.


DisplayChange Event

DisplayChange Event 137
Applies To: Root

Description

If enabled, this event is reported when the user changes the screen resolution or number of colours. The event is reported for information only; you cannot prevent the change from occurring.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DisplayChange' or 137
[3] | Height | Integer. Number of pixels in the y-direction
[4] | Width | Integer. Number of pixels in the x-direction
[5] | Number of colours | Integer.


DockAccept Event

DockAccept Event 483
Applies To: CoolBand CoolBar Form SubForm ToolControl

Description

If enabled, this event is reported by a host object just before it accepts a client object docking operation. This event is reported (by the host) immediately after the DockRequest is reported (by the client).

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 7-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DockAccept' or 483
[3] | Client Object | ref or character vector
[4] | Edge | character vector
[5] | y-position | number
[6] | x-position | number
[7] | Outline rectangle | 4-element nested

Elements 4-7 of this event message are the same as those reported by DockMove, and the effect of a callback function is identical. See DockMove for further information.


DockCancel Event

DockCancel Event 485
Applies To: CoolBand CoolBar Form SubForm ToolControl

Description

If enabled, this event is reported by a client object when the user aborts a docking operation by pressing Escape.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DockCancel' or 485

This event is reported for information only and cannot be cancelled or inhibited in any way.

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.


DockEnd Event

DockEnd Event 484
Applies To: CoolBand CoolBar Form SubForm ToolControl

Description

If enabled, this event is reported by a client object after it has been successfully docked in a host object.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DockEnd' or 484

This event is reported for information only and cannot be cancelled or inhibited in any way.


DockMove Event

DockMove Event 481
Applies To: CoolBand CoolBar Form SubForm ToolControl

Description

If enabled, this event is reported by a host object when a dockable object (the client) is dragged over it. The event will only be reported if the name of the client object is included in the list of objects that the host object will accept, which is defined by its DockChildren property.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 7-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DockMove' or 481
[3] | Client Object | ref or character vector
[4] | Edge | character vector
[5] | y-position | number
[6] | x-position | number
[7] | Outline rectangle | (see below)

The 4th element of the event message Edge is a character vector that indicates along which edge of the host object the client object will be docked if the mouse button is released. It is either 'Top', 'Bottom', 'Left', 'Right' or 'None'. The latter indicates that the object will not be docked. An object will dock only if the mouse pointer is inside, and sufficiently near to an edge of, the host.

The 5th and 6th elements of the event message report the position of the mouse pointer in the host object.

The 7th element of the event message is a 4-element nested vector containing the y-position, x-position, height and width of a rectangle. If Edge is 'None', this is the bounding rectangle of the client object. Otherwise, the rectangle describes a docking zone in the host that the client object will occupy when the mouse button is released.

If a callback function returns 0, the system displays the bounding rectangle and not a docking zone, and the docking operation is inhibited. You could use this mechanism to prohibit docking along one or more edges, whilst allowing it along others.

A callback function may modify the event message to cause a different sized docking zone to be displayed, or to force docking along a particular edge.

The DockMove event is generated repeatedly as the docking object is dragged.


DockRequest Event

DockRequest Event 482
Applies To: CoolBand CoolBar Form SubForm ToolControl

Description

If enabled, this event is reported by a client object just before it is docked in a host object, when the user releases the mouse button.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 7-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DockRequest' or 482
[3] | Host Object | ref or character vector
[4] | Edge | character vector
[5] | y-position | number
[6] | x-position | number
[7] | Outline rectangle | 4-element nested

Elements 4-7 of this event message are the same as those reported by DockMove, and the effect of a callback function is identical. See DockMove for further information.


DockStart Event

DockStart Event 480
Applies To: CoolBand CoolBar Form SubForm ToolControl

Description

If enabled, this event is reported by a dockable object (one whose Dockable property is set to 1) when the user starts to drag it using the mouse.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DockStart' or 480

A callback function may prevent the docking operation from starting by returning 0.

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.


DragDrop Event

DragDrop Event 11

Applies To

Description

If enabled, this event is reported when the user drops one object (the dragged object) onto another (the target object). The event is generated by the target object, i.e. the object which is being dropped on.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 7-element vector as follows :

[1] | Target Object | ref or character vector
[2] | Event | 'DragDrop' or 11
[3] | Dragged Object | ref or character vector
[4] | Y | y-position of mouse pointer in the target object
[5] | X | x-position of mouse pointer in the target object
[6] | H | height of dragged object in the coordinate system of the target object
[7] | W | width of dragged object in the coordinate system of the target object
[8] | Shift State | numeric scalar containing the sum of the values associated with the Shift(1), Ctrl(2) and Alt(4) keys when the object was dropped.

Note that Y, H, X and W are all reported relative to the target object.


DropDown Event

DropDown Event 45

Applies To

Description

If enabled, this event is reported when the user clicks the drop-down button in a Combo, ComboEx, ColorButton, DateTimePicker or Menu object, just before the drop-down list, colour selection, calendar or -menu is displayed.

For a Button this event only applies if the Style of the Button is Split. For such a Button and for the ButtonEdit object there is no default processing for the event and it is the responsibility of the programmer to take appropriate action in a call-back function.

For a DateTimePicker this event only applies if the Style of the DateTimePicker is 'Combo'.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DropDown' or 45

This event is reported for information only and cannot be disabled or modified in any way.

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.


DropFiles Event

DropFiles Event 450

Applies To

Description

If enabled, this event is reported when the user drags a file icon or a set of file icons and drops them onto the object. The system takes no action other than to report the event.

Note that the event is only reported if AcceptFiles is set to 1.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DropFiles' or 450
[3] | Files | Vector of character vectors containing the file names.
[4] | Item number | Integer. The index of the item within the object onto which the file(s) was dropped. Applies only to objects that have an Items property such as List, ListView and TreeView.
[5] | Shift state | Integer. Sum of 1=shift key, 2=Ctrl key, 4=Alt key


DropObjects Event

DropObjects Event 455

Applies To

Description

If enabled, this event is reported when the user drags an object icon or a set of object icons from the Explorer Tool or Find Objects Tool (which are part of the Dyalog APL Session) and drops them onto the object. The system takes no action other than to report the event. You can use this event to extend drag-drop functionality in your Session. For example, you could perform an operation by drag-dropping an APL object icon onto a Button in the Session toolbar.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DropObjects' or 455
[3] | Objects | Vector of character vectors containing the object names.
[4] | Item number | Integer. The index of the item within the object onto which the file(s) was dropped. Applies only to objects that have an Items property such as List, ListView and TreeView. Otherwise this value is -1.
[5] | Shift state | Integer. Sum of 1=Shift key, 2=Ctrl key, 4=Alt key


DyalogCustomMessage1 Event

DyalogCustomMessage1 Event 95
Applies To: Form

Description

This event allows external applications and dynamic link libraries to insert events into the Dyalog APL/W message queue.

DyalogCustomMessage1 may be invoked from a C program as follows:

msg=RegisterWindowMessage("DyalogCustomMessage1");
SendMessage(hWnd,msg,wParam,lParam);

where hWnd is the window handle of the object in the Dyalog APL Workspace. If the object is a Form, this may be obtained using FindWindow(). If not, hwnd may be passed to the external process as an argument to a function.

The parameters wParam and lParam are reported as numeric arguments to the APL callback function.

NOTE: It is not possible to pass pointers to data in wParam or lParam. When the APL callback executes the pointers may not be valid.

If a callback function is attached to the event, the callback function will be run when the event reaches the top of the queue.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The result of a callback function is not returned to the external application.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'DyalogCustomMessage1' or 95
[3] | wparam | integer
[4] | lparam | integer


EndEditLabel Event

EndEditLabel Event 301
Applies To: ListView TreeView

Description

If enabled, this event is reported when the user signals completion of an edit operation in a ListView or TreeView object. This occurs when the item being edited loses the focus or when the user presses the Enter key. The default processing for the event is to update the item label (string) with the edited text in the pop-up edit box.

You may disable the update operation by setting the action code for the event to ¯1. You may also prevent the update from occurring by returning 0 from a callback function. You may specify the text used to update the item by returning the event message (containing the desired text) from a callback function. Finally, you may change the text of any item dynamically by calling EndEditLabel as a method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'EndEditLabel' or 301
[3] | Item number | Integer. The index of the item.
[4] | Text | character vector containing the text that will be used to update the item's label.


EndSplit Event

EndSplit Event 282
Applies To: Splitter

Description

If enabled, this event is reported when the user releases the left mouse button to signify the end of a drag operation on a Splitter object.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'EndSplit' or 282
[3] | Y | y-position of top left corner
[4] | X | x-position of top left corner
[5] | H | height of the Splitter
[6] | W | width of the Splitter

See also StartSplit, Splitting.


ExitApp Event

ExitApp Event 132
Applies To: Root

Description

If enabled, this event is reported when the user attempts to terminate a Dyalog APL/W application from the Windows Task List.

The Windows Task list displays the names of all running applications. The name displayed for a Dyalog APL/W application is defined by the Caption property of the system object Root. If you fail to define this property, there will be no entry for the application in the Task List.

If you wish to prevent the user from terminating your application from the Windows Task List, you may disable this event by setting its action code to ¯1. However, if you do this, your user may be puzzled as to why the operation does not work as expected. An alternative is to attach a callback function to the event which displays a message box. Not only does this allow you to provide user feedback, but you can provide confirm/cancel options. If your callback function returns a zero, your application will not be terminated.

Note that this event only provides for termination via the Windows Task List. See also the ExitWindows event.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ExitApp' or 132


ExitWindows Event

ExitWindows Event 131
Applies To: Root

Description

If enabled, this event is reported when the user attempts to terminate the Windows Operating System. When this is done, Windows gives all running applications the opportunity to prevent it. Typically, an application that has unsaved changes will display a dialog box warning the user of this situation and offering the opportunity to cancel the termination. The default action for this event is to allow Windows to close. You can prevent this by returning a zero from a callback function. You can also prevent the user from closing Windows down by disabling the event altogether. This is achieved by setting its action code to ¯1. In most cases this is less preferable than the callback method as it does not allow you to inform the user as to why Windows won't terminate.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ExitWindows' or 131
[3] | Flag | 0 or 1

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.


Expanding Event

Expanding Event 302
Applies To: Grid TreeView

Description

If enabled, this event is reported by a Grid or a TreeView object just before it is about to expand to show additional rows or children of the current item.

In a Grid, this occurs when the user clicks the picture or tree line in the row title.

In a TreeView, this occurs when the user double-clicks the item label or clicks in the button or on the tree line to the left of the item label.

The default processing for the event is to expand the tree at the corresponding point.

You may disable the expand operation by setting the action code for the event to ¯1. You may also prevent the expand from occurring by returning 0 from a callback function. You may expand an object dynamically under program control by calling Expanding as a method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Expanding' or 302
[3] | Item number | Integer. The index of the row or item.


Expose Event

Expose Event 32

Applies To

Description

If enabled, this event is reported when part or all of the object's window is exposed to view. Under normal circumstances, APL repaints the exposed region automatically. However, if you have drawn unnamed graphical objects (which are not managed by APL) you should use this event to redraw them when required. Note that APL will itself repaint any named objects in the region before reporting the event.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Expose' or 32
[3] | Y | y-position of top-left corner of exposed region
[4] | X | x-position of top-left corner of exposed region
[5] | H | height of exposed region
[6] | W | width of exposed region

This event cannot be disabled by setting its action code to ¯1. Similarly, setting the result of a callback function to 0 has no effect on it.


FileBoxCancel Event

FileBoxCancel Event 72
Applies To: BrowseBox FileBox

Description

If enabled, this event is reported when a FileBox is closed because the user has pressed the "Cancel" button or closed it.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'FileBoxCancel' or 72
[3] | File name | character vector containing the name of the currently selected file (empty if none)


FileBoxOK Event

FileBoxOK Event 71
Applies To: BrowseBox FileBox

Description

If enabled, this event is reported when a FileBox is closed because the user has pressed the "Open" or "Save" button.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'FileBoxOK' or 71
[3] | File name | character vector containing the name of the currently selected file (empty if none)


FontCancel Event

FontCancel Event 242

Applies To

Description

If enabled, this event is reported when the user has pressed the Cancel button or closed the font selection dialog box that is displayed by the ChooseFont method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'FontCancel' or 242


FontOK Event

FontOK Event 241

Applies To

Description

If enabled, this event is reported when the user has pressed the OK button in the font selection dialog box that is displayed by the ChooseFont method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'FontOK' or 241
[3] | Font | nested vector
[4] | Colour | RGB triplet

The font specification in the 3rd element of the event message is a 7-element nested vector that describes the chosen font. See Font Object for further details.

The colour specification in the 4th element of the event message is a 3-element integer vector of RGB values for the colour chosen by the user.


FrameContextMenu Event

FrameContextMenu Event 411
Applies To: Form SubForm

Description

If enabled, this event is reported when the user clicks and releases the right mouse button over the non-client area of an object, e.g. the title bar in a Form.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'FrameContextMenu' or 411
[3] | Y | y-position of the mouse (number)
[4] | X | x-position of the mouse (number)

For further details, see ContextMenu Event.


GesturePan Event

GesturePan Event 494

Applies To

Description

This event is reported when the user touches one or two fingers on an object and drags them .

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GesturePan' or 494
[3] | Flags | integer which reports the state of the gesture
[4] | Location | 2-element integer vector containing the y and x-position respectively of the point at which the gesture applies. These are reported in pixel coordinates relative to the origin (top-left corner) of the object reporting the event.
[5] | Distance | 2-element integer vector containing the high and low parts (words) of a 64-bit integer that indicates the distance between the two fingers. This will be (0 0) if only one finger is used.

The Flags parameter [3] which reports the state of the Gesture, is an integer with the value 0, 1 (GF_BEGIN), 2 (GF_INERTIA), 4 (GF_END) or 6 (GF_END+GF_INERTIA) with the following meanings:

Name | Value | Description
 | 0 | A gesture is in progress
GF_BEGIN | 1 | A gesture is starting.
GF_INERTIA | 2 | A gesture has triggered inertia.
GF_END | 4 | A gesture has finished.

The term inertia refers to built-in Windows processing which provides a standardised user-interface including smooth acceleration and de-acceleration of an object.

When the user first touches an object and begins to drag his finger(s), the object generates a GesturePan event with a Flags parameter of 1 (GF_BEGIN). Subsequently, if the user drags the object steadily it generates a series of GesturePan events with a Flags parameter of 0. When the user lifts his finger(s) away, the object generates a final GesturePan event, with a Flags parameter of 4 (GF_END).

If the user flicks an object, the system typically continues to generate GesturePan events after the user has ceased to touch the object. These events are generated in response to the acceleration and deceleration imparted by the flick, and the Flags parameter for these generated events will be 2 (GF_INERTIA) followed (for the last GesturePan event) by 6 (GF_END+GF_INERTIA).

No other event will be reported between the start and end of a series of GesturePan events.

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.

Returning zero from the callback disables any default handling by the operating system.


GesturePressAndTap Event

GesturePressAndTap Event 497

Applies To

Description

This event is reported when the presses one finger on an object and then taps it with a second finger.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GesturePressAndTap' or 497
[3] | Flags | integer which reports the state of the gesture
[4] | Location | 2-element integer vector containing the y and x-position respectively of the point midway between the two fingers. These are reported in pixel coordinates relative to the origin (top-left corner) of the object reporting the event..
[5] | Offset | 3-element integer vector whose first element is (currently) 0 and whose second and third elements contain the (y,x) offset of the second finger relative to the first.

The Flags parameter [3] which reports the state of the Gesture, is an integer with the value 0, 1 (GF_BEGIN), or 4 (GF_END):

Name | Value | Description
 | 0 | A gesture is in progress
GF_BEGIN | 1 | A gesture is starting.
GF_END | 4 | A gesture has finished.

When the user taps with his second finger, the object generates a GesturePressAndTap event with a Flags parameter of 1 (GF_BEGIN). Subsequently, until the user removes his first finger, it generates a series of GesturePressAndTap events with a Flags parameter of 0. When the user lifts his first finger away, the object generates a final GesturePressAndTap event, with a Flags parameter of 4 (GF_END)

No other event will be reported between the start and end of a series of GesturePressAndTap events.

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.

Returning zero from the callback disables any default handling by the operating system.


GestureRotate Event

GestureRotate Event 495

Applies To

Description

This event is reported when the user touches two fingers on an object and twists them clockwise or anticlockwise.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GestureRotate' or 495
[3] | Flags | integer which reports the state of the gesture
[4] | Location | 2-element integer vector containing the y and x-position respectively of the point midway between the two fingers. These are reported in pixel coordinates relative to the origin of the screen.
[5] | Angle | a scalar number which represents the angle of rotation of the twist measured in radians (0 → ○2) from the x-axis in a counter-clockwise direction.

The Flags parameter [3] which reports the state of the Gesture, is an integer with the value 0, 1 (GF_BEGIN),or 4 (GF_END) with the following meanings:

Name | Value | Description
 | 0 | A gesture is in progress
GF_BEGIN | 1 | A gesture is starting.
GF_END | 4 | A gesture has finished.

When the user first touches two fingers on an object and begins to twist, the object generates a GestureRotate event with a Flags parameter of 1 (GF_BEGIN). As the user continues to twist his fingers, the object generates a series of GestureRotate events with a Flags parameter of 0. When the user lifts one or both fingers away, the object generates a final GestureRotate event, with a Flags parameter of 4 (GF_END).

No other event will be reported between the start and end of a series of GestureRotate events.

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.

Returning zero from the callback disables any default handling by the operating system.


GestureTwoFingerTap Event

GestureTwoFingerTap Event 496

Applies To

Description

This event is reported when the user taps two fingers at the same time on an object

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GestureTwoFingerTap' or 496
[3] | Flags | integer which reports the state of the gesture
[4] | Location | 2-element integer vector containing the y and x-position respectively of the point midway between the two fingers. These are reported in pixel coordinates relative to the origin (top-left corner) of the object reporting the event..
[5] | Distance | 2-element integer vector containing the high and low parts (words) of a 64-bit integer that indicates the distance between the two fingers.

The Flags parameter [3] which reports the state of the Gesture, is always an integer with the value 5 (GF_BEGIN+GF_END).

Name | Value | Description
GF_BEGIN | 1 | A gesture is starting.
GF_END | 4 | A gesture has finished.

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.

Returning zero from the callback disables any default handling by the operating system.


GestureZoom Event

GestureZoom Event 493

Applies To

Description

This event is reported when the user touches two fingers on an object and moves them apart or towards each other.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GestureZoom' or 493
[3] | Flags | integer which reports the state of the gesture
[4] | Location | 2-element integer vector containing the y and x-position respectively of the centre point of the zoom (the point midway between the two fingers). These are reported in pixel coordinates relative to the origin (top-left corner) of the object reporting the event.
[5] | Distance | 2-element integer vector containing the high and low parts (words) of a 64-bit integer that indicates the distance between the two fingers.

The Flags parameter [3] which reports the state of the Gesture, is an integer with the value 0, 1 (GF_BEGIN),or 4 (GF_END) with the following meanings:

Name | Value | Description
 | 0 | A gesture is in progress
GF_BEGIN | 1 | A gesture is starting.
GF_END | 4 | A gesture has finished.

When the user first touches two fingers on an object and begins to move them apart or towards each other, the object generates a GestureZoom event with a Flags parameter of 1 (GF_BEGIN). As the user continues to moves the fingers apart or towards each other, the object generates a series of GestureZoom events with a Flags parameter of 0. When the user lifts one or both fingers away, the object generates it generates a final GestureZoom event, with a Flags parameter of 4 (GF_END).

No other event will be reported between the start and end of a series of GestureZoom events.

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.

Returning zero from the callback disables any default handling by the operating system.


GetDayStates Event

GetDayStates Event 266
Applies To: Calendar

Description

If enabled, this event is reported when a Calendar object requires the APL program to provide day state information for the range of dates it is about to display.

The Calendar object displays day numbers using either the normal or the bold font attribute. However, it does not store this information beyond the month or months currently displayed.

When the Calendar control scrolls (and potentially at other times), it generates a GetDayStates event to ask you (the APL program) to tell it which of the dates that are about to be shown, should be displayed using the bold font attribute.

If you wish any dates to be displayed using the bold font attribute, you must attach a callback function to this event which returns day state information in its result.

By default, all dates are displayed using the normal font attribute, so you need only do this if you want any dates highlighted in bold.

You may not disable or nullify the operation that caused GetDayStates to fire by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GetDayStates' or 266
[3] | First Date | an integer (IDN)
[4] | Last Date | an integer (IDN)
[5] | Bold Dates | an integer vector of IDNs.

When the callback function is invoked, the 3rd and 4th elements of the event message contain IDNs for the first and last date in the range of dates that the Calendar object is about to display. The 5th element of the event message contains those IDNs within this range of dates that the Calendar control already knows are to be displayed using the bold font attribute. This will typically be empty.

The result of your callback function should be the same event message with only the 5th element modified in any way. This should contain the IDNs of the dates (within the range specified by the 3rd and 4th elements) that are to be displayed using the bold font attribute.

Example:

Suppose that you keep a variable BOLD_DATES in the Calendar object. This variable is a vector of IDN values that defines those dates that the user has somehow identified as special and that you wish to display in bold, The following callback function could be applied:

    ∇ MSG←DAYSTATES MSG;MASK;⎕IO
[1]   ⍝ Callback function for the GetDayStates event
[2]   ⍝ Object (⊃MSG) contains a variable BOLD_DATES
[3]   ⍝ that defines ALL the IDNs that are to be displayed in bold
[4]   ⍝ We need to return only those that fall within the range
[5]   ⍝ of dates that are about to be displayed by the Calendar
[6]    ⎕CS⊃MSG
[7]    ⎕IO←1
[8]    MASK←BOLD_DATES≥3⊃MSG
[9]    MASK←MASK∧BOLD_DATES≤4⊃MSG
[10]   MSG[5]←⊂MASK/BOLD_DATES
     ∇

You may also set the font attribute for particular days by calling GetDayStates as a method.

For example, to set the bold attribute for IDN 36048 (11 September 1998) in a Calendar object called 'F.CAL1', you could execute the expression:

      F.CAL1.GetDayStates 36048 36048 36048

To clear the bold attribute for the same day:

      F.CAL1.GetDayStates 36048 36048 ⍬

Note that the Calendar object will ignore any IDNs you specify that are outside the range of dates that it is currently displaying.


GetTipText Event

GetTipText Event 325
Applies To: ListView TreeView

Description

If enabled, this event is reported by a TreeView or ListView object just before it displays a tip for a specific row.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GetTipText' or 325
[3] | Item index | Integer (⎕IO dependant)
[4] | SubItem index | Integer (⎕IO dependant, currently always equal to ⎕IO)
[5] | TipText | The text to be displayed.

Modifying and returning the 5th element of the argument to the callback function allows the application to change the displayed tip.

The text can be set to a character array of rank 2 or less.

The default processing for the event is to display the default tip (if there is one).

The associated callback is run immediately while the windows notification is still on the stack. See High-Priority Callback Functions.


GotFocus Event

GotFocus Event 40

Applies To

Description

If enabled, this event is generated when the user has moved the keyboard focus to a new object by clicking the left mouse button, pressing TAB, or using a cursor key.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GotFocus' or 40
[3] | Object name | character vector (name of object which previously had the focus)

The third element (object name) is empty if the focus was obtained from another application window.

The GotFocus event is generated after the focus has changed. The default processing is therefore to take no action. However, if you disable the event by setting its action code to ¯1, or inhibit it by returning a 0 from your callback function, the focus is automatically restored to the object (or external application) that had lost it.


GridCopy Event

GridCopy Event 191
Applies To: Grid

Description

If enabled, this event is reported when the user presses Ctrl+Insert and there are selected cells in the Grid. The default action of the event is to copy the contents of the selected block of cells to the clipboard. You may disable this effect entirely by setting the action code of the event to ¯1. You may also disable the copy operation by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'GridCopy' or 191
[3] | Start | 2-element integer vector or matrix containing the row, column address(es) of the top left cell(s) in the selected block(s)
[4] | End | 2-element integer vector or matrix containing the row, column address(es) of the bottom right cell(s) in the selected block
[5] | Values | 2-element nested vector. The first element is a matrix containing the values of the selected block(s) of cells. This is the data that will be copied to the clipboard. The second element is a Boolean matrix containing the values of the CellSet property for the selected block(s) of cells.

Note that the values of Start and End are sensitive to the index origin, ⎕IO.

If more than one block of cells is selected, Start and End are matrices whose rows identify the start and end cells of each of the selected blocks, and Data is the contents of the selected blocks catenated along the appropriate dimension according to their relative positions in the Grid.

You may copy cells under program control by calling GridCopy as a method.

To copy a specific block of cells to the clipboard whether or not they are selected, you must specify the Start and End parameters. For example, the following expression will copy the 3x3 block of cells in the top-left of the Grid (⎕IO is 1) to the clipboard:

     Gridname.GridCopy (1 1) (3 3)

If you omit these parameters, the currently selected block of cells will be copied to the clipboard. If no cells are selected, the entire contents of the Grid will be copied. i.e.

     Gridname.GridCopy ⍬

The data copied to the clipboard is registered in Dyalog (APL internal), Wk3 (Lotus), XlTable (Excel) and tab/new-line delimited text formats.


GridCopyError Event

GridCopyError Event 196
Applies To: Grid

Description

If enabled, this event is reported when the user presses Ctrl+Insert and there is more than one block of selected cells in the Grid and the blocks are non-conformable. The default action of the event is to generate a Beep. Setting the action code of this event to ¯1, or returning a 0 from a callback function attached to it, disables the Beep.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'GridCopyError' or 196
[3] |  | Zilde
[4] |  | Zilde
[5] | Start | A 2-column integer matrix whose rows identify the address of the first cell (row, column) of each of the selected blocks of cells.
[6] | End | A 2-column integer matrix whose rows identify the address of the last cell (row, column) of each of the selected blocks of cells.

Note that the values of Start and End are sensitive to the index origin, ⎕IO.


GridCut Event

GridCut Event 190
Applies To: Grid

Description

If enabled, this event is reported when the user presses Shift+Delete and there are selected cells in the Grid. The default action of the event is to copy the contents of the selected block(s) of cells to the clipboard and then to empty the selected cells. You may disable this effect entirely by setting the action code of the event to ¯1. You may also disable the cut operation by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'GridCut' or 190
[3] | Start | 2-element integer vector or matrix containing the row, column address(es) of the top left cell(s) in the selected block(s)
[4] | End | 2-element integer vector or matrix containing the row, column address(es) of the bottom right cell in the selected block
[5] | Data | 2-element nested vector. The first element is a matrix containing the values of the selected block(s) of cells. This is the data that will be copied to the clipboard. The second element is a Boolean matrix containing the values of the CellSet property for the selected block(s) of cells.

Note that the values of Start and End are sensitive to the index origin, ⎕IO.

If more than one block of cells is selected, Start and End are matrices whose rows identify the start and end cells of each of the selected blocks, and Data is the contents of the selected blocks catenated along the appropriate dimension according to their relative positions in the Grid.

The data copied to the clipboard is registered in Dyalog (APL internal), Wk3 (Lotus), XlTable (Excel) and tab/new-line delimited text formats.


GridDelete Event

GridDelete Event 193
Applies To: Grid

Description

If enabled, this event is reported when the user presses Delete and there are selected cells in the Grid. The default action of the event is to empty the selected cells. You may disable this effect entirely by setting the action code of the event to ¯1. You may also disable the delete operation by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'GridDelete' or 193
[3] | Start | 2-element integer vector or matrix containing the row, column address(es) of the top left cell(s) in the selected block(s)
[4] | End | 2-element integer vector or matrix containing the row, column address(es) of the bottom right cell(s) in the selected block(s)

Note that the values of Start and End are sensitive to the index origin, ⎕IO.

If more than one block of cells is selected, Start and End are matrices whose rows identify the start and end cells of each of the selected blocks.


GridDropSel Event

GridDropSel Event 195
Applies To: Grid

Description

If enabled, this event is reported when the user drag/drops a selected block of cells in the Grid. The default action is that the contents of the selected cells replace the values in the block of cells onto which they are dropped and this block now becomes selected.

You may disable the drag/drop facility entirely by setting the action code of the event to ¯1. You may also disable an individual drag/drop operation by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GridDropSel' or 195
[3] | Start | 2-element integer vector containing the row, column address of the top left cell in the selected block
[4] | Size | 2-element integer vector containing the number of rows and columns in the selected block
[5] | Target | 2-element integer vector containing the row/column address of the top left cell onto which the selected block is being dropped
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down
[7] | Undo flag | 0 or 1
[8] | Values | Matrix containing the values of the selected block of cells. This is the data that will replace the values in the target cells.
[9] | CellSet flags | Boolean Matrix containing the values of the CellSet property for the selected block of cells. This will replace the values of the CellSet property of the target cells.

The shift state in element 6 is intended to allow the APL programmer to implement an insert operation instead of a copy or move operation if required.

You may copy the contents of one block of cells to another by calling GridDropSel as a method. If so, you need only specify the Start, Size and Target parameters. Note that the result block becomes selected.

The Undo flag is always 1 if the event was generated by the user.


GridKeyPress Event

GridKeyPress Event 24
Applies To: Grid

Description

If enabled, this event is generated when the user presses and releases a key in a Grid cell.

The GridKeyPress is reported on the Grid, after the KeyPress event, which is reported on the Input object associated with the current cell.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GridKeyPress' or 24
[3] | Input Code | character scalar or vector
[4] | ASCII code | integer scalar
[5] | Key Number | integer scalar
[6] | Shift State | integer scalar
[7] | Input Object | ref or character vector

For a full description of elements [3-6], see KeyPress event.

The 7th element of the event message contains either a reference to, or the name of the Input object associated with the current cell and on which the corresponding KeyPress event has been reported.

The default action of the GridKeyPress event is to pass a KeyPress event message back to the appropriate Input object to be actioned. The GridKeyPress is reported on the Grid, after the KeyPress event on the Input object. If a callback on the Input object's KeyPress event returns 0 or if a callback on GridKeyPress returns 0, the keystroke will be ignored.


GridPaste Event

GridPaste Event 192
Applies To: Grid

Description

If enabled, this event is reported when the user presses Shift+Insert and there is data in the clipboard that is in a suitable format for the Grid. The default action of the event is to copy the contents of the clipboard into the currently selected block of cells, or, if no cells are selected, into the block of cells starting at the current cell (CurCell). Note that if there is a selected range of cells and the shape of the data being pasted does not exactly match the size of the selected range, the system generates a GridPasteError event in addition to the GridPaste event.

You may disable the paste facility entirely by setting the action code of the event to ¯1. You may also disable an individual paste operation by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GridPaste' or 192
[3] | Values | New values (taken from the clipboard) which are to replace the existing values of the block of cells defined by Start and End.
[4] | CellSet flags | Boolean Matrix containing the new values of the CellSet property for the block of cells defined by Start and End.
[5] | Start | 2-element integer vector containing the row, column address of the top left cell the selected block. If there is no selection, this is the address of the current cell(CurCell).
[6] | End | 2-element integer vector containing the row, column address of the bottom right cell in the selected block. If there is no selection, this is the address of the bottom right cell of the block starting at the current cell that will be overwritten

You can replace the contents of a contiguous block of cells with the data in the clipboard, or with an arbitrary matrix of values, by calling GridPaste as a method.

If you call GridPaste with an argument of ⍬, the data is taken from the clipboard; otherwise the data to be pasted is specified by the Values and CellSet flags parameters.. If you omit Start, data is pasted into the currently selected range of cells. If there are no cells selected, data is pasted starting at the current cell (CurCell). In either case, the block of replaced cells becomes selected.


GridPasteError Event

GridPasteError Event 194
Applies To: Grid

Description

If enabled, this event is reported when the user presses Shift+Insert and there is data in the clipboard, but the system is unable to paste the data into the Grid. This occurs if there is a currently selected block of cells whose shape does not match the shape of the data in the clipboard. It also occurs if there is no selected block of cells, and pasting the data in starting at the current cell (CurCell) would overflow the Grid. Setting the action code of this event to ¯1, or returning a 0 from a callback function attached to it, has no effect.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'GridPasteError' or 194
[3] | Values | Contents of the clipboard.
[4] | CellSet flags | Boolean array indicating which elements of the clipboard data are empty.
[5] | Start | 2-element integer vector containing the row, column address of the top left cell in the selected block. If there is no selection, this is the address of the current cell (CurCell).
[6] | End | 2-element integer vector containing the row, column address of the bottom right cell in the selected block. If there is no selection, this is the address of the bottom right cell of the block starting at the current cell that will be overwritten
[7] | Error Number | 4 (RANK ERROR) or 5 (LENGTH ERROR)


GridSelect Event

GridSelect Event 165
Applies To: Grid

Description

If enabled, this event is reported when the user performs or cancels the selection of a block of cells in a Grid object. This event is reported after the selection has changed. Setting its action code to ¯1 has no effect and the result of a callback function cannot be used to alter the selection that has been made. You may however control the user's ability to make selections using the CellSelect property.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'GridSelect' or 165
[3] | Start | 2-element integer vector or matrix containing the row, column address(es) of the top left cell(s) in the selected block(s)
[4] | End | 2-element integer vector or matrix containing the row, column address(es) of the bottom right cell(s) in the selected block

Note that the values of Start and End are sensitive to the index origin, ⎕IO.

If the selection is made with the mouse, the GridSelect event is reported when the left mouse button is released. If the selection is made using the cursor keys, the GridSelect event is reported when the Shift key is released.

The GridSelect event is also generated when the current selection is cancelled by clicking on a cell with the mouse or by pressing a cursor key.


HScroll Event

HScroll Event 39
Applies To: Form SubForm

Description

If enabled, this event is generated when the user attempts to move the thumb in a horizontal scrollbar in a Form or SubForm. This event occurs only in a Form whose HScroll property is set to ¯1 and is distinct from the Scroll event that is generated by a Scroll object. The event may be generated in one of three ways:

  • dragging the thumb.
  • clicking in one of the "arrow" buttons situated at the ends of the scrollbar. This is termed a small change, the size of which is defined by Step[3].
  • clicking in the body of the scrollbar. This is termed a large change, the size of which is defined by Step[4].

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'HScroll' or 39
[3] | Scroll Type | numeric
[4] | Position | numeric

The value of Scroll Type is 0 (drag), 1 or ¯1 (small change) or 2 or ¯2 (large change). The sign indicates the direction.

The value of Position is the new (requested) position of the thumb. Notice however, that the event is generated before the thumb is actually moved. If your callback function returns a scalar 0, the position of the thumb will remain unaltered.


HThumbDrag Event

HThumbDrag Event 442
Applies To: Form SubForm

Description

If enabled, this event is generated when the user attempts to drag the thumb in a horizontal scrollbar in a Form or SubForm. This event occurs only in a Form or SubForm whose HScroll property is set to ¯1 and is distinct from the Scroll event that is generated by a Scroll object.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'HThumbDrag' or 442
[3] | Position | numeric

The value of Position is the new (requested) position of the Thumb. Setting the action code of this event to ¯1, or returning a 0 from a callback function attached to it, has no effect.


Help Event

Help Event 400

Applies To

Description

If enabled, this event is reported when the user clicks on an object which has a callback defined for this event, the user having previously clicked on the Question (?) button in the title bar of the parent Form. The presence of the Question (?) button is determined by the value of the HelpButton property.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Help or 400
[3] | Y-coordinate | Number
[4] | X-coordinate | Number

The y and x-coordinates refer to the position of the mouse pointer in the object which was clicked on, and are reported in the coordinate system of that object.


HideComment Event

HideComment Event 224
Applies To: Grid

Description

If enabled, a HideComment event is generated just before a comment window is hidden as a result of the user moving the mouse-pointer away from a commented cell.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'HideComment' or 224
[3] | Row | integer
[4] | Column | integer

You may prevent the comment from being hidden by returning 0 as the result of a callback function.

Note that if the comment window relates to a row or column title, the value reported in element [3] or [4] of the event message is ¯1.

Invoked as a method, HideComment is used to hide a comment that has previously been displayed by ShowComment. For example, the following expression hides the comment associated with the cell at row 2, column 1.

      F.G.HideComment 2 1

If HideComment is called with an argument of ⍬, all comments are hidden.


Idle Event

Idle Event 130
Applies To: Root

Description

If enabled, this event is generated whenever APL looks to see if there is an event on the queue and finds it empty. Its purpose is to allow an application to perform some background processing when the user is not doing anything. It is unwise to use this event directly from the Session as it will occur repeatedly and may lock you out.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function is a 2-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'Idle' or 130


IndexChanged Event

IndexChanged Event 210
Applies To: Grid

Description

If enabled, this event is reported when the value of the Index property of a Grid has changed as a result of user interaction. The event is reported after the Grid has been scrolled. You may not modify or nullify the operation with a 0-return callback and you may not call IndexChanged as a method or generate this event using ⎕NQ. To cause a Grid to scroll, use ⎕WS to set its Index property.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'IndexChanged or 210
[3] | Row | Integer.
[4] | Column | Integer.


ItemDblClick Event

ItemDblClick Event 342
Applies To: ListView TreeView

Description

If enabled, this event is reported when the user double-clicks a mouse button when the mouse pointer is over an item in a ListView or TreeView object. This event is reported for information only and may not be controlled in any way using a callback function. Generating the event with ⎕NQ, or calling it as a method, has no effect.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ItemDblClick' or 342
[3] | Item number | Integer. The index of the item.
[4] | Mouse button | Integer.
[5] | Shift state | Integer. Sum of 1=shift key, 2=Ctrl key, 4=Alt key
[6] | Position | Integer. Indicates the position of the mouse-pointer within the item. It is either 2 (over the icon), 4 (over the label), 8 (over the line), or 16 (over the symbol).


ItemDown Event

ItemDown Event 340
Applies To: ListView TreeView

Description

If enabled, this event is reported when the user depresses a mouse button when the mouse pointer is over an item in a ListView or TreeView object. This event is reported for information only and may not be controlled in any way using a callback function. Generating the event with ⎕NQ, or calling it as a method, has no effect.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ItemDown' or 340
[3] | Item number | Integer. The index of the item.
[4] | Mouse button | Integer.
[5] | Shift state | Integer. Sum of 1=shift key, 2=Ctrl key, 4=Alt key
[6] | Position | Integer. Indicates the position of the mouse-pointer within the item. It is either 2 (over the icon), 4 (over the label), 8 (over the line), 16 (over the symbol) or 32 (to the right of the label).


ItemUp Event

ItemUp Event 341
Applies To: ListView TreeView

Description

If enabled, this event is reported when the user releases a mouse button when the mouse pointer is over an item in a ListView or TreeView object. This event is reported for information only and may not be controlled in any way using a callback function. Generating the event with ⎕NQ, or calling it as a method, has no effect.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ItemUp' or 341
[3] | Item number | Integer. The index of the item.
[4] | Mouse button | Integer.
[5] | Shift state | Integer. Sum of 1=shift key, 2=Ctrl key, 4=Alt key
[6] | Position | Integer. Indicates the position of the mouse-pointer within the item. It is either 2 (over the icon), 4 (over the label), 8 (over the line), or 16 (over the symbol).


KeyError Event

KeyError Event 23
Applies To: ButtonEdit Edit Spinner

Description

If enabled, this event is generated when the user presses and releases a key on the keyboard that is invalid for the FieldType of the object and has been ignored. This event is reported for information only and you may not disable it or modify it in any way.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'KeyError' or 23
[3] | Character | character scalar
[4] | Character code | integer scalar
[5] | Key Number | integer scalar
[6] | Shift state | integer scalar

In the Classic Edition, the resolution of the keystroke to a character (in ⎕AV) is performed using the Input Translate Table. In the Unicode Edition, the resolution is performed by the Operating System.

In the Unicode Edition, the Character Code is the Unicode code point of the character that the user entered. In the Classic Edition, it is a number in the range 0-255 which specifies the ASCII character that would normally be generated by the keystroke, and is independent of the Input Translate Table. If there is no corresponding ASCII character, the ASCII code reported is 0.

The key number is the physical key number reported by Windows when the key is pressed.

The Shift State indicates which (if any) of the Shift, Ctrl and Alt keys are down at the same time as the key is pressed. It is the sum of the following numbers :

Thus a Shift State of 3 indicates that the user has pressed the key in conjunction with both the Shift and Ctrl keys. A Shift State of 0 indicates that the user pressed the key on its own.


KeyPress Event

KeyPress Event 22

Applies To

Description

If enabled, this event is generated when the user presses and releases a key on the keyboard. It is reported for whichever object has the keyboard focus at the time.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'KeyPress' or 22
[3] | Input Code | character scalar or vector
[4] | Character code | integer scalar
[5] | Key Number | integer scalar
[6] | Shift state | integer scalar

If the keystroke resolves to a character, the Input Code is a character scalar.

If the keystroke resolves to a command recognised by Dyalog APL, such as UC (Up Cursor) or ER (Enter) the Input Code contains the corresponding 2-element character vector.

In the Classic Edition, the resolution of the keystroke to a character (in ⎕AV) or to a command, is performed using the Input Translate Table.

In the Unicode Edition, the resolution is performed by the Operating System. However, if the keystroke resolves to a navigation or control key (such as Cursor Up or Enter), the same 2-character "command" is reported. Note however that commands that are purely internal to Dyalog APL (such as Trace, commonly Ctrl+Enter) are not reported as such and the Input Code will be empty.

In the Unicode Edition, the Character Code is the Unicode code point of the character that the user entered. In the Classic Edition, it is a number in the range 0-255 which specifies the ASCII character that would normally be generated by the keystroke, and is independent of the Input Translate Table. If there is no corresponding ASCII character, the ASCII code reported is 0.

The key number is the physical key number reported by Windows when the key is pressed.

The Shift State indicates which (if any) of the Shift, Ctrl and Alt keys are down at the same time as the key is pressed. It is the sum of the following numbers :

1 | Shift key down
2 | Control key down
4 | Alt key down

Thus a Shift State of 3 indicates that the user has pressed the key in conjunction with both the Shift and Ctrl keys. A Shift State of 0 indicates that the user pressed the key on its own.

Example

     ∇ Key;Form1
[1]    'Form1'⎕WC'Form'('Event' 'KeyPress' 'Keycb')
[2]    ⎕DQ'Form1'
     ∇

     ∇ Keycb msg
[1]    DISPLAY msg
     ∇

On running function Key, the following output will be displayed as a result of the user pressing the following 5 keys in succession:

  1. "a"
  2. Shift+"a"
  3. Cursor Up
  4. β ("b" using a Greek keyboard)
  5. ⍳ (Ctrl+"i" using a UK APL keyboard)

Unicode Edition

┌→─────────────────────────────┐
│ ┌→────┐ ┌→───────┐           │
│ │Form1│ │KeyPress│ a 97 65 0 │
│ └─────┘ └────────┘ -         │
└∊─────────────────────────────┘
┌→─────────────────────────────┐
│ ┌→────┐ ┌→───────┐           │
│ │Form1│ │KeyPress│ A 65 65 1 │
│ └─────┘ └────────┘ -         │
└∊─────────────────────────────┘

┌→───────────────────────────────┐
│ ┌→────┐ ┌→───────┐ ┌→─┐        │
│ │Form1│ │KeyPress│ │UC│ 0 38 0 │
│ └─────┘ └────────┘ └──┘        │
└∊───────────────────────────────┘
┌→───────────────────────────────┐
│ ┌→────┐ ┌→───────┐             │
│ │Form1│ │KeyPress│ β 9075 90 1 │
│ └─────┘ └────────┘ -           │
└∊───────────────────────────────┘
┌→───────────────────────────────┐
│ ┌→────┐ ┌→───────┐             │
│ │Form1│ │KeyPress│ ⍳ 9075 73 2 │
│ └─────┘ └────────┘ -           │
└∊───────────────────────────────┘

Classic Edition

┌→─────────────────────────────┐
│ ┌→────┐ ┌→───────┐           │
│ │Form1│ │KeyPress│ a 97 65 0 │
│ └─────┘ └────────┘ -         │
└∊─────────────────────────────┘
┌→─────────────────────────────┐
│ ┌→────┐ ┌→───────┐           │
│ │Form1│ │KeyPress│ A 65 65 1 │
│ └─────┘ └────────┘ -         │
└∊─────────────────────────────┘
┌→───────────────────────────────┐
│ ┌→────┐ ┌→───────┐ ┌→─┐        │
│ │Form1│ │KeyPress│ │UC│ 0 38 0 │
│ └─────┘ └────────┘ └──┘        │
└∊───────────────────────────────┘
┌→────────────────────────────────┐
│ ┌→────┐ ┌→───────┐ ┌⊖┐          │
│ │Form1│ │KeyPress│ │ │ 223 66 0 │
│ └─────┘ └────────┘ └─┘          │
└∊────────────────────────────────┘
┌→────────────────────────────┐
│ ┌→────┐ ┌→───────┐          │
│ │Form1│ │KeyPress│ ⍳ 9 73 2 │
│ └─────┘ └────────┘ -        │
└∊────────────────────────────┘


Locator Event

Locator Event 80
Applies To: Locator

Description

If enabled, this event is generated when the user releases a mouse button, or presses any key (other than a cursor movement key) during a ⎕DQ on a Locator object.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 9-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Locator' or 80
[3] | Y | y-position of Locator after ⎕DQ
[4] | X | x-position of Locator after ⎕DQ
[5] | H | height of Locator after ⎕DQ
[6] | W | width of Locator after ⎕DQ
[7] | Mouse Button | number of the button which was released (0 if keystroke)
[8] | Keystroke | character scalar or vector containing the "Input Code" for the key that terminated the operation
[9] | Shift state | integer scalar


LostFocus Event

LostFocus Event 41

Applies To

Description

If enabled, this event is generated when the user transfers the keyboard focus away from the object in question.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'LostFocus' or 41
[3] | Object name | character vector (name of object that has received the focus)

If the focus is transferred to a window that is not part of the Dyalog APL GUI Interface, the third element is an empty vector.

The LostFocus event is generated after the focus has changed. The default processing is therefore to take no action. However, if you inhibit the event by returning a 0 from your callback function, the focus is automatically restored to the object that had lost it.


MDIActivate Event

MDIActivate Event 42
Applies To: SubForm

Description

This event is generated when the user activates a particular SubForm that is the child of an MDIClient. This occurs when the user clicks the left mouse button in the SubForm or selects it from the menu nominated for this purpose (see MDIMenu property). You may also call MDIActivate as a method.

Note that this event is reported after the action has taken place and cannot be disabled by returning 0 from a callback function or by setting its action code to ¯1.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'MDIActivate' or 42
[3] | Object name | character vector

Note that the 3rd element of the event message is either an empty vector or contains the name of the SubForm that was previously the active one in the same MDIClient.


MDIDeactivate Event

MDIDeactivate Event 43
Applies To: SubForm

Description

This event is generated when the user activates a different SubForm that is the child of an MDIClient, thereby de-activating the current one which causes this event. This occurs when the user clicks the left mouse button in another SubForm or selects it from the menu nominated for this purpose (see MDIMenu property). You may also call MDIDeactivate as a method.

Note that this event is reported after the action has taken place and cannot be disabled by returning 0 from a callback function or by setting its action code to ¯1.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'MDIDeactivate' or 43
[3] | Object name | character vector

Note that the 3rd element of the event message contains the name of the SubForm that has now been made the active one in the same MDIClient.


MouseDblClick Event

MouseDblClick Event 5

Applies To

Description

If enabled, this event is reported when the user presses and then releases a mouse button twice within a short space of time. The duration of this time is set through the Windows Control Panel.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'MouseDblClick' or 5
[3] | Y | y-position of mouse (number)
[4] | X | x-position of mouse (number)
[5] | Button | button double clicked (number) 1 = left button 2 = right button 4 = middle button
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down

In a graphical object (Circle, Ellipse, Image, Marker, Poly and Rect), the position of the mouse is reported relative to the top-left corner of its bounding rectangle.

If you enable MouseDown and MouseUp events in addition to MouseDblClick events, double-clicking a mouse button will generate the following sequence of events :

  1. MouseDown
  2. MouseUp
  3. MouseDblClick
  4. MouseUp


MouseDown Event

MouseDown Event 1

Applies To

Description

If enabled, this event is reported when the user presses one of the mouse buttons. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'MouseDown' or 1
[3] | Y | y-position of mouse (number)
[4] | X | x-position of mouse (number)
[5] | Button | button pressed (number) 1 = left button 2 = right button 4 = middle button
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down

If you enable this event it is advisable that you ALSO enable MouseUp events. Otherwise, the slight delay in running your callback function will cause the down and up sequence to be reversed.

In a graphical object (Circle, Ellipse, Image, Marker, Poly and Rect), the position of the mouse is reported relative to the top-left corner of its bounding rectangle.


MouseEnter Event

MouseEnter Event 6

Applies To

Description

If enabled, this event is reported when the user moves the mouse pointer into (over) an object. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'MouseEnter' or 6
[3] | Object name | character vector (name of previous object)

This event is generated when the user moves the mouse pointer across the boundary and into an object. The first element of the event message is the name of the object over which the mouse pointer now resides. The 3rd element of the event message contains the name of the object that was previously under the mouse pointer, or is an empty vector if the mouse pointer was not previously over a Dyalog APL/W object.


MouseLeave Event

MouseLeave Event 7

Applies To

Description

If enabled, this event is reported when the user moves the mouse pointer out of an object. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'MouseLeave' or 7
[3] | Object name | character vector (name of new object)

This event is generated when the user moves the mouse pointer across the boundary and away from an object. The first element of the event message contains the name of the object that previously contained the mouse pointer and which generated the event when it crossed its boundary. The third element contains the name of the object which now contains the mouse pointer or is an empty vector if the mouse pointer is not now over a Dyalog APL/W object.


MouseMove Event

MouseMove Event 3

Applies To

Description

If enabled, this event is reported when the user moves the mouse. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'MouseMove' or 3
[3] | Y | y-position of mouse (number)
[4] | X | x-position of mouse (number)
[5] | Button | button released (number) 1 = left button 2 = right button 4 = middle button
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down

In a graphical object (Circle, Ellipse, Image, Marker, Poly and Rect), the position of the mouse is reported relative to the top-left corner of its bounding rectangle.

Note that rapid movement of the mouse will not necessarily cause an overwhelming number of MouseMove events to be reported, as several small movements are automatically combined into one large one.


MouseUp Event

MouseUp Event 2

Applies To

Description

If enabled, this event is reported when the user releases one of the mouse buttons. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'MouseUp' or 2
[3] | Y | y-position of mouse (number)
[4] | X | x-position of mouse (number)
[5] | Button | button released (number) 1 = left button 2 = right button 4 = middle button
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down

In a graphical object (Circle, Ellipse, Image, Marker, Poly and Rect), the position of the mouse is reported relative to the top-left corner of its bounding rectangle.


MouseWheel Event

MouseWheel Event 8

Applies To

Description

If enabled, this event is reported when the user rotates the mouse wheel.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 9-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'MouseWheel' or 8
[3] | Y | y-position of mouse (number)
[4] | X | x-position of mouse (number)
[5] | Button | button pressed 1 = left button 2 = right button 4 = middle button
[6] | Shift State | sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down
[7] | Delta | integer
[8] | Lines | integer
[9] | Wheel Delta | integer

The value of Delta indicates the distance that the wheel is rotated, expressed in multiples or divisions of Wheel Delta. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user.

Lines specifies the number of lines to scroll when the wheel is rotated by I Mouse Delta unit. A value of ¯1 indicates that a whole screen is to be scrolled. These values are defined by the user's preferences (Control Panel/Mouse).


MsgBtn1 Event

MsgBtn1 Event 61
Applies To: MsgBox

Description

If enabled, this event is reported when the user responds to a MsgBox object by clicking its first (leftmost) button. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'MsgBtn1' or 61


MsgBtn2 Event

MsgBtn2 Event 62
Applies To: MsgBox

Description

If enabled, this event is reported when the user responds to a MsgBox object by clicking its second (from the left) button. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'MsgBtn2' or 62


MsgBtn3 Event

MsgBtn3 Event 63
Applies To: MsgBox

Description

If enabled, this event is reported when the user responds to a MsgBox object by clicking its third (from the left) button. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'MsgBtn3' or 63


PageActivate Event

PageActivate Event 360
Applies To: PropertyPage

Description

If enabled, this event is reported when the user switches from one PropertyPage to another in a PropertySheet object. This event is reported by the new page after the page change has occurred and the page change may not be disabled by a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PageActivate' or 360

You may select a particular page by calling PageActivate as a method, or by setting the PageActive or PageActiveObject property of the PropertySheet.


PageApply Event

PageApply Event 350
Applies To: PropertyPage

Description

If enabled, this event is reported when the user clicks the Apply button in a PropertySheet. Note however, that the event is actually reported by each of its PropertyPage objects whose Changed property is currently 1, i.e. the event is reported by each of the pages that the user has changed.

The default processing for this event is to set the Changed property of the PropertyPage to 0. If you disable the event or return a 0 from a callback function, the Changed property is not reset. Note that the Apply button in a PropertySheet is active if the value of the Changed property of any of the PropertyPage objects is 1.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PageApply' or 350


PageBack Event

PageBack Event 353
Applies To: PropertyPage

Description

If enabled, this event is reported when the user switches from one PropertyPage to another in a Wizard PropertySheet object by clicking its Back button. This event is reported by the old page after the page change has occurred and the page change may not be disabled by a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PageBack' or 353


PageCancel Event

PageCancel Event 351
Applies To: PropertyPage

Description

If enabled, this event is reported when the user presses the Cancel button in a PropertySheet object and is reported by the current PropertyPage. This event is reported for information only and may not be disabled by a callback function. However, the operation will also generate a Close event reported by the PropertySheet itself that may be disabled by a callback.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PageCancel' or 351


PageChanged Event

PageChanged Event 356
Applies To: PropertyPage

Description

If enabled, this event is reported when the Changed property of a PropertyPage is altered by user action. It is not reported if you reset the Changed property using ⎕WS.

The Changed property is reset by two separate user actions. It is set to 1 when the user alters any of the controls on the PropertyPage. It is reset to 0 when the user clicks the Apply button, although this action may be disabled by a callback function on the PageApply event.

The PageChanged event is reported for information only and may not itself be disabled or affected by a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PageChanged' or 356
[3] | Changed value | New value for the Changed property (0 or 1).


PageDeactivate Event

PageDeactivate Event 361
Applies To: PropertyPage

Description

If enabled, this event is reported when the user switches from one PropertyPage to another in a PropertySheet object. This event is reported by the old page after the page change has occurred and the page change may not be disabled by a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PageDeactivate' or 361


PageFinish Event

PageFinish Event 355
Applies To: PropertyPage

Description

If enabled, this event is reported when the user clicks the Finish button in a Wizard PropertySheet. This event is reported by current (last) PropertyPage. The event is reported for information only and cannot be affected by a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PageFinish' or 355


PageHelp Event

PageHelp Event 352
Applies To: PropertyPage

Description

If enabled, this event is reported when the user clicks the Help button in a Wizard PropertySheet. This event is reported by current PropertyPage. The event is reported for information only and cannot be affected by a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PageHelp' or 352


PageNext Event

PageNext Event 354
Applies To: PropertyPage

Description

If enabled, this event is reported when the user switches from one PropertyPage to another in a Wizard PropertySheet object by clicking its Next button. This event is reported by the old page after the page change has occurred and the page change may not be disabled by a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PageNext' or 354


PreCreate Event

PreCreate Event 534
Applies To: ActiveXControl

Description

If enabled, this event is reported when an instance of an ActiveXControl is created. The PreCreate event is generated at the point the instance is made.

An ActiveXControl also generates a Create event, which occurs after the PreCreate event at the point when the host application requires the instance to appear visually.

Note that at the time that PreCreate is generated, the ActiveXControl does not have a window.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'PreCreate' or 534


Protected Event

Protected Event 470
Applies To: RichEdit

Description

If enabled, this event is reported when the user attempts to alter protected text in a RichEdit. See CharFormat property.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Protected' or 470


Retracting Event

Retracting Event 304
Applies To: Grid TreeView

Description

If enabled, this event is reported by a Grid or a TreeView object just before it is about to retract to hide the children of the current item.

In a Grid, this occurs when the user clicks the picture or tree line in the row title.

In a TreeView, this occurs when the user double-clicks the item label or clicks in the button or on the tree line to the left of the item label, when the item is in its expanded state.

The default processing for the event is to retract the tree at the corresponding point.

You may disable the retract operation by setting the action code for the event to ¯1. You may also prevent the retraction from occurring by returning 0 from a callback function. You may retract Grid a or a TreeView dynamically under program control by calling Retracting as a method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Retracting' or 304
[3] | Item number | Integer. The index of the item.


Scroll Event

Scroll Event 37
Applies To: Scroll TrackBar

Description

If enabled, this event is generated when the user attempts to move the thumb in a scrollbar. This can be done in one of three ways:

  1. dragging the thumb.
  2. clicking in one of the "arrow" buttons situated at the ends of the scrollbar. This is termed a small change, the size of which is defined by Step[1].
  3. clicking in the body of the scrollbar. This is termed a large change, the size of which is defined by Step[2].

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Scroll' or 37
[3] | Scroll Type | numeric
[4] | Position | numeric

The value of Scroll Type is 0 (drag), 1 or ¯1 (small change) or 2 or ¯2 (large change). The sign indicates the direction.

The value of Position is the new (requested) position of the thumb. Notice however, that the event is generated before the thumb is actually moved. If your callback function returns a scalar 0, the position of the thumb will remain unaltered.


SelDateChange Event

SelDateChange Event 265
Applies To: Calendar

Description

If enabled, this event is reported when the user changes the date, or range of dates, that is selected in a Calendar object. This event is also reported when the Calendar object is scrolled and the selection changes automatically to another month.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'SelDateChange' or 265
[3] | First Date | an integer (IDN)
[4] | Last Date | an integer (IDN)


Select Event

Select Event 30

Applies To

Description

For a Button with Style 'Push' this event is generated when the user "pushes" the button. This can be done by clicking the left mouse button, or by pressing the Enter key or the space bar when the Button has the focus. The Select event can also be generated when the Button does not have the focus, by pressing the Enter key when its Default property is 1 or by pressing the ESC key when its Cancel property is 1.

For a Button with Style 'Radio' or 'Check' this event is generated when the user toggles the button from one state to another. This can be achieved by clicking the left mouse button or by pressing the space bar when the Button has the focus.

For a Combo or List object, a Select event is generated when the user selects an item from the list, whether by pressing the arrow keys or by clicking the left mouse button.

For a MenuItem, a Select event is generated when the user chooses the item.

For all other objects, this event is generated when the user presses the keys associated with the object's Accelerator property.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | Event code


ServiceNotification Event

ServiceNotification Event 94
Applies To: Root

Description

This event is generated in an APL service whenever the Windows Service Control Manager (SCM) requests a change of state. See APL Application as a Service.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ServiceNotification' or 94
[3] | Action | Integer.
[4] | State | 7-element integer vector

For further details, see the on-line documentation for SERVICE_STATE and the function HashDefine in the sample workspace aplservice.

The state of a Windows service is determined by the user and the Windows Service Control Manager (SCM).

When the SCM requests a change of state, the APL interpreter responds by setting its state to the corresponding pending level (SERVICE_STOPPED_PENDING, SERVICE_RUNNING_PENDING or SERVICE_PAUSED_PENDING) and then generates a ServiceNotification event.

It is the responsibility of the APL service to process this event, perform the appropriate application tasks, and then respond (to the SCM) by calling the SetServiceState method to confirm that the service has reached the desired state.


SetColSize Event

SetColSize Event 176
Applies To: Grid ListView

Description

If enabled, this event is reported when the user changes the width of a column in a Grid or ListView object, or changes the width of the row titles in a Grid. This may be done by dragging a border with the mouse or by double-clicking over a border. In the former case, the default action is to adjust the width of the appropriate column or the width of the row title area to the size selected by the user. In the latter case, the default action is to adjust the width to the maximum required to display all the data.

In either case, you can disable the default action by setting the event action code to ¯1 or you can selectively prevent a particular resize operation from taking place by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'SetColSize' or 176
[3] | Column number | Integer. This is sensitive to the index origin, ⎕IO, but is ¯1 if the user has resized the row titles in a Grid.
[4] | Width | Integer containing the value of the (new)column width. This is ¯3 if the user has double-clicked to request automatic width adjustment.
[5] | Undo flag | 0 or 1

You can resize a column or resize the row titles under program control by calling SetColSize as a method. If you specify ¯1 as the Width parameter, the column will be resized to its default width .. If you specify a value of ¯2 the column will be resized to fit the data. The following expression will size the first NCOLS columns of a Grid called F.G to fit the data and the column titles:

      {F.G.SetColSize ⍵ ¯3}¨⍳NCOLS

The Undo flag is applicable only to a Grid object and is always 1 if the event was generated by the user.


SetItemPosition Event

SetItemPosition Event 322
Applies To: ListView

Description

If enabled, this event is reported when the user drag-drops an item within a ListView object. This operation may be disabled by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 7-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'SetItemPosition' or 322
[3] | Item number | Integer. The index of the item.
[4] | Y-position | Integer. New y-position of the item.
[5] | X-position | Integer. New x-position of the item.
[6] | Button number | Integer. The mouse button used to perform the drag.
[7] | Shift State | Integer: Sum of shift key codes (number) 1 = Shift key is down 2 = Ctrl key is down 4 = Alt key is down


SetRowSize Event

SetRowSize Event 175
Applies To: Grid

Description

If enabled, this event is reported when the user changes the height of a row or changes the height of the column titles. This may be done by dragging a border with the mouse or by double-clicking over a border. In the former case, the default action is to adjust the height of the appropriate row or the height of the column title area to the size selected by the user. In the latter case, the default action is to adjust the height to the maximum required to display all the data.

In either case, you can disable the default action by setting the event action code to ¯1 or you can selectively prevent a particular resize operation from taking place by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'SelRowSize' or 175
[3] | Row number | Integer. This is sensitive to the index origin, ⎕IO, but is ¯1 if the user has resized the column titles.
[4] | Height | Integer containing the value of the (new) row height. This is ¯3 if the user has double-clicked to request automatic height adjustment.
[5] | Undo flag | 0 or 1

You can resize a row or resize the column titles under program control by calling SetRowSize as a method. If you specify ¯1 as the Height parameter, the row will be resized to its default height .. If you specify a value of ¯2 the row will be resized to fit the data. The following expression will set the heights of first NROWS rows of a Grid called F.G to fit the data and the row titles.

      {F.G.SetRowSize ⍵ ¯3}¨⍳NROWS

The Undo flag is always 1 if the event was generated by the user.


SetSpinnerText Event

SetSpinnerText Event 421
Applies To: Spinner

Description

If enabled, this event is generated when the user clicks one of the spin buttons in a Spinner object. The event is reported after the value of the Thumb property has been updated but before the Text property has been changed. You may use this event to set the text in the Spinner dynamically instead of relying on it being updated automatically.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'SetSpinnerText' or 421
[3] | Thumb value | Integer. The new value of the Thumb property resulting from the user pressing one of the spin buttons.
[4] | Text | The text that is about to be put into the edit field.

The SetSpinnerText event is designed to allow you to dynamically set the text in the Spinner in response to a spin button. It might be used in circumstances where the set of items you wish to present to your user is not predictable in advance.


ShowComment Event

ShowComment Event 223
Applies To: Grid

Description

If enabled, a Grid will generate a ShowComment event when the user rests the mouse pointer over a commented cell. You may use this event to modify the appearance of the comment dynamically.

The event message reported as the result of ⎕DQ or supplied as the right argument to your callback function is an 8-element vector containing the following:

[1] | Object | ref or character vector
[2] | Event | 'ShowComment' or 223
[3] | Cell row | integer
[4] | Cell column | integer
[5] | Comment text | character vector
[6] | Window height | integer, pixels
[7] | Window width | integer, pixels
[8] | Tip behaviour flag | (1 = yes; 0 = no)

A callback function may modify the standard behaviour. You may prevent the comment from being displayed by returning 0 as the result of the callback. Alternatively, you may modify the comment text, its window size, or its pop-up behaviour by changing the appropriate element(s) of the event message and returning the new event message as the result.

Note that if the comment window relates to a row or column title, the value reported in element [3] or [4] of the event message is ¯1.

You may display the comment associated with a particular cell under program control by calling ShowComment as a method. In this case, only the Cell row and Cell column parameters need be specified. If however, you wish to override the comment text and/or its window size, you may do so (temporarily) by specifying the corresponding parameters. By default, a comment displayed under program control does not exhibit tip behaviour but remains visible until it is explicitly removed using the HideComment method.

Note that a comment will only be displayed if the specified cell is marked as a commented cell.


Spin Event

Spin Event 420
Applies To: Spinner UpDown

Description

If enabled, this event is generated when the user clicks one of the spin buttons in a Spinner object. The event is reported before the value of the Thumb property has been updated. You may disable the operation of the spin buttons by disabling this event. You may selectively prevent the user selecting a particular value by returning 0 from a callback function. You may also return a modified event message as a result in order to set the Thumb property to a different value.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Spin' or 420
[3] | Thumb value | Integer. The new value of the Thumb property resulting from the user pressing one of the spin buttons.
[4] | Adjustment | Integer. The amount by which the new value of the Thumb differs from its previous value.


Splitting Event

Splitting Event 281
Applies To: Splitter

Description

If enabled, this event is reported while a Splitter object is being dragged, between a StartSplit and an EndSplit. This event is only reported if full-drag is enabled.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Splitting' or 281
[3] | Y | y-position of top left corner
[4] | X | x-position of top left corner
[5] | H | height of the Splitter
[6] | W | width of the Splitter

See also StartSplit, EndSplit.


StartSplit Event

StartSplit Event 280
Applies To: Splitter

Description

If enabled, this event is reported when the user depresses the left mouse button over a Splitter object to signify the beginning of a drag operation.

This event is reported for information alone. You may not disable or nullify the event by setting the action code for the event to ¯1 or by returning 0 from a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'StartSplit' or 280

See also EndSplit, Splitting.


StateChange Event

StateChange Event 35
Applies To: Form SubForm

Description

This event is generated by a Form or SubForm when the user attempts to change the State of a Form, by minimising it, maximising it, or restoring it from a minimised or maximised state. The event is reported before the window changes state. You may prevent the state change by disabling the event (action code ¯1) or by returning a 0 result from an attached callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'StateChange' or 35
[3] | Window state | 0 (about to be restored) 1 (about to be minimised) 2 (about to be maximised)


SysColorChange Event

SysColorChange Event 134
Applies To: Root

Description

If enabled, this event is reported when the user or another application updates the system colour palette. The event is reported after the change has taken place and cannot be disabled or inhibited in any way. If you want your application to respond to colour palette changes, this event gives you the opportunity of doing so.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'SysColorChange' or 134


TCPAccept Event

TCPAccept Event 371
Applies To: TCPSocket

Description

If enabled, this event is reported when a client connects to a server TCPSocket object.

You may not disable or nullify the operation by setting the action code for the event to ¯1 or by returning 0 from a callback function. You may also not call TCPAccept as a method or generate this event artificially using ⎕NQ.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'TCPAccept' or 371
[3] | Socket handle | an integer

The socket handle reported by this event is the socket handle for the original listening socket that was associated with the TCPSocket before the client connected.

If you want your server to remain available for other clients, you must create a new TCPSocket object in a callback function attached to this event. The new TCPSocket object must be created by cloning the original listening socket. This is done by specifying the socket handle as the value of its SocketNumber property. You may not specify any other properties (except Event and Data) in the ⎕WC statement that creates the new clone object.

The default processing for this event is to close the socket handle reported by the 3rd element of the event message unless it has been associated with a new TCPSocket object by the callback function as described above. You may prevent this from occurring by returning 0 from a callback function. This may be necessary in a multithreaded application.

You may not call TCPClose as a method or generate this event artificially using ⎕NQ.


TCPClose Event

TCPClose Event 374
Applies To: TCPSocket

Description

If enabled, this event is reported when the remote end of a TCP/IP connection breaks the connection.

You may not disable or nullify the operation by setting the action code for the event to ¯1 or by returning 0 from a callback function. You may also not call TCPClose as a method or generate this event artificially using ⎕NQ.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'TCPClose' or 374


TCPConnect Event

TCPConnect Event 372
Applies To: TCPSocket

Description

If enabled, this event is reported when a server accepts the connection of a client TCPSocket object and is reported by the client.

You may not disable or nullify the operation by setting the action code for the event to ¯1 or by returning 0 from a callback function. You may also not call TCPConnect as a method or generate this event artificially using ⎕NQ.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'TCPConnect' or 372


TCPError Event

TCPError Event 370
Applies To: TCPSocket

Description

This event is generated when a fatal TCP/IP error occurs and is reported by a TCPSocket object.

The default processing for this event is to display a message box containing details of the TCP/IP error. You may disable the display of this message box by setting the action code for the event to ¯1 or by returning 0 from a callback function attached to it.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'TCPError' or 370
[3] | Error code | a number
[4] | Error text | a character vector


TCPGotAddr Event

TCPGotAddr Event 377
Applies To: TCPSocket

Description

If enabled, this event is reported when a host name (specified by the RemoteAddrName or LocalAddrName property) is resolved to an IP address.

You may not disable or nullify the operation by setting the action code for the event to ¯1 or by returning 0 from a callback function. You may also not call TCPGotAddr as a method or generate this event artificially using ⎕NQ.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'TCPGotAddr' or 377

Note that the IP address is not reported in the event message but may be obtained from RemoteAddr or LocalAddr as appropriate.


TCPGotPort Event

TCPGotPort Event 378
Applies To: TCPSocket

Description

If enabled, this event is reported when a port name (specified by the RemotePortName or LocalPortName property) is resolved to a port number.

You may not disable or nullify the operation by setting the action code for the event to ¯1 or by returning 0 from a callback function. You may also not call TCPGotPort as a method or generate this event artificially using ⎕NQ.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'TCPGotPort' or 378

Note that the port number is not reported in the event message but may be obtained from RemotePort or LocalPort as appropriate.


TCPReady Event

TCPReady Event 379
Applies To: TCPSocket

Description

If enabled, this event is reported when the TCP/IP buffers are free and there is no data waiting to be sent in the internal APL queue.

This event is provided to enable you to control the transmission of a large amount of data that cannot be handled in a single call to TCPSend.

The amount of data that the system can handle in one go is limited by TCP/IP buffers, the speed of the network, and the amount of Windows memory and disk space available for buffering.

You may not disable or nullify the operation by setting the action code for the event to ¯1 or by returning 0 from a callback function. However, you may call TCPReady as a method or generate this event artificially using ⎕NQ.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'TCPReady' or 379


TCPRecv Event

TCPRecv Event 373
Applies To: TCPSocket

Description

If enabled, this event is reported when data is received by a TCPSocket object.

You may not disable or nullify the operation by setting the action code for the event to ¯1 or by returning 0 from a callback function. You may also not call TCPRecv as a method or generate this event artificially using ⎕NQ.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'TCPRecv' or 373
[3] | Data | the data received
[4] | IP address | character vector
[5] | Port number | integer

Elements [4-5] refer to the IP address and port number of the remote process that sent the data.

If the SocketType is 'Stream', this information will be identical to the values of the RemoteAddr and RemotePort respectively.

If the SocketType is 'UDP' and there is potentially more than one partner sending you data, the IP address and port number information provided by the TCPRecv event is more reliable than the current values of RemoteAddr and RemotePort as these may already have changed.


ThumbDrag Event

ThumbDrag Event 440
Applies To: Scroll TrackBar

Description

If enabled, this event is generated when the user drags the thumb in a TrackBar object. The event is reported after the value of the Thumb property has been updated and is reported continuously as the thumb is dragged. You may not disable this event or alter its effect with a callback function.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'ThumbDrag' or 440
[3] | Thumb value | Integer. The new value of the Thumb property resulting from the user dragging the thumb.


Timer Event

Timer Event 140
Applies To: Timer

Description

This event is generated at regular intervals by a Timer object and is typically used to fire a callback function to perform a task repeatedly. Returning a 0 from a callback function attached to a Timer event has no effect. The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2 element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'Timer' or 140


VScroll Event

VScroll Event 38
Applies To: Form SubForm

Description

If enabled, this event is generated when the user attempts to move the thumb in a vertical scrollbar in a Form or SubForm. This event occurs only in a Form whose VScroll property is set to ¯1 and is distinct from the Scroll event which is generated by a Scroll object. The event may be generated in one of three ways :

  1. dragging the thumb
  2. clicking in one of the "arrow" buttons situated at the ends of the scrollbar. This is termed a small change, the size of which is defined by Step[1].
  3. clicking in the body of the scrollbar. This is termed a large change, the size of which is defined by Step[2].

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 4-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'VScroll' or 38
[3] | Scroll Type | numeric
[4] | Position | numeric

The value of Scroll Type is 0 (drag), 1 or ¯1 (small change) or 2 or ¯2 (large change). The sign indicates the direction.

The value of Position is the new (requested) position of the thumb. Notice however that the event is generated before the thumb is actually moved. If your callback function returns a scalar 0, the position of the thumb will remain unaltered.


VThumbDrag Event

VThumbDrag Event 441
Applies To: Form SubForm

Description

If enabled, this event is generated when the user attempts to drag the thumb in a vertical scrollbar in a Form or SubForm. This event occurs only in a Form or SubForm whose HScroll property is set to ¯1 and is distinct from the Scroll event that is generated by a Scroll object.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 3-element vector as follows:

[1] | Object | ref or character vector
[2] | Event | 'VThumbDrag' or 441
[3] | Position | numeric

The value of Position is the new (requested) position of the Thumb. Setting the action code of this event to ¯1, or returning a 0 from a callback function attached to it, has no effect.


WinIniChange Event

WinIniChange Event 133
Applies To: Root

Description

If enabled, this event is reported when another application changes relevant registry settings using the standard API calls. The event is reported after the change has taken place and cannot be disabled or inhibited in any way. If your application depends upon registry settings, this event gives you the opportunity of refreshing these parameters if they are changed.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'WinIniChange' or 133


Abort Method

Abort Method 103
Applies To: Printer

Description

This method causes the print job to be aborted and all pending output to be discarded.

The Abort method is niladic.

If you attach a callback function to this method and have it return a value of 0, the print job will continue.


AddChildren Method

AddChildren Method 310
Applies To: TreeView

Description

This method is used to add child items to an item in a TreeView object

The argument to AddChildren is a 3, 4 or 5 element array as follows:

[1] | Item number | Integer.
[2] | New items | Vector of character vectors.
[3] | Depth vector | Integer vector.
[4] | Picture vector | Integer vector.
[5] | Selected picture vector | Integer vector.

Item number specifies the index of the item to which the child items are to be added.

New items is a vector of character vectors containing the labels for the new child items.

Depth vector is an integer vector specifying the depth of each of the new items relative to the parent item to which they are being added. The first element of this array must be 0.

Picture vector and Selected picture vector are optional and specify values of ImageIndex and SelImageIndex respectively for each of the new items.

The result is the index at which the first new item has been inserted.


AddComment Method

AddComment Method 220
Applies To: Grid

Description

This method is used to add a new comment to a Grid.

The argument to AddComment is a 3, 4 or 5 element array as follows:

[1] | Row | integer
[2] | Column | integer
[3] | Comment text | character array
[4] | Height in pixels | integer
[5] | Width in pixels | integer

For example, the following statement associates a comment with the cell at row 2, column 1; the text of the comment is "Hello", and the size of the comment window is 50 pixels (high) by 60 pixels (wide).

      F.G.AddComment 2 1 'Hello' 50 60

Note that if you specify a row number of ¯1, the comment is added to the corresponding column title. Similarly, if you specify a column number of ¯1, the comment is added to the corresponding row title.

The height and width of the comment window, specified by the last 2 elements of the argument are both optional. If the cell already has an associated comment, the new comment replaces it.

You can use a dfn to add several comments in one statement; for example:

      (1 2)(2 3){F.G.AddComment ⍺,⊂⍵}¨'Hello' 'Goodbye'

Note that just before the comment is displayed, the Grid generates a ShowComment event which gives you the opportunity to (temporarily) change the text and/or window size of a comment dynamically.

The comment text specified by the 5th element of the argument to ⎕NQ must be a simple character scalar, vector, matrix or vector of vectors. Text specified by a simple character vector will be wrapped automatically if necessary. A matrix or vector of vectors may be used to explicitly specify multi-line text. If the array is a vector whose first element is an opening brace ({), the text is assumed to be in rich-text format (RTF) and is displayed accordingly. Note that there is no way for the user to scroll the text in the comment window and it is entirely your responsibility to ensure that the size of the window is appropriate for its contents.


AddItems Method

AddItems Method 308
Applies To: TreeView

Description

This method is used to add items to a TreeView object

The argument to AddItems is a 3, 4 or 5-element array as follows:

[1] | Item number | Integer.
[2] | New items | Vector of character vectors.
[3] | Depth vector | Integer vector.
[4] | Picture vector | Integer vector.
[5] | Selected picture vector | Integer vector.

Item number specifies the index of the item to which the child items are to be added.

New items is a vector of character vectors containing the labels for the new child items.

Depth vector is an integer vector specifying the depth of each of the new items relative to the parent item to which they are being added. The first element of this array must be 0. This element may be omitted. If so, it is assumed to be all 0s.

Picture vector and Selected picture vector are optional and specify values of ImageIndex and SelImageIndex respectively for each of the new items.

The new items are inserted with the first one being placed at the same level in the hierarchy as the item specified in element [1].

The result is an integer that reports the index position at which the first of the new items has been inserted.


AnimClose Method

AnimClose Method 291
Applies To: Animation

Description

The AnimClose method closes the AVI file that is currently loaded in an Animation object. The display is reset to the object's background colour.

The AnimClose method is niladic.


AnimOpen Method

AnimOpen Method 290
Applies To: Animation

Description

The AnimOpen method opens an AVI file in an Animation object.

The argument to AnimOpen is a 1 or 2-element array as follows:

[1] | File | character vector
[2] | Resource id | integer

If a single element is specified, it represents the name of a .AVI file.

If 2 elements are specified, the first element specifies the name of a DLL or EXE and the second element identifies the particular AVI resource stored in that file. The identifier may be its name (a character string) or its resource id (a non-zero positive integer).

If the AutoPlay property is set to 1, the animation will play immediately. Otherwise, only the first frame will be displayed.

Note that the Animation object can only play AVI files or resources that have no sound and can only display uncompressed AVI files or .AVI files that have been compressed using Run-Length Encoding (RLE). If you attempt to open an inappropriate AVI file, the operation will fail with a DOMAIN ERROR and the following message will be displayed in the Status Window:

AVI file includes sound data or is in a format not supported by the Animation object


AnimPlay Method

AnimPlay Method 292
Applies To: Animation

Description

The AnimPlay method plays an AVI clip in an Animation object.

The argument to AnimPlay is a 3-element array as follows:

[1] | Repeat | integer
[2] | From | integer
[3] | To | integer

Repeat specifies the number of times the clip is repeated. A value of -1 causes the clip to be repeated indefinitely.

From is a 0-based index of the frame where playing begins and must be less than 65536. A value of zero means begin with the first frame in the AVI clip

To is a 0-based index of the frame where playing ends and must be less than 65536. A value of -1 means end with the last frame in the AVI clip

The last frame remains displayed until the clip is unloaded using AnimClose or until another clip is loaded.


AnimStop Method

AnimStop Method 293
Applies To: Animation

Description

The AnimStop method stops playing an AVI clip in an Animation object.

AnimStop is niladic.

The last frame remains displayed until the clip is unloaded using AnimClose or until another clip is loaded.


Animate Method

Animate Method 29

Applies To

Description

The Animate method enables you to produce special effects when showing or hiding objects. There are three types of animation: roll, slide, and alpha-blended fade.

The argument to Animate is a 1 or 2-element array as follows:

[1] | Effects | integer
[2] | Play time | integer

The value of the Effects parameter is the sum of the following flags:

Flag | Value | Description
AW_HOR_POSITIVE | 1 | Animates the window from left to right. This flag can be used with roll or slide animation. It is ignored when used with the AW_CENTER flag.
AW_HOR_NEGATIVE | 2 | Animates the window from right to left. This flag can be used with roll or slide animation. It is ignored when used with the AW_CENTER flag.
AW_VER_POSITIVE | 4 | Animates the window from top to bottom. This flag can be used with roll or slide animation. It is ignored when used with the AW_CENTER flag.
AW_VER_NEGATIVE | 8 | Animates the window from bottom to top. This flag can be used with roll or slide animation. It is ignored when used with the AW_CENTER flag.
AW_CENTER | 16 | Makes the window appear to collapse inward if being hidden or expand outward if being displayed
AW_SLIDE | 262144 | Uses slide animation. By default, roll animation is used. This flag is meaningless on its own but is ignored when used with the AW_CENTER flag.
AW_BLEND | 524288 | Uses a fade effect. This flag can be used only for a Form.

The Playtime parameter is optional and specifies the length of time over which the animation is played in milliseconds. The default value depends upon the animation but is typically 200 milliseconds.


Browse Method

Browse Method 585
Applies To: OCXClass OLEClient

Description

The Browse method is retained for compatibility with previous versions of Dyalog APL, but is no longer relevant and has no effect.


CancelToClose Method

CancelToClose Method 367
Applies To: PropertySheet

Description

This method is used to change the buttons in a PropertySheet object. Its effect is to disable the Cancel button and, if the Style of the PropertySheet is 'Standard', it changes the text of the OK button to "Close". There is no result.

The CancelToClose method is niladic.


CellFromPoint Method

CellFromPoint Method 200
Applies To: Grid

Description

This method converts from Grid co-ordinates to cell co-ordinates.

The argument to CellFromPoint is a 2-element array as follows:

[1] | y-coordinate | number in Grid co-ordinates
[2] | x-coordinate | number in Grid co-ordinates

The result is a 2-element vector containing the following:

[1] | y-coordinate | number in cell co-ordinates
[2] | x-coordinate | number in cell co-ordinates


ChooseFont Method

ChooseFont Method 240

Applies To

Description

This method is used to display the standard Windows font selection dialog box.

The argument to ChooseFont is ⍬ or a 1 or 2-element array as follows:

[1] | Printer name | character scalar or vector.
[2] | Modify flag | 0 or 1.

If the argument is ⍬ or the first element of the argument is '', the user is offered a list of fonts suitable for use on the screen. If not, the user is offered a choice of fonts suitable for the specified Printer object. If you omit the 2nd element, the modify flag defaults to 0.

The dialog box is initialised with the properties of the Font object specified in the first element of the event message.

When the user presses the "OK" button, the "Cancel" button or closes the dialog box, ChooseFont terminates. Its result is either 0 (user pressed "Cancel") or a 2-element vector. In the latter case, the first element is an 8-element array that describes the selected font as described below, and the second element is a 3-element RGB colour vector.

[1] | Face name of selected font (character vector)
[2] | Character height in pixels (integer)
[3] | Fixed width or not (Boolean)
[4] | Italic or not (Boolean)
[5] | Underline or not (Boolean)
[6] | Weight (integer)
[7] | Angle of rotation (integer)
[8] | Character set (see CharSet)

If the modify flag was 1, the Font object is redefined to match the user's selections and all the objects that reference the Font are redrawn.


ColChange Method

ColChange Method 159
Applies To: Grid

Description

This method is used to change the data in a column of a Grid.

The argument to ColChange is a 2-element array as follows:

[1] | Column number | integer
[2] | Column data | array

Note that the Column data must be a scalar or a vector whose length is equal to the number of rows in the Grid. Its elements may be scalar numbers, character vectors or matrices.


ColSorted Method

ColSorted Method 174
Applies To: Grid

Description

This method is used to specify that an image is to be displayed in a Grid column title to indicate the column has been sorted.

The argument to ColSorted is a 2-element array as follows:

[1] | Column number | Integer.
[2] | Sorted state | Integer. -1 = Sorted Down 0 = Unsorted 1 = Sorted Up

The column title for the appropriate column is redrawn to include the appropriate image.

If you wish to use your own images, you may specify them using the ColSortImages property.

      'F'⎕WC'Form' 'Grid: ColSorted Method'
      'F.G'⎕WC'Grid'('Posn' 0 0)(100 100)
      F.G.Values←(COUNTRIES,POPULATION,[1.5]AREA)
      F.G.ColTitles←'Country' 'Population' 'Area'
      F.G.TitleWidth←0

      F.G.Values←(Values[⍋Values[;2];])
      F.G.ColSorted 2 1

      F.G.(Values←Values[⍒↑Values[;1];])
      F.G.ColSorted 2 0
      F.G.ColSorted 1 ¯1


DateToIDN Method

DateToIDN Method 264
Applies To: Calendar DateTimePicker Root

Description

This method is used to convert a date from ⎕TS format into an IDN suitable for use in a Calendar object.

The argument to DateToIDN is a 3-element array as follows:

[1] | Year | Integer
[2] | Month | Integer
[3] | Day | Integer

DateToIDN will also accept a single enclosed argument containing these values. In either case, if you specify more than 3 numbers, excess elements they will be ignored.

Examples

      F.C.DateToIDN 1998 9 11
36048
      F.C.DateToIDN ⊂1998 9 11
36048
      F.C.DateToIDN ⎕TS
36048
      F.C.DateToIDN,⎕TS
36048


DelCol Method

DelCol Method 155
Applies To: Grid

Description

This method is used to delete a specified column from a Grid object.

The argument to DelCol is a 1 or 2-element vector as follows:

[1] | Column number | number of the column (integer) to delete
[2] | Undo flag | 0 or 1 (optional; default 0)

If the Undo flag 1, the column may subsequently be restored by invoking the Undo method. If the Undo flag is omitted or is 0, the operation may not be undone.


DelComment Method

DelComment Method 221
Applies To: Grid

Description

This method is used to delete a comment from a Grid.

The argument to DelComment is a 2 array as follows or ⍬:

[1] | Row | integer
[2] | Column | integer

For example, the following expression removes the comment associated with the cell at row 2, column 1.

      F.C.DelComment 2 1

Note that to delete a comment associated with a row or column title, the appropriate element in the argument should be ¯1.

If the argument is ⍬, all comments are deleted.


DelRow Method

DelRow Method 154
Applies To: Grid

Description

This method is used to delete a specified row from a Grid object.

The argument to DelRow is a 1 or 2-element array as follows:

[1] | Row number | number of the row (integer) to delete
[2] | Undo flag | 0 or 1 (optional; default 0)

If the Undo flag is 1, the column may subsequently be restored by invoking the Undo method. If the Undo flag is omitted or is 0, the operation may not be undone.


DeleteChildren Method

DeleteChildren Method 311
Applies To: TreeView

Description

This method is used to delete child items from a parent item in a TreeView object.

The argument to DeleteChildren is a scalar or 1 element array as follows:

[1] Item number Integer.

Item number specifies the index of the parent item from which the child items are to be removed.

The result is an integer that indicates the number of children that have been removed from the parent item.


DeleteItems Method

DeleteItems Method 309
Applies To: TreeView

Description

This method is used to delete items from a TreeView object.

The argument to DeleteItems is a 2-element array as follows:

[1] | Item number | Integer.
[2] | Number of Items | Integer.

Item number specifies the index of the first item to be removed.

Number of items specifies the number of items to be removed and refers to those items at the same level in the TreeView hierarchy as the Item number. Number of items is optional and defaults to 1.

Note that any children of these items will also be removed.

The result is an integer that indicates the total number of items, including children, that have been removed from the TreeView.


DeleteTypeLib Method

DeleteTypeLib Method 521
Applies To: Root

Description

The DeleteTypeLib method removes a loaded Type Library from the workspace.

The argument to DeleteTypeLib is as follows:

[1] TypeLib character vector

The Type Library may be identified by its name or by its class id.

The result is 0, 1 or ¯1.

If successful, the specified Type Library, and all dependant Type Libraries not referenced by any other currently loaded Type Libraries, are removed from the active workspace. The result is 1.

If the specified Type Library is in use, no action is taken and the result is 0.

If the argument is not the name or CLSID of a loaded Type Library, no action is taken and the result is ¯1.


Detach Method

Detach Method 270

Applies To

Description

This method is used to detach the GUI component from an object without losing the functions, variables and sub-namespaces that it may contain.

The Detach method is niladic.

The effect of this method is to remove the GUI component associated with the named object, leaving behind a plain namespace of the same name. All non-GUI child objects are retained. GUI child objects are either destroyed, or similarly converted to plain namespaces depending upon the values of their KeepOnClose properties.


DuplicateColumn Method

DuplicateColumn Method 178
Applies To: Grid

Description

This method is used to duplicate a column in a Grid object.

The argument to DuplicateColumn is a 2, 3, 4 or 5-element vector as follows:

[1] | Source Column number | number of the column (integer) to be duplicated
[2] | Target Column number | new column number (integer)
[3] | Comment flag | 0 or 1 (optional, default 1)
[4] | Lock flag | 0 or 1 (optional, default 1)
[5] | Undo flag | 0 or 1 (optional; default 0)

If the Comment flag is 1 (the default), any Comments associated with cells in the source column are duplicated in the target column.

If the Lock flag is 1 (the default), the lock state of the column is duplicated; otherwise, the new column is not locked.

If the Undo flag is 1, the column may subsequently be restored by invoking the Undo method. If this element is omitted or is 0, the operation may not be undone.


DuplicateRow Method

DuplicateRow Method 177
Applies To: Grid

Description

This method is used to duplicate a row in a Grid object.

The argument to DuplicateRow is a 2, 3, 4 or 5-element vector as follows:

[1] | Source Row number | number of the row (integer) to be duplicated
[2] | Target Row number | new row number (integer)
[3] | Comment flag | 0 or 1 (optional, default 1)
[4] | Lock flag | 0 or 1 (optional, default 1)
[5] | Undo flag | 0 or 1 (optional; default 0)

If the Comment flag is 1 (the default), any Comments associated with cells in the source row are duplicated in the target row.

If the Lock flag is 1 (the default), the lock state of the row is duplicated; otherwise, the new row is not locked.

If the Undo flag is 1, the row may subsequently be restored by invoking the Undo method. If this element is omitted or is 0, the operation may not be undone.


FileRead Method

FileRead Method 90
Applies To: Bitmap Cursor Icon Metafile RichEdit

Description

This method causes the object to be recreated from the file named in its File property.

The FileRead method is niladic.

[1] | Object | ref or character vector
[2] | Event | 'FileRead' or 90

If you attach a callback function to this event and have it return a value of 0, the object will not be recreated from file.


FileWrite Method

FileWrite Method 91
Applies To: Bitmap Cursor Icon Metafile RichEdit

Description

This method causes the object to be written to the file named in its File property. For the Bitmap and Icon objects this method will write a file of type .BMP and .ICO to a file with the appropriate extension. If File specifies any other extension, the method will fail with a DOMAIN ERROR:

 DOMAIN ERROR: This object cannot be saved to this type of file.

The FileWrite method is niladic.

If you attach a callback function to this event and have it return a value of 0, the object will not be written to file. You could use this to avoid overwriting an existing file.


Flush Method

Flush Method 135
Applies To: Root

Description

This method forces any objects that have been created but not yet shown to be displayed. Normally, Dyalog APL/W buffers the display of new objects unless they are being created by a callback function. This event can be used to override the buffering.

The Flush method is niladic.


GetBuildID Method

GetBuildID Method 992
Applies To: Root

Description

This method is used to obtain the Build ID of a Dyalog executable or the checksum of a file.

The argument to GetBuildID is ⍬ or a single item as follows:

[1] File name character vector

The (shy) result is an 8-element character vector of hexadecimal digits that represents the Build ID.

If the argument is ⍬, the build id is that of the current version of Dyalog that is running the expression.

Note that although this method is designed to uniquely identify different versions of Dyalog by its checksum, it may be used to obtain a checksum for any arbitrary file.

Examples:

      GetBuildID ⍬
38091b76
      GetBuildID 'E:\DYALOG81\DYALOG.EXE'
cbf0d376
      GetBuildID 'myfile'
4a29334d

Note that if the file does not exist, the result is 00000000.


GetCellRect Method

GetCellRect Method 201
Applies To: Grid

Description

This method returns the rectangle associated with a particular cell in a Grid.

The argument to GetCellRect is a 2-element vector as follows:

[1] | Row | integer
[2] | Column | integer

The result is a 2-element nested vector. The first element contains the y and x-coordinate of the top-left corner of the cell. The second element contains the height and width of the cell.

The result is reported in terms of the coordinate system of the Grid object.


GetCommandLine Method

GetCommandLine Method 145
Applies To: Root

Description

The GetCommandLine method returns the command line that was used to start the current Dyalog APL session or application.

The GetCommandLine method is niladic.

The result is a character vector.

Examples

      GetCommandLine
"C:\Program Files\Dyalog\Dyalog APL-64 13.2 Unicode\dyalog.exe"
      ⎕←2 ⎕NQ '.' 'GetCommandLine'
"C:\Program Files\Dyalog\Dyalog APL-64 13.2 Unicode\dyalog.exe"

Note

GetCommandLine only works on Windows, and its use is deprecated in favour of GetCommandLineArgs, which works on all platforms.


GetCommandLineArgs Method

GetCommandLineArgs Method 148
Applies To: Root

Description

The GetCommandLineArgs method returns the command and the arguments to the command that was used to start the current Dyalog APL session or application.

The GetCommandLineArgs method is niladic.

The result is a vector of character vectors. For example:

      GetCommandLineArgs
 C:\Dyalog10\dyalog.exe  -Dw  YY_WINDOW=-30
      DISPLAY 2 ⎕NQ '.' 'GetCommandLineArgs'
┌→───────────────────────────────────────────────┐
│ ┌→─────────────────────┐ ┌→──┐ ┌→────────────┐ │
│ │c:\dyalog10\dyalog.exe│ │-Dw│ │YY_WINDOW=-30│ │
│ └──────────────────────┘ └───┘ └─────────────┘ │
└∊───────────────────────────────────────────────┘


GetComment Method

GetComment Method 222
Applies To: Grid

Description

This method is used to retrieve the comment associated with a cell in a Grid.

The argument to GetComment is a 2-element array as follows:

[1] | Row | integer
[2] | Column | integer

For example, the following expression retrieves the comment associated with the cell at row 3, column 1.

      F.C.GetComment 3 1
 1 3  Hello  175 100

Note that to retrieve a comment associated with a row or column title, the appropriate element in the argument should be ¯1.

If there is no comment associated with the specified cell, the result is a scalar 1.


GetEnvironment Method

GetEnvironment Method 510
Applies To: Root

Description

This method is used to obtain information about one or more parameters that were specified in the Dyalog command line, your Windows registry, or defined as environment variables. If a value is defined in several places (for example, MAXWS in the command line overriding MAXWS in the registry), GetEnvironment follows exactly the same logic as is used by Dyalog APL itself and so obtains the same value.

The argument to GetEnvironment is a single item as follows:

[1] Parameter name(s) see below

Parameter names is simple character vector or vector of character vectors specifying one or more parameters.

The result is a simple character vector or a vector of character vectors.

Examples:

      GetEnvironment 'MAXWS'
2G
     GetEnvironment ⊂'LOG_SIZE' 'MAXWS'
 16  2G

Note that you may use GetEnvironment to obtain the values of your own arbitrary parameters given on the APL command line or specified as environment variables.

GetEnvironment is not supported by DYALOG.DLL because it does not use parameters.


GetEventInfo Method

GetEventInfo Method 551
Applies To: OCXClass OLEClient

Description

This method is used to obtain information about a particular event or set of events supported by a COM object.

For each event supported by a COM object, the author will have registered the data type of its result (if it has a result), a help message or description of the event (optional) and the name and data type of each of its parameters. These event parameters make up the array returned by ⎕DQ or supplied as an argument to your callback function. The GetEventInfo method returns this information.

The argument to GetEventInfo is a single item as follows:

[1] Event name(s) see below

Event name(s) is a simple character vector or a vector of character vectors specifying one or more names of events supported by the object.

The result is a nested vector with one element per event name. Each element of this vector is itself a vector of 2-element character vectors. For each event, the first item describes the help message or description (if any) registered for the event and the data type of its result. Each of the remaining elements contains a parameter name and its corresponding data type.

Example:

      CLNAME←'Microsoft Multimedia Control, Version 6.0'
      'MM' ⎕WC 'OCXClass' CLNAME
      MM.EventList
 Done  BackClick  PrevClick  NextClick  PlayClick  ...
      DISPLAY ↑MM.GetEventInfo 'Done'
┌→───────────────────────────────────────────────────┐
↓ ┌→─────────────────────────────┐ ┌→──────┐         │
│ │Occurs when an MCI command ...│ │VT_VOID│         │
│ └──────────────────────────────┘ └───────┘         │
│ ┌→─────────┐                     ┌→──────────────┐ │
│ │NotifyCode│                     │VT_PTR to VT_I2│ │
│ └──────────┘                     └───────────────┘ │
└∊───────────────────────────────────────────────────┘

Note that if the event does not produce a result, the data type of the result is reported as 'VT_VOID'.


GetFocus Method

GetFocus Method 511

Applies To

Description

This method is used to obtain the name of the object that currently has the input focus.

The GetFocus method is niladic.

The result is a simple character vector. An empty result indicates that no Dyalog APL GUI object has the input focus.

See also: GetFocusObj.


GetFocusObj Method

GetFocusObj Method 509

Applies To

Description

This method is used to obtain a ref to the object that currently has the input focus.

The GetFocusObj method is niladic.

The result is a ref. If there is no Dyalog APL GUI object with the input focus, the result is ⎕NULL.

See also: GetFocus.


GetItemHandle Method

GetItemHandle Method 313
Applies To: TreeView

Description

This method is used to obtain the window handle of a particular item in a TreeView object.

The argument for GetItemHandle is a single item as follows:

[1] Item number Integer.

Item number is the index of the item concerned.

The result is an integer containing the window handle of the item.


GetItemPosition Method

GetItemPosition Method 323
Applies To: ListView

Description

This method is used to obtain the position of a particular item in a ListView object.

The argument for GetItemPosition is a single item as follows:

[1] Item number Integer

Item number is the index of the item concerned.

The result is a 2-element vector containing the position of the item.


GetItemState Method

GetItemState Method 306
Applies To: ListView TreeView

Description

This method is used to obtain the status of a particular item in a ListView or TreeView object.

The argument for GetItemState is a single item as follows:

[1] Item number Integer

Item number is the index of the item concerned. Be aware that this is index origin dependent.

The result indicates the state of the item as the sum of one or more of the following codes:

¯1 | Error (most likely the Item number is invalid)
1 | Item has the focus
2 | Item is selected
8 | Item is highlighted for dropping
16 | Item is displayed in bold text
32 | Item is expanded
64 | Item is or has been expanded
4096 | Item is checked. See CheckBoxes


GetMethodInfo Method

GetMethodInfo Method 552
Applies To: OCXClass OLEClient

Description

This method is used to obtain information about a particular method or set of methods supported by a COM object.

For each method supported by a COM object the author will have registered a help message or description of the method (this is in fact optional), the data type of its result (if it has a result), and the name and data type of each of the parameters that must be supplied when you invoke it. The GetMethodInfo method returns this information.

The argument to GetMethodInfo is a single item as follows:

[1] Method name(s) see below

Method name(s) is a simple character vector or a vector of character vectors specifying one or more names of methods supported by the object.

The result is a nested vector with one element per method name. Each element of this vector is itself a vector of 2-element character vectors. For each method, the first item describes the help message or description (if any) registered for the method and the data type of its result. Note that if the event does not produce a result, the data type of the result is reported as 'VT_VOID'. Each of the remaining elements contains a parameter name and its corresponding data type.

Example

      CLNAME←'Microsoft Multimedia Control, Version 6.0'
      'MM' ⎕WC 'OCXClass' CLNAME
      MM.MethodList
 AboutBox  Refresh  OLEDrag

      DISPLAY ↑ MM.GetMethodInfo 'AboutBox'
┌→──────────────┐
↓ ┌⊖┐ ┌→──────┐ │
│ │ │ │VT_VOID│ │
│ └─┘ └───────┘ │
└∊──────────────┘


GetMinSize Method

GetMinSize Method 275
Applies To: Calendar

Description

This method is used to obtain the minimum size that you must specify for a Calendar object for it to display a complete month.

The GetMinSize method is niladic.

The (shy) result of the method is a 2-element numeric vector containing the minimum height and width required for the object to display a complete month.


GetParentItem Method

GetParentItem Method 312
Applies To: TreeView

Description

This method is used to obtain the index of the parent of a particular item in a TreeView object.

The argument for GetParentItem is a single item as follows:

[1] Item number Integer.

Item number is the index of the item concerned.

The result is an integer containing the index of the parent item.


GetPropertyInfo Method

GetPropertyInfo Method 550
Applies To: OCXClass OLEClient

Description

This method is used to obtain information about a particular property or set of properties supported by a COM object.

For each property supported by a COM object, the author will have registered the property name, its data type, and an optional help message or description of the property. GetPropertyInfo returns this information.

The argument to GetPropertyInfo is a single item as follows:

[1] Property name(s) see below

Property name(s) is a simple character vector or a vector of character vectors specifying one or more names of properties supported by the object.

The result is a nested vector with one element per property name. Each element of this vector is itself a 2-element vector of character vectors containing the data type and help message for the corresponding property.

Example

      CLNAME←'Microsoft Multimedia Control, Version 6.0'
      'MM' ⎕WC 'OCXClass' CLNAME
      MM.PropList
 Type  DeviceType  AutoEnable  PrevVisible ...

      DISPLAY ↑MM.GetPropertyInfo 'PrevVisible'
┌→──────────────────────────────────────────────────────┐
↓ ┌→────────────────────────────────────────┐ ┌→──────┐ │
│ │Determines if the Prev button is visible.│ │VT_VOID│ │
│ └─────────────────────────────────────────┘ └───────┘ │
│ ┌→─┐                                        ┌→──────┐ │
│ │⌈P│                                        │VT_BOOL│ │
│ └──┘                                        └───────┘ │
└∊──────────────────────────────────────────────────────┘

If the data type of a property is VT_USERDEFINED, it means that the property may assume one of a set of values defined by a type list. In this case, the name of the type list is returned in place of the string "VT_USERDEFINED". Further information can be obtained using GetTypeInfo with this name as a parameter.


GetServiceState Method

GetServiceState Method 92
Applies To: Root

Description

This method is used to obtain the current state of a Dyalog APL service running under Windows. See APL Application as a Service.

The GetServiceState method is niladic.

The result of the method is a 7-element numeric vector corresponding to the SERVICE_STATUS structure which is described in C++ as follows:

typedef struct _SERVICE_STATUS {
  DWORD dwServiceType;
  DWORD dwCurrentState;
  DWORD dwControlsAccepted;
  DWORD dwWin32ExitCode;
  DWORD dwServiceSpecificExitCode;
  DWORD dwCheckPoint;
  DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;.

For further details, see the on-line documentation for SERVICE_STATE and the function HashDefine in the sample workspace aplservice.


GetTextSize Method

GetTextSize Method 146

Applies To

Description

The GetTextSize method obtains the size of the bounding rectangle of a text item in a given font. The result is given in the co-ordinate system of the object in question. This method is useful for positioning Text objects.

GetTextSize duplicates the functionality of the TextSize property. It is recommended that you use GetTextSize instead of TextSize which may be removed in a future release of Dyalog APL.

The argument to GetTextSize is a 1 or 2-element array as follows:

[1] | Text item | character array
[2] | Font name | character vector

When you invoke GetTextSize you give the text item in whose size you are interested and, optionally, the name of a Font object. The text item may be a simple scalar, a vector or a matrix. If the Font is omitted, the result is given using the current font for the object in question.

Examples

      'F'⎕WC'Form'
      F.GetTextSize'Hello World'
3.385416667 10.7421875
      'FNT1' ⎕WC 'Font' 'Arial' 72
      F.GetTextSize'Hello World'  '#.FNT1'
18.75 65.4296875
      F.Coord←'Pixel'
      F.FontObj←'FNT1'
      F.GetTextSize'Hello World'
16 77


GetTypeInfo Method

GetTypeInfo Method 553
Applies To: OCXClass OLEClient

Description

This method is used to obtain information about a type list supported by a COM object.

The argument to GetTypeInfo is a single item as follows:

[1] | Type List name(s) | see below
[2] | Value | (usually) numeric
[3] | Description | character vector

Type List name(s) is a simple character vector or a vector of character vectors specifying one or more names of type lists supported by the object.

The result is a nested vector with one element per Type List. Each element of this vector is itself a 3-element vector of character vectors made up as follows:

[1] | Name of Constant | character vector
[2] | Value | (usually) numeric
[3] | Description | character vector


GetVisibleRange Method

GetVisibleRange Method 262
Applies To: Calendar

Description

This method is used to obtain the range of dates that is currently visible in a Calendar object.

The GetVisibleRange method is niladic.

The result is a 2-element integer vector containing the first and last dates currently displayed by the object, reported as IDNs.


GreetBitmap Method

GreetBitmap Method 138
Applies To: Root

Description

This method is used to display or remove a bitmap, typically during initialisation of a Dyalog runtime application.

The argument to GreetBitmap is ⍬ or a 2 element vector as follows:

[1] | Display | 0 = off, 1 = on.
[2] | Bitmap file name | Character vector.

If the argument is ⍬, the bitmap is removed.

The image may also be displayed initially by setting parameter: greet_bitmap on the command line, e.g.:

c:\myapp\dyalogrt greet_bitmap=mylogo myws

The image is displayed until either an untrapped error occurs, causing the interpreter to (attempt to) display the session window, or the GreetBitmap method is called.


IDNToDate Method

IDNToDate Method 263
Applies To: Calendar DateTimePicker Root

Description

This method is used to convert a date from an IDN into ⎕TS format (year, month, day). The corresponding day of the week is also obtained.

The argument to IDNToDate is a single item as follows:

[1] IDN Integer

The result is a 4-element integer vector containing the year, month, day, and weekday corresponding to the IDN that was specified.

The value of the 4th element, weekday, is an integer in the range 0-6 that specifies on which day of the week the specified date falls (0=Monday).

Example

      F.C.IDNToDate 36048
1998 9 11 4


ListTypeLibs Method

ListTypeLibs Method 520
Applies To: Root

Description

The ListTypeLibs method reports the names and CLSIDs of all the loaded Type Libraries.

The ListTypeLibs method is niladic.

The result is a nested vector with one element per loaded Type Library.

Each element is a vector of 2-element characater vectors. The first is the name of the Type Library; the second is its class identifier or CLSID.

Example:

      'EX'⎕WC'OLEClient' 'Excel.Application'
      ⍴ListTypeLibs
3
      ↑⊃ListTypeLibs
Microsoft Excel 9.0 Object Library
{00020813-0000-0000-C000-000000000046}

      ↑⊃¨ListTypeLibs
Microsoft Excel 9.0 Object Library
Microsoft Visual Basic for Applications Extensibility 5.3
Microsoft Office 9.0 Object Library


LockColumns Method

LockColumns Method 227
Applies To: Grid

Description

This method is used to lock one or more columns of a Grid object. However, LockColumns is not supported in combination with hierarchical column titles as specified by the ColTitleDepth property.

The argument to LockColumns is a 1 or 2-element vector as follows.

[1] | Column(s) | integer scalar, vector or matrix
[2] | Lock flag | 0 or 1

Column(s) may be a scalar or a vector specifying the column or columns to be locked or unlocked. Alternatively, it may be a matrix whose first row specifies the columns to be locked and whose second row specifies where they are to be locked.

If the Lock flag is 1, the corresponding columns are locked. This is the default and may be omitted. If the Lock flag is 0, the corresponding columns are unlocked

Examples:

      F.G.LockColumns 3         ⍝Lock 3rd column
      F.G.LockColumns 3 0       ⍝Unlock 3rd column
      F.G.LockColumns (4 5)     ⍝Lock 4th & 5th cols
      F.G.LockColumns (2 1⍴8 4) ⍝Lock 8 at 4
      F.G.LockColumns 3         ⍝Lock 3rd column
      F.G.LockColumns 3 0       ⍝Unlock 3rd column
      F.G.LockColumns (4 5)     ⍝Lock 4th & 5th cols
      F.G.LockColumns (2 1⍴8 4) ⍝Lock 8 at 4

The result is an integer matrix containing the indices of all locked columns and the positions at which they are currently locked.

The expression:

      F.G.LockColumns ⊂⍬

may therefore be used to obtain the indices of the locked columns, and:

      F.G.LockColumns(F.G.LockColumns ⊂⍬) 0

unlocks all currently locked columns.

Locks are additive. If column 4 is locked, locking column 5 results in both columns 4 and 5 being locked.

A locked column remains fixed in position and does not scroll sideways. The user may enter and edit cells in a locked column in the normal way, but the behaviour of the various cell movement keys (Tab, left and right cursor, and so forth) differs when a locked column is encountered. As a general rule, if a keystroke attempts to move the cursor into a locked column from an adjacent column, and the adjacent column has been scrolled, it is unscrolled and the cursor remains in the (new) column adjacent to the fixed column. If not, the cursor moves into the locked column.

When you lock a column, the position you specify for it to be locked at is a position in the data and not the physical position of the column as displayed in the Grid . The physical column in the Grid depends upon the value of the Index property at the time it was locked.

If C is the value specified for where a given column is to be locked, the value of the physical column P at which it will be displayed in the Grid named GRID is:

      P←C-(2⊃GRID ⎕WG 'Index')-⎕IO

Furthermore, the position of a locked column given by the result of the LockColumns method changes (with the Index property) as the Grid is scrolled.


LockRows Method

LockRows Method 226
Applies To: Grid

Description

This method is used to lock one or more Rows of a Grid. However, LockRows is not supported in combination with hierarchical row titles as specified by the RowTitleDepth property.

The argument to LockRows is a 1 or 2-element vector as follows.

[1] | Row(s) | integer scalar, vector or matrix
[2] | Lock flag | 0 or 1

Row(s) may be a scalar or a vector specifying the row or rows to be locked or unlocked. Alternatively, it may be a matrix whose first row specifies the data rows to be locked and whose second row specifies where in the Grid they are to be locked.

If the Lock flag is 1, the corresponding rows are locked. This is the default and may be omitted. If the Lock flag is 0, the corresponding rows are unlocked.

Examples:

      F.G.LockRows 3         ⍝Lock 3rd row
      F.G.LockRows 3 0       ⍝Unlock 3rd row
      F.G.LockRows (4 5)     ⍝Lock 4th and 5th rows
      F.G.LockRows (2 1⍴8 4) ⍝Lock row 8 at 4
      F.G.LockRows 3         ⍝Lock 3rd row
      F.G.LockRows 3 0       ⍝Unlock 3rd row
      F.G.LockRows (4 5)     ⍝Lock 4th and 5th rows
      F.G.LockRows (2 1⍴8 4) ⍝Lock row 8 at 4

The result is an integer matrix containing the indices of all locked rows and the positions at which they are currently locked.

The expression:

      F.G.LockRows ⊂⍬

may therefore be used to obtain the indices of the locked rows, and

      F.G.LockRows(F.G.LockRows ⊂⍬) 0

unlocks all currently locked rows.

Locks are additive. If row 4 is locked, locking row 5 results in both rows 4 and 5 being locked.

A locked row remains fixed in position and does not scroll vertically. The user may enter and edit cells in a locked row in the normal way, but the behaviour of the various cell movement keys (Tab, up and down cursor, and so forth) differs when a locked row is encountered. As a general rule, if a keystroke attempts to move the cursor into a locked row from an adjacent row, and the adjacent row has been scrolled, it is unscrolled and the cursor remains in the (new) row adjacent to the fixed row. If not, the cursor moves into the locked row.

When you lock a row, the position you specify for it to be locked at is a position in the data and not the physical position of the column as displayed in the Grid. The physical column in the Grid depends upon the value of the Index property at the time it was locked.

If R is the value specified for where a given row is to be locked, the value of the physical row P at which it will be displayed in the Grid named GRID is given by the expression:

P←R-(⊃GRID ⎕WG 'Index')-⎕IO

Furthermore, the position of a locked row given by the result of the LockRows method changes (with the Index property) as the Grid is scrolled.


MDIArrange Method

MDIArrange Method 112
Applies To: MDIClient

Description

This method causes the MDIClient object to organise the icons associated with any minimised child Forms into regimented rows and columns. To permit the user to carry out this action, it is recommended that a suitable callback function or expression is attached to a MenuItem or Button. The callback function or expression should then call MDIArrange.

The MDIArrange method is niladic.


MDICascade Method

MDICascade Method 110
Applies To: MDIClient

Description

This method causes the MDIClient object to organise its child Forms in an overlapping fashion. To permit the user to carry out this action, it is recommended that a suitable callback function or expression is attached to a MenuItem or Button. The callback function or expression should then call MDICascade.

The MDICascade method is niladic.


MDITile Method

MDITile Method 111
Applies To: MDIClient

Description

This method causes the MDIClient object to organise its child Forms as a row or column. To permit the user to carry out this action, it is recommended that a suitable callback function or expression is attached to a MenuItem or Button. The callback function or expression should then call the MDITile method.

Note that because there are restrictions concerning the minimum height and width of a window, MS-Windows does not necessarily respond as requested. If the MDIClient is itself of insufficient size, or if it contains a large number of child Forms, Windows may choose to tile the Forms in a row when a column was specified or vice versa. It may also choose to ignore the event entirely.

The argument to MDITile is ⍬, or a single item as follows:

[1] Tile Mode 0 (vertical)
1 (horizontal)

If the argument is ⍬, the Tile Mode defaults to 0.


MakeGIF Method

MakeGIF Method 261
Applies To: Bitmap

Description

This method is used to generate a GIF representation of a picture from a Bitmap object suitable for display by a Web browser.

The MakeGIF method is niladic.

The result is an integer vector containing the encoded GIF image.

Example:

      ⍴GIF←BM.MakeGIF
19620


MakePNG Method

MakePNG Method 260
Applies To: Bitmap

Description

This method is used to generate a PNG (Portable Network Graphics) representation of a picture from a Bitmap object suitable for display by a Web browser.

The MakePNG method is niladic.

The result is an integer vector containing the encoded PNG image.

Example:

      ⍴PNG←BM.MakePNG
4930


NameFromHandle Method

NameFromHandle Method 136
Applies To: Root

Description

This method is used to obtain the name of a particular object from the value of its Handle property.

The argument to NameFromHandle is a single item as follows:

[1] Handle The value of the Handle property from an existing object.

The result is a character vector containing the name of the object.


NewPage Method

NewPage Method 102
Applies To: Printer

Description

This method causes a Printer to start a new page

The NewPage method is niladic.

If you attach a callback function to this event and have it return a value of 0, the page throw will not occur.


OLEAddEventSink Method

OLEAddEventSink Method 540
Applies To: OCXClass OLEClient

Description

This method connects a named event sink to a COM object and adds the events defined by that event sink to the EventList property of the associated namespace.

The argument to OLEAddEventSink is a single item as follows:

[1] Event sink name character vector

The result is a number that represents the handle of the event sink. This may be subsequently required.


OLEDeleteEventSink Method

OLEDeleteEventSink Method 541
Applies To: OCXClass OLEClient

Description

This method disconnects a named event sink from a COM object and removes the events defined by that event sink from the EventList property of the associated namespace.

This method may be used to remove an event sink that was established automatically when the OLE object was created.

The argument to OLEDeleteEventSink is a single item as follows:

[1] Event sink name character vector


OLEListEventSinks Method

OLEListEventSinks Method 542
Applies To: OCXClass OLEClient

Description

This method returns the names of event sinks that are currently connected to a COM object.

The list contains the names of all the event sinks that were connected automatically when the object was created, together with any that you have added subsequently using OLEAddEventSink.

The OLEListEventSinks method is niladic.

The result is a vector of character vectors containing the names of the event sinks connected to the object.


OLEQueryInterface Method

OLEQueryInterface Method 543
Applies To: ActiveXContainer OLEClient

Description

This method is used to obtain the methods and properties associated with a particular interface that is provided by a COM object. An interface is simply a pointer to a table of methods (not properties) that are exported by an object.

Note that methods and properties exported using the standard IDispatch interface are established automatically when the object is created. OLEQueryInterface is required only to support alternative or additional interfaces that the object may implement.

The argument to OLEQueryInterface is a single item as follows:

[1] Interface name character vector

The result is a namespace.

It is normal, although not strictly required, that the new namespace be a child of the one for which the method is run.

Note that if the object does not support a type library, the new namespace will be empty and you will have to establish functions corresponding to the methods exported by the interface using SetMethodInfo.


OLERegister Method

OLERegister Method 530
Applies To: OLEServer

Description

This method is used to register an OLEServer object and may be used to install Dyalog OLE Servers as part of a run-time installation.

If the argument to the OLERegister method is a simple character vector, this is treated as text to be inserted into the command line argument for the interpreter. All other arguments are silently ignored.

Note: it is currently necessary to run the APL from which this method is called with Administrator privileges.


OLEUnregister Method

OLEUnregister Method 531
Applies To: OLEServer

Description

This method is used to unregister an OLEServer object that has previously been saved by Dyalog APL.

The OLEUnregister method is niladic.

This method removes all traces of the object from the Windows registry and erases its Type Library file.

Note that the name of the object removed from the registry is the name of the OLEServer object prefixed by the string "dyalog."


Print Method

Print Method 100
Applies To: Printer

Description

This method causes any spooled output to be printed.

The Print method is niladic.

If you attach a callback function to this event and have it return a value of 0, the printout will not be spooled.


ProgressStep Method

ProgressStep Method 250
Applies To: ProgressBar

Description

This method is used to increment the thumb in a ProgressBar object.

The ProgressStep method is niladic.

The ProgressStep method causes the ProgressBar to attempt to increment its thumb by the value of its Step property, taking into account the settings of its Limits and Wrap properties.

If the values of the Thumb, Step and Limits properties are THUMB, STEP and LIMITS respectively, the new value of Thumb (and the corresponding position of the highlighted bar) is:

if Wrap is 0:

      LIMITS[2]⌊THUMB+STEP

if Wrap is 1:

      LIMITS[1]+(1+LIMITS[2]-LIMITS[1])|THUMB+STEP-LIMITS[1]


RTFPrint Method

RTFPrint Method 461
Applies To: RichEdit

Description

This method is used to print the contents (RTFText) of a RichEdit object.

The argument to RTFPrint is ⍬, or a 1 to 4-element array as follows:

[1] | Printer name | Optional - character vector (see below)
[2] | Print range | Optional - (see below)
[3] | Number of copies | Optional - Integer.
[4] | Collate | Optional - 0 or 1

Printer name may be the name of an existing Printer object, or the (Windows) name of an installed printer. If you use the latter, the document will be spooled immediately. An empty vector implies the default printer.

Print range may be a simple character vector containing 'All', 'Pages', or 'Selection'. Alternatively, it may be a 3 or 4-element nested vector containing:

[1] | 'All', 'Pages', or 'Selection'
[2] | Start page (integer)
[3] | End page (integer)
[4] | Maximum pages (ignored)


RTFPrintSetup Method

RTFPrintSetup Method 460
Applies To: Printer RichEdit

Description

This method is used to display a print set-up dialog box. The dialog box allows the user to select a particular printer, the pages to be printed and other information. The user's choices are returned in the result.

The argument to RTFPrintSetup is ⍬, or a 1 to 3-element array as follows:

[1] | Print range | Optional - (see below)
[2] | Number of copies | Optional - Integer.
[3] | Collate | Optional - 0 or 1

Print range may be a simple character vector containing 'All', 'Pages', or 'Selection'.

Alternatively, it may be a 3 or 4-element nested vector containing:

[1] | 'All', 'Pages', or 'Selection'
[2] | Start page (integer)
[3] | End page (integer)
[4] | Maximum pages

Maximum pages (4th element of Print range) may be an integer number, or the name of a reference object. The latter allows the system to calculate the total number of pages required. If the object to which the RTFPrintSetup event is sent is a RichEdit, this is the name of a printer object. If the object to which the RTFPrintSetup event is sent is a Printer, this is the name of a RichEdit object. Both are required because the number of pages of a printed document is dependent upon both the content of the document and the characteristics of the device upon which it will be printed.

If the user presses OK, the result is a 4-element vector containing the user's choices as follows:

[1] | Printer name | character vector
[2] | Print range | (see above)
[3] | Number of copies | Integer
[4] | Collate | 0 or 1

Example:

      F.T.RTFPrintSetup ('All' 1 1 'PR')
 IBM 4039 LaserPrinter PS   Pages  2 3 3  1 0


RowChange Method

RowChange Method 158
Applies To: Grid

Description

This method is used to change the data in a row of a Grid object.

The argument to RowChange is a 2-element array as follows.

[1] | Row number | integer
[2] | Row data | array

Row data must be a scalar or a vector whose length is equal to the number of columns in the Grid. Its elements may be scalar numbers, character vectors or matrices.


RowSetVisibleDepth Method

RowSetVisibleDepth Method 173
Applies To: Grid

Description

This method is used to set the maximum visible depth of data in rows of a Grid.

The argument to RowSetVisibleDepth is a numeric scalar as follows

[1] Depth integer

All rows in the grid that have a value of RowTreeDepth less than or equal to Depth are expanded. Rows with a value of RowTreeDepth greater than Depth are collapsed.

Note: Expanding and Retracting events are not generated when this method is called.

Examples

      'F'⎕WC'Form' 'Grid: TreeView Feature'
      'F.G'⎕WC'Grid'(30 2⍴2/⍳30)
      F.G.RowTreeDepth←30⍴0 1 2 2

      F.G.RowSetVisibleDepth 1

      F.G.RowSetVisibleDepth 99


SetCellSet Method

SetCellSet Method 171
Applies To: Grid

Description

The SetCellSet method sets the value of the CellSet property of a Grid for a particular cell.

The argument to SetCellSet is a 3-element array as follows:

[1] | Row | integer
[2] | Column | integer
[3] | Value | 0 or 1


SetCellType Method

SetCellType Method 156
Applies To: Grid

Description

This method is used to change the type of a particular cell in a Grid.

The argument to SetCellType is a 3-element vector as follows :

[1] | Cell row | integer
[2] | Cell column | integer
[3] | Cell type | integer


SetEventInfo Method

SetEventInfo Method 547
Applies To: ActiveXControl OLEServer

Description

This method is used to register an event that may be generated by an ActiveXControl or OLEServer object.

A host application that wishes to attach a callback function to an event in a Dyalog APL ActiveXControl or OLEServer, needs to know the name of the event and the number and data types of any parameters that the event may supply. It also needs to know the data type (if any) of the result that the callback function may be expected to pass back to the control.

An ActiveXControl or OLEServer generates an event in the host application using 4 ⎕NQ. The right argument is a vector whose first 2 elements are character vectors containing the names of the ActiveXControl or OLEServer and the event respectively. The parameters for the event are passed as additional elements in the argument.

Another way to think about it is that when you generate an event using 4 ⎕NQ, you are effectively calling a function, of your specification, in the host application. To enable the host application to accept the function call, it needs to know the number of parameters that you will supply and their data types.

A further consideration is that if you specify that the data type of a parameter is a pointer (e.g. 'VT_PTR TO I4') this will allow a callback function to modify the parameter in-situ. If so, the result returned by 4 ⎕NQ will be the modified values of any such parameters; this is a similar mechanism to ⎕NA.

The argument to SetEventInfo is a 1, 2, 3 or 4-element array as follows:

[1] | Event name | character vector
[2] | Event info | nested array (see below)
[3] | Help ID | integer
[4] | DISPID | integer. See DISPID (Dispatch ID)

Event info

Event info, specifies an optional help string which describes what the event does, the data type of the result (if any) and the names and data types of its arguments.

If the event is fully described, each element of Event Info is a 2-element vector of character vectors. The first element contains the help string and the COM data type of the result that the callback function in the host application is expected to supply. Subsequent elements contain the name and COM data type of each of the parameters supplied by the event.

However, both the help string and the names of the parameters are optional and may be omitted. If so, one or more elements of Event Info may be a simple character vector.

Help ID

This is an integer value that identifies the help context id for the event within the help file associated with the HelpFile property of the ActiveXControl object. The value ¯1 means that no help is provided. APL stores this information in the registry from where it may be retrieved by the host application.

Example

The example Dual ActiveXControl, that is fully described elsewhere, generates a ChangeValue1 event. This event occurs when the user moves the thumb in a TrackBar that is internal to an instance of the ActiveXControl.

The external ChangeValue1 event is fired by an internal APL callback function (called ChangeValue) that is attached to ThumbDrag and Scroll events on the TrackBar object. The internal callback function is :

[0]   ChangeValue MSG
[1]   ⍝ Callback for ThumbDrag and Scroll
[2]   Value1←4 ⎕NQ'' 'ChangeValue1'(⊃¯1↑MSG)
[3]   CalcValue2
[4]   'V1'⎕WS'Text'(⍕Value1)
[5]   'V2'⎕WS'Text'(⍕Value2)

Note that ChangeValue[2] generates the external ChangeValue1 event by invoking 4 ⎕NQ, passing it the new value provided by the TrackBar. However, the host application is permitted to modify that value, returning it in the result of 4 ⎕NQ. This result, rather than the TrackBar value itself, is then used to update other (Label) controls in the object.

The following statements were used to declare the ChangeValue1 event The event provides a single parameter named Value1 that may be modified in-situ by a callback function in the host application. The callback is not, otherwise, expected to return a result.

      INFO←⊂'Occurs when the value of the control is changed' 'VT_VOID'
      INFO,←⊂'Value1' 'VT_PTR TO VT_I4'
      F.Dual.SetEventInfo 'ChangeValue1' INFO

If the host application was Visual Basic, a suitable callback function might be:

Private Sub Dual1_ChangeValue1(Value1 As Long)
Value1=2*(Value1\2)
End Sub

This callback function receives the proposed new value of the control as the parameter Value1, and modifies it, forcing it to be an even number.


SetFinishText Method

SetFinishText Method 366
Applies To: PropertySheet

Description

The SetFinishText method sets the caption of the Finish button in a Wizard-style PropertySheet.

The argument to SetFinishText is a single item as follows:

[1] Finish button text character vector


SetFnInfo Method

SetFnInfo Method 545
Applies To: ActiveXControl OLEServer

Description

This method is used to describe an APL function that is to be exported as a method, a Property Get Function, or a Property Put Function of an ActiveXControl or OLEServer object.

An exported function must be a niladic or monadic defined function (dfns and derived functions are not allowed) and may optionally return a result. Ambivalent functions (functions with optional left argument) are allowed, but will be called monadically by the host application.

COM syntax differs from APL syntax in many ways and the SetFnInfo method is required to declare an APL function to COM in terms that COM understands. In particular, although monadic APL functions take just one argument, COM functions may take several parameters, and some may be optional.

A function exported by SetFnInfo will be called by a host application with the number of parameters that SetFnInfo has described. The argument received when the function is called by a host application, will be a nested vector of this length.

The argument to SetFnInfo is a 2, 3, 4, 5 or 6-element array as follows:

[1] | Function name | character vector
[2] | Function info | nested array (see below)
[3] | Help ID | integer
[4] | Function type | integer
[5] | Property name | character vector
[6] | DISPID | integer. See DISPID (Dispatch ID)

Function info

This specifies an optional help string which describes what the function does, the data type of the result (if any) and the names and data types of its arguments.

If the function syntax is fully described, each element of Function Info is a 2-element vector of character vectors. The first element contains the help string and the COM data type of the function's result. Subsequent elements contain the name and COM data type of each parameter.

However, both the help string and the names of the parameters are optional and may be omitted. If so, one or more elements of Function Info may be a simple character vector.

Consider a very basic function ADD in an ActiveXControl called F.dbase, that is designed to add a record to a personnel database. The database consists only of a list of names, ages and addresses.

Function ADD expects to be called with a name (character string), age (number) and address (character string), and returns a result 0 or 1 (Boolean) according to whether the record was successfully added. This function could be declared as follows:

      HELP←'Adds a new record to the personnel database'
      SPEC←⊂(HELP 'VT_BOOL')      ⍝ Result is Boolean
      SPEC,←⊂('Name' 'VT_BSTR')   ⍝ 1st param called 'Name' is a string
      SPEC,←⊂('Age' 'VT_I4')      ⍝ 2nd param called 'Age' is an integer
      SPEC,←⊂('Address' 'VT_BSTR')⍝ 3rd param called 'Address' is a string

      F.dbase.SetFnInfo 'ADD' SPEC

Alternatively, but much less helpfully, the function could be declared to take a single unnamed nested argument, leaving it to the host application programmer to guess at its structure :

      SPEC←⊂('' 'VT_BOOL')              ⍝ No help string, result is Boolean
      SPEC,←⊂('' 'VT_ARRAY OF VT_VARIANT') ⍝ Param is a nested array
      F.dbase.SetFnInfo 'ADD'SPEC

Help ID

This is an integer value that identifies the help context id within the help file associated with the HelpFile property of the ActiveXControl object. The value ¯1 means that no help is provided. APL stores this information in the registry from where it may be retrieved by the host application.

Function type

This specifies the type of function being exported. This is an integer with one of the following values:

1 | Function is a method
2 | Function is a property get function
4 | Function is a property put function

In both these last two cases, the name of the property, which is totally independent of the name of the APL function, is given as Property name.

If omitted, the function type is method.


SetItemImage Method

SetItemImage Method 315
Applies To: TreeView

Description

This method is used to allocate a picture icon to a particular item in a TreeView object.

The argument to SetItemImage is a 2-element array as follows:

[1] | Item number | Integer.
[2] | Picture index | Integer.

Item number is the index of the item concerned.

Picture index is an index into the array of bitmapped images in the corresponding ImageList object which is referenced via the ImageListObj property.


SetItemState Method

SetItemState Method 307
Applies To: ListView TreeView

Description

This method is used to set the status of a particular item in a ListView or TreeView object.

The argument to SetItemState is a 2-element array as follows:

[1] | Item number | Integer. The index of the item concerned.
[2] | Status | Integer

The status of an item is calculated as the sum of one or more of the following state codes:

¯1 | Error (most likely the Item number is invalid)
1 | Item has the focus
2 | Item is selected
8 | Item is highlighted for dropping
16 | Item is displayed in bold text
32 | Item is expanded
64 | Item is or has been expanded
4096 | Item is checked. See CheckBoxes


SetMethodInfo Method

SetMethodInfo Method 556
Applies To: OCXClass OLEClient

Description

This method is used to redefine the arguments or data types associated with a method that is exported by a COM object. SetMethodInfo is used to override the information provided by the object's Type Library.

The argument to SetMethodInfo is a 2 or 3-element array as follows:

[1] | Method name | character vector
[2] | Method info | nested vector (see below)
[3] | Method index | integer

If you wish to describe the method completely, the structure of Method info should be identical to the structure returned by GetMethodInfo, although abbreviated formats are also allowed.

If the object exports the method directly, and not through the standard IDispatch interface, you must also specify Method Index, which is the index of the method in the object's virtual table (vtable). This information may be available in printed documentation or in a C-language header file.

For example, the InchesToPoint method exported by Excel.Application takes a single argument whose name is Arg1 and whose data type is VT_R8. The function returns a result of the same data type. The details provided in the Excel.Application Type Library are in fact correct, but if you wanted to redefine them, the following statements could be used to describe the InchesToPoints method.

      'EX' ⎕WC 'OLEClient' 'Excel.Application' ('AutoBrowse' 0)

      methodinfo← ('' 'VT_R8')('Arg1' 'VT_R8')
      EX.SetMethodInfo 'InchesToPoints' methodinfo

Note that the structure of variable methodinfo is identical to the result of the GetMethodInfo method.

      DISPLAY methodinfo
┌→───────────────────────────────────┐
│ ┌→────────────┐ ┌→───────────────┐ │
│ │ ┌⊖┐ ┌→────┐ │ │ ┌→───┐ ┌→────┐ │ │
│ │ │ │ │VT_R8│ │ │ │Arg1│ │VT_R8│ │ │
│ │ └─┘ └─────┘ │ │ └────┘ └─────┘ │ │
│ └∊────────────┘ └∊───────────────┘ │
└∊───────────────────────────────────┘

      DISPLAY EX.GetMethodInfo 'InchesToPoints'
┌→───────────────────────────────────┐
│ ┌→────────────┐ ┌→───────────────┐ │
│ │ ┌⊖┐ ┌→────┐ │ │ ┌→───┐ ┌→────┐ │ │
│ │ │ │ │VT_R8│ │ │ │Arg1│ │VT_R8│ │ │
│ │ └─┘ └─────┘ │ │ └────┘ └─────┘ │ │
│ └∊────────────┘ └∊───────────────┘ │
└∊───────────────────────────────────┘

Unless you are going to call the method using the names of its arguments, these names are clearly superfluous and may be omitted, for example:

      methodinfo← 'VT_R8' 'VT_R8'
      EX.SetMethodInfo 'InchesToPoints' methodinfo


SetPropertyInfo Method

SetPropertyInfo Method 554
Applies To: OCXClass OLEClient

Description

This method is used to redefine a property that is exported by a COM object. SetPropertyInfo is used to override the information provided by the object's Type Library.

The argument to SetPropertyInfo is a 2 or 3-element array as follows:

[1] | Property name | character vector
[2] | Property info | nested vector
[3] | Property function | integer
[4] | DISPID | integer. See DISPID (Dispatch ID)

For example, the Visible property exported by Excel.Application has the data type VT_BOOL and may be declared as follows:

      'EX' ⎕WC 'OLEClient' 'Excel.Application'
      EX.SetPropertyInfo 'Visible' 'VT_BOOL'

Property function may be required if the property value is retrieved or set via a function. This typically applies if the property takes parameters and will result in the property being fixed as a function rather than as a variable. Such properties may have a PropertyGet function, a PropertyPut function and/or a PropertyPutByReference function. If so, it is necessary to say to which of these three functions the details apply. The value of Property function is an integer 2 (PropertyGet), 4 (PropertyPut), or 8 (PropertyPutByReference).

For example, the following statement declares the PropertyGet function for the Item property of the Fields collection of the OLE object DAO.DBEngine. This property takes an index (into the collection) and returns an object.

      Fields.SetPropertyInfo 'Item'('VT_DISPATCH' 'VT_I4')2


SetServiceState Method

SetServiceState Method 93
Applies To: Root

Description

This method is used to set the state of a Dyalog APL service running under Windows. See APL Application as a Service.

The argument to the SetServiceState method is the desired state of the service. This should be one of the following numeric values:

SERVICE_STOPPED | 1
SERVICE_RUNNING | 4
SERVICE_PAUSED | 7

The state of a Windows service is determined by the user and the Windows Service Control Manager (SCM).

When the SCM requests a change of state, the APL interpreter responds by setting its state to the corresponding pending level (SERVICE_STOPPED_PENDING, SERVICE_RUNNING_PENDING or SERVICE_PAUSED_PENDING) and then generates a ServiceNotification event.

It is the responsibility of the APL service to process this event, perform the appropriate application tasks, and then respond (to the SCM) by calling the SetServiceState method to confirm that the service has reached the desired state.


SetVarInfo Method

SetVarInfo Method 546
Applies To: ActiveXControl OLEServer

Description

This method is used to describe an APL variable that is to be exported as a property of an ActiveXControl or OLEServer object.

The argument to SetVarInfo is a 2 or 3-element array as follows:

Variable info is either a simple character vector that specifies the COM data type of the variable, or a 2-element vector of character vectors whose first element specifies a help string and whose second element specifies the COM data type.

Help ID is an optional integer value that identifies the help context id within the help file associated with the HelpFile property of the ActiveXControl object. The value ¯1 means that no help is provided. APL stores this information in the registry from where it may be retrieved by the host application.


SetWizard Event

SetWizard Event 365
Applies To: PropertySheet

Description

If enabled, this event is reported when the user has clicked the Next or Back button in a PropertySheet with Style 'Wizard'. This action also generates PageNext (or PageBack) and PageDeactivate and PageActivate events. The SetWizard event is the final event to be reported as a result of this action, and is the only one that is affected by the result of a callback function. The event message reports the active/inactive state of the 3 page changing buttons (Back, Next and Finish) that should result from the action. Note that the Next and Finish buttons occupy the same position and are mutually exclusive.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 5-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'SetWizard' or 365
[3] | Active state Back | 0 or 1
[4] | Active state Next | 0 or 1
[5] | Active state Finish | 0 or 1
[6] | Finish caption | character vector

You may alter the state of the buttons by changing elements [3-5] of the event message and returning it as a result of your callback. You may also set the state of the buttons at any time by calling SetWizard as a method.

When the event is reported by ⎕DQ, element 6 is an empty vector. If you modify it and return it in the result of a callback, the caption of the Finish button changes accordingly and the Back and Next buttons disappear. This happens regardless of the states you specified in elements [3-5].


Setup Method

Setup Method 101
Applies To: Printer

Description

This method causes the system to display a standard Printer Setup dialog box and thereby allows the user to alter the printer settings. This is a "modal" dialog box that must be closed before the APL application can continue.

The Setup method is niladic.

If you attach a callback function to this event and have it return a value of 0, the dialog box will not appear.


ShowBalloonTip Method

ShowBalloonTip Method 860
Applies To: SysTrayItem

Description

The ShowBalloonTip method displays a BalloonTip in a SysTrayItem object.

The argument to ShowBalloonTip is a 1, 2, 3 or 4-element array as follows:

[1] | Title | character vector
[2] | Text | character vector or matrix
[3] | Icon | Integer scalar, a character vector or a ref
[4] | Flags | Integer

The Title parameter is the text to be displayed in the BalloonTip title (maximum length 64).

The Text parameter is the text (maximum length 256) to be displayed in the BalloonTip. If omitted or empty, the BalloonTip is not displayed.

If the Icon parameter is an integer, it means:

0 | No icon
1 | Information icon
2 | Warning icon
3 | Error icon

Other values represent the name or a ref to an Icon object. If the Icon parameter is omitted, no icon is displayed in the BalloonTip.

If the Icon parameter specifies a large Icon object (32 x 32 bits) the Flags parameter must be 32. Otherwise this parameter is not used.


ShowHelp Method

ShowHelp Method 580
Applies To: OCXClass OLEClient

Description

This method is used to display the Windows help file for a COM object or the help topic associated with one of its properties, events or methods.

The argument to ShowHelp is ⍬, or a single item as follows :

[1] Topic character vector.

Topic specifies the name of a property, event or method.

In the case of an OLE Control, the object name may be the name of the OCXClass or an instance of the OCXClass.


ShowItem Method

ShowItem Method 316
Applies To: TreeView

Description

This method is used to display a particular item in a TreeView object.

The argument to ShowItem is a single item as follows:

[1] Item number Integer.

Item number specifies the index of the item concerned.

In order to display the requested item, the parent item (if any) will be opened and the object will be scrolled if necessary.


ShowProperties Method

ShowProperties Method 560
Applies To: OCXClass

Description

This method is used to display the PropertySheet for an instance of an OLE Control. The user may then modify some or all of the properties of the control by changing values in the property sheet. This facility is intended to be used in the context of a GUI design tool but may also be useful in certain end-user applications.

The ShowProperties method is niladic.


ShowSIP Method

ShowSIP Method 25

Applies To

Description

ShowSIP applies only to PocketAPL. In versions of Dyalog APL for other platforms, it has no effect.

This method displays and hides the Input Panel.

The argument to ShowSIP is 1 (display the Input Panel) or 0 (hide the Input Panel).

The argument to ShowSIP is 0 or 1 as follows:

[1] Mode Boolean
0 = hide the Input Panel.
1 = display the Input Panel

The result of ShowSIP is 1 if the Input Panel was previously displayed, or 0 if it was previously hidden.


TCPGetHostID Method

TCPGetHostID Method 376
Applies To: Root TCPSocket

Description

This method is used to obtain the IP Address of your PC.

The TCPGetHostID method is niladic.

The (shy) result is a character string containing your IP address. If you have more than one, it will return the first.

For example:

      TCPCetHostID
193.32.236.43


TCPSend Method

TCPSend Method 375
Applies To: TCPSocket

Description

This method is used to send data to a remote process connected to a TCPSocket object

The argument to TCPSend is a 1 or 3-element array as follows:

[1] | Data | the data to be sent
[2] | IP address | character vector
[3] | Port number | integer

If Style is 'Char', the data to be sent must be a character vector. If Style is 'Raw', the data to be sent must be an integer vector whose elements are in the range -128 to 255. If Style is 'APL', any array may be transmitted.

The optional IP address and Port number parameters specify the intended recipient of the message and apply only if the SocketType is 'UDP', in which case they are mandatory. If the SocketType is 'Stream', these parameters will be ignored and should be omitted.


TCPSendPicture Method

TCPSendPicture Method 380
Applies To: TCPSocket

Description

This method is used to transmit a picture represented by a Bitmap object to a TCP/IP socket. The picture may be transmitted in GIF or in PNG format.

The argument to TCPSendPicture is a 1 or 2-element array as follows:

[1] | Bitmap name | character vector
[2] | Picture format | character vector, 'GIF' or 'PNG'

If Picture format is omitted, the default is GIF format.

Note that the Style of the TCPSocket object must be set to 'Raw' before you execute the TCPSendPicture method.

The (shy) result of the method is an integer that reports the number of bytes that were transmitted.

Example:

      S1.TCPSendPicture 'BM' 'PNG'
4930

Note: Although PNG is recognised as the latest graphics standard for displaying pictures, not all Web browsers support it.

See also: MakeGIF, MakePNG


Undo Method

Undo Method 170
Applies To: Grid

Description

This method is used to undo the previous change in a Grid object.

The Grid object maintains a buffer of the most recent 8 changes made by the user since the Values property was last set by ⎕WC or ⎕WS.

Your application can restore these changes one by one by calling the Undo method on the Grid. The Undo method restores the most recent change made by the user and removes that change from the undo stack.

It is therefore not possible to "undo an undo".

The argument to Undo is ⍬, or a single item as follows :

[1] Number of changes integer

If called with an argument of ⍬, the default value for the Number of changes is 1. This restores the most recent change.


Wait Method

Wait Method 147

Applies To

Description

The Wait method is the same as executing ⎕DQ on the object.

The Wait method is niladic.

      'F'⎕WC'Form'
...
      Z←F.Wait


Introduction

The Dyalog APL Development Environment includes a Session Manager, an Editor, and a Tracer all of which operate in windows on the screen. The session window is created when you start APL and is present until you terminate your APL session. In addition there may be a number of edit and/or trace Windows, which are created and destroyed dynamically as required. All APL windows are under the control of Windows and may be selected, moved, resized, maximised and minimised using the standard facilities that Windows provides.


APL Keyboards

The Classic and Unicode Editions of Dyalog APL for Windows use different techniques for mapping keystrokes to APL characters and to special command shortcuts.

The Classic Edition uses a proprietary technique for these mappings.

By default, the Unicode Edition uses Microsoft's IME (Input Method Editor) technology. Many other applications use the same technology, which means that the Dyalog Unicode IME may be used not only with Dyalog APL for Windows Unicode Edition, but also with word processing applications, spreadsheets, terminal emulators etc. Therefore with the Dyalog Unicode IME installed, and with a suitable font selected, APL characters can be entered and viewed in many other applications.

As an alternative to the Dyalog Unicode IME, whose installation requires Administrator privileges, the key mapping for the Unicode Edition may be specified in the Windows registry. See Unicode Edition and the Registry Keyboard.

In both Classic and Unicode Editions APL characters are generated when the user presses certain combinations of meta keys in conjunction with the normal character keys. Meta keys include Shift, Ctrl and Alt.

For both input techniques it is possible to alter the mapping of keystrokes to APL characters, and to add support for new languages. It is also possible to alter the keystrokes which define special command keyboard shortcuts. For further details, see Unicode Edition Keyboard or Classic Edition Keyboard

Unicode Edition and the Dyalog Unicode IME

The Dyalog Unicode IME is the default input mechanism for generating APL characters for Unicode editions of Dyalog APL. The version of the IME supplied with version 17.0 can be used with version 12.1 and later, provided that they are patched to a version created on or after 1st April 2011.

The Dyalog Unicode IME defines the mapping of keystrokes to Unicode characters. Only keystrokes which resolve to characters that either do not appear on the standard keyboard or which differ from those that appear on the standard keyboard are included in the selectable translate table. In effect the Dyalog Unicode IME can be regarded as an overlay of the standard keyboard which contains just APL characters.

The Dyalog Unicode IME supplied with Version 17.0 includes support for Belgian, Danish, Finnish, French, German, Italian, Spanish Swedish and British and American English keyboards, based on the Dyalog hardware keyboard layout; these keyboard layouts are described at http://dfns.dyalog.com/n_keyboards.htm. Note that for Danish, British and American English keyboards the older layouts, based on the Dyalog APL Ctrl Keyboard, are included in the UnicodeIME\aplkeys directory.

The default keyboard mapping for unsupported languages is American English.

The IME translate tables include mappings for the special command keystrokes used by Dyalog APL.

These command keystroke mappings are ignored by applications unless the application is explicitly named in the Dyalog Unicode IME configuration. It is expected that only terminal emulators used for running UNIX-based versions of Dyalog APL will use this feature.

In particular, Dyalog APL for Windows Unicode Edition does not use the mappings in the translate tables; the mappings are defined under Options/Configure/Keyboard Shortcuts (see Keyboard Shortcuts Tab).

Note that the Dyalog Unicode IME replaces any previous IME, as well as the Dyalog Ctrl and Dyalog AltGr keyboards.

Unicode Edition and the Registry Keyboard

The Registry Keyboard provides an alternative mechanism for the Unicode Edition. This feature maps keystrokes to APL characters using entries in the Windows Registry. Dyalog supports the mechanism but does not provide the mappings which must therefore be defined by the user.

Note that the Dyalog IME is used if it is available; the Registry Keyboard mechanism is used only if the Dyalog IME is not installed.

The mappings are defined in the Registry sub-folder :

Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Dyalog\Dyalog APL/W-64 17.0 Unicode\KeyboardShortcuts\chars

Each entry consists of theUnicode code point of an APL character followed by the keystroke to which it is mapped.

The keystroke is defined by 4 hexadecimal values which specify the key, the shift-state, and 2 zeros. The key is represented by the Unicode code point of the symbol engraved upon it, so (on a UK keyboard) the <1> key is hex 31 and the <A> key is hex 41. The Shift-states values are the sum of 1 (Shift), 2 (Ctrl), 4 (Alt).

"0x230A"=hex:44,02,00,00
"0x235F"=hex:38,03,00,00

In the first entry, the APL character is Unicode code point 230A which is ⌊. The key is <D> (hex 44) and the shift-state is Ctrl (hex 02).

In the second entry, the APL character is Unicode code point 235F which is ⍟. The character is entered by pressing <*> ( hex 38) with Shift+Ctrl (hex 03).

Classic Edition

The mapping for each of the ⎕AV positions and its associated keystroke is defined by a selectable translate table. ⎕AV includes all the APL symbols used by Dyalog APL as well as all the (non-APL) characters which appear on a standard keyboard. This mapping only works with Classic Edition.

The Classic Edition installation also includes the Dyalog Unicode IME (described below) so that users may enter APL characters into other applications; the Dyalog Unicode IME is however not used by the Classic Edition itself.

The Classic Edition includes support for Danish, Finnish, French, German, Italian, Swedish, and both British and American English keyboards. The default keyboard mapping for unsupported languages is American English.

Backtick Keyboard

In addition to the standard APL keyboards, the RIDE keyboard may be used natively. See Backtick Keyboard.


Session Manager

The Dyalog APL/W session is fully configurable. Not only can you change the appearance of the menus, tool bars and status bars, but you can add new objects of your choice and attach your own APL functions and expressions to them. Functions and variables can be stored in the session namespace. This is independent of the active workspace; so there is no conflict with workspace names, and your utilities remain permanently accessible for the duration of the session. Finally, you may set up different session configurations for different purposes which can be saved and loaded as required.

The session window is defined by an object called ⎕SE. This is very similar to a Form object, but has certain special properties. The menu bar, tool bar and status bars on the session window are in fact MenuBar, ToolControl and StatusBar objects owned by ⎕SE. All of the other components such as menu items and tool buttons are also standard GUI objects. You may use ⎕WC to create new session objects and you may use ⎕WS to change the properties of existing ones. ⎕WG and ⎕WN may also be used with ⎕SE and its children.

Components of the session that perform actions (MenuItem and Button objects) do so because their Event properties are defined to execute system operations or APL expressions. System operations comprise a pre-defined set of actions that can be performed by Dyalog APL/W. These are coded as keywords within square brackets. For example, the system operation [WSClear] produces a clear ws, after first displaying a dialog box for confirmation. You may customise your session by adding or deleting objects and by attaching system operations or APL expressions to them.

Like any other object, ⎕SE is a namespace that may contain functions and variables. Furthermore, ⎕SE is independent of the active workspace and is unaffected by )LOAD and )CLEAR. It is therefore sensible to store commonly used utilities, particularly those utilities that are invoked by events on session objects, in ⎕SE itself, rather than in each of your application workspaces.

The possibility of configuring your APL session so extensively leads to the requirement to have different sessions for different purposes. To meet this need, sessions are stored in special files with a .DSE (Dyalog Session) extension. The default session (i.e. the one loaded when you start APL) is specified by the session_file parameter. You may customise this session and then save it over the default one or in a separate file. You can load a new session from file at any stage without affecting your active workspace.

Positioning the Cursor

The cursor may be positioned within the current APL window by moving the mouse pointer to the desired location and then clicking the Left Button. The APL cursor will then move to the character under the pointer.

Selection

Dragging the mouse selects the text from the point where the mouse button is depressed to the point where the button is released. When you select multiple lines, the use of the left mouse button always selects text from the start of the line. A contiguous block of text can be selected by dragging with the right mouse button.

Double-clicking the left mouse button to the left of a line selects the whole line, including the end-of-line character.

Scrolling

Data can be scrolled in a window using the mouse in conjunction with the scrollbar.

Invoking the Editor

The Editor can be invoked by placing the mouse pointer over the name of an editable object and double-clicking the left button on the mouse. If you double-click on the empty Input Line it acts as "Naked Edit" and opens an edit window for the suspended function (if any) on the APL stack. For further details, see Invoking the Editor. See also "Installation and Configuration Guide: DoubleClickEdit".

The Current Object

If you position the input cursor over the name of an object in the session window, that object becomes the current object. This name is stored in the CurObj property of the Session object and may be used by an application or a utility program. This means that you can click the mouse over a name and then select a menu item or click a button that executes code that accesses the name.

The Session Pop-up Menu

Clicking the right mouse button brings up the Session pop-up menu. This is described later in this chapter.

Drag-and-Drop Editing

Drag-and-Drop editing is the easiest way to move or copy a selection a short distance within an edit window or between edit windows.

To move text using drag-and-drop editing:

  1. Select the text you want to move.
  2. Point to the selected text and then press and hold down the left mouse button. When the drag-and-drop pointer appears, drag the cursor to a new location.
  3. Release the mouse button to drop the text into place.

To copy text using drag-and-drop editing:

  1. Select the text you want to move.
  2. Hold down the Ctrl key, point to the selected text and then press and hold down the left mouse button. When the drag-and-drop pointer appears, drag the cursor to a new location.
  3. Release the mouse button to drop the text into place.

If you drag-and-drop text within the Session window, the text is copied and not moved whether or not you use the Ctrl key.

Interrupts

To generate an interrupt, click on the Dyalog APL icon in the Windows System Tray; then choose Weak Interrupt or Strong Interrupt. To close the menu, click Cancel. Alternatively, to generate a weak interrupt, press Ctrl+Break, or select Interrupt from the Action menu on the Session Window.


Unified_Edition_Keyboard

Unicode Edition Keyboard

Introduction

Unicode Edition supports the use of standard Windows keyboards that have the additional capability to generate APL characters when the user presses Ctrl, Alt, AltGr (or some other combination of meta keys) in combination with the normal character keys.

Dyalog APL is supplied with the Dyalog Unicode IME keyboard for a range of different languages as listed below. The intention is that only APL characters and characters that appear in locations different from the underlying keyboard are defined; any other keystroke is passed through as is.

Installation

During the Installation of Dyalog APL Unicode Edition, setup installs the Dyalog Unicode IME (IME). For any given Input Language the IME consists of an additional service for that Input Language, and a translate table which maps keystrokes for the appropriate keyboard to Unicode code points for APL characters

An IME service is installed for every Input Language that the user who installs Dyalog APL has defined, as well as every Input Language for which Dyalog has support.

The keyboard mappings are defined for the following national languages: Belgian, Danish, Finnish, French, German, Italian, Spanish, Swedish and British and American English

These mappings are described at http://dfns.dyalog.com/n_keyboards.htm.

For any other Input Language the American English translate table is selected. Note that some Input Languages are defined to be substitutes for other Input Languages; for example Australian English Input is a substitute for American English Input, Austrian German Input a substitute for German German Input. In these cases the IME will install the appropriate translate table. It is also possible to create support for new languages or to modify the existing support. See the IME User Guide for further details.


IME Configuration

Configuring the Dyalog APL IME

The Dyalog Unicode IME is added as an additional service to all keyboards defined to the user and the administrator at the time that the IME was installed.

For each IME the underlying keyboard layout file will be the same as that defined for the base keyboard. The layout file is a DLL created by Microsoft.

The language specified in the description of the IME is the name of the IME translate table that has been associated with the IME for the specific keyboard. In the case of languages not supported by the IME the keyboard will default to en-US.

IME Properties

To change the properties of the IME go to Options/Configure/Unicode Input tab and select Configure Layout:

Input translate table:

The translate table defines the mapping between APL characters and the keystrokes that generate those APL characters. It is possible to alter the mapping or to create support for new keyboards by altering the translate table, or by selecting a different translate table. See the IME User Guide for more details.

Backtick Keyboard

The Backtick keyboard provided by the RIDE may be used natively. By default it is disabled. To enable it, check the box labelled Enable Backtick Keyboard introducer. You may replace the backtick character (`) with an alternative character to act as the introducer for APL glyphs, but take care to choose a character that is otherwise unused.

For information on using this keyboard interface, see http://docs.dyalog.com/16.0/RIDE User Guide.pdf Section 7.4.

Overstrikes:

In the original implementations of APL, many of the special symbols could only be generated by overstriking one character on top of another as is reflected in the appearance of the glyphs. For example, the symbol for Grade Up (⍋) is actually the symbol for delta (∆) superimposed on the symbol for vertical bar (|)

In Dyalog APL such symbols can be generated either by a single keystroke, or (in Replace mode) by overtyping one symbol with another. For example ⍋ may be generated using Shift+Ctrl+4, or by switching to Replace mode and typing the three keystrokes Ctrl+h, Left-Cursor, Ctrl+m.

Using the Dyalog Unicode IME the character can also be entered by pressing Ctrl+Bksp, Ctrl+m, Ctrl+h. Note that Ctrl+Bksp is the default Overstrike Introducer Key (key code OS).

Use Overstrike popup:

With this option selected, when the character following the Overstrike Introducer Key is pressed, a popup box displays all the overstrikes which contain the last character typed: in the example below Ctrl+Bksp has been followed by Ctrl+h:

Note the fine (red) line under the ∆. This indicates that an overstrike creation operation is in progress.

The input of the symbol ⍋ can be completed by pressing Ctrl+m, or by moving the selection up and down the pop-up list using Cursor-Up or Cursor-Down.

Overstrikes do not require the OS introducer key:

With this option selected, the IME identifies characters which are part of a valid overstrike, and when such a character is entered into the session, begins an overstrike creation operation.


Classic Edition Keyboard

The standard Classic Edition keyboard tables are files supplied in the aplkeys sub-directory named cc.din where cc is the standard 2-character country code, e.g. uk.din.

Note that the standard tables do not support the entry of APL underscored characters ⍙ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ.

The standard table supports two modes of use; traditional (mode 0) and unified (mode 1). The keyboard starts in mode 1 and may be switched between modes by clicking the Uni/Apl field in the status bar or by keying * on the Numeric-Keypad.

The Classic Edition keyboard layout is close to that of the Unicode Edition, but does not include certain symbols which are only provided in the Unicode Edition.


Keyboard Shortcuts

The terms keyboard shortcut (Unicode Edition) and command (Classic Edition) are used herein to describe a keystroke that generates an action, rather than one that produces a symbol.

Unicode Edition

Unicode Edition provides a number of shortcut keys that may be used to perform actions. For compatibility with Classic Edition and with previous Versions of Dyalog APL, these are identified by 2-character codes; for example the action to start the Tracer is identified by the code <TC>, and mapped to user-configurable keystrokes.

In the Unicode Edition, Keyboard Shortcuts are defined using Options/Configure/Keyboard Shortcuts and stored in the Windows Registry. Note that the Unicode IME translate tables have definitions for the Keyboard Shortcuts too; these are ignored by the interpreter, and are intended for use with terminal emulators being used in conjunction with non-GUI versions of Dyalog APL.

To the right of the last symbol in the Language Bar is the Keyboard Shortcut icon [image]. If you hover the mouse over this icon, a pop-up tip is displayed to remind you of your keyboard shortcuts as illustrated below.

Classic Edition

Commands fall into four categories, namely cursor movement, selection, editing directives and special operations, and are summarised in the following tables. The input codes in the first column of the tables are the codes by which the commands are identified in the Input Translate Table.

Table 32: Cursor Movement Commands

Input Code | Keystroke | Description
LS | Ctrl+PgUp | Scrolls left by a page
RS | Ctrl+PgDn | Scrolls right by a page
US | PgUp | Scrolls up by a page
DS | PgDn | Scrolls down by a page
LC | Left Arrow | Moves the cursor one character position to the left
RC | Right Arrow | Moves the cursor one character position to the right
DC | Down Arrow | Moves the cursor to the current character position on the line below the current line
UC | Up Arrow | Moves the cursor to the current character position on the line above the current line
UL | Ctrl+Home | Move the cursor to the top-left position in the window
DL | Ctrl+End | Moves the cursor to the bottom-right position in the window
RL | End | Moves the cursor to the end of the current line
LL | Home | Moves the cursor to the beginning of the current line
LW | Ctrl+Left Arrow | Moves the cursor to the beginning of the word to the left of the cursor
RW | Ctrl+Right Arrow | Moves the cursor to the end of the word to the right of the cursor
TB | Ctrl+Tab | Switches to the next session/edit/trace window
BT | Ctrl+Shift+Tab | Switches to the previous session/edit/trace window

Table 33: Selection Commands

Input Code | Keystroke | Description
Lc | Shift+Left Arrow | Extends the selection one character position to the left
Rc | Shift+Right Arrow | Extends the selection one character position to the right
Lw | Ctrl+Shift+Left Arrow | Extends the selection to the beginning of the word to the left of the cursor
Rw | Ctrl+Shift+Right Arrow | Extends the selection to the end of the word to the right of the cursor
Uc | Shift+Up Arrow | Extends the selection to the current character position on the line above the current line
Dc | Shift+Down Arrow | Extends the selection to the current character position on the line below the current line
Ll | Shift+Home | Extends the selection to the beginning of the current line
Rl | Shift+End | Extends the selection to the end of the current line
Ul | Ctrl+Shift+Home | Extends the selection to the beginning of the first line in the window
Dl | Ctrl+Shift+End | Extends the selection to the end of the last line in the window
Us | Shift+PgUp | Extends the selection up by a page
Ds | Shift+PgDn | Extends the selection down by a page

Table 34: Editing Directives

Input Code | Keystroke | Description
DI | Delete | Deletes the selection
DK | Ctrl+Delete | Deletes the current line in an Edit window. Deletes selected lines in the Session Log
CT | Shift+Delete | Removes the selection and copies it to the clipboard
CP | Ctrl+Insert | Copies the selection into the clipboard
FD | Ctrl+Shift+Enter | Reapplies the most recent undo operation
BK | Ctrl+Shift+Bksp | Performs an undo operation
PT | Shift+Insert | Copies the contents of the clipboard into a window at the location selected
OP | Ctrl+Shift+Insert | Inserts a blank line immediately after the current one (editor only)
HT | Tab | Indents text
TH | Shift+Tab | Removes indentation
RD | Keypad-slash | Reformats a function (editor only)
TL | Ctrl+Alt+L | Toggles localisation of the current name
GL | Ctrl+Alt+G | Go to [line]
AO | Ctrl+Alt+, | Add Comments
DO | Ctrl+Alt+. | Delete Comments
AC |  | Align Comments

Table 35: Special Operations

Input Code | Keystroke | Description
IN | Insert | Insert on/off
LN | Keypad-minus | Line numbers on/off
ER | Enter | Execute
ED | Shift+Enter | Edit
TC | Ctrl+Enter | Trace
EP | Esc | Exit
QT | Shift+Esc | Quit


Session Colour Scheme

The Session Colour Scheme

Within the Development Environment, different colours are used to identify different types of information. These colours are normally defined by registry entries and may be changed using the Colour Configuration dialog box as described later in this chapter.

In the Classic Edition, colours may alternatively be defined in the Output Translate Table (normally WIN.DOT). This table recognises up to 256 foreground and 256 background colours which are referenced by colour indices 0-255. These colour indices are mapped to physical colours in terms of their Red, Green and Blue intensities (also 0-255). Foreground and background colours are specified independently as Cnnn or Bnnn. For example, the following entry in the Output Translate Table defines colour 250 to be red on magenta.

   C250: 255 0 0   + Red foreground
   B250: 255 0 255 + Magenta background

The first table below shows the colours used for different session components. The second table shows how different colours are used to identify different types of data in edit windows.

Table 36: Default Colour Scheme - Session

Colour | Used for | Default
249 | Input and marked lines | Red on White
250 | Session log | Black on White
252 | Tracer : Suspended Function | Yellow on Black
253 | Tracer : Pendent Function | Yellow on Dark Grey
245 | Tracer : Current Line | White on Red

Table 37: Default Colour Scheme Edit windows

Colour | Array Type | Editable | Default
236 | Simple character matrix | Yes | Green on Black
239 | Simple numeric | No | White on Dk Grey
241 | Simple mixed | No | Cyan on Dk Grey
242 | Character vector of vectors | Yes | Cyan on Black
243 | Nested array | No | Cyan on Dk Grey
245 | ⎕OR object | No | White on Red
248 | Function or Operator | No | White on Dk Cyan
254 | Function or Operator | Yes | White on Blue

Syntax Colouring in the Session

As an adjunct to the overall Session Colour Scheme, you may choose to apply a syntax colouring scheme to the current Session Input line(s). You may also extend syntax colouring to previously entered input lines, although this only applies to input lines in the current session; syntax colouring information is not remembered in the Session Log.

Syntax colouring may be used to highlight the context of names and other elements when the line was entered. For example, you can identify global names and local names by allocating them different colours.

See Colour Selection Dialog for further details.


The Session Window

The primary purpose of the session window is to provide a scrolling area within which you may enter APL expressions and view results. This area is described as the session log. Normally, the session window will have a menu bar at the top with a tool bar below it. At the bottom of the session window is a status bar. However, these components of the session may be extensively customised and, although this chapter describes a typical session layout, your own session may look distinctly different. A typical Session is illustrated below.

A typical Session window

Window Management

When you start APL, the session is loaded from the file specified by the session_file parameter. The position and size of the session window are defined by the Posn and Size properties of the Session object ⎕SE, which will be as they were when the session file was last saved.In a Windows shortcut to an application, the Run: state may be one of "Normal window", "Minimised" and "Maximised". There are other states which can be set when a process is spawned. If the Run: state is Normal or Default, Dyalog APL will use the settings in the current session file to determine the state and size of the session on startup; for all other states (including Maximised and Minimised) these states will be used, superceding the settings in the current session file. 1

The name of the active workspace is shown in the title bar of the window, and changes if you rename the workspace or )LOAD another.

You can move, resize, minimise or maximise the Session Window using the standard Windows facilities.

In addition to the Session Window itself, there are various subsidiary windows which are described later in the Chapter. In general, these subsidiary windows may be docked inside the Session window, or may be stand-alone floating windows. You may dock and undock these windows as required. The standard Session layout illustrated above, contains docked Editor, Tracer and SIStack windows.

Note that the session window is only displayed when it is required, i.e. when APL requests input from or output to the session. This means that end-user applications that do not interact with the user through the session will not have an APL session window.

Docking

Nearly all of the windows used in the Dyalog APL IDE may be docked in the Session window or be stand-alone floating windows. When windows are docked in the Session, the Session window is split into resizable panes, separated by splitters. The following example, using the Status window, illustrates the principles involved. (The use of the Status window is described later in this Chapter.)

To start with, the Status window is hidden. You may display it by selecting the Status menu item from the Tools menu. It initially appears as a floating (undocked) window as shown below.

If you press the left mouse button down over the Status window title bar, and drag it, you will find that when the mouse pointer is close to an edge of the Session window, the drag rectangle indicates a docking zone as shown below. This indicates the space that the window will occupy if you now release the mouse button to dock it.

The next picture shows the result of the docking operation. The Session window is now split into 2 panes, with the Status window in the upper pane and the Session log window in the lower pane. You can resize the panes by dragging with the mouse.

You will notice that a docked window has a title bar (in this case, the caption is Status) and 3 buttons which are used to Minimise, Maximise and Close the docked window.

The next picture shows the result of minimising the Status window pane. All that remains of it is its title bar. The Minimise button has changed to a Restore button, which is used to restore the pane to its original size.

You can pick up a docked window and then re-dock it along a different edge of the Session as illustrated below.

Docking the Status window along the left edge of the Session causes the Session window to be split into two vertical panes. Notice how the title bar is now drawn vertically.

If you click the right mouse button over any window, its context menu is displayed. If the window is dockable, the context menu contains the following options:

Undock | Undocks the docked window. The window is displayed at whatever position and size it occupied prior to being docked
Hide Caption | Hides the title bar of the docked window
Dockable | Specifies whether the window is currently dockable or is locked in its current state. You can use this to prevent the window from being docked or undocked accidentally

The last picture shows the effect of using Hide Caption to remove the title bar. In this state, you can resize the pane with the mouse, but the Minimise, Maximise and Close buttons are not available. However, you can restore the object's title bar using its context menu.


Language Bar

The Language Bar is an optional window which is initially docked to the Session Window, to make it easy to pick APL symbols without using the keyboard.

If you hover the mouse pointer over a symbol in the Language Bar, a pop-up tip is displayed to remind you of its usage. If you click on a symbol in the Language Bar, that symbol is inserted at the cursor in the current line in the Session.

Popup Menu

If you click the right mouse button in the Language Bar, the context menu displays the following options:

Item | Description
Insert Space Before | Inserts a blank space before the current symbol (or blank)
Delete | Deletes the current symbol (or blank)
Help | Displays the (F1) help topic for the current symbol.
Use the Session font | Displays the symbols using the current Session font (by default the symbols are displayed using a small font)
Revert to defaults | Removes all user customisation and reverts to the standard Language Bar.


Entering and Executing Expressions

Introduction

The session contains the input line and the session log. The input line is the last line in the session, and is (normally) the line into which you type an expression to be evaluated.

The session log is a history of previously entered expressions and the results they produced.

If you are using a log file, the Session log is loaded into memory when APL is started from the file specified by the log_file parameter. When you close your APL session, the Session log is written back out to the log file, replacing its previous contents.

In general you type an expression into the input line, then press Enter (ER) to run it. After execution, the expression and any displayed results become part of the session log.

You can move around in the session using the scrollbar, the cursor keys, and the PgUp and PgDn keys. In addition, Ctrl+Home (UL) moves the cursor to the beginning of the top-line in the Log and Ctrl+End (DL) moves the cursor to the end of the last (i.e. the current) line in the session log. Home (LL) and End (RL) move the cursor to the beginning and end respectively of the line containing the cursor.

Deleting Lines

You may delete one or more lines from the Session using the DK command (Ctrl+Delete). This action removes the current line or the selected block of lines from the Session window and from the Session log. The removal is permanent and you will be prompted to confirm:

Auto Complete

As you start to enter characters in an APL expression, the Auto Complete suggestions pop-up window (AC for short) offers you a choice based upon the characters you have already entered and the current context.

For example, if you enter a ⎕, AC displays a list of all the system functions and variables. If you then enter the character r, the list shrinks to those system functions and variables beginning with the letter r, namely ⎕refs, ⎕rl, ⎕rsi, and ⎕rtl. Instead of entering the remaining characters, you may select the appropriate choice in the AC list. This is done by pressing the right cursor key.

If you begin to enter a name, AC will display a list of namespaces, variables, functions, operators that are defined in the current namespace. If you are editing a function, AC will also include names that are localised in the function header.

If the current space is a GUI namespace, the list will also include Properties, Events and Methods exposed by that object.

As an additional refinement, AC remembers a certain number of previous auto complete operations, and uses this information to highlight the most recent choice you made.

For example, suppose that you enter the two characters )c. AC offers you )clear thru' )cs, and you choose )cs from the list. The next time you enter the two characters )c, AC displays the same list of choices, but this time )cs is pre-selected.

You can disable or customise Auto Completion from the Auto Complete page in the Configuration dialog box which is described later in this chapter.

Executing an Expression

To execute an expression, you type it into the input line, then press Enter (ER). Alternatively, you can select Execute from the Action menu. Following execution, the expression and any displayed results become part of the session log.

Instead of entering a new expression in the input line, you can move back through the session log and re-execute a previous expression (or line of a result) by simply pointing at it with the cursor and pressing Enter. Alternatively, you can select Execute from the Action menu. You may alter the line before executing it. If you do so, it will be displayed using colour 249 (Red on White), the same as that used for the input line. When you press Enter the new line is copied to the input line prior to being executed. The original line is restored and redisplayed in the normal session log colour 250 (Black on White).

An alternative way to retrieve a previously entered expression is to use Ctrl+Shift+Bksp (BK) and Ctrl+Shift+Enter (FD). These commands cycle backwards and forwards through the input history, successively copying previously entered expressions over the current line. When you reach the expression you want, simply press Enter to re-run it. These operations may also be performed from the Edit menu in the session window.

Executing Several Expressions

You can execute several expressions, by changing more than one line in the session log before pressing Enter. Each line that you change will be displayed using colour 249 (Red on White). When you press Enter, these marked lines are copied down and executed in the order they appear in the log.

Note that you don't actually have to change a line to mark it for re-execution; you can mark it by overtyping a character with the same character, or by deleting a leading space for instance.

It is also possible to execute a contiguous block of lines. To do this, you must first select the lines (by dragging the mouse or using the keyboard) and then copy them into the clipboard using Shift+Delete (CT) or Ctrl+Insert (CP). You then paste them back into the session using Shift+Insert (PT). Lines pasted into the session are always marked (Red on White) and will therefore be executed when you press Enter. To execute lines from an edit window, you use a similar procedure. First select the lines you want to execute, then cut or copy the selection to the clipboard. Then move to the session window and paste them in, then press Enter to execute them.

Session Print Width (PW)

Throughout its history, APL has used a system variable ⎕PW to specify the width of the user's terminal or screen. Session output that is longer than ⎕PW is automatically wrapped and split into multiple lines on the display. This feature of APL was designed in the days of hard-copy terminals and has become less relevant in modern Windows environments.

Dyalog APL continues to support the traditional use of ⎕PW, but also provides an alternative option to have the system wrap Session output according to the width of the Session Window. This behaviour may be selected by checking the Auto PW checkbox in the Session tab of the Configuration dialog box.

Using Find/Replace in the Session

The search and replace facilities work not just in the Editor as you would expect, but also in the Session. For example, if you have just entered a series of expressions involving a variable called SALES and you want to perform the same calculations using NEWSALES, the following commands will achieve it:

Enter SALES in the Find box, and NEWSALES in the Replace box. Now click the Replace All button. You will see all occurrences of SALES change to NEWSALES. Furthermore, each changed line in the session becomes marked (Red on White). Now click on the session and press Enter (or select Execute from the Action menu).

Once displayed, the Find or Find/Replace dialog box remains on the screen until it is either closed or replaced by the other. This is particularly convenient if the same operations are to be performed over and over again, and/or in several windows. Find and Find/Replace operations are effective in the window that previously had the focus.


Value Tips

If you hover the mouse pointer over a name in the Session or Debugger window, APL will display a pop-up window containing the value of the symbol under the mouse pointer.

For example, in the following picture the mouse pointer was moved over the name of the variable HW in the Session window.

The next picture illustrates the Value Tip displayed when the mouse is hovered over the name of the variable MAT.

Similarly, if you hover the mouse pointer over the name of a function, the system displays the body of the function as a pop-up, as illustrated below.


Value Tips for External Functions

Value Tips can also be used to investigate the syntax of external functions. If you hover over the name of an external function, the Value Tip displays its Function Signature.

For example, in the example below, the mouse is hovered over the external function dt.AddMonths and shows that it requires a single integer as its argument.

Should the external function provide more than one signature, they are all shown in the Value Tip as illustrated below. Here the function ToString has four different overloads.


Configuring Value Tips

You may enable/disable Value Tips and select other options from the General tab of the Configuration dialog box as shown below.

You may experiment by changing the value of the delay before which Value Tips are displayed, until you find a comfortable setting.

Note that the colour scheme used to display the Value Tip for a function need not necessarily be the same colour scheme as you use for the function editor.


Array Editor

The Array EditorArray Editor Version 1 Release 1 © Copyright davidliebtag.com 2012, 2015 1 allows you to edit arbitrary arrays. It is invoked by either:

  • Clicking the [image] icon in the Session toolbar when the mouse pointer is over the name of a suitable variable.
  • Calling the user command ]array.edit, specifying the name of a suitable variable as its argument.
  • Calling it directly via ⎕NA

The Array Editor draws data using a format that is similar to the output of the DISPLAY function. For example:

Documentation

Full documentation for the Array Editor, including a list of the keystrokes it uses, is available from the Help menu in the Array Editor's window.

Supported Arrays

The Array Editor supports arrays that consist solely of characters and/or numbers. You may not use it to edit an array that contains an object reference or a ⎕OR.

Reject unsupported data

The way that the Arrays Editor reacts to unsupported arrays is determined by the value of the Reject unsupported data option which is accessed by the Options/Reject unsupported data menu item on the Array Editor menubar.

If this is set to true (the default), and you try to edit an array containing an object reference, the Array Editor will refuse to start and the system will generate an error message.

⎕SE.NumEd.numed: Unexpected error in array editor:
        DOMAIN ERROR  Argument contained data that is
               neither simple or nested.

If this option is cleared, the Array editor will start but you will not be able to do anything. It is therefore advisable that you leave this option set.

Notes

  • The Array Editor is supplied only with Unicode Editions of Dyalog APL/W. Please visit www.davidliebtag.com for details about availability and support for Classic Editions of Dyalog APL/W.
  • Namespaces are not supported.
  • Internal representations returned by ⎕OR are not supported.
  • Only one instance of the Array Editor may be executed at a time.
  • All calls to interpreter primitives use a value of 3 for ⎕ML.
  • Negative numbers must be represented using high minus signs. For example, ¯3 not -3.

Implementation

The Array Editor is implemented by a DLL named dlaedit.dll (32-bit) or dlaedit64.dll (64-bit).

The DLL exports two functions: DyalogEditArray and DyalogEditArrayTitle. The latter is used when you click the [image] icon in the Session toolbar (via the APL function ⎕SE.NumEd.numed) and by the user command ]array.edit

Calling the Array Editor Directly

If you wish to use the Array Editor directly, you may do so as follows using ⎕NANote that these are not standard ⎕NA calls, but rather use an extension to ⎕NA, called Direct Workspace Access. Dyalog does not intend to make this feature generally available at present: if you are interested in this feature please contact sales@dyalog.com. 2.

For both DyalogEditArray and DyalogEditArrayTitle the first argument is the array to be edited, while the second argument is a place holder and should always be 0

For DyalogEditArrayTitle the 3rd argument is a character vector whose contents are displayed in the caption of the array editor window.

The result is the newly altered array.

Examples

⎕NA'dlaedit.dll|DyalogEditArray <pp >pp'              ⍝ 32-bit
⎕NA'dlaedit.dll|DyalogEditArrayTitle <pp >pp <0C2[]'  ⍝ 32-bit

⎕NA'dlaedit64.dll|DyalogEditArray <pp >pp'            ⍝ 64-bit
⎕NA'dlaedit64.dll|DyalogEditArrayTitle <pp >pp <0C2[]'⍝ 64-bit

New←DyalogEditArray Old 0
New←DyalogEditArrayTitle Old 0 Name


Session GUI

The Session GUI Hierarchy

As distributed, the Session object ⎕SE contains two CoolBar objects. The first, named ⎕SE.cbtop runs along the top of the Session window and contains the toolbars. The second, named ⎕SE.cbbot, runs along the bottom of the Session windows and contains the statusbars.

The menubar is implemented by a MenuBar object named ⎕SE.mb.

The toolbars in ⎕SE.cbtop are implemented by four CoolBand objects, bandtb1, bandtb2, bandtb3 and bandtb4 each containing a ToolControl named tb.

The statusbars in ⎕SE.cbbot are implemented by two CoolBand objects, bandtb1 and bandtb2, each containing a StatusBar named sb.


Session MenuBar

The Session MenuBar

The Session MenuBar (⎕SE.mb) contains a set of menus as follows. Note that, unless specified, the screen-shots are taken using Unicode Edition and the keyboard short-cuts will be different in Classic Edition.

The File Menu

The File menu (⎕SE.mb.file) provides a means to execute those APL System Commands that are concerned with the active and saved workspaces. The contents of a typical File menu and the operations they perform are illustrated below.

Table 38: File Menu Operations

Item | Action | Description
New | [WSClear] | Prompts for confirmation, then clears the workspace
Open | [WSLoad] | Prompts for a workspace file name, then loads it
Copy | [WSCopy] | Prompts for a workspace file name, then copies it
Save | [WSSave] | Saves the active workspace
Save As | [WSSaveas] | Prompts for a workspace file name, then saves it
Export | [Makeexe] | Creates a bound executable, an OLE Server, an ActiveX Control, or a .NET Assembly. See Creating Executables and COM Servers.
Export to Memory | [MakeMemory Assembly] | Creates an in-memory .NET Assembly
Close AppDomain | [CloseAppDomain] | Closes .NET App Domain
Drop | [WSDrop] | Prompts for a workspace file name, then erases it
Edit Text File | [EditTextFile] | Displays the Open Source File dialog to select a file to exit.
Print | [PrintFnsInNS] | Prints functions and operators in current namespace
Print Setup | [PrintSetup] | Invokes the print set-up dialog box
Continue | [Continue] | Saves the active workspace in CONTINUE.DWS and exits APL
Exit | [Off] | Exits APL

Edit Text File

The Edit Text File menu item allows you to edit a Dyalog script file (.dyalog) or an arbitrary text file. The system prompts you to choose the file as shown below:

The file is then displayed in the Editor, allowing you to change it and save it. See Editing Scripts and Text Files.

The Edit Menu

The Edit menu (⎕SE.mb.edit) provides a means to recall previously entered input lines for re-execution and for copying text to and from the clipboard.

Unicode Edition

Classic Edition

Table 39: Edit menu operations

Item | Action | Description
Back | [Undo] | Displays the previous input line. Repeated use of this command cycles back through the input history.
Forward | [Redo] | Displays the next input line. Repeated use of this command cycles forward through the input history.
Cut | [Delete] | Cuts the selected text to the clipboard
Copy | [Copy] | Copies the selection to the clipboard
Paste | [Paste] | Pastes the text contents of the clipboard into the session log at the current location. The new lines are marked and may be executed by pressing Enter.
Paste Unicode | [PasteUnicode] | Same as Paste, but gets the Unicode text from the clipboard and converts to ⎕AV. Classic Edition only
Paste Non-Unicode | [PasteAnsi] | Same as Paste, but gets the ANSI text from the clipboard and converts to ⎕AV. Classic Edition only
Find | [Find] | Displays the Find dialog box
Replace | [Replace] | Displays the Find/Replace dialog box

The View Menu

The View menu (⎕SE.mb.view) toggles the visibility of the Session Toolbar, StatusBar, and Language Bar.

Table 40: View menu operations

Item | Action | Description
Toolbar |  | Shows/Hides Session toolbars
Statusbar |  | Shows/Hides Session statusbars
LanguageBar |  | Shows/Hides Language Bar

The Windows Menu

This contains a single action (⎕SE.mb.windows) which is to close all of the Edit and Trace windows and the Status window.

Table 41: Window menu operations

Item | Action | Description
Close all Windows | [CloseAll] | Closes all Edit and Trace windows

Note that [CloseAll] removes all Trace windows but does not reset the state indicator.

In addition, the Window menu will contain options to switch the focus to any subsidiary windows that are docked in the Session as illustrated above.

The Session Menu

The Session menu (⎕SE.mb.session) provides access to the system operations that allow you to load a session (⎕SE) from a session file and to save your current session (⎕SE) to a session file. If you use these facilities rarely, you may wish to move them to (say) the Options menu or even dispense with them entirely.

Table 42: Session menu operations

Item | Action | Description
Open | [SELoad] | Prompts for a session file name, then loads the session from it, replacing the current one. Sets the File property of ⎕SE to the name of the file from which the session was loaded.
Save | [SESave] | Saves the current session (as defined by ⎕SE) to the session file specified by the File property of ⎕SE
Save As | [SESaveAs] | Prompts for a session file name, then saves the current session (as defined by ⎕SE) in it. Resets the File property of ⎕SE.

The Log Menu

The Log menu (⎕SE.mb.log) provides access to the system operations that manipulate Session log files.

Table 43: Log menu operations

Item | Action | Description
New | [NewLog] | Prompts for confirmation, then empties the current Session log
Open | [OpenLog] | Prompts for a Session log file, then loads it into memory, replacing the current Session log
Save | [SaveLog] | Saves the current Session log in the current log file, replacing its previous contents
Save As | [SaveLogAs] | Prompts for a file name, then saves the current Session log in it
Print | [PrintLog] | Prints the contents of the Session log

The Action Menu

The Action menu (⎕SE.mb.action) may be used to perform a variety of operations on the current object or the current line. The current object is the object whose name contains the cursor. The current line is that line that contains the cursor. The Edit, Copy Object, Paste Object and Print Object items operate on the current object. For example, if the name SALES appears in the session and the cursor is placed somewhere within it, SALES is the current object and will be copied to the clipboard by selecting Copy object or opened up for editing by selecting Edit.

Table 44: Action menu operations

Item | Action | Description
Edit | [Edit] | Edit the current object
Trace | [Trace] | Executes the current line under the control of the Tracer
Execute | [Execute] | Executes the current line
Copy Object | [ObjCopy] | Copies the contents of the current object to the clipboard
Paste Object | [ObjPaste] | Pastes the contents of the clipboard into the current object, replacing its previous value
Print Object | [ObjPrint] | Prints the current object. Note that if the object is being edited, the version of the object displayed in the edit window is printed.
Clear Stops | [ClearTSM] | Clears all ⎕STOP, ⎕MONITOR and ⎕TRACE settings
Interrupt | [Interrupt] | Generates a weak interrupt
Reset | [Reset] | Performs )RESET

The Options Menu

The Options menu (⎕SE.mb.options) provides configuration options.

Table 45: Options menu operations

Item | Action | Description
Expose GUI Properties | [ExposeGUI] | Exposes the names of properties, methods and events in GUI objects
Expose Root Properties | [ExposeRoot] | Exposes the names of the properties, methods and events of the Root object
Expose Session Properties | [ExposeSession] | Exposes the names of the properties, methods and events of ⎕SE
Line Numbers | [LineNumbers] | Toggle the display of line numbers in edit and trace windows on/off
Disable traps in session | [DisableTrapsAtSuspension] | Disables the error trapping mechanism used by :Trap and ⎕TRAP. This can be useful in debugging applications.
Configure | [Configure] | Displays the Configuration dialog box
Colours | [ChooseColors] | Displays the Colours Selection dialog box

The values associated with the Expose GUI, Expose Root and Expose Session options reflect the values of these settings in your current workspace and are saved in it. When you change these values through the Options menu, you are changing them in the current workspace only.

The default values of these items are defined by the parameters default_wx, PropertyExposeRoot and PropertyExposeSE which may be set using the Object Syntax tab of the Configuration dialog.

The Tools Menu

The Tools menu (⎕SE.mb.tools) provides access to various session tools and dialog boxes.

Table 46: Tools Menu Operations

Item | Action | Description
Explorer | [Explorer] | Displays the Workspace Explorer tool
Search | [WSSearch] | Displays the Workspace Search tool
Status | [Status] | Displays or hides the Status window
AutoStatus | [AutoStatus] | Toggle; if checked, causes the Status window to be displayed when a new message is generated for it
Event Viewer | [EventViewer] | Displays or hides the Event Viewer
Properties | [ObjProps] | Displays a property sheet for the current object

The Threads Menu

The Threads menu (⎕SE.mb.threads) provides access to various session tools and dialog boxes.

Table 47: Threads Menu Operations

Item | Action | Description
Show Threads | [Threads] | Displays the Threads Tool
Show Stack | [Stack] | Displays the SI Stack window
Show Token Pool | [TokenPool] | Displays the Token Pool window
Auto Refresh | [ThreadsAutoRefresh] | Refreshes the Threads Tool on every thread switch
Pause on Error | [ThreadsPauseOnError] | Pauses all threads on error
Pause all Threads | [ThreadsPauseAll] | Pauses all threads
Resume all Threads | [ThreadsResumeAll] | Resumes all threads
Restart all Threads | [ThreadsRestartAll] | Restarts all threads

The Help Menu

The Help menu (⎕SE.mb.help) provides access to the help system which is packaged as a single Microsoft HTML Help compiled help file named help\dyalog.chm.

Table 48: Help menu operations

Label | Action | Description
Documentation Centre | [DocCenter] | Opens your web browser on help\index.html which displays an index to the on-line PDF documentation and selected internet links
Read Me | [ReadMe] | Opens help\dyalog_readme.htm in your default web browser. Note that setup_readme.htm is also included in this directory
Latest Enhancements | [RelNotes] | Opens help\dyalog.chm, starting at the first topic in the Version 17.0 Release Notes section. Note that previous Release Notes are also included for your convenience.
Language Help | [LangHelp] | Opens help\dyalog.chm, starting at the first topic in the Language Reference section
Gui Help | [GuiHelp] | Opens help\dyalog.chm, starting at the first topic in the Object Reference section
Third Party Licences | [LicenceHelp] | Opens help\dyalog.chm, starting at the first topic in the Licences for third-party components
Dyalog Web Site | [DyalogWeb] | Opens your web browser on the Dyalog home page
Email Dyalog | [DyalogEmail] | Opens your email client and creates a new message to Dyalog Support, with information about the Version of Dyalog APL you are running
About Dyalog APL | [About] | Displays an About dialog box


Session Pop-Up Menu

The Session popup menu (⎕SE.popup) is displayed by clicking the right mouse button anywhere in the Session or Editor window.

If the mouse pointer is over a visible object name, the popup menu allows you to edit, print, delete it or view its properties. Note that the name of the pop-up menu is specified by the Popup property of ⎕SE.

Table 49: Session popup menu operations

Item | Action | Description
Edit | [Edit] | Edits the current object
Chart Wizard | ⎕SE.Dyalog.Chart. DoChart | Opens Chart Wizard on current object
Print | [ObjPrint] | Prints the current object. Note that if the object is being edited, the version of the object displayed in the edit window is printed.
Delete | [ObjDelete] | Erases the current object
Properties | [GUIHelp] | Displays the Object Properties dialog box for the current object
Help | [Help] | Displays the help topic associated with the current object or the APL symbol under the cursor
Select All | [selectall] | Selects all text (Editor only)
Cut | [Cut] | Deletes selected text
Copy | [Copy] | Copies the selection to the clipboard
Paste | [Paste] | Pastes the text contents of the clipboard into the session log at the current location. The new lines are marked and may be executed by pressing Enter.
Paste Unicode | [PasteUnicode] | Same as Paste, but gets the Unicode text from the clipboard and converts to ⎕AV
Paste Non-Unicode | [PasteAnsi] | Same as Paste, but gets the ANSI text from the clipboard and converts to ⎕AV
Copy Object | [ObjCopy] | Copies the contents of the current object to the clipboard
Paste Object | [ObjPaste] | Pastes the contents of the clipboard into the current object
Line Numbers | [LineNumbers] | Toggles line numbers on/off
Align Comments | [AlignComments] | Aligns Comments to current column
Explorer | [Explorer] | Displays the Workspace Explorer
Search | [WSSearch] | Displays the Find Objects tool
Event Viewer | [EventViewer] | Displays the Event Viewer
Threads | [Threads] | Displays the Threads Tool
Status | [Status] | Displays the Status window
Colours | [ChooseColors] | Displays the Colour Selection dialog
Interrupt | [Interrupt] | Generates a weak interrupt
Open link | [OpenLink] | Opens the URL or link using the appropriate program. Unicode Edition only.
Copy link to clipboard | [CopyLink] | Copies the URL or link to the Windows Clipboard. Unicode Edition only.

For the last two items, see Underline URLs and links)


The Session Toolbars

The Session toolbars are contained by four separate CoolBand objects, allowing you to configure their order in whichever way you choose. The tool buttons appear differently according to whether or not Native Look and Feel is enabled.

The bitmaps for the buttons displayed on the session tool bar are implemented by three ImageList objects owned by the CoolBar ⎕SE.cbtop. These represent the ToolButton images in their normal, highlighted and inactive states and are named iln, ilh and ili respectively. These images derive from three bitmap resources contained in dyalog.exe named tb_normal, tb_hot and tb_inactive.

If Native Look and Feel is enabled all three bitmap resources are mapped to a different set of images which are capable of reflecting the Visual Styles in use.

Native Look and Feel Enabled

Native Look and Feel Disabled

Workspace (WS) Operations

Clear Workspace | Executes the system operation [WSClear] which asks for confirmation, then clears the workspace
Load Workspace | Executes the system operation [WSLoad] which displays a file selection dialog box and loads the selected workspace
Copy Workspace | Executes the system operation [WSCopy] which displays a file selection dialog box and copies the (entire) selected workspace
Save Workspace | Executes the system operation [WSSaveas] which displays a file selection dialog box and saves the workspace in the selected file
Export Workspace | Executes the system operation [MakeExe] which re-exports the workspace using the settings, parameters and options that were previously selected using the Create Bound File dialog
Print Functions | Executes the system operation [PrintFnsInNS] that prints all the functions and operators in the current namespace

Object Operations

Copy Object | Executes the system operation [ObjCopy] which copies the contents of the current object to the clipboard
Paste Object | Executes the system operation [ObjPaste] which copies the contents of the clipboard into the current object, replacing its previous value
Print Object | Executes the system operation [ObjPrint]. Prints the current object. Note that if the object is being edited, the version of the object displayed in the edit window is printed.
Edit Object | Executes the system operation [Edit] which edits the current object using the standard system editor
Edit Array | Executes a defined function in ⎕SE that edits the current object using the Array Editor (Unicode Edition) or a spreadsheet-like interface based upon the Grid object (Classic Edition). See Array Editor
SharpPlot | Executes a defined function in ⎕SE that runs the Chart Wizard to plot the current object using the ]chart User Command.

Tools

Explorer | Executes the system operation [Explorer] which displays the Workspace Explorer tool
Search | Executes the system operation [WSSearch] which displays the Workspace Search tool
Line Numbers | Executes the system operation [LineNumbers] which toggles the display of line numbers in edit and trace windows on and off
Clear all Stops | Executes the system operation [ClearTSM] which clears all ⎕STOP, ⎕MONITOR and ⎕TRACE settings

Edit Operations

Copy Selection | Executes the system operation [Copy] which copies the selected text to the clipboard
Paste Selection | Executes the system operation [Paste] which pastes the text in the clipboard into the current window at the insertion point
Recall Last | Executes the system operation [Undo] which recalls the previous input line from the input history stack
Recall Next | Executes the system operation [Redo] which recalls the next input line from the input history stack

Session Operations

Load Session | Executes the system operation [SELoad] which displays a file selection dialog box and loads the selected Session File
Boxing On/Off | Executes the user command ]boxing to toggle boxing on/off.
Select Font | Selects the font to be used in the Session window
Select Font Size | Selects the size of the font to be used in the Session window


Session StatusBar

The Session Status Bar

The session status bar is represented by two CoolBands each of which contains a StatusBar object. There are a number of StatusFields as illustrated below. Your own status bar may be configured differently.

Classic Edition

Unicode Edition

The StatusField objects owned by the session StatusBar may have special values of Style, which are used for operations relevant only to the Session. These styles are summarised in the tables shown below.

Table 50: Session status fields: first row

StatusField | Style | Description
hint | None | Displays hints for the session objects, or "Ready..." when APL is waiting for input
insrep | InsRep | Displays the mode of the Insert key (Ins or Rep)
mode | KeyMode | Displays the keyboard mode. This is applicable only to a multi-mode keyboard. The text displayed is defined by the Mn= string in the Input Table. Classic Edition Only
num | NumLock | Indicates the state of the Num Lock key. Displays "NUM" if Num Lock is on, blank if off
caps | CapsLock | Indicates the state of the Caps Lock key. Displays "Caps" if Caps Lock is on, blank if off
pause | Pause | Displays a flashing red "Pause" message when the Pause key is used to halt session output

Table 51: Session status fields: second row

StatusField | Style | Description
curobj | CurObj | Displays the name of the current object (the name last under the input cursor)
tc | ThreadCount | Displays the number of threads currently running (minimum is 1)
dqlen | DQLen | Displays the number of events in the APL event queue
trap | Trap | Turns red if ⎕TRAP is set
si | SI | Displays the length of ⎕SI. Turns red if non-zero
io | IO | Displays the value of ⎕IO. Turns red if ⎕IO is not equal to the value of the default_io parameter
ml | ML | Displays the value of ⎕ML. Turns red if ⎕ML is not equal to the value of the default_ml parameter

Toggle Status Fields

In the default Session files distributed with this release, the Statusfields used to display the value of ⎕IO, the state of the Insert key (Ins/Rep) and the current keyboard mode (e.g. Apl/Uni) have callback functions attached to MouseDblClick. This means that you can toggle the state of these fields by double-clicking with the left mouse button.

If you dislike this behaviour, you may set the Event property of the StatusFields to 0 and re-save the Session file. Alternatively, you may modify the buildse workspace and rebuild the Session from scratch.


Status Window

The Status window is used to display system messages and supplementary information. These include the operations that take place when you register an OLEServer or ActiveXControl.

The Status window is also used to display supplementary information about errors. For example if you attempt to use a .NET method with incorrect argument(s) you will get a suitable error message in the Status window, in addition to the DOMAIN ERROR message in the Session.

Example

      ⎕USING←'System'
      bd←⎕NEW DateTime(2015 4) ⍝ Typo (2015 4 30)
DOMAIN ERROR
      bd←⎕NEW DateTime(2015 4) ⍝ Typo (2015 4 30)
     ∧

The Status window can be explicitly displayed or hidden using the [Status] system operation which is associated with the Tools/Status menu item. There is also an option to have the Status window appear automatically whenever a new message is written to it. This option is selected using the [AutoStatus] system operation which is associated with the Tools/AutoStatus menu item.

Note that when you close the Status window, all the system messages in it are cleared.


Workspace Explorer

The Workspace Explorer Tool

The Explorer tool is a modeless dialog box that may be toggled on and off by the system action [Explorer]. In a default Session, this is attached to a MenuItem in the Tools menu and a Button on the session toolbar.

The Explorer contains two sub-windows. The one on the left displays the namespace structure of your workspace using a TreeView. The right-hand window is a ListView that displays the contents of the namespace that is selected in the TreeView.

The Explorer is closely modelled on the Windows Explorer in Windows and the facilities it provides are very similar. For Windows users, the operation of this tool is probably self-explanatory. However, other users may find the following discussion useful.

Exploring the Workspace

The TreeView displays the structure of your workspace. Initially it shows the root and Session namespaces # and ⎕SE. The icon for # is open indicating that its contents are those that appear in the ListView. You can expand or collapse the TreeView of the workspace structure by clicking on the mini-buttons (labelled + and -) or by double-clicking the icons. A single click on a closed namespace icon opens it and causes its contents to be displayed in the ListView. Another way to open a namespace is to double-click its icon in the ListView. Only one namespace can be open at a time. The icons used in the display are described below.

Class
Namespace (closed)
GUI Namespace (closed)
Namespace (open)
GUI Namespace (open)
Function
Variable
Operator
Indicates an object that has been erased
Type Library
.NET object

Viewing and Arranging Objects

The ListView displays the contents of a namespace in one of four different ways namely Large Icon view, Small Icon view, List view or Details view. You can switch between views using the View menu or the tool buttons that are provided. In the first three views, the system displays the name of the object together with an icon that identifies its type. In Details view, the system displays several columns of additional information. You may resize the column widths by dragging or double-clicking the lines in the header. To hide a column, drag its width to the far left. The additional columns are:

Location | This is the namespace containing the object. By definition, this is the same for all of the objects shown in the ListView and is normally hidden
Description | For a function or operator, this is the function header stripped of localised names and comment. For a variable, the description indicates its rank, shape and data type. For a namespace, the description indicates the nature of the namespace; a plain namespace is described as namespace, a GUI Form object is described as Form, and so forth.
Size | The size of the object as reported by ⎕SIZE.
Modified on | For functions and operators, this is the timestamp when the object was last fixed. For other objects this field is empty.
Modified by | For functions and operators, this is the name of the user who last fixed the object. For other objects this field is empty.

In any view, you may arrange the objects in ascending order of name, size, timestamp or class by clicking the appropriate tool button. In Details view, you may sort in ascending or descending order by clicking on the appropriate column heading. The first click sorts in ascending order; the second in descending order.

Moving and Copying Objects

You can move and copy objects from one namespace to another using drag-drop or from the Edit menu.

To move one or more objects using drag-and-drop editing:

  1. Select the objects you want to move in the ListView.
  2. Point to one of the selected objects and then press and hold down the left mouse button. When the drag-and-drop pointer appears, drag the object(s) to another namespace in the TreeView. To indicate which of the namespaces is the current target, its name will be highlighted as you drag the selected object(s) over the TreeView.
  3. Release the mouse button to drop the objects into place. The objects will disappear from the ListView because they have been moved to another namespace.

To copy one or more objects using drag-and-drop editing, the procedure is the same except that you must press and hold the Ctrl key before you release the mouse button.

You may also move and copy objects using the Edit menu. To do so, select the object(s) and then choose Move or Copy from the Edit menu. You will be prompted for the name of the namespace into which the objects are to be moved or copied. Enter the namespace and click OK.

Editing and Renaming Objects

You can open up an edit window for a function or variable by double-clicking its icon, or by selecting it and choosing Edit from the Edit menu or from the popup menu. You may rename an object by clicking its name (as opposed to its icon) and then editing this text. You may also select the object and choose Rename from the Edit menu or from the popup menu. Note that when you rename an object, the original name is discarded. Unlike changing a function name in the editor, this is not a copy operation.

Using the Explorer as an Editor

If you open the Fns/Ops item, the names of the functions and operators in the namespace are displayed below it alphabetically in the left (tree view) pane. When you select one of these names, the function itself is opened in the right (list view) pane.

You may use this feature to quickly cycle through the functions (or variables) in a namespace, pressing cursor up and cursor down in the left (tree view) pane to move from one to another.

You may also edit the function directly in the right (list view) pane before moving on to another.

The File Menu

The File menu, illustrated above, provides the following actions. All but Print setup and Close act on the object or objects that are currently selected in the ListView.

Print | Prints the object(s). Note that if an object is open in the editor, the version shown in the edit window is printed.
Print setup | Displays the Print Configuration dialog box.
Delete | Erases the object(s).
Rename | Renames the object. This option only applies when a single object is selected.
Properties | Displays a property sheet; one for each object that is selected.
Close | Closes the Explorer

The Edit Menu

The Edit menu, illustrated above, provides the following actions. The Edit, Copy and Move operations act on the object or objects that are currently selected in the ListView.

Edit | Opens an edit window for each of the objects selected.
Copy | Prompts for a namespace and copies the object(s) there.
Move | Prompts for a namespace and moves the object(s) there.
Select Functions | Selects all of the functions and operators in the ListView.
Select Variables | Selects all of the variables in the ListView.
Select None | Deselects all of the objects in the ListView.
Select All | Selects all of the objects in the ListView.
Invert Selection | Deselects the selected objects and selects all those that were not selected.

The Options Menu

The Options menu, illustrated above, provides the following actions.

Toolbar | Displays or hides the Explorer toolbar.
Toolbar Captions | Displays or hides the button captions on the Explorer toolbar.
StatusBar | Displays or hides the Explorer statusbar.
Type Libraries | Enables/disables the exploring of Type Libraries
Expand All | Expands all namespaces and sub-namespaces in the TreeView, providing a complete view of the workspace structure, including or excluding the Session object ⎕SE.
Refresh Now | Redisplays the TreeView and ListView with the current structure and contents of the workspace. Used if Auto Refresh is not enabled.
Auto Refresh | Specifies whether or not the Explorer immediately reflects changes in the active workspace.

If Auto Refresh is checked the Explorer is updated every time APL returns to desk-calculator mode. This means that it is always in step with the active workspace. If you have a large number of objects displayed in the Explorer, the update may take a few seconds and you may wish to prevent this by un-checking this menu item If you do so, the Explorer must be explicitly updated by selecting the Refresh Now action.

The View Menu

The View menu, illustrated above, provides the following actions.

Columns | Allows you to select which columns you wish to display.
Large Icons | Selects Large Icon view in the ListView.
Small Icons | Selects Small Icon view in the ListView.
List Icons | Selects List view in the ListView.
Details | Selects Details view in the ListView.
Scope | Allows you to choose whether the Explorer displays objects in local scope or in global scope.
Arrange Icons | Sorts the items in the ListView by name, type, size or date.
Line up Icons | Rearranges the icons into a regular grid.
Auto Arrange | If checked, the icons are automatically re-arranged when appropriate

.

The Tools Menu

The Tools menu, illustrated above, provides the following actions.

Find | Displays the Find Objects Tool
Go to | Prompts for a namespace and then opens that namespace in the TreeView, displaying its contents in the ListView
Go to Session Space | Opens the namespace in the TreeView control corresponding to the current space in the Session.
Set Session Space | Sets the current space in the Session to be the namespace that is currently open in the TreeView.


Browsing Classes

Classes are represented by [image] icons. The picture below shows 3 classes: Bird, Parrot and DomesticParrot.

If you open the # node in the left-hand pane, you see the contents of # as a tree.

Browsing Class Scripts

Selecting DomesticParrot in the left-hand pane brings up its Class Script in the right-hand pane.

… and selecting Parrot in the left-hand pane brings up the Class Script for Parrot.

… and finally, selecting Bird in the left-hand pane brings up the Class Script for Bird.

If you open a Class node, a tree appears to help you to navigate within the Class script. In the picture below, the user has opened the [Methods] node and then clicked on Speak. The system has responded by scrolling to (if necessary) and highlighting the appropriate section of the script.


Browsing Type Libraries

When the View/Type Libraries option is enabled, the Workspace Explorer allows you to:

  • Browse the Type Libraries for all the COM server objects that are installed on your computer, whether or not they are loaded in your workspace.
  • Load Type Libraries for COM objects
  • Browse the Type Library associated with an OLEClient object that is already instantiated in the workspace.

If the Microsoft .NET Framework is installed, you may in addition:

  • Load Metadata for specific .NET classes
  • Browse the loaded Metadata, viewing information about classes, methods, properties and so forth.

If the Type Libraries option is enabled, the Workspace Explorer displays a folder labelled TypeLibs which, when opened, displays two others labelled Loaded Libraries and Registered Libraries as shown below.

Browsing Registered Libraries

If you open the Registered Libraries folder, the Workspace Explorer will display in the tree view pane the names of all the Type Libraries associated with the COM Server objects that are installed on your computer.

If you select one of these Library names, some summary information is displayed in the list view pane.

For example, the result of selecting the Microsoft Excel 12.0 Object Library is illustrated below.

If instead, you select the Registered Libraries folder itself, the list of Registered Type Libraries is displayed in the list view pane

Loading a Type Library

You can load a library shown in the tree view pane by selecting Load from its context menu.

In either case, a message box will appear asking you to confirm. The operation to load a Type Library may take a few moments to complete.

Notice that if the selected Library references any other libraries, they too will be loaded. For example, loading the Microsoft Excel 12.0 Object Library brings in the Microsoft Office 12.0 Object Library and the Microsoft Visual Basic for Applications Extensibility 5.3 Library too. It also contains references to a general library called the OLE Automation Type Library, so this is also loaded.

When you )SAVE your workspace, all of the Type Libraries that you have loaded will be saved with it. Note that type library information can take up a considerable amount of workspace.

Browsing Loaded Libraries

If you have already loaded any Type Libraries into the workspace, using the Workspace Explorer or as a result of creating one or more OLEClient objects, you can select and open the Loaded Libraries folder.

The picture below illustrates the effect of having loaded the Microsoft Excel 12.0 Object Library.

Notice that any external references to other libraries causes these to be brought in too.

If you select a loaded Type Library, summary information is displayed in the list view pane.

If you open a loaded Type Library, four sub-folders appear named Object CoClasses, Objects, Enums and Event Sets respectively.

Object CoClasses

A Type Library describes a number of objects. Typically, all of the objects have properties and methods, but only some of them, perhaps just a few, generate events. Objects which generate events are represented by CoClasses, each of which has a pointer to the object itself and a pointer to an event set.

For example, the Microsoft Excel 12.0 Object Library contains seven CoClasses named Application, Chart, Global etc as shown below.

Opening the Application folder you can see that the Application CoClass comprises the _Application object coupled with the AppEvents event set as shown below.

The specific methods, properties and events supported by the CoClass object can be examined by opening the appropriate sub-folder. The same information for these and other objects is also accessible from the Objects and Event Sets folders as discussed below.

Objects

The Objects folder contains several sub-folders each of which represents a named object defined in the library.

Each object folder contains two sub-folders named Methods and Properties. Selecting one of these causes the list of Methods or Properties to be displayed in the list view pane. The picture below shows the Methods exposed by the Microsoft Excel 12.0 Range object.

If you open the Methods or Properties subfolder, you can display more detailed information about individual Methods and Properties. For example, the following picture shows information about the SaveAs method exposed by the Microsoft Excel 12.0 Worksheet object.

This tells you that the SaveAs method takes up to 10 parameters of which the first, Filename, is mandatory and is of data type VT_BSTR (a character string). Note that [in] indicates that the parameter is an input parameter.

Incidentally, the optional Fileformat parameter is an example of a parameter whose value must be one of a list of Enumerated Constants. Even without looking at the documentation, the possible values can be deduced by browsing the Enums folder, with the results shown below.

You can therefore deduce that the following expression, executed in the namespace associated with the currently active worksheet, will save the sheet in comma-separated format (CSV) in a file called mysheet.csv:

     SaveAs 'MYSHEET.CSV' xlCSV

or

     SaveAs 'MYSHEET.CSV' 6

Event Sets

The Event Sets folder contains several sub-folders each of which represents a named set of events generated by the objects defined in the library.

If you open one of these event sets, the names of the events it contains are displayed in the tree view pane. If you then select one of the events, its details are displayed in the list view pane as shown below.

This example shows that when it fires, the SheetActivate event invokes your callback function with a single argument named Sh whose datatype is VT_DISPATCH (in practice, a Worksheet object).

Enums

The Enums folder will typically contain several sub-folders each of which represents a named set of enumerated constants.

If you select one of these sets, the names and values of the constants it contains are displayed in the list view pane as shown below.


Browsing .NET Classes

Microsoft supplies a tool for browsing .NET Class libraries called ILDASM.EXE ILDASM.EXE can be found in the .NET SDK and is distributed with Visual Studio 1.

As a convenience, the Dyalog APL Workspace Explorer has been extended to perform a similar task as ILDASM so that you can gain access to the information within the context of the APL environment.

The information that describes .NET classes, which is known as its Metadata, is part of the definition of the class and is stored with it. This Metadata corresponds to Type Information in COM, which is typically stored in a separate Type Library.

To gain information about one or more .NET Classes, open the Workspace Explorer, right click the Metadata folder, and choose Load.

This brings up the Browse .NET Assembly dialog box as shown below. Navigate to the .NET assembly of your choice, and click Open.

The .NET Classes provided with the .NET Framework are typically located in C:\WINDOWS\Microsoft.NET\Framework64\V4.0.30319 (on a 64-bit computer). The last named folder is the Version number.

The most commonly used classes of the .NET Namespace System are stored in this directory in an Assembly named mscorlib.dll, along with a number of other fundamental .NET Namespaces.

The result of opening this Assembly is illustrated in the following screen shot. The somewhat complex tree structure that is shown in the Workspace Explorer merely reflects the structure of the Metadata itself.

Opening the System/ Classes sub-folder causes the Explorer to display the list of classes contained in the .NET Namespace System as shown in the picture below.

The Constructors folder shows you the list of all of the valid constructors and their parameter sets with which you may create a new instance of the Class by calling New. The constructors are those named .ctor; you may ignore the one named .cctor, (the class constructor) and any labelled as Private.

For example, you can deduce that DateTime.New may be called with three numeric (Int32) parameters, or six numeric (Int32) parameters, and so forth. There are in fact seven different ways that you can create an instance of a DateTime.

For example, the following statement may be used to create a new instance of DateTime (09:30 in the morning on 30th April 2001):

      mydt←⎕NEW DateTime (2001 4 30 9 30 0)

      mydt
30/04/2001 09:30:00

The Properties folder provides a list of the properties supported by the Class. It shows the name of the property followed by its data type. For example, the DayOfYear property is defined to be of type Int32.

You can query a property by direct reference:

      mydt.DayOfWeek
Monday

Notice too that the data types of some properties are not simple data types, but Classes in their own right. For example, the data type of the Now property is itself System.DateTime. This means that when you reference the Now property, you get back an object that represents an instance of the System.DateTime object:

      mydt.Now
07/11/2001 11:30:48
      ⎕TS
2001 11 7 11 30 48 0

The Methods folder lists the methods supported by the Class. The Explorer shows the data type of the result of the method, followed by the name of the method and the types of its arguments. For example, the IsLeapYear method takes an Int32 parameter (year) and returns a Boolean result.

      mydt.IsLeapYear 2000
1

Many of the reported objects are listed as Private, which means they are inaccessible to users of the class – you are not able to call them or inspect their value. For more information about classes, see Language Reference Guide: Object Oriented Programming Introducing Classes.


Object Properties Dialog

Object Properties Dialog Box

The Object Properties dialog box displays detailed information for an APL object. It is displayed by executing the system action [ObjProps]. In a default Session, this is provided in the Tools menu, the Session popup menu and from the Explorer. An example (for a function) is shown below.

Properties Tab

The Properties tab displays general information about the object. For a function, this includes an extract from its header line, when it was last modified, and by whom.

Value Tab

For a variable, the Values tab displays the value of the variable. For a function, it displays its canonical representation.

Monitor Tab

The Monitor tab applies only to a function and displays the result of ⎕MONITOR. The Reset button resets ⎕MONITOR for the lines on which it is currently set. The Set All Lines button sets ⎕MONITOR to monitor all the lines in the function. The Clear All Lines switches ⎕MONITOR off.

COM Properties Tab

The COM Properties tab applies only to a function in an OLEServer or ActiveXControl namespace. The tab is used to define arguments and data types for an exported Method or Property. For further information, see Interface Guide.

Net Properties Tab

The Net Properties tab applies only to a function in a NetType namespace. The tab is used to define arguments and data types for an exported Method or Property. For further information, see .NET Interface Guide: .


Editor

The Editor

Invoking the Editor

The editor may be invoked in several ways. From the session, you can use the system command )ED or the system function ⎕ED, specifying the names(s) of the object(s) to be edited. You can also type the name of the object and then press Shift+Enter (ED), click the Edit tool on the tool bar, or select Edit from the Action menu. If you invoke the editor when the cursor is positioned on the empty input line, with a suspended function in the state indicator, the editor is invoked on the suspended function and the cursor is positioned on the line at which it is suspended. This is termed naked edit. These ways of invoking the editor apply only in the session window

In addition, there is a general point-and-edit facility which works in edit and trace windows too. Simply position the input cursor over a name and double-click the left mouse button. Alternatively, you can press Shift+Enter or select Edit from the File menu. The name can appear in the Session, in an Edit window, or in a Trace window; the effect is the same. Note that, in the Session, typing a name and pressing Shift+Enter is actually a special case of point-and-edit. Note also that a naked edit can be invoked by double-clicking the left mouse button in the empty input line.

The type of a new object defaults to function/operator unless the object is shadowed, in which case it defaults to a variable (vector of character vectors). You can however specify the type of a new object explicitly using )ED or ⎕ED. For example, typing ")ED ∊LIST -MAT" in a CLEAR WS would create Edit windows for a vector of character vectors named LIST and a character matrix called MAT. See )ED or ⎕ED for details.

If the name is not already being edited, it is assigned a new edit window. If you edit a name which is already being edited, the system focuses on the existing edit window rather than opening a new one. Edit windows are displayed using the colour combination associated with the type of the object being edited.

Window Management (Standard)

Unless Classic Dyalog mode is selected (Options/Configure/Trace/Edit), the Editor is a Multiple Document Interface (MDI) window that may be a stand-alone window, or be docked in the Session window. Each of the objects being edited is displayed in a separate sub-window. Individual edit windows are managed using standard MDI facilities.

The first edit sub-window window is created at the position specified by the edit_first_y and edit_first_x parameters which are specified in terms of the size of a character in the current font relative to the top-left corner of the main Editor window. Subsequent ones are staggered according to the values of the edit_offset_y and edit_offset_x parameters.

The initial size of an edit window is specified by the edit_rows and edit_cols parameters.

Note that the blue triangles indicate that the line of text is longer than can be displayed in the current Edit window.

By default, the Session has the Editor docked along the right edge of the Session window. When you edit a function, the Editor window automatically springs into view as illustrated below.

You can resize the Editor pane to view more or less of the Session itself, by dragging its title bar.

Using the buttons in the title bar, you can instantly maximise the Editor pane to allow you to concentrate on editing, or minimise it to reveal the entire Session. In either case, the restore button quickly restores the 2-pane layout.

The picture below shows the effect of maximising the Editor. The BUILD_SESSION edit window is itself maximised within the Editor too.

Note that when the Editor has the focus, the Editor menubar is displayed in place of the Session menubar.

Window Management (Classic Dyalog mode)

If Classic Dyalog mode is selected (Options/Configure/Trace/Edit) each Edit window is a top-level window created as a child of the Session window. This means that normally Edit windows appear on top of the Session. However, if the SessionOnTop parameter is set, the Session window, when given the focus, will appear on top of Edit windows.

When the first Edit window is opened, its position is determined as follows:

  • If the ClassicModeSavePosition parameter is set, the first Edit window is displayed at the position that was previously occupied by the most recently saved Edit window.
  • If not, the first edit window is created at the position specified by the edit_first_y and edit_first_x parameters which are specified in terms of the size of a character in the current font relative to the top-left corner of the screen.

The initial size of an edit window is specified by the edit_rows and edit_cols parameters.

Subsequent ones are staggered according to the values of the edit_offset_y and edit_offset_x parameters.

Moving around an edit window

You can move around in the edit window using the scrollbar, the cursor keys, and the PgUp and PgDn keys. In addition, Ctrl+Home (UL) moves the cursor to the beginning of the top-line in the object and Ctrl+End moves the cursor to the end of the last line in the object. Home (LL) and End (RL) move the cursor to the beginning and end respectively of the line containing the cursor.

Closing an edit window

Closing an edit window from its System Menu has the same effect as choosing Exit from the File Menu; namely that it fixes the object in the workspace and then closes the edit window.

Minimising an edit window

Minimising an edit window causes it to be displayed as a Dyalog APL Edit icon, with the name of the object underneath. The edit window can be restored in the normal way, or by an attempt to re-edit the same name.

Selecting Text

You may select text in an Editor window by clicking the left or right mouse button over any character, dragging out a highlighed area, and then releasing the mouse button. When using the left button, moving up or down one line extends the selection from the beginning of that line, so the selection may be ragged. The right button selects a rectangularr box.

Editor ToolBar

In the table below, the first image shows the appearance of the toolbutton with Native Look and Feel enabled; the second with it disabled.

Button | Description
Toggle line numbers | Toggles Line numbers on/off
Toggle tree view | Toggles the treeview on/off. See Editing Classes.
Previous Location | Certain operations (such as selecting an item in the treeview) reposition the caret in the Editor window. This button moves the caret back to its previous location.
Comment selected text | Inserts a comment symbol to the left of the selection in each of the selected lines.
Uncomment selected text | Removes the comment symbol (if present) from the left-most column of the selection in each of the selected lines.
Save changes and return | Saves changes and closes the current edit window
Search Box | Enter search text and click one of the following two buttons
Search for Next Match | Locates the next occurrence of the search text
Search for Previous Match | Locates the previous occurrence of the search
Search hidden text | Determines whether or not the search examines collapsed blocks
Match case | Specifies whether or not the search is case-sensitive
Match whole word | Specifies whether or not the search matches a whole word
Use Regular Expressions | Specifies whether or not the search uses PCRE regular expressions
Refactor text as method | Inserts a Method template for the selected name
Refactor text as field | Inserts a Field template for the selected name
Refactor text as property | Inserts a Property template for the selected name

The File Menu

The File menu illustrated above is displayed when editing a simple object and provides the following options.

Item | Description
Fix | Fixes the object in the workspace, but leaves the edit window open. Edit history is also preserved. If the data has changed and the confirm_fix parameter is set, you will be prompted to confirm.
Fix whole script | (Disabled unless editing a script)
Open File | Allows you to edit a Dyalog script file or an arbitrary text file.
Save | Saves the file being edited.
Save As | Renames and saves the file being edited.
Always ask on close | Toggles the value of the confirm_fix parameter.
Edit | Opens an Edit window on the name under the cursor (Disabled when there is no such name).
Print | Prints the current contents of the edit window
Print Setup | Displays the Print Configuration dialog box
Properties | Displays the Object Properties dialog box for the current object
Exit (and Fix) | Fixes the object in the workspace and closes the edit window. If the data has changed and the confirm_exit parameter is set, you will be prompted to confirm
Exit (and fix script) | (Disabled unless editing a script)
Exit and discard changes | Closes the edit window, but does not fix the object in the workspace. If the data has changed and the confirm_abort parameter is set, you will be prompted to confirm.

The File Menu (editing a script)

Fix whole script | Fixes the entire script
Fix only functions | Fixes only the functions in the script.
Exit and fix whole script | Fixes the entire script, and exits the Editor.
Exit and fix only functions | Fixes only the functions in the script and exits the Editor.

Editing Scripts

Suppose that you have a Class that manages a list of items in a shared Field, so somewhere in the script would appear a line such as:-

     :Field shared public List←⍬

You run your application for a bit, and List, which was initially empty, gets updated as new instances of the Class are created. You then edit the Class to add a new function, or fix a bug. In this instance, when you exit the editor you may not want List to be reset back to the empty vector although you do want the new version of the function(s) in the Class to be fixed.

Nevertheless whenever you edit the Class when it is not suspended, you probably always want the entire script to be re-fixed, and List re-initialised.

The options in the File menu shown above provide for these alternatives.

In addition, the Configuration Dialog (see Fixing Scripts) allows you to define the behaviour of the keystrokes <EP> and <S1> for both the suspended case and the non-suspended case. This association will be displayed against the appropriate action according to the state of the script you are editing.

The Edit Menu

The Edit menu provides a means to execute those commands that are concerned with editing text. The Edit menu and the actions it provides are described below.

Item | Description
Reformat | Reformats the function body in the edit window, indenting control structures as appropriate.
Reformat Scripts Automatically | If checked, the Editor will automatically reformat a Dyalog script when it loads it.
Undo | Undoes the last change made to the object. Repeated use of this command sequentially undoes each change made since the edit window was opened.
Redo | Re-applies the previous undone change. Repeated use of this command sequentially restores every undone change.
Select All | Selects and highlights the entire contents of the Edit window.
Cut | Copies the selected text to the clipboard and removes it from the object.
Copy | Copies the selected text to the clipboard.
Paste | Copies the text in the clipboard into the object at the current location of the input cursor.
Paste Unicode | Same as Paste, but gets the Unicode text from the clipboard and converts to ⎕AV
Paste Non-Unicode | Same as Paste, but gets the ANSI text from the clipboard and converts to ⎕AV.
Clear | Deletes the selection or the character under the cursor. Has no effect on the clipboard
Open Line | Inserts a blank line immediately below the current one.
Delete Line | Deletes the current line.
Goto Line | Prompts for a line number, then positions the cursor on that line.
Find | Displays the Find dialog box.
Replace | Displays the Replace dialog box.
Highlight All Matches | If checked, all strings in the object being edited that match the search string are highlighted. The highlightedted items change dynamically as the search string is entered or changed.
Comment selected lines | Adds a comment symbol to the beginning of all selected lines.
Uncomment selected lines | Removes a comment symbol from the beginning of all selected lines.
Toggle Local name | Adds or removes the name under the cursor to/from the function header line.

The Find and Replace items are used to display the Find dialog box and the Find/Replace dialog box respectively. These boxes are used to perform search and replace operations and are described later in this Chapter.

Once displayed, each of the two dialog boxes remains on the screen until it is either closed or replaced by the other. This is convenient if the same operations are to be performed over and over again, and/or in several windows. Find and Find/Replace operations are effective in the window that previously had the focus.

The Syntax Menu

The Syntax menu illustrated above provides options to specify how the data displayed in the Editor window is to be syntax coloured. For workspace objects, the default is APL for functions and operators, and Nothing for variables.

Item | Syntax Colour as
Nothing | Variable
APL | Function
JSON | JSON array
XML | XML array

The Window Menu

The Window menu provides a means to control the display of the various edit windows. The Window menu and the actions it provides are described below.

Item | Description
Close All Windows | Closes all the edit windows. If Confirm on Edit Window Closed is checked, you will be prompted to confirm for any objects that you have changed.
Cascade | Arranges the edit windows in overlapping fashion.
Tile Vertically | Arranges the edit windows tiled one above the other.
Tile Horizontally | Arranges the edit windows tiled alongside one another.
Arrange Icons | Arranges any minimised edit windows.
Editor | Allows you to Select the edit window corresponding to the named object.

The Refactor Menu

The Refactor menu illustrated above applies only when editing a Class and provides the following options. In each case, the user must highlight a name in the Edit window, and then select one of these options to insert the appropriate template for that name into the body of the Class.

Item | Description
Add text as Field | Inserts a Field template for the selected name.
Add text as Property | Inserts a Property template for the selected name.
Add text as Method | Inserts a Method template for the selected text name.

The View Menu

The View menu, illustrated above, provides the following actions.

Item | Description
Trace | Displays a column to the left of the function that displays ⎕TRACE settings
Stop | Displays a column to the left of the function that displays ⎕STOP settings
Monitor | Displays a column to the left of the function that displays ⎕MONITOR settings
Line Numbers | Toggles the display of line numbers on/off.
Function Line Numbers | Toggles the display of line numbers on individual functions on/off. This option is only enabled when editing a Class, Namespace script or Interface.
Tree View | Toggles the display of the treeview in the left-hand pane.
Compiler Errors | If enabled, the Editor identifies which lines of code would not compile. These are identified by a red vertical line to the left. Hovering over the red bar gives you a pop-up telling you what the compiler didn't like about that line of the function.
Outlining | Turns outlining on and off.
Expand All Outlines | Expands all outlines.
Collapse All Outlines | Collapses all outlines
Expand all Outlines below here | Expands all outlines below the level of the current line.

Function Line Numbers

The Function Line Numbers option in the Editor menu provides an additional level of line-numbering. If selected, line numbers are displayed independently on each individual function (or operator) in the Class. This option is only enabled when you are editing a Class, Namespace script or Interface, and is disabled for all other types of object.

Note that function line-numbering and general line-numbering are independent options and it is possible to have the entire Class numbered (from [0] to the number of lines in the Class) in addition to having line-numbering on each individual function.

Using the Editor

Creating a New Function

Type the name of your function and invoke the editor. To do this you may press Shift+Enter, or select Edit from the Action menu, or double-click the left button on your mouse, or click the Edit tool in the tool bar. A new window will appear on the screen with the name you have chosen displayed in the top border. The name is also inserted in the function header and the cursor positioned to the right. The new window is automatically given the input focus.

Line-Numbers on/off

Try changing the line numbers setting by clicking on the Line Numbers option in the Options menu. Note that line-numbering on/off is effective for all edit windows.

Adding Lines

If the keyboard is in Insert mode, pressing Enter at the end of a line opens you a new blank line under the current one and positions the cursor there ready for input. You can also open a new blank line by pressing Ctrl+Shift+Insert (OP).

If the cursor is at the end of the last line in the function, pressing Enter adds another line even if the keyboard is in Replace mode.

Indenting Text

Dyalog APL allows you to insert leading spaces in lines of a function and (unless the AutoFormat parameter is set) preserves these spaces between editing sessions. Embedded spaces are however discarded. You can enter spaces using the space bar or the Tab key. Pressing Tab inserts spaces up to the next tab stop corresponding to the value of the TabStops parameter. If the AutoIndent parameter is set, new lines are automatically indented the same amount as the preceding line.

Reformatting

The RD command (which by default is mapped to Keypad-Slash) reformats a function according to your AutoFormat and TabStops settings. See Trace/Edit Tab.

Deleting Lines

To delete a block of lines, select them by dragging the mouse or using the keyboard and then press Delete or select Clear from the Edit menu. A quick way to delete the current line without selecting it first is to press Ctrl+Delete (DK) or select Delete Line from the Edit menu.

Copying Lines

Select the lines you wish to copy by dragging the mouse or using the keyboard. Then press Ctrl+Insert or select Copy from the Edit menu. This action copies the selection to the clipboard. Now position the input cursor where you wish to make the copy and press Shift+Insert, or select Paste from the Edit menu. You can also use this method to duplicate a ragged block of text.

To copy text using drag-and-drop editing:

  1. Select the text you want to move.
  2. Hold down the Ctrl key, point to the selected text and then press and hold down the left mouse button. When the drag-and-drop pointer appears, drag the cursor to a new location.
  3. Release the mouse button to drop the text into place.

Moving Lines

Select the lines you wish to copy by dragging the mouse or using the keyboard. Then press Shift+Delete or select Cut from the Edit menu. This action copies the selection to the clipboard and removes it. Now position the input cursor at the new location and press Shift+Insert, or select Paste from the Edit menu. You can also use this method to move a ragged block of text.

To move text using drag-and-drop editing:

  1. Select the text you want to move.
  2. Point to the selected text and then press and hold down the left mouse button. When the drag-and-drop pointer appears, drag the cursor to a new location.
  3. Release the mouse button to drop the text into place.

Joining and Splitting Lines

To join a line to the previous one: select Insert mode; position the cursor on the first character in the line; press Bksp.

To split a line: select Insert mode; position the cursor at the place you want it split; press Return.

Toggling Localisation

The TL command (which by default is mapped to Ctrl+Up) toggles the localisation of the name under the cursor. If the name is currently global, pressing Ctrl+Up causes the name to be added to the list of locals in the function header. If the name is already localised, pressing Ctrl+Alt+l removes it from the header.

Aligning Comments

When you press the <AC> key, or select Align Comments in the Editor's context menu, the alignment of the comments in every line in the function will be changed so that the left-most comment (Lamp) symbol is in the same column as the cursor, except that:

  • Comment symbols that are preceded only by white space, i.e. comments in lines that contain no code, are ignored and are not adjusted in any way.
  • Comment symbols that lie between the first column and the first tab stop will remain in or be moved to the first column. For information on setting tab stops, see Installation & Configuration Guide: Configuration Dialog (Edit/Trace Tab).
  • Comment symbols will not move further left than the end of the statement.

When a comment is re-aligned, text to the right of the left-most comment symbol (including spaces and other comment symbols) will remain fixed in relation to that symbol.

Note that there is no keystroke associated with this command by default; the user must define one. See Installation & Configuration Guide: Configuration Dialog (Keyboard Shortcuts Tab).

Stop, Trace and Monitor Controls

If any of the Stop, Trace, and Monitor options of the View menu are set, the Editor displays an area to the left of the function body containing up to 3 columns. If a function line is enabled by ⎕TRACE,⎕STOP or ⎕MONITOR the corresponding column displays a yellow circle (trace), red circle (stop) or clock symbol (monitor).

When you move the mouse-pointer over this area, the pointer displays the appropriate symbol and you can toggle the corresponding setting on and off by clicking the mouse.

White Space in Source Code

Settings that impact the automatic reformatting of code can cause changes to whitespace – this can be interpreted as changes to the source code. This means that:

  • opening a scripted object in the Edit window can cause the source of that object to change (when closing an Edit window, you might be prompted to save a function even though you have not made any changes to it).
  • viewing an object can change its file timestamp; source code management systems can subsequently report changes due to the changed file timestamp.
  • source code changes resulting from reformatting will be evident in the results of system functions such as ⎕AT, ⎕SRC, ⎕CR, ⎕VR and ⎕NR.

Outlining

When you are editing a function, outlining identifies the blocks of code within control structures, and allows you to collapse and expand these blocks so that you can focus your attention on particular parts of the code

The picture below shows the result of opening the function ⎕SE.cbtop.TB_POPUP.

      )ed ⎕SE.cbtop.TB_POPUP

Notice that the various control structure blocks are delineated by a treeview diagram.

  • When you hover the mouse pointer over one of the boxes that mark the start of a block, the line marking the extent of that block becomes highlighted, as shown above.
  • If you click on a [image] box, the corresponding section collapses, so that only the first line of the block is displayed, as shown below.
  • If you click on a [image] box, the corresponding section is expanded.

Sections

Functions and scripted objects (classes, namespaces etc.) can be subdivided into Sections with :Section and :EndSection statements. Both statements may be followed by an optional and arbitrary name or description. The purpose is to split the function up into sections that you can open and close in the Editor, thereby aiding readability and code management. Sections have no effect on the execution of the code, but must follow the nesting rules of other control structures.

The following picture illustrates the use of sections in a function called DumpWindow. The function is divided into 5 sections named Comments, Init, NAs, MakeBitmap and CopyToClipBoard.

The first picture shows the function with all sections closed.

The next picture shows the effect of opening the Comments section. Notice how this is delineated by the statements:

      :Section Comments
      ...
      :EndSection Comments

And with the Init section opened too:

Finally, with all the sections opened:

Editing Classes

The picture below shows the result of opening the ComponentFile class. Notice how each function is delineated separately and that each function is individually line-numbered.

      )ed ComponentFile

The outlining feature really comes into its own when editing classes because you can collapse and expand whole functions. The picture below shows the effect of collapsing all but the Append method.

When you edit a class, a separate treeview is optionally displayed in the left pane to make it easy to navigate within the class. When you click on a name in the treeview, the editor automatically scrolls the appropriate section into view (if necessary) and positions the edit cursor at its start. The picture below illustrates the result of opening the [Methods] section and then clicking on Rename.

Sections within Scripts

Scripts can also be subdivided into Sections using :Section and :EndSection statements. As with single functions, the purpose is only to split the script up into sections that you can open and close in the Editor. Sections have no effect on the execution of the code.

The following picture illustrates a Class named actuarial which, for editing purposes, has been sub-divided into five separate Sections named Main, MenuHandlers, Validation, Utilities and OldCode. In this picture, all the Sections are closed.

The next picture shows the effect of opening just the Main section.

Notice that this section is delimited by the two statements:

      :Section Main
      ...
      :EndSection Main

In this picture the 3 functions within the Main section are temporarily closed.

Similarly, the section called Validation is delimited by:

      :Section Validation
      ...
      :EndSection Validation


Find and Replace Dialogs

The Find and Find/Replace dialog boxes are used to locate and modify text in an Edit window.

Search For | Enter the text string that you want to find. Note that the text from the last 10 searches is available from the drop-down list. If appropriate, the search text is copied from the Find Objects tool. This makes it easy to first search for functions containing a particular string, and then to locate the same string in the functions.
Replace With | Enter the text string that you want to use as a replacement. Note that the text from the last 10 replacements is available from the drop-down list.
Match Case | Check this box if you want the search to be case-sensitive.
Match Whole Word | Check this box if you want the search to only match only whole words.
Use Regular Expressions | Check this box if you want to use Regular Expressions.
AutoMove | If checked, the Find or Find/Replace dialog box will automatically position itself so as not to obscure a matched search string in the edit window.
Direction | Select Up or Down to control the direction of search.

Using Find and Replace

Find and Replace work on the concept of a current search string and a current replace string which are entered using the Find and Find/Replace Dialog boxes. These boxes also contain buttons for performing search/replace operations.

Suppose that you want to search through a function for references to the string "Adam". It is probably best to work from the start of the function, so first position the cursor there (by pressing Ctrl+Home). Then select Find from the Edit menu. The Find Dialog box will appear on your screen with the input cursor positioned in the edit box awaiting your input. Type "Adam" and click the Find Next button (or press Return), and the cursor will locate the first occurrence. Clicking Find Next again will locate the second occurrence. You can change the direction of the search by selecting Up instead of Down. You could search another function for "Adam" by opening a new Edit window for it and clicking Find Next. You do not have to redefine the search string.

Now let us suppose that you wish to replace all occurrences of "Adam" with "Amanda". First select Replace from the Edit menu. This will cause the Find Dialog box to be replaced by the Find/Replace Dialog box. Enter the string "Amanda" into the box labelled Replace With, then click Replace All. All occurrences of "Adam" in the current Edit window are changed to "Amanda". To repeat the same global change in another function, simply open an edit window and click Replace All again. If instead you only want to change particular instances of "Adam" to "Amanda" you may use Find Next to locate the ones you want, and then Replace to make each individual alteration.

Text searches are performed using PCRE. If the Use Regular Expressions box is checked, the full range of regular expressions provided by PCRE are available for use. See PCRE Regular Expression Syntax Summary.

Saving and Quitting

To save the function and terminate the edit, press Esc (EP) or select Exit from the File menu. The new version of the function replaces the previous one (if any) and the edit window is destroyed.

Alternatively, you can select Fix from the File menu. This fixes the new version of the function in the workspace, but leaves the edit window open. Note that the history is also retained, so you can subsequently undo some changes and fix the function again.

To abandon the edit, press Shift+Esc (QT) or select Abort from the File menu. This destroys the edit window but does not fix the function. The previous version (if any) is unchanged.


Editing Scripts and Text Files

The Editor may also be used to edit Dyalog script files (.dyalog files) and general text files.

There are two ways to choose the file to be edited. If the file exists, you can select it from the Open source file dialog by clicking File/Edit Text File from the Session menu bar.

Alternatively, type )ED followed by the pathname to the file. To identify the name given as a file, it must either contain a slash character ("\" or "/") or be preceded by one.

Examples

      )ED c:\Dyalog15.0\myscript.dyalog
      )ED c:\Dyalog15.0\pete.txt

      )ED /x.txt  ⍝ x.txt in current directory

      )ed / x.txt ⍝ ditto

      )ed / y     ⍝ y in current directory

If the named file does not exist, you will be asked whether or not you want to create it:

If you edit a Dyalog script file, the editor will treat it as such and provide the same formatting and syntax colouring as if it were a script in the workspace.

Otherwise, the file will be edited as if it were a character vector with embedded new-lines.

When you exit the editor with Exit and fix, you will be offered a number of alternatives depending upon the type of file, as shown below.

Saving a Text file.

Note that if you choose Save as text in the workspace, information about the file and the text variable associated with it is retained in the workspace. This information may be obtained using 5176⌶ and 5177⌶. See List Loaded Files and List Loaded File Objects.

Saving a Script file.

Note that if you choose Fix as code in the workspace or Save as text in the workspace, information about the file and the text variable associated with it is retained in the workspace. This information may be obtained using 5176⌶ and 5177⌶. See List Loaded Files and List Loaded File Objects.

Fix as code in the workspace

If you choose this option, the file will be updated and the script will also be fixed in the workspace. Note that if the script refers to a base class or other external elements, it cannot be fixed unless these elements are also present in the workspace.

Save as text in the workspace

If you choose this option, the file will be updated and the contents of the file will also be saved to a variable in the workspace. First you will see the following warning dialog, which may be disabled subsequently by checking Do not ask this question again.

Then you will be prompted to supply its name, which may be a new name or the name of an existing variable:

Only save file to disk

If you choose this option, the file will be updated but nothing will be changed in the workspace.

Discard changes

If you choose this option, all changes will be discarded and nothing saved.


The Tracer

The Tracer is a visual debugging aid that allows you to step through an application line by line. During a Trace you can track the path taken through your code, display variables in edit windows and watch them change, skip forwards and backwards in a function. You can cutback the stack to a calling function and use the Session and Editor to experiment with and correct your code. The Tracer may be invoked in several ways as discussed below.

Tracing an expression

Firstly, you may explicitly trace an expression that executes one or more defined functions or operators by typing the expression then pressing Ctrl+Enter (TC) or by selecting Trace from the Action menu. This lets you step through the execution of an expression from the beginning.

In the same way as when you execute a statement by pressing Enter, the expression is (if necessary) copied down to the input line and then executed. However, if the expression includes a reference to an unlocked defined function or operator, execution halts at its first line and a Trace window containing the suspended function or operator is displayed on the screen. The cursor is positioned to the left of the first line which is highlighted.

Naked Trace

The second way to invoke the Tracer is when you have a suspended function in the state indicator and you press Ctrl+Enter (TC) on the empty input line. This is termed naked trace. The same thing can be achieved by selecting Trace from the Action menu on the Session Window.

The effect of naked trace is to open the Tracer and to position the cursor on the currently suspended line. It is exactly as if you had traced to that point from the Input Line expression whose execution caused the suspension.

Automatic Trace

The third way to invoke the Tracer is to have the system do it automatically for you whenever an error occurs. This is achieved by setting the Show trace stack on error option in the Trace/Edit tab of the Configuration dialog (Trace_on_error parameter). When an error occurs, the system will automatically deploy the Tracer. Note that this means that when an error occurs, the Trace window will then receive the input focus and not the Session window.

Tracer Options

From Version 10.1 onwards, the Tracer is designed to be docked in the Session window.

In previous versions of Dyalog APL, the Tracer was implemented as a stack of separate windows (one per function on the calling stack) or as a single, but still separate, window.

You can disable the standard behaviour by selecting Classic Dyalog mode from the Trace/Edit tab of the Configuration dialog box.

If you do so, you may then choose to have the Tracer operate in multiple windows or in a single window.

These alternatives are discussed later in this Chapter.

The Trace Window

The Tracer is implemented as a single dockable window that displays the function that is currently being executed. There are two subsidiary information windows which are also fully dockable. The first of these (SIStack) displays the current function calling stack; the second (Threads) displays a list of running threads.

In the default Session files, the Tracer is docked along the bottom edge of the Session window. When you invoke the Tracer, it springs up as illustrated below. In this example, the function being traced is ⎕SE.UCMD, which is invoked by typing a user-command, in this case ]display.

In the default layout, the SIstack window is displayed alongside the main Tracer window, although this can be hidden or made to appear as a separate floating window, as required.

Trace Tools

The Tracer may be controlled from the keyboard, or by using the Trace Tools which are arranged along the title bar of the Debugger window. Note that the button names are solely for reference purposes in the description that follows.

Button | Name | Key Code | Keystroke | Description
 | Exec | ER | Enter | Execute expression
 | Trace | TC | Ctrl+Enter | Trace expression
 | Back | BK | Ctrl+Shift+Bksp | Go back one line
 | Fwd | FD | Ctrl+Shift+Enter | Skip current line
 | Continue | BH |  | Stop on next line of calling function
 | Restart | RM | →⎕LC | Continue execution of this thread
 | Restart all |  |  | Continue execution of all threads
 | Edit | ED | Shift+Enter | Edit name
Button | Name | Key Code | Keystroke | Description
 | Exit | EP | Esc | Quit this function
 | Intr |  | Ctrl+Pause | Interrupt
 | Reset | CB |  | Clear trace/stop/monitor for this object
 |  | LN |  | Toggle line numbers
 |  |  |  | Search for next match
 |  |  |  | Search for previous match
 |  |  |  | Search hidden text
 |  |  |  | Match case
 |  |  |  | Match whole word
 |  |  |  | Use Regular Expressions

Using the Trace Tools, you can single-step through the function or operator by clicking the Exec and/or Trace buttons. If you click Exec the current line of the function or operator is executed and the system halts at the next line. If you click Trace, the current line is executed but any defined functions or operators referenced on that line are themselves traced. After execution of the line the system again halts at the next one. Using the keyboard, the same effect can be achieved by pressing Enter or Ctrl+Enter.

The illustration below shows the state of execution having clicked Exec 16 times to reach ⎕SE.UCMD[17].

Execution Reached ⎕SE.UCMD[17]

The next illustration shows the result of clicking Trace at this point. This caused the system to trace into ⎕SE.SaltUtils.Spice, the function called from ⎕SE.UCMD[17].

Notice how each function call on the stack is represented by an item in the SIstack window.

Execution Reached ⎕SE.SALTUtils.Spice [1]

The illustration below shows the state of execution having traced deeper into the system.

Execution reached four levels deep

At this stage, the state indicator is as follows:

      )SI
⎕SE.SALT.Load[1]*
⎕SE.SALTUtils.Spice[146]
⎕SE.UCMD[17]

Controlling Execution

The point of execution may be moved by clicking the Back and Fwd buttons in the Trace Tools window or, using the keyboard, by pressing Ctrl+Shift+Bksp and Ctrl+Shift+Enter. Notice however that these buttons do not themselves change the state indicator or the display in the SIStack window. This happens only when you restart execution from the new point.

You can cut back the stack by clicking the <EP> button in the Trace Tools window. This causes execution to be suspended at the start of the line which was previously traced. The same effect can be achieved using the keyboard by pressing Esc. It can also be done by selecting Exit from the File menu on the Trace Window or by selecting Close from its system menu.

The <RM> button removes the Trace window and resumes execution. The same is achieved by the expression →⎕LC.

The <BH> button continues execution until the current function has run to completion and control has returned to the calling function. It leaves the Trace window displayed and allows you to watch execution progress.

Using the Session and the Editor

Whilst using the Tracer you can skip to the Session or to any Edit window and back again. While it is docked, you may resize the Tracer pane by dragging its title bar, and you may use the buttons provided to maximise, minimise and restore the Tracer pane within the Session window.

Unless you move it, the cursor is positioned to the left of the suspended line in the top Trace window.

Depending where the cursor is in the tracer window, pressing Shift+Enter (ED) or selecting Edit from the File menu may cause an edit window to open. If the cursor is in the first column of the Trace window, or on whitespace, the Editor is opened on function or operator on top of the stack. If the cursor in on a name, the Editor is opened on the name under the cursor (point-and-edit). With the cursor in any other location, no action is undertaken.

When you finish editing, the window reverts to a trace window with the new definition of the function or operator displayed.

You may also open a new edit window from within the Tracer using point-and-edit.

You can copy text from a trace window to the session for editing and execution or for experimentation.

It is possible to skip from the Tracer to the Session and then re-invoke the Tracer on a different expression.

Setting Break-Points

Break-points are defined by ⎕STOP and may be toggled on and off in an Edit or Trace window by clicking in the appropriate column. The example below illustrates a function with a ⎕STOP break-point set on line [5].

⎕STOP break-points set or cleared in an Edit window are not established until the function is fixed. ⎕STOP break-points set or cleared in a Trace window are established immediately.

Clearing All Break-Points

You can clear all break-points by pressing the above button in the Trace Tools window. This in fact resets ⎕STOP for all functions in the workspace.

The Classic mode Tracer

If you select Classic Dyalog mode from the Trace/Edit tab in the Configuration dialog box, the Tracer behaves in the same way as in Dyalog APL Version 8.2. However, the Tracer is not dockable in the Session.

If you select the Classic mode Tracer, you may choose between multiple trace windows or a single trace window using the Single Trace Window option.

Multiple Trace Windows

The following behaviour is obtained by deselecting the Single Trace Window option.

  • Each function on the SI stack is represented by a separate trace window. The top window contains the function that is currently executing, other windows display functions further up the stack, in the order in which they were called.
  • When you press Ctrl+Enter or click the Trace button on a line that calls another function, a new trace window appears on top of the stack and displays the newly called function.
  • When a function exits, its trace window disappears and the focus moves to the previous trace window. When the last function in a traced suspension exits, the last trace window disappears.
  • If you click the Quit this function button in the Trace Tools window, or press Escape, or close the trace window by clicking on its [X] button or typing Alt-F4, the top trace window disappears and the focus moves to the previous trace window
  • If you close any of the trace windows further down the stack, the stack will be cut back to the corresponding point, i.e. to the line of code that called the function whose trace window you closed.
  • The <RM> button removes all the trace windows and resumes execution. The same is achieved by the expression →⎕LC. The <CS> button also continues execution, but leaves the trace windows displayed and allows you to watch their progress.
  • If you minimise any of the trace windows, the entire stack is minimised to a single icon, from which it may be restored.
  • If you drag any Trace window with the mouse and at the same time press Ctrl+Shift, the entire set of Trace windows is dragged.

Note that a maximum of 50 Trace windows may be displayed.

Single Trace Window

The following behaviour is obtained by selecting the Single Trace Window option.

  • The trace window contains a combo box whose drop-down displays the contents of the SI stack. This box is not provided if there are multiple trace windows.
  • The trace window is re-used when tracing into, or returning from, a called function. This means that there is never more than one trace window present.
  • When the last function in a traced suspension exits, the trace window disappears.
  • If you click the Quit this function button in the Trace Tools window, or press Escape, the current function is removed from the stack and the trace window reused to display the calling function if there is one.
  • Closing the trace window by clicking on its [X] button or typing Alt-F4 removes the window and clears the current suspension. It is equivalent to typing naked branch (→) in the session window.
  • If you move or resize the trace window, APL remembers its position, so that it reappears in the same position when next used.


The Threads Tool

The Threads Tool is used to monitor and debug multi-threaded applications. To display the Threads Tool, select Show Threads Tool from the Session Threads menu, or Threads from the Session pop-up menu.

The above picture illustrates a situation using the lift.dws workspace after executing the function RUN. The Pause on Error option was enabled and a Stop was set on RUN[63]. When RUN suspended at this point, all other threads (1-8) were automatically Paused. Note that all other threads happen to be Paused in the middle of calls to system functions

The columns of the Threads Tool display the following information.

Column | Description
Tid | The Thread ID (⎕TID) and name (⎕TNAME) if set
Location | The currently executing line of function code
State | Indicates what the thread is doing. (see below)
Flags | Normal or Paused.
Treq | The Thread Requirements (⎕TREQ)

Thread States

State | Description
Pending | Not yet running
Initializing | Not yet running
Defined function | Between lines of a defined function
Dfn | Between lines of a dfn
Suspended | Indicates that the thread is suspended and is able to accept input from the Session window.
Session | Indicates that Session window is connected to this thread.
(no stack) | Indicates that the thread has no SI stack and the Session is connected to another thread. This state can only occur for Thread 0.
Exiting | About to be terminated
:Hold | Waiting for a :Hold token
:EndHold | Waiting for a :Hold token
⎕DL | Executing ⎕DL
⎕DQ | Executing ⎕DQ
⎕NA | Waiting for a DLL (⎕NA) call to return.
⎕TGET | Executing ⎕TGET, waiting for a token
⎕TGET (Ready to continue) | Executing ⎕TGET, having got a token
⎕TSYNC | Waiting for another thread to terminate
Awaiting request | Indicates a thread that is associated with a .NET system thread, but is currently unused
Called .NET | Waiting for a call to .NET to return.

Paused/Normal

In addition to the thread state as described above, a thread may be Paused or Normal as shown in the Flags column. A Paused thread is one that has temporarily been removed from the list of threads that are being scheduled by the thread scheduler. A Paused thread is effectively frozen.

Threads Tool Pop-Up Menu

Switch to | Selecting this item causes APL to attempt to suspend (if necessary) and switch to the selected thread, connecting it to the Session and Debugger windows.
Interrupt | Causes a (STRONG) interrupt in the selected thread the next time it is scheduled, essentially it allows you to target an interrupt at a specific thread.
Ignore Interrupts | Allows you to specify that the selected thread should ignore weak interrupts.
Refresh Now | Refreshes the Threads Tool display to show the current position and state of each thread.
Auto Refresh | Selecting this item causes the Threads Tool to be updated continuously, so that it shows the latest position and state of each thread.
Pause Threads on Error | If this item is checked, APL automatically Pauses all other threads when a thread suspends due to an error or an interrupt.
Paused | This item toggles a thread between being Paused and Normal. It Pauses a Normal thread and resumes a Paused thread.
Pause All | This item causes all threads to be Paused.
Resume All | This item resumes all threads.
Restart All | This item resumes all Paused threads, restarts all suspended threads, and closes the Debugger.


Debugging Threads

The Debugger provides a tabbed interface that allows you to easily switch between suspended threads for debugging purposes. To keep things simple for non-threaded applications, Tabs are only displayed if there is a thread suspended that is other than Thread 0. The following picture shows the Debugger open on a multi-threaded application (LIFT.DWS) when only Thread 0 is suspended. This has been achieved by setting a stop on RUN[63]

In the next picture, the user has chosen to display the Threads Tool and then dock it between the Session and Debugger windows. Note that only one thread, thread 0 (Run) is suspended. All the other threads are Paused (because Pause on Error is enabled).

The user then uses the context menu to Switch To Thread 6 (whose name is Lady 6) which was Paused on PERSON[7] in the middle of a ⎕TGET. The act of switching to this thread caused it to be suspended at the beginning of its current line PERSON[7] and the Debugger now displays two Tabs to represent the two suspended threads. Note that both the thread id and the thread name are displayed on the Tabs.

Note also that the Session window is connected to the thread indicated by the selected Tab. In this case, typing MYFLOOR into the Session window displays the value of the local variable MYFLOOR in Thread 6 (Lady 6).

You can use the Tabs to switch between the suspended threads, so clicking the Tab labelled 0:Run causes the display to change to the picture shown below. The Session is now connected to Thread 0 (Run), so the value of ⎕LC is 63.


The Event Viewer

The Event Viewer can be used to monitor events on Dyalog APL GUI objects. To display the Event Viewer, select Event Viewer from the Session Tools menu.

You can choose:

  • which types of events you want to monitor
  • which objects you want to monitor

In the example illustrated above, the user has chosen to monitor events on a Form #.F. Furthermore, the user has chosen to monitor GotFocus, LostFocus, MouseUp, MouseDblClick and Configure events.

Entries in the Action column report the action that was associated with the event at the time it was placed in the queue. This may or may not be the same as the action that is associated with the event when it reaches the top of the event queue and is processed.

The Spy Menu

The Spy menu, illustrated above, provides the following options and actions.

Item | Description
Clear | Clears all of the event information that is currently displayed in the Event Viewer.
Copy | Copies the highlighted rows to the clipboard.
All | In this mode all the events are displayed in the Event Viewer as they occur, whether or not there is an action associated with them.
When Placed in Object's Queue | In this mode only events that have associated actions are displayed in the event viewer. Note that KeyPress events are always queued and therefore always appear, even if there is no associated action.
Current Queue State | In this mode the Event Viewer displays a snapshot of the internal event queue. Only those events that are currently in the internal APL event queue waiting to be processed are displayed.
Enable Logging | This item switches event logging on and off.
Close | Closes the Event Viewer

The Columns Menu

The Columns menu allows you to choose which information is displayed for the events you are monitoring.

Item | Description
ObjectName | If checked, this item displays the name of the object on which the event occurred.
ObjectType | If checked, this item displays the type of the object on which the event occurred.
Event Name | If checked, this item displays the name of the event that occurred.
Event Number | If checked, this item displays the event number of the event that occurred.
Parameters | If checked, this item displays the parameters for the event that occurred. These are the items that would be passed in the argument to a callback function.
Action | If checked, this item displays the action associated with the event when the event is placed in the event queue, for example the name of a callback function, or an expression to be executed.
Thread ID | If checked, this item displays the thread id of the thread in which the event occurred
NQed | If checked, this item displays 0 or 1 according to whether or not the event occurred naturally or was generated programmatically by ⎕NQ.
Event ID | If checked, this item displays the event id of the event that occurred. This id is used internally.
TimeStamp | If checked, this item displays the time stamp of the event that occurred.

The Select Menu

The Select menu allows you to highlight certain events in the Event Viewer. For example, if you are monitoring TCP/IP events on a number of TCPSockets, you can highlight just the events for a particular socket.

Item | Description
Select All | Highlights all the events.
Select Matching Events | Highlights all the events that have the same Object and Event Name (or Event Number) as the currently selected event.
Select All Events on This Object | Highlights all the events that have the same Object as the currently selected event.
Select All Events of this Type | Highlights all the events that have the same Event Name (or Event Number) as the currently selected event

These items are also available from the pop-up menu that appears when you press the right mouse button over an event displayed in the Event Viewer window.

The Options Menu

The Options menu allows you to choose which information is displayed for the events you are monitoring.

Item | Description
Always on Top | If checked, this item causes the Event Viewer window to be displayed above all other windows (including other application windows).
Use APL font | If checked, this item causes the information displayed in the Event Viewer window to be displayed using the APL font (the same font as is used in the Session window). If not, the system uses the appropriate Windows font.
Settings... | Displays the Event Viewer Options Dialog Box.

Options Dialog Box

The Event Viewer Options dialog box allows you to select the objects and events that you wish to monitor.

Events to view

The list box shows all the events that are support by the Dyalog APL GUI and allows you to select which events are to be monitored. User defined events may be selected by checking the User defined events box. Only those events that are selected will be reported. You can sort the events by name or by event number by clicking the appropriate column header.

Objects to view

Item | Description
Find Tool Select from List | This tool allows you to choose a single specific Dyalog APL GUI object that you want to monitor. To use it, drag the Find Tool and move it over your Dyalog APL GUI objects. As you drag it, the individual objects are highlighted and their details displayed in the Name, Type, Thread ID and Handle fields. Drop the Find Tool on the object of your choice. Clicking the Select from List button brings up a dialog box that displays the entire Dyalog APL GUI structure as a tree view. You can choose a single object by selecting it.
Parent Object | Enables event reporting on the selected object's immediate parent.
Child Objects | Enables event reporting on the all selected object's descendants (at any level).
Same Thread | Enables event reporting on all the objects in the same thread as the selected object.
All Objects | Enables event reporting on all Dyalog APL GUI objects.
Objects of Type Select from List | Activates the adjoining Select button and disables all other Object selection mechanisms. Clicking the Select from List button brings up a dialog box that allows you to choose which types of Dyalog APL GUI objects you want to monitor.


Session Object

The Session Object

Purpose: | The Session object ⎕SE is a special system object that represents the session window and acts as a parent for the session menus, tool bar(s) and status bar.
Children | Form, MenuBar, Menu, MsgBox, Font, FileBox, Printer, Bitmap, Icon, Cursor, Clipboard, Locator, Timer, Metafile, ToolBar, StatusBar, TipField, TabBar, ImageList, PropertySheet, OLEClient, TCPSocket, CoolBar, ToolControl, BrowseBox
Properties | Type, Caption, Posn, Size, File, Coord, State, Event, FontObj, YRange, XRange, Data, TextSize, Handle, HintObj, TipObj, CurObj, CurPos, CurSpace, Log, Input, Popup, RadiusMode, MethodList, ChildList, EventList, PropList
Methods | ChooseFont, FileRead, FileWrite
Events | Close, Create, FontOK, FontCancel, WorkspaceLoaded, SessionPrint

Description

There is one (and only one) object of type Session and it is called ⎕SE. You may use ⎕WG, ⎕WS and ⎕WN to perform operations on ⎕SE, but you cannot expunge it with ⎕EX nor can you recreate it using ⎕WC. You may however expunge all its children. This will result in a bare session with no menu bar, tool bar or status bar.

⎕SE is loaded from a session file when APL starts. The name of the session file is specified by the session_file parameter. If no session file is defined, ⎕SE will have no children and the session will be devoid of menu bar, tool bar and status bar components.

You may use all of the standard GUI system functions to build or configure the components of the Session to your own requirements. You may also control the Session by changing certain of its properties.

Note that the Session reports a Create event when APL is first started, and a WorkspaceLoaded event when a workspace is loaded or on a clear ws.

The Session also reports a SessionPrint event when certain types of output are about to be displayed. This may be used to alter the normal default display.

Read-Only Properties

The following properties of ⎕SE are read-only and may not be set using ⎕WS:

Type | A character vector containing 'Session'
Caption | A character vector containing the current caption in the title bar of the Session window.
TextSize | Reports the bounding rectangle for a text string. For a full description, see TextSize in Object Reference.
CurObj | A character vector containing the name of the current object. This is the name under or immediately to the left of the input cursor.
CurPos | A 2-element integer vector containing the position of the input cursor (row and column number) in the session log. This is ⎕IO dependent. If ⎕IO is 1, and the cursor is positioned on the character at the beginning of the first (top) line in the log, CurPos is (1 1). If ⎕IO is 0, its value would be (0 0).
CurSpace | A character vector which identifies the namespace from which the current expression was executed. If the system is not executing code, CurSpace is the current space and is equivalent to the result of ⊃''⎕NS''.
Handle | The window handle of the Session window.
Log | A vector of character vectors containing the most recent set of lines (input statements and results) that are recorded in the session log. The first element contains the top line in the log.
Input | A vector of character vectors containing the most recent set of input statements (lines that you have executed) contained in the input history buffer.
ChildList | A vector of character vectors containing the types of object that can be created as a child of ⎕SE.
MethodList | A vector of character vectors containing the names of the methods associated with ⎕SE.
EventList | A vector of character vectors containing the names of the events generated by ⎕SE
PropList | A vector of character vectors containing the names of the properties associated with ⎕SE.

Read/Write Properties

The following properties of ⎕SE may be changed using ⎕WS:

Coord | Specifies the co-ordinate system for the session window.
Data | May be used to associate arbitrary data with the session object ⎕SE.
Event | You may use this property to attach an expression or callback function to the Create event or to user-defined events. A callback attached to the Create event can be used to initialise the Session when APL starts.
File | The full pathname of the session file that is associated with the current session. This is the file name used when you save or load the session by invoking the FileRead or FileWrite method.
FontObj | Specifies the APL font. In general, the FontObj property may specify a font in terms of its face name, size, and so forth or it may specify the name of a Font object. For applications, the latter method is recommended as it will result in better management of font resources. However, in the case of the Session object, it is recommended that the former method be used.
HintObj | Specifies the name of the object in which hints are displayed. Unless you specify HintObj individually for session components, this object will be used to display the hints associated with all of the menu items, buttons, and so forth in the session. The object named by this property is also used to display the message "Ready..." when APL is waiting for input.
Popup | A character vector that specifies the name of a popup menu to be displayed when you click the right mouse button in a Session window.
Posn | A 2-element numeric vector containing the position of the top-left corner of the session window relative to the top-left corner of the screen. This is reported and set in units specified by the Coord property.
Size | A 2-element numeric vector containing the height and width of the session window expressed in units specified by the Coord property.
State | An integer that specifies the window state (0=normal, 1=minimised, 2=maximised). You may wish to use this property to minimise and later restore the session under program control. If you save your session with State set to 2, your APL session will start off maximised.
TipObj | Specifies the name of the object in which tips are displayed. Unless you specify TipObj individually for session components, this object will be used to display the tips associated with all of the menu items, buttons, and so forth in the session.
XRange | See Object Reference
YRange | See Object Reference

Special Properties

The following properties of ⎕SE are used internally by Dyalog tools such as SALT. They are not intended nor supported for general use and are not reported by PropList.

StatusWindow | This read-only property returns a reference to the Status Window. The expression: (⎕SE.⎕WG'StatusWindow')⎕WG'Text' returns the (read-only) contents of the status window.
Editor | This read-only property returns a reference to the Editor Window. The Editor generates the special events Fix, AfterFix and Format.

Special Events

The following special events are generated by ⎕SE or its child objects. They are used internally by Dyalog tools such as SALT. They are not intended nor supported for general use.

AfterFix | This event is reported by the Editor after it has successfully fixed a new object, or a new version of an object, in the workspace.
Fix | This event is reported by the Editor when the user attempts to fix an object.
Format | This event is reported by the Editor when the user attempts to format an object.
SessionPrint | This event is reported when a value is about to be displayed in the Session window. The default display of the value may be intercepted by a callback function and displayed differently. This event is used by the ]box and ]rows user commands.
WorkspaceLoaded | This event is generated when a workspace is loaded or upon )CLEAR.


AfterFix Event

AfterFix Event 822
Applies To: Editor

Description

If enabled, this event is reported immediately after the Editor has successfully fixed a new object, or a new version of an object, in the workspace.

You may not nullify or modify the event with a 0-returning callback, nor may you generate the event using ⎕NQ, or call it as a method. However, returning 0 from a callback will cause the Edit window to remain open if the user action was Fix and Exit (EP).

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 7-element vector as follows :

[1] | Object | ref to the Editor object
[2] | Event | 'AfterFix' or 822
[3] | Contents | the contents of the Edit window, as a vector of character vectors
[4] | Space | ref to the namespace in which the object will be fixed
[5] | Old Name | a character vector containing the original name of the object when it was opened by the Editor
[6] | New Name | a character vector containing the name of the object which was fixed. This is empty if the object is a variable.
[7] | File Name | a character vector containing the name of the file (if any) associated with the object.


Fix Event

Fix Event 820
Applies To: Editor

Description

If enabled, this event is reported when the user attempts to fix an object from the Editor window. It is reported immediately, before the user's action is processed in any way by the Editor.

The default action is to check whether the object has changed. If not, no further action takes place. If the object has changed, the system validates the contents of the Edit window, and either displays an error dialog or fixes a new version of the object in the workspace. If the user action was to fix and exit (EP), the Edit window is closed unless the validation failed.

If the callback function returns 0, the default action is aborted in its entirety (not even the validation takes place) and the Edit window remains open.

You may not generate the event using ⎕NQ, or call it as a method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 7-element vector as follows :

[1] | Object | ref to the Editor object
[2] | Event | 'Fix' or 820
[3] | Contents | the contents of the Edit window, as a vector of character vectors
[4] | Space | ref to the namespace in which the object will be fixed
[5] | Old Name | a character vector containing the original name of the object when it was opened by the Editor
[6] | New Name | a character vector containing the new name of the object. This is empty if the object is a variable.
[7] | File Name | a character vector containing the name of the file (if any) associated with the object.

For objects whose names are part of the content of the Edit window, this event is not reported if the name is missing or invalid. Instead the system will display an error dialog box.


Format Event

Format Event 821
Applies To: Editor

Description

If enabled, this event is reported when the user attempts to format an object in the Editor window.

If the callback function returns 0, the contents of the Edit window are not reformatted.

You may not generate the event using ⎕NQ, or call it as a method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 6-element vector as follows :

[1] | Object | ref to the Editor object
[2] | Event | 'Format' or 821
[3] | Contents | the contents of the Edit window, as a vector of character vectors
[4] | Space | ref to the namespace in which the object will be fixed
[5] | Old Name | a character vector containing the original name of the object when it was opened by the Editor
[6] | New Name | a character vector containing the new name of the object. This is empty if the object is a variable.


SessionPrint Event

SessionPrint Event 526
Applies To: Session

Description

If enabled, this event is reported when a value is about to be displayed in the Session. It is generated by the display of a variable or the result of a function including system variables and functions. Error messages and output from system commands do not generate this event.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'SessionPrint' or 526

The attachment of a callback function intercepts and annuls the normal display of any value.

Note that this event may be extended in future; in particular the number of elements in the event message may be increased, and the event may be generated by some system commands. You should therefore allow for such extensions in any code which refers to SessionPrint.

When the event is generated, the left argument of the callback function contains the value which was about to be displayed. The callback function may display this or any other value, using default output or by assignment to ⎕. If so, this output will be processed normally, without generating a subsequent SessionPrint event. If the callback fails to explicitly display anything, nothing will appear in the Session.

Example

      ⎕VR'⎕SE.TimeStamp'
     ∇ VAL TimeStamp EV
[1]    ⎕TS VAL
     ∇

      '⎕SE'⎕WS'Event' 'SessionPrint' '⎕SE.TimeStamp'

      2
 2014 9 18 16 20 38 318  2

      ⎕A
 2014 9 18 16 20 44 668  ABCDEFGHIJKLMNOPQRSTUVWXYZ

The result (if any) of the callback function is ignored.

You may not disable the event (by setting its action to ¯1), nor generate the event using ⎕NQ, nor call it as a method.


WorkspaceLoaded Event

WorkspaceLoaded Event 525
Applies To: Session

Description

If enabled, this event is reported when a workspace is loaded or on a clear ws. You may not nullify or modify the event with a 0-returning callback, nor may you generate the event using ⎕NQ, or call it as a method.

The event message reported as the result of ⎕DQ, or supplied as the right argument to your callback function, is a 2-element vector as follows :

[1] | Object | ref or character vector
[2] | Event | 'WorkspaceLoaded' or 525

This event is fired immediately after a workspace has been loaded and before the execution of ⎕LX.

The callback function you attach should be defined in ⎕SE.


Configuring the Session

As supplied, your default session will have a menu bar, a tool bar and a status bar. There are many ways in which you may configure this set-up, including the following:

You may select a different APL font or character size.

You may alter the appearance of the menus by changing the Caption properties of the various Menu and MenuItem objects. For example, you may prefer the menus to appear in your own language.

You may alter the structure of the menus. For example, you may wish to create a Search menu directly on the menu bar rather than having Find and Replace as part of the Edit menu.

You may add new Menu and MenuItem objects to the menu bar, or new Button objects to the tool bar, that execute APL functions or expressions for you. You can store the code inside the ⎕SE namespace so that it is remains available when you switch from one workspace to another.

You may add other objects to the tool bar to allow you to provide input for your functions or to display output. For example, you may display a Combo object that offers you a selection of names applicable to a particular task.

You may add additional toolbars.

You may remove objects too; for example, you can remove fields from the StatusBar or even delete it entirely. Indeed, you may dispense with the menu bar and/or tool bar as well.

This section illustrates how you can configure your session using worked examples. The examples are by no means exhaustive, but are designed to demonstrate the principles. Please note that the structure and names of the objects used in these examples may not be identical to your default session as supplied. Before you attempt to change your session, please check the structure and the object names using ⎕WN and ⎕WG. The supplied session was created using the function BUILD_SESSION in the workspace BUILDSE. If you wish to make substantial changes to your session, you may find it most convenient to edit the functions in this workspace, re-run BUILD_SESSION, and then save it.

Please note that these examples assume that Expose Session Properties is enabled.

Changing the Font

The APL session font is defined by the Font property of ⎕SE. To change the font permanently, you should select a different Font and/or size of Font using the combo and spinner boxes on the Session toolbar, and save your Session.

Classic Edition is distributed with bitmap fonts suitable for use on your screen, and TrueType fonts for your printer. You can use the TrueType font on the screen, but it is less attractive than the bitmap fonts at low resolutions. The bitmap fonts come in two sizes (16 x 8 and 22 x 11) and two weights (normal and bold). You may select other sizes, so long as the height is a multiple of 16 or 22. The scaling is performed automatically by Windows.

Changing Menu Appearance

The name of the Session MenuBar is '⎕SE.mb'. To simplify the specification of object names, we will first change space to the MenuBar itself:

      )CS ⎕SE.mb
⎕SE.mb

The names of the Menu objects owned by the MenuBar are given by the expression:

      'Menu' ⎕WN ''
file  edit  view  windows  session  log  action  options  tools  threads  help

The current caption on the file menu is:

    file.Caption
&File

To change the Caption to Workspace:

    file.Caption←'Workspace'

To change the colour of the New option in the File menu to red:

    file.clear.FCol←255 0 0

Reorganising the Menu Structure

This example shows how you may alter the structure of the session menus by adding a Search menu to the menu bar to provide access to the Find and Find/Replace dialog boxes and removing these options from the Edit menu.

To simplify the process, we will first change space into the MenuBar object itself:

      )CS ⎕SE.mb
⎕SE.mb

Then we can begin by adding the Search menu. You can specify where the new menu is to be added using its Posn property. In this case, Search will be added at position 3 (after Edit).

      'search'⎕WC 'Menu' '&Search' 3

Next we will remove the Find and Replace MenuItem objects from the Edit menu. Their names can be obtained from ⎕WN:

      'MenuItem'⎕WN'edit'
edit.prev  edit.next  edit.clear  edit.copy  edit.paste
edit.find  edit.replace

It is worth noting that these MenuItems perform their actions because their Event property is set to execute the system operations [Find] and [Replace] respectively when they are selected.

      edit.find.Event
  Select  [Find]
      edit.replace.Event
  Select  [Replace]

The following statement removes them from the Edit menu:

      ⎕EX¨'edit.find' 'edit.replace'

and the following statements add them to the Search menu:

      'search.find' ⎕WC 'MenuItem' '&Find'
                        ('Event' 'Select' '[Find]')
      'search.replace' ⎕WC 'MenuItem' '&Replace'
                        ('Event' 'Select' '[Replace]')

Adding your own MenuItem

This example shows how you can add a menu item that executes an APL expression. In this case we will do something very simple; namely add a Time option to the Tools menu which will execute ⎕TS. Notice that the statement also defines a Hint. This will be displayed when you select the option, prior to releasing the mouse button to action it.

Once again, we will start by changing space into the Tools menu itself

      )CS ⎕SE.mb.tools
⎕SE.mb.tools

Then we will define a new MenuItem to perform the action we require:

      'ts'⎕WC'MenuItem' '&Time'
             ('Event' 'Select' '⍎⎕TS')
             ('Hint' 'Display Timestamp')

The ⍎ symbol is very important and distinguishes an expression to be executed immediately, as in this case, from a callback function. The resulting Tools menu now appears as follows:

A customised Tools menu

Selecting Time produces the following output in the session:

      2007 12 10 17 10 2 0

Adding your own Tool Button

This example shows how you can add a button to the session tool bar that executes an APL function called XREF.

XREF analyses the function whose name is under the cursor, listing the names of the other functions that it calls in a Form.

     ∇ XREF;REFS;FN
[1]    :If 0<⍴FN←'⎕SE'⎕WG'CurObj'
[2]    :AndIf 3=⎕NC FN
[3]        REFS←⎕REFS('⎕SE'⎕WG'CurSpace'),'.',FN
[4]        REFS←(↓REFS)~¨' '
[5]        REFS←(3.1=⎕NC REFS)/REFS
[6]        REFS←REFS~⊂FN
[7]        :If 0<⍴REFS
[8]            'F'⎕WC'Form'('Functions called by ',FN)
[9]            F.FontObj←⎕SE.FontObj
[10]           'F.L'⎕WC'List'REFS(0 0)(100 100)
[11]       :EndIf
[12]   :EndIf
     ∇

XREF[1] gets the value of the CurObj property of ⎕SE which reports the name under the cursor.

XREF[3] prefixes this name by its pathname which comes from the CurSpace property which reports the user's current namespace.

To make this function available from a Session tool button, we need to do a number of things. Firstly, we must install the function in ⎕SE so that it is always there, regardless of the current active workspace. This is easily achieved using the Explorer or ⎕NS.

      '⎕SE' ⎕NS 'XREF'

Next we will add a new button to the tool bar in the Tools CoolBand. Ideally we would use a suitable bitmap, but to simplify the example, we will use a standard text button:

      )CS ⎕SE.cbtop.bandtb3.tb
⎕SE.cbtop.bandtb3.tb

      'xref' ⎕WC 'Button' 'XREF'
      'xref' ⎕WS 'Event' 'Select' '⍎⎕SE.XREF'

Adding a tool button

All that remains is to save the new Session.


User Commands

Dyalog APL includes a mechanism to define User Commands.

User commands are developer tools, written in APL, which can be executed without having to explicitly copy code into your workspace and/or save it in every workspace in which you want to use it.

A User Command is a name prefixed by a closing square bracket, which may be niladic or take an argument. A User Command executes APL code that is typically stored somewhere outside the current active workspace.

By default, the existing SPICE command processor is hooked up to the user command mechanism, and a number of new SPICE commands have been added. For example:

      ]display 'hello' (⍪'world')
┌→────────────┐
│ ┌→────┐ ┌→┐ │
│ │hello│ ↓w│ │
│ └─────┘ │o│ │
│         │r│ │
│         │l│ │
│         │d│ │
│         │w│ │
│         └─┘ │
└∊────────────┘

The implementation of User Commands is very simple: If a line of input begins with a closing square bracket (]), and there exists a function by the name ⎕SE.UCMD, then the interpreter will call that function, passing the input line (without the bracket) as the right argument.

To add a user command, drop a new Spice command file in the folder SALT\Spice.


File Explorer Integration

Unicode Edition Only

You can browse the contents of workspaces and Dyalog script files using the preview pane of Windows File Explorer. The following example show what you see in the preview pane when you select the supplied workspace ddb.dws.

When you move the cursor to the next workspace in the list, dfns.dws, the preview pane is immediately updated to show its contents.

If you open the Fns/Ops node and click on a function name, the function is displayed. The next picture shows the function assign.

You can also browse Dyalog script files. The following picture shows what you see when you select the fileUtils.dyalog file.

Note that you may only view workspace objects and scripts in the preview pane, it is not possible to edit them in the preview pane.

Editing Dyalog Scripts

You may edit a script file from File Explorer by first selecting the script file and then choosing Edit from the File Explorer context menu.

This brings up the standard Dyalog Editor, in a stand-alone window, just as it would appear if undocked from the Session, as shown in the next picture.


Overview

This manual describes various interfaces between Dyalog APL and Windows.

Chapter 1 introduces the concepts of the Dyalog APL Graphical User Interface (GUI) and describes, in outline, how the system works.

Chapter 2 contains a tutorial which takes you step-by-step through the implementation of a simple GUI application.

Chapters 3 explains how to draw graphics using primitive graphical objects such as Poly, Bitmap and Metafile objects.

Chapter 4 describes how to use toolbars, tab controls and status bars.

Chapter 6 covers the important Grid object that provides a spreadsheet interface for displaying and editing tables of data and

Chapters 7 and 8 describe the Multiple Document Interface (MDI) and docking. Further GUI material is provided in the WTUTOR, WTUTOR95 and WDESIGN workspaces.

Chapters 9-11 describe the various ways in which Dyalog APL may communicate with other Windows applications using Component Object Model (COM) interfaces. These interfaces allow APL to act as an OLE Automation server and client, and allow you to write ActiveX controls in Dyalog APL.

Chapter 12 describes the DDE interface which is implemented using (traditional) APL shared variables. However, please note that DDE has all but been replaced by COM, and is no longer promoted as a major technology by Microsoft.


Concepts

The Dyalog APL GUI is based upon four important concepts; objects, properties, events and methods.

Objects

Objects are instances of classes that contain information and provide functionality. Most Dyalog APL objects are GUI objects that may be displayed on the screen and with which you can interact. An example of an object is a push-button (an instance of class Button) which you may press to cause the program to take a particular action. Objects are defined in hierarchies.

Objects are also namespaces and may contain functions, variables, and indeed other namespaces. This allows you to store the code and data that is required by a given object within that object. Functions and variables stored in an object are hidden and protected from conflicts with functions and variables in the outside workspace and with those in other objects.

Properties

Each object has an associated set of properties which describe how it looks and behaves. For example, a Button has a property called Caption which defines the character string to be displayed in it. It also has a property called Type which may be Push (the button appears to move in and out when it is pressed), Radio (the button has two states and may be toggled on and off); and so forth.

Events

During interaction with the user, an object is capable of generating events. There are essentially two types of event, raw events and object events. Raw events are typically associated with a particular hardware operation. Pressing a mouse button, pressing a key on the keyboard, or moving the mouse pointer are examples of raw events. An object event is generated by some action that is specific to the object in question, but which may typically be achieved by a variety of hardware operations.

An example is the Select event. For a Button object, this event is generated when the user presses the Button. In MS-Windows, this can be done in several ways. Firstly, the user may click the left mouse button over the object. Secondly, under certain circumstances, the Select event can be generated when the user presses the Enter key. Finally, the event will occur if the user presses a "short-cut" (mnemonic) key that is associated with the Button.

Methods

Methods are effectively functions that an object provides; they are things that you may invoke to make the object do something for you. In Dyalog APL, the distinction between methods and events is tenuous, because events also make objects perform actions and you may generate events under program control. For example, a Scroll event is generated by a scrollbar when the user moves the thumb. Conversely, you can make a scrollbar scroll by generating a Scroll event. Nevertheless, the concept of a method is useful to describe functions that can only be invoked by a program and are not directly accessible to the user.

Objects

The following objects are supported.

System Objects
Root | system-level object
Printer | for hard-copy output
Clipboard | provides access to Windows clipboard
Container Objects
CoolBand | represents a band in a CoolBar
CoolBar | a container for CoolBand objects
Form | top-level Window
MDIClient | container for MDI windows
SubForm | acts as an MDI window or a constrained Form
Group | a frame for grouping Buttons and other objects
Static | a frame for drawing and clipping graphics
StatusBar | ribbon status bar
TabBar | contains TabBtns (tabs)
TabControl | contains TabButtons (tabs)
ToolBar | ribbon tool bar
ToolControl | standard Windows tool control
PropertySheet | contains PropertyPages
PropertyPage | tabbed or paged container for other controls
Splitter | divides a container into panes
Menu
MenuBar | pull-down menu bar
Menu | pop-up menu
MenuItem | selects an option or action
Separator | separator between items
Action |
Button | selects an option
ToolButton | performs an action or selects an option
TabBtn | selects a tabbed SubForm
TabButton | selects a tabbed SubForm
Scroll | scroll bar
UpDown | spin buttons
Locator | graphical (positional) input device
Timer | generates events at regular intervals
Information
Label | displays static text
StatusField | displays status information
MsgBox | displays a message box
TipField | displays pop-up context sensitive help
ProgressBar | displays the progress of a lengthy operation
Input & Selection
Calendar | displays a month calendar control
Grid | displays a data matrix as a spreadsheet
Edit | text input field
RichEdit | text input with word-processing capabilities
Spinner | input field with spin buttons
List | for selecting an item
ListView | displays a collection of items for selection
Combo | edit field with selectable list of choices
TreeView | displays a hierarchical collection of items
TrackBar | a slider control for analogue input/output
FileBox | prompts user to select a file
Resource
Font | loads a font
Bitmap | defines a bitmap
Icon | defines an icon
ImageList | defines a collection of bitmaps or icons
Metafile | loads a Windows Metafile
Cursor | defines a cursor
Graphical Output
Circle | draws a circle
Ellipse | draws an ellipse
Marker | draws a series of polymarkers
Poly | draws lines
Rect | draws rectangles
Image | displays Bitmaps, Icons and Metafiles
Text | draws graphical text
Miscellaneous
ActiveXContainer | represents the application hosting a Dyalog APL ActiveXControl
ActiveXControl | represents an ActiveX control written in Dyalog APL
NetClient | provides access to .NET Classes
NetControl | instantiates a .NET Control.
NetType | exports an APL namespace as a Net Class
OCXClass | provides access to OLE Custom Controls
OLEClient | provides access to OLE Automation objects
OLEServer | enables APL to act as an OLE Automation server
SM | specifies a window for ⎕SM(character mode interface)
TCPSocket | provides an interface to TCP/IP sockets

Implementation Overview

The Dyalog APL GUI is implemented by the following system functions :

⎕DQ | Dequeue | processes user actions, invoking callbacks
⎕NQ | Enqueue | generates an event under program control
⎕WC | Create Object | creates new object with specified properties
⎕WG | Get Properties | gets values of properties from an object
⎕WN | Object Names | reports names of all children of an object
⎕WS | Set Properties | sets values of properties for an object

GUI Objects are a special type of namespace and have a name class of 9. They may therefore be managed like any other workspace object. This means that they can be localised in function headers and erased with ⎕EX. GUI objects are saved with your workspace and reappear when it is loaded or copied.


Creating Objects

You create objects using ⎕WC. Its left argument is a character vector that specifies the name of the object to be created. Its right argument specifies the object's Type and various other properties. Its (shy) result is the full pathname of the newly created object.

The following statement creates a Form called 'f1' with the title "A Default Form" and with default size, position, etc.

      'f1' ⎕WC 'Form' 'A Default Form'

Naming Objects

Objects are created in a hierarchy. The Form we have just created is a "top-level" object to which we can attach other child objects, like buttons, scrollbars and so forth. You can create any number of top-level objects like this, up to a limit imposed by MS-Windows and your system configuration.

For reasons which will become apparent later, there is a single Root object whose name is '.' (dot) or '#'. It acts a bit like the root directory in a Windows system file structure, and is the implied parent of all the top-level objects you create.

When you create a top-level object, you don't actually have to specify that it is a child of the Root; this is implied. For any other object, you specify its position in the hierarchy by including the names of its "parent", "grand-parent", and so forth in its name.

Object names are specified in the form:

    'grandparent.parent.child'

where the "." character is used to separate the individual parts of the name. There is no explicit limit to the depth of the object hierarchy; although in practice it is limited by the rules governing which objects may be children of which others.

Complete object names must be unique, although you could use the same sub-name for two objects that have different parents. For example, it would be valid to have 'form1.btn1' and 'form2.btn1'.

Apart from the "." separator, names may include any of the characters A-Z, a-z, and 0-9. They are case-sensitive, so 'Form1' is not the same name as 'form1'.

For graphical objects, it is permissible to omit the last part of the name, although the parent name must be specified followed by a "." (dot). Further information is given later in this chapter.

Specifying Properties

The right argument of ⎕WC is a list of properties for the object being created. Apart from trivial cases, it is always a nested vector. The first item in the list must specify the object's Type. Other properties take default values and need not always be defined. Properties are discussed more fully in the next section.

Saving Objects

GUI Objects are namespaces with nameclass 9.2. Like any other namespace they are saved in the workspace when it is saved and rebuilt when the workspace is re-loaded. The expression )OBJECTS or ⎕NL 9.2 may be used to report their names. Like other namespaces, GUI objects may be copied from a saved workspace using )COPY or ⎕CY.

The Object Hierarchy

This example illustrates how an object hierarchy is defined. The following statements create a Form called 'accounts' which contains a Group called 'type' and some Buttons called 'PLAN', 'BUDGET' and 'ACTUAL'. The embedded spaces in these statements are intended only to improve clarity. The numbers refer to the object's position within its parent. This will be discussed in detail later.

'accounts'             ⎕WC 'Form' 'Accounts'
'accounts.type'        ⎕WC 'Group' 'Account Type'
'accounts.type.PLAN'   ⎕WC 'Button' 'PLAN'   (20 35)
'accounts.type.BUDGET' ⎕WC 'Button' 'BUDGET' (45 30)
'accounts.type.ACTUAL' ⎕WC 'Button' 'ACTUAL' (70 32)

Schematically, this object structure looks as follows:

                            __ACTUAL
        .___accounts___type___BUDGET
                            __PLAN


Properties

Properties may be set using the system functions ⎕WC and ⎕WS and their values may be retrieved using ⎕WG.

If the system variable ⎕WX is set to 1, properties may be set using assignment and referenced by name as if they were variables. This is generally faster and more convenient than using ⎕WS and ⎕WG.

Certain properties, in particular the Type property, can only be set using ⎕WC. There is no obvious rule that determines whether or not a property can only be set by ⎕WC; it is a consequence of the Windows API.

However, any property that can be set by ⎕WS can be set using assignment and the values of all properties can be retrieved by direct reference or using ⎕WG.

Setting Properties with Assignment

You may set the value of a property using the assignment arrow ←. For example:

      'F' ⎕WC 'Form'

The following statement sets the Caption property to the string "Hello World":

      F.Caption←'Hello World'

Strand assignment may be used to set several properties in a single statement:

      F.Size F.Posn←(40 50)(10 10)

However, distributed assignment is even more concise:

      F.(Size Posn)←(40 50)(10 10)

Normal namespace path rules apply, so the following are all equivalent:

      #.F.Caption←'Hello World'
      )CS F
#.F
      Caption←'Hello World'
      :With 'F'
          Caption←'Hello World'
          Posn←40 50
          Size←10 10
          ...
      :EndWith

Notice however, that used directly in this way, Property names are case-sensitive. The following expressions assign values to variables in F and have no effect on the Caption property.

      F.caption←'Hello World'
      F.CAPTION←'Hello World'

Retrieving property values by reference

You may obtain the value of a property as if it were a variable, by simply referring to the property name. For example:

      F.Caption←'Hello World'

      F.Caption
Hello World

You can retrieve the values of several properties in one statement using strand notation:

      F.Caption F.Posn F.Size
 Hello World  40 50  10 10

Although, once again, the use of parentheses is even more concise:

      F.(Caption Posn Size)
 Hello World  40 50  10 10

Although setting and referencing a Property appears to be no different to setting and referencing a variable, it is not actually the same thing at all. When you set a Property (whether by assignment or using ⎕WC or ⎕WS) to a particular value you are making a request to Windows to do so; there is no guarantee that it will be honoured. For example, having asked for a Font with face name of "Courier New", you cannot change its Fixed property to 0, because the Courier New font is always fixed pitch.

      'F'⎕WC'Font' 'Courier New'
1
      F.Fixed←0
      F.Fixed
1

Setting Properties with ⎕WC

Properties may also be set by the right argument of ⎕WC. In these cases, they may be specified in one of two ways; either by their position in the argument, or by a keyword followed by a value. The keyword is a character vector containing the name of the property. Its value may be any appropriate array. Property names and value keywords are not case sensitive; thus 'Form' could be spelled 'form', 'FORM', or even 'fOrM'

The Type property, which specifies the type of the object, applies to all objects and is mandatory. It is therefore the first to be specified in the right argument to ⎕WC, and is normally specified without the Type keyword. The value associated with the Type property is a character vector.

With the exception of Type, all other properties have default values and need only be specified if you want to override the defaults. For example, the following statements would give you a default Button in a default Group in a default Form:

  'form'      ⎕WC 'Form'
  'form.g'    ⎕WC 'Group'
  'form.g.b1' ⎕WC 'Button'

Properties are specified in a sequence chosen to put the most commonly used ones first. In practice, this allows you to specify most properties by position, rather than by keyword/value pairs. For example, the Caption property is deemed to be the "most used" property of a Button and is specified second after Type. The following two statements are therefore equivalent:

   'F1.B1' ⎕WC 'Button' 'OK'
   'F1.B1' ⎕WC 'Button' ('Caption' 'OK')

The third and fourth properties are (usually) Posn, which specifies the position of a child within its parent, and Size which specifies its size. The following statements all create a Form with an empty title bar, whose top left corner is 10% down and 20% across from the top left corner of the screen, and whose height is 60% of the screen height and whose width is 40% of the screen width.

   'form' ⎕WC 'Form' '' (10 20) (60 40)
   'form' ⎕WC 'Form' '' ('Posn' 10 20) ('Size' 60 40)
   'form' ⎕WC 'Form' '' ('Posn' 10 20) (60 40)
   'form' ⎕WC 'Form' ('Posn' 10 20) (60 40)

Changing Property Values with ⎕WS

Once you have created an object using ⎕WC, you are free to alter most of its properties using ⎕WS. However in general, those properties that define the overall structure of an object's window cannot be altered using ⎕WS. Such immutable properties include Type and (for some objects) Style. Note that if you find that you do need to alter one of these properties dynamically, it is a simple matter to recreate the object with ⎕WC.

The syntax for ⎕WS is identical to that of ⎕WC. The following examples illustrate how the properties of a Button can be altered dynamically. Note that you can use ⎕WS in a callback function to change the properties of any object, including the one that generated the event.

Create "OK" button at (10,10) that calls FOO when pressed

 'form.b1' ⎕WC 'Button' 'OK' (10 10)

Some time later, change caption and size

 'form.b1' ⎕WS ('Caption' 'Yes') ('Size' 20 15)

Note that if the right argument to ⎕WS specifies a single property, it is not necessary to enclose it. How the Property List is Processed

The system is designed to give you as much flexibility as possible in specifying property values. You should find that any "reasonable" specification will be accepted. However, you may find the following explanation of how the right argument of ⎕WC and ⎕WS is parsed, useful. The casual reader may wish to skip this page.

Items in the right argument are processed one by one. If the next array in the argument is a simple array, or a nested array whose first element is not a character vector, the array is taken to be the value of the next property, taking the properties in the order defined for that object type.

When the system encounters a nested array whose first element is a character vector, it is checked against the list of property names. If it is not a property name, the entire array is taken to define the value of the next property as above.

If the first element is a property name, the remainder of the nested array is taken to be the value of the corresponding property. For convenience, considerable latitude is allowed in how the structure of the property value is specified.

After assigning the value, the parser resets its internal pointer to the property following the one named. Thus in the third and fourth examples on the preceding page, omitting the Size keyword is acceptable, because Size is the next property after Posn.

In the reference section for each object, you will find the list of properties applicable to that object, given in the order in which they are to be specified. This information is also reported by the PropList property, which applies to all objects. The list of properties may also be obtained by executing the system command )PROPS in an object's namespace.

The Event Property

Of the many different properties supported, the Event property is rather special. Most of the other properties determine an object's appearance and general behaviour. The Event property, however, specifies how the application reacts to the user. Furthermore, unlike most other properties, it takes not a single value, but a set of values, each of which determines the action to be taken when a particular event occurs. In simple terms, an event is something that the user can do. For example, pressing a mouse button, pressing a key, selecting an item from a menu, are all examples of events.

Like any other property, the Event property may be set by assignment or using ⎕WC and ⎕WS. Using assignment, you can specify settings for the entire set of events, or you can set individual events one by one.

Each type of event has a name and a number. Although you may identify an event either by its name or by its number, the use of its name is generally preferable. The exception to this is user-defined events which may only be specified by number.

The list of events supported by a particular object is available from its EventList property, or by executing the system command )EVENTS in an object's namespace.

To specify an individual event, you assign the action to the event name which is optionally prefixed by the string 'on'. For example, the name for the event that occurs when a user presses a key is 'KeyPress'. To this you assign an action. Event actions are described in detail later in this chapter, but most commonly action is a character vector containing the name of a function. This is termed a callback function, because it will be automatically called for you when the corresponding event occurs. So if F1 is a Form, the statement:

      F1.onKeyPress←'CHECK_KEY'

specifies that the system is to call the function CHECK_KEY whenever the user presses a key when F1 has the input focus.

Using ⎕WC and ⎕WS, the same effect can be obtained by:

      'F1'⎕WC'Form' ('Event' 'onKeyPress' 'CHECK_KEY')

or

      'F1'⎕WS 'Event' 'onKeyPress' 'CHECK_KEY'

When a callback function is invoked, the system supplies an event message as its right argument, and (optionally) an array that you specify, as its left argument. The event message is a nested vector that contains information about the event. The first element of the event message is always either a namespace reference to the object that generated the event or a character vector containing its name.

To instruct the system to pass the object name instead of a reference, you must use the event name on its own (omitting the 'on' prefix) or the event number. This method is retained for compatibility with previous versions of Dyalog APL that did not support namespace references. For example, either of the following statements will associate the callback function 'CHECK_KEY' with the KeyPress event. However, when 'CHECK_KEY' is called, it will be called with the character string 'F1' in the first element of the right argument (the event message) instead of a direct reference to the object F1.

      F1.Event←'KeyPress' 'CHECK_KEY'
      'F1'⎕WS 'Event' 'KeyPress' 'CHECK_KEY'
      'F1'⎕WS 'Event' 22 'CHECK_KEY'

Note that by default, all events are processed automatically by APL, and may be ignored by your application unless you want to take a specific action. Thus, for example, you don't have to handle Configure events when the user resizes your Form; you can just let APL handle them for you.

Before looking further into events, it is necessary to describe how control is passed to the user, and to introduce the concept of the event queue.

For further details, see the description of the Event property in the Object Reference.


User Interaction and Events

User Interaction & Events

Giving Control to the User

As we have seen, ⎕WC and ⎕WS are used to build up the definition of the user-interface as a hierarchy of objects with properties. Notice that the interface is defined not only in terms of its appearance and general behaviour, but also by specification of the Event property, in terms of how it reacts to user actions.

Once you have defined your interface, you are ready to give control to the user. This is simply done by calling ⎕DQ. Alternatively, you may use the Wait method (if appropriate) which is identical to ⎕DQ in its operation.

⎕DQ performs several tasks. Firstly, it displays all objects that have been created but not yet drawn. When you create objects, Dyalog APL/W automatically buffers the output so as to avoid unpleasant flashing on the screen. Output is flushed when APL requires input (at the 6-space prompt) and by ⎕DQ. Thus if you write a function that creates a Form containing a set of controls, nothing is drawn until, later on in the function, you call ⎕DQ. At this point the Form and its contents are displayed in a single screen update, which is visually more pleasing than if they were drawn one by one. A second task for ⎕DQ is to cause the system to wait for user events. Objects that you create are immediately active and capable of generating events. During development and testing, you can immediately use them without an explicit wait. However, unless your application uses the Session in conjunction with GUI objects you must call ⎕DQ to cause the application to wait for user input. In a run-time application, ⎕DQ is essential.

The argument to ⎕DQ specifies the objects with which the user may interact. Objects may be specified by name or by reference. If the argument is #, '#' or '.', the user may interact with all active objects owned by the current thread and with any new objects which are created in callback functions. If not, the argument should specify refs to or names of one or more top-level objects such as Form, PropertySheet, Clipboard, or a single modal object such as FileBox, Locator, MsgBox or Menu. All specified objects must be owned by the current thread.

In general, ⎕DQ first updates the screen with any pending changes, then hands control to the user and waits for an event. If its argument is #, '#', or '.', ⎕DQ processes events for all active objects, i.e. for those objects and their children whose Active property is 1. If the right argument specifies one or more top-level objects (such as Form, PropertySheet), ⎕DQ processes events for all of these objects and their children, and (if the current thread is thread 0) for the Root object, but ignores any others, even though they may be currently active.

If the right argument specifies a single modal object, ⎕DQ activates the object, handles user-interaction with it, and then deactivates it when the user has finished. An event is generated according to the manner in which the user terminated.

Events are managed by both the Operating System and by ⎕DQ using a queue. A detailed understanding of how the queue works is not absolutely necessary, and you may skip the following explanation. However, if you are planning to develop major applications using the GUI, please continue.

The Event Queue

There are in fact two separate queues, one maintained by Windows and one internal to APL. The Windows queue is used to capture all events that APL needs to process. These include events for your GUI objects as well as other events concerned with APL's own Session Window, Edit Windows, etc. At various points during execution, APL reads events from the Windows queue and either processes them immediately or, if they are events concerned with objects you have defined with ⎕WC, APL places them on its own internal queue. It is this queue to which ⎕DQ looks for its next event.

When ⎕DQ receives an event, it can either ignore it, process it internally, execute a string, call a callback function, or terminate according to the action you have defined for that event. The way you define different actions is described in detail later in this Chapter.

If you have disabled a particular event by setting its action code to ¯1, ⎕DQ simply ignores it. For example, if you set the action code of a KeyPress event to ¯1, keystrokes in that object will be ignored. If you have told ⎕DQ to process an event normally (the default action code of 0) ⎕DQ performs the default processing for the event in question. For example, the default processing for a KeyPress event in an Edit object is to display the character and move the input cursor.

If you have associated a string or a callback function with a particular event in a particular object, ⎕DQ executes the string or invokes the callback function for you. During the execution of the string or the callback function, the user may cause other events. If so, these are added to APL's internal queue but they are not acted upon immediately. When the execution of the string or the callback function terminates, control returns to ⎕DQ which once more looks to the internal queue. If another event has been added while the callback function was running, this is read and acted upon. If not, ⎕DQ looks to the Windows queue and waits for the next event to occur.

If you have associated an asynchronous callback function with an event (by appending the character "&" to the name of the function), ⎕DQ starts the callback function in a new thread and is then immediately ready to process the next event; ⎕DQ does not wait for an asynchronous callback function to complete.

If ⎕DQ reads an event with an associated action code of 1, it terminates and returns the event message which was generated by the event, as a result. The normal processing for the event is not actioned. During the time between ⎕DQ terminating and you calling it again, events are discarded. Events are only stored up in the queue if ⎕DQ is active (i.e. there is a ⎕DQ in the state indicator). It is therefore usually better to process events using callback functions.

Assignment and reference to the Event Property

There are a number of special considerations when using assignment and reference to the Event property.

You can set the action for a single event by prefixing the Event name by "on". For example, to set the action of a MouseUp event on a Form F to execute the callback function FOO:

      F.onMouseUp←'UP'
      F.onMouseUp
 #.UP

Notice that the value returned (#.UP) is not necessarily exactly the same as you set it (UP).

If you reference the Event property, you will obtain all the current settings, reported in order of their internal event number. Notice the use of distributed strand notation to set more than one event in the same statement.

      F.(onMouseUp onMouseDown)←'UP' ('DOWN' 42)
      F.Event
  onMouseDown  #.DOWN  42   onMouseUp  #.UP

If you set the Event property using assignment, all the event actions are redefined, i.e. previous event settings are lost. For example:

      F.(onMouseUp onMouseDown)←'UP' ('DOWN' 42)
      F.Event
  onMouseDown  #.DOWN  42   onMouseUp  #.UP

      F.Event←'onMouseMove' 'MOVE'
      F.Event
  onMouseMove  #.MOVE

The All event can also be set by assignment, and it too clears previous settings. Notice too that a subsequent reference to a specific event using the "on" prefix, will report the "All" setting, unless it is specifically reset.

      F.(onMouseUp onMouseDown)←'UP' ('DOWN' 42)
      F.Event
  onMouseDown  #.DOWN  42   onMouseUp  #.UP

      F.onAll←'FOO'
      F.Event
  onAll  #.FOO

      F.onMouseMove
 #.FOO

      F.Event←'onMouseMove' 'MOVE'
      F.Event
  onMouseMove  #.MOVE

If no events are set, the result obtained by ⎕WG and the result obtained by referencing Event directly are different:

      'F'⎕WC'Form'
      DISPLAY 'F'⎕WG'Event'
.→--.
|0 0|
'~--'
      DISPLAY F.Event
.⊖------------.
| .→--------. |
| | .⊖. .⊖. | |
| | | | | | | |
| | '-' '-' | |
| '∊--------' |
.∊------------.

Callback Functions

By setting the action code to 1 for all the events you are interested in, you could write the control loop in your application as:

   Loop:  Event ← ⎕DQ 'system'
          test Event[1] (object name)
          and  Event[2] (event code)
          →Label
   Label: process event for object
          →Loop

However, such code can be error prone and difficult to maintain. Another limitation is that events that occur between successive calls on ⎕DQ are discarded.

An alternative is to use callback functions. Not only do they encourage an object-oriented modular approach to programming, but they can also be used to validate the user's actions and prevent something untoward happening. For example, a callback function can prevent the user from terminating the application at an inappropriate point. The use of callback functions will also produce applications that execute faster than those that process events by exiting ⎕DQ and looping back again as above.

You associate a callback function with a particular event or set of events in a given object. There is nothing to prevent you from using the same callback function with several objects, but it only makes sense to do so if the processing for the event(s) is common to all of them. The object that caused the event is identified by the first element of the right argument when the callback is invoked.

When an event occurs that has an action set to a character vector, the system looks for a function with that name. If none exists ⎕DQ terminates with a VALUE ERROR. If the function does exist, it is called. If the callback function was called FOO and it stopped on line [1], the state indicator would be:

      )SI
FOO[1]*
⎕DQ
...

A callback function may be defined with any syntax, i.e. it may be dyadic, monadic, or niladic. If it is monadic or dyadic, ⎕DQ calls it with the event message as its right argument. If the function is dyadic, its left argument will contain the value of the array that was associated with the event.

A callback function is otherwise no different from any other function that you can define. Indeed there is nothing to prevent you from calling one explicitly in your code. For example, a callback function that is invoked automatically could call a second callback function directly, perhaps to simulate another event.

By default, a callback function is run synchronously. This means that ⎕DQ waits for it to return a result before attempting to process any other events. Events that are generated by Windows while the callback function is running are simply queued.

Alternatively, you may specify that a callback function is to be run asynchronously. In this case, ⎕DQ starts the function in a new thread, but instead of waiting for it to complete, proceeds immediately to the next event in the queue. See Asynchronous Callbacks for further information.

Modifying or Inhibiting the Default Processing

It is often desirable to inhibit the normal processing of an event, and it is occasionally useful to substitute some other action for the default. One way of inhibiting an event is to set its action code to ¯1. However this mechanism is non-selective and is not always applicable. You can use it for example to ignore all keystrokes, but not to ignore particular ones.

Synchronous callback functions provide an additional mechanism which allows you to selectively inhibit default processing of an event. The mechanism also allows you to modify the event in order to achieve a different effect.

For example, you can use a callback function to ignore a particular keystroke or set of keystrokes, or even to replace the original keystroke with a different one. Similarly, you can use a callback function to selectively ignore a LostFocus event to prevent the user from leaving an input field if the data in the field is invalid. Callback functions therefore give you much finer control over event processing. The mechanism uses the result returned by the callback function and operates as follows.

When an event occurs that has a synchronous callback function attached, ⎕DQ invokes the callback function (passing it the event message as its right argument) before performing any other action and waits for the callback to complete. When the callback function terminates (exits) ⎕DQ examines its result.

If the callback function returned no result, or returned a scalar 1 or the identical event message with which it was invoked, ⎕DQ then carries out the default processing for the event in question. If the callback function returned a 0, ⎕DQ takes no further action. Finally, if the callback returns a different event message (from the one supplied as its right argument), ⎕DQ performs the default processing associated with the new event rather than with the original one.

For example, consider a callback function attached to a KeyPress event in an Edit object. When the user presses a key, for the sake of example, the unshifted "a" key, ⎕DQ invokes the callback function, passing it the corresponding event message as its right argument. This event message includes information about which key was pressed, in this case "a". The various possibilities are:

  • If the callback function returns a value of 1 or the same event message with which it was invoked, ⎕DQ carries out the default processing for the original event. In this case a lower-case "a" is displayed in the field.
  • If the callback function returns a value of 0, ⎕DQ takes no further action and (unless code in the callback function actions the keystroke directly) the keystroke is ignored.
  • If the callback function modifies the event message and changes the key from an "a" to a "b", ⎕DQ carries out the default processing associated with the new event, and displays a lower-case "b" instead.

Note that asynchronous callback functions may not be used to modify or inhibit the default processing because their results are ignored.

See also: High-Priority Callback Functions.

Generating Events using ⎕NQ

The ⎕NQ system function is used to generate events under program control and has several uses.

Firstly, it can be used to do something automatically for the user. For example, the following expression gives the input focus to the object Form1.ED1.

        ⎕NQ Form1.ED1 'GotFocus'

Secondly, ⎕NQ can be used to generate user-defined events which trigger special actions either by invoking callback functions or by causing ⎕DQ to terminate. For example, if you were to define the Event property on 'Form1' as:

      'Form1' ⎕WS ('Event' 1001 'FOO')('Event' 1002 1)

The expression:

      ⎕NQ Form1 1001 'Hello' 42

would cause ⎕DQ to invoke the function FOO, passing it the entire event message (#.Form1 1001 'Hello' 42) as its right argument. Similarly, the expression:

      ⎕NQ 'Form1' 1002 23.59

would cause ⎕DQ to terminate with the array ('Form1' 1002 23.59) as its result.

⎕NQ can be used to generate events in one of three ways which affect the context in which the event is processed.

If it is used monadically as in the examples above, or with a left argument of 0, ⎕NQ adds the event specified in its right argument onto the bottom of the event queue. The event is then processed by ⎕DQ when it reaches the head of the queue. You can add events to the queue prior to calling ⎕DQ, or from within a callback function which is itself called by ⎕DQ. In either case, the context in which the event is finally processed may be completely different from the context in which the event was placed on the queue. When used in this way, the result of ⎕NQ is always an empty character vector.

If you use ⎕NQ with a left argument of 1, the event is processed there and then by ⎕NQ itself. If there is a callback function attached to the event, ⎕NQ invokes it directly. Thus like ⎕DQ, ⎕NQ can appear in the state indicator ⎕SI or )SI. This use of ⎕NQ is used to generate an event for an object that is not currently included in a ⎕DQ, and is the usual way of generating the special (non-user) events on the Printer and other objects. It is also used when you want to cause an event to occur immediately without waiting for any events already in the queue to be processed first. When used in this way, the result of ⎕NQ is either an empty character vector, or the result of the callback function if one is attached.

If you use ⎕NQ with a left argument of 2, APL immediately performs the default processing (if any) for the event, bypassing any callback function. This case of ⎕NQ is often used within a callback function to put the object into the state that it would otherwise be in when the callback terminated. When used in this way, the result of ⎕NQ is 1. To avoid processing the event twice, the callback function should return 0.

The use of ⎕NQ with a left argument of 2, is the same as calling the event as a method, and this is discussed in the next section.

A left argument of 4 is a special case that is used by an ActiveXControl or NetType object to generate an event in its host application. See Introduction for details.


Methods

Calling Methods

A method is similar to a function in that it may or may not take an argument, perform some action, and return a result.

Examples are the Print, NewPage, Setup and Abort methods, all of which cause a Printer object to take a particular action.

If the system variable ⎕WX is 1, you may invoke an object's method using exactly the same syntax as you would use to call a function in that object.

For example, to execute the IDNToDate method of a Calendar object named F.CAL, you can use the expression:

      F.CAL.IDNToDate 36525
2000 1 1 5

When you call a method in this way, the method name is case-sensitive and if you spell it incorrectly, you will get a VALUE ERROR.

      F.CAL.idntodate 36525
VALUE ERROR
      F.C.idntodate 36525
     ^

Invoking Methods with ⎕NQ

Methods may also be called using ⎕NQ with a left argument of 2, indeed if ⎕WX is 0, this is the only way to call a method.

The result of the method is returned by ⎕NQ. Note however that the result is shy.

For example, for a TreeView object you can obtain status information about a particular item in the object using the GetItemState method:

      ⎕←2 ⎕NQ 'f.tv' 'GetItemState' 6
96

Or you can call the IDNToDate method of a Calendar object F.C as follows:

     ⎕←2 ⎕NQ 'F.CAL' 'IDNToDate' 36525
2000 1 1 5

When you call a method using 2 ⎕NQ, the method name is not case-sensitive.

     ⎕←2 ⎕NQ 'F.CAL' 'idntodate' 36525
2000 1 1 5

Events as Methods

Methods and events are closely related and most events can be invoked as methods.

For example, you can reposition and resize a Form in one step by calling its Configure event as a method. The argument you supply is the same as the event message associated with the event, but with the first two items (Object and Event code) omitted.

      F.Configure 10 10 30 20

Or, using 2 ⎕NQ

     2 ⎕NQ 'F' 'Configure' 10 10 30 20

Notice that when you call an event as a method, you are executing the default processing associated with the event. The setting for the Event property is ignored and, in particular, any callback associated with the event is not executed.


High-Priority Callback Functions

A high-priority callback function is one that is invoked by a high-priority event which demands that Dyalog must return a result to the operating system before it may process any other event. Such high-priority events include Configure, ExitWindows, DateTimeChange, DockStart, DockCancel, DropDown, GetTipText, GesturePan, GestureZoom, GestureRotate, GestureTwoFingerTap, GesturePressAndTap.

If a high-priority callback function is traced or stops for any reason, the system is in limbo until the windows notification has been actioned. This will occur only when the callback exits. During this time, it is not possible to reset the state indicator or save the workspace. In the following example, there is a deliberate error on GenCB[2] which is assigned as the callback function for the GesturePan event on object f.s1.

      f.s1.onGesturePan←'GenCB'
     ∇ GenCB m
[1]    m
[2]    ∘
     ∇

[user drags finger in object]

 #.f.s1  GesturePan  1  84 103  0 0
SYNTAX ERROR
GenCB[2] ∘
        ∧
      )si
#.GenCB[2]*
⎕DQ
      →
DOMAIN ERROR: Operation cannot be completed with an "external" call on the stack
      →
     ∧
      )reset
Can't )RESET with external call on the stack.
      )clear
Can't )CLEAR with external call on the stack.
      )save
Cannot perform operation with calls to or from external functions or certain callbacks.

The only way to restore the situation to normal is to force the callback function to exit. For example:

      →0
      )si

Thread-Switching and :Hold

Dyalog cannot perform thread-switching during the execution of a high-priority callback.

:Hold is not permitted in a high-priority callback and an attempt to use it will cause the error:

 DOMAIN ERROR: Cannot :Hold within high priority callback


GUI Objects as Namespaces

GUI objects are a special type of namespace and this has several useful implications. Firstly, instead of creating the children of an object from outside in the workspace, you can use )CS to change to an object and create them from within. The only restriction is that you can only create GUI objects that are valid as children of the current object. A second benefit is that you can put the callback functions, together with any global variables they require, into the objects to which they apply. Consider the following example.

First make a Form F1

      'F1' ⎕WC 'Form' 'GUI Objects as Namespaces'
                      ('Size' 25 50)

Then change to the Form's namespace

      )CS F1
#.F1

Now you can create a Group (or any other child object), but because you are already inside the Form, the name you give to the Group will be taken as being relative to the Form. In other words, you must specify the part of the name that applies to the Group itself, leaving out the 'F1.' prefix that you would use if you executed the statement outside in the workspace.

      'CH' ⎕WC 'Group' 'Counter' (10 10)( 70 60)

You can continue to create other objects

      'OK'  ⎕WC 'Button' '&Ok' (20 80)(⍬ 15)
      'CAN' ⎕WC 'Button' '&Cancel' (60 80) (⍬ 15)
      'FNT' ⎕WC 'Font' 'Arial' 16 ('Weight' 700)

If you ask for a list of objects, you will see only those within the current namespace

      )OBJECTS
CAN     CH      FNT     OK

When you are inside an object you can also set (or get) a property directly, so you can set the FontObj property for the Form with the following statement.

      FontObj←'FNT'

You can achieve the same with ⎕WS by omitting its left argument:

      ⎕WS 'FontObj' 'FNT'

You can create a child of the Group from outside it ...

      'CH.UP' ⎕WC 'Button' '+1' (20 10)(30 20)

or you can change to it and create others from within...

      )CS CH
#.F1.CH
      'DOWN' ⎕WC 'Button' '-1' (60 10)(30 20)
      'FNT' ⎕WC 'Font' 'Arial' 32
      'CTR' ⎕WC 'Label' ('FieldType' 'Numeric' )
                ('FontObj' 'FNT')

Once again, if you request a list of objects you will see only those in the current namespace.

      )OBJECTS
CTR     DOWN    FNT     UP

You can create functions and variables in a GUI namespace in exactly the same way as in any other. So, for example, you could create a variable called COUNT and a function CHANGE to update it:

      COUNT ← 0

     ∇ INCR CHANGE MSG
[1]    COUNT←COUNT+INCR
[2]    CTR.Value←COUNT
     ∇

You can also make CHANGE a callback function for the two Buttons.

      UP.onSelect←'CHANGE' 1
      DOWN.onSelect←'CHANGE' ¯1

Notice that because you were in the F1.CH namespace when you made this association, the event will fire the function CHANGE in the F1.CH namespace and, furthermore, it will execute it within that namespace. Hence the names referenced by the function are the local names, i.e. the variable COUNT and the Label CTR, within that namespace.

So if you now switch back to the outer workspace

      )CS
#

and click on the buttons...

The result will appear approximately as shown below

Attaching GUI Objects to Namespaces

Monadic ⎕WC is used to attach a GUI component to an existing object. The existing object must be a pure namespace or an appropriate GUI object (one that can legitimately be placed at that point in the object hierarchy). The operation may be performed by changing space to the object or by running ⎕WC inside the object using the dot syntax. For example, the following statements are equivalent.

      )CS F
#.F
      ⎕WC 'Form'  ⍝ Attach a Form to this namespace

      )CS
#
      F.⎕WC'Form' ⍝ Attach a Form to namespace F

Monadic ⎕WC is often used in conjunction with the KeepOnClose property. This property specifies whether or not an object remains in existence when its parent Form (or in the case of a Form, the Form itself) is closed by the user or receives a Close event.

This facility is particularly useful if you wish to have functions and variables encapsulated within your Forms. You may want to save these structures in your workspace, but you do not necessarily want the Forms to be visible when the workspace is loaded.

An alternative way to achieve this is to prevent the user from closing the Form and instead make it invisible. This is achieved by intercepting the Close event on the Form and set its Visible property to 0. Then, when the Form is subsequently required, its Visible property is set back to 1. However, if the Form needs adjustment because the workspace was loaded on a PC with different screen resolution or for other reasons, it may not be easy to achieve the desired result using ⎕WS. Monadic ⎕WC is generally a better solution.

Namespace References and GUI Objects

The use of a GUI name in an expression is a reference to the GUI object, or ref for short. If you assign a ref or call a function with a ref as an argument, the reference to the GUI object is copied, not the GUI object itself.

So for example, if you have a Form named F:

      'F'⎕WC 'Form'

Assigning F to F1, does not create a second Form F1; it simply creates a second reference (F1) to the Form F. Subsequently, you can manipulate the Form F using either F or F1.

      F1←F
      F1
#.F
      F1.Caption←'Hello World'
      F.Caption
Hello World

Similarly, if you call a function with F as the argument, the local argument name becomes a second reference to the Form, and a new Form is not created:

Here is a simple function which approximately centres a Form in the middle of the screen:

     ∇ R←SHOW_CENTRE FORM;OLD;SCREEN
[1]    SCREEN←⊃'.'⎕WG'DevCaps'
[2]    OLD←FORM.Coord
[3]    FORM.Coord←'Pixel'
[4]    R←FORM.Posn←⌊0.5×SCREEN-FORM.Size
[5]    FORM.Coord←OLD
     ∇

The function can be called using either F or F1 (or any other Form) as an argument:

      SHOW_CENTRE F
287 329
      SHOW_CENTRE F1
287 329

A ref to a GUI object can conveniently be used as the argument to :With; for example, the SHOW_CENTRE function can instead be written as follows:

     ∇ R←SHOW_CENTRE FORM;OLD;SCREEN
[1]    SCREEN←⊃'.'⎕WG'DevCaps'
[2]    :With FORM
[3]        OLD←Coord
[4]        Coord←'Pixel'
[5]        R←Posn←⌊0.5×SCREEN-Size
[6]        Coord←OLD
[7]    :EndWith
     ∇

If instead, you actually want to duplicate (clone) a GUI object, you may do so by calling ⎕WC with a ref as the right argument and the new name as the left argument.

For example:

    'F' ⎕WC 'Form' 'Cloning Example'
    'F.B' ⎕WC 'Group' 'Background' (10 10)(80 30)
    'F.B.R' ⎕WC 'Button' 'Red' (20 10)('Style' 'Radio')
    'F.B.B' ⎕WC 'Button' 'Blue' (50 10)('Style' 'Radio')
    'F.B.G' ⎕WC 'Button' 'Green' (80 10)('Style' 'Radio')

Then, instead of creating a second Group for selecting Foreground colour line by line as before, you can clone the "Background" Group as follows:

      'F.F' ⎕WC F.B

The new Group F.F is an exact copy of F.B and will have the same Posn, Size and Caption, as well as having identical children. To achieve the desired result, it is therefore only necessary to change its Posn and Caption properties; for example:

      F.F.Caption F.F.Posn ← 'ForeGround' (10 60)

The result is illustrated below.

Note that when a namespace is cloned in this way, the objects (functions, variables and other namespaces) within it are not necessarily duplicated. Instead, the objects in cloned namespaces are in effect just pointers to the original objects. However, if you subsequently change the clone, or the original object to which it refers, the two are de-coupled and a second copy ensues. This mechanism makes it possible to create large numbers of instances of a single class namespace without consuming an excessive amount of workspace.


Modal Dialog Boxes

Up to now, it has been assumed that your user has constant access to all of the interface features and controls that you have provided. The user is in charge; your application merely responds to his requests.

Although this is generally considered desirable, there are times when a particular operation must be allowed to complete before anything else can be done. For example, an unexpected error may occur and the user must decide upon the next course of action (e.g. Continue, Restart, Quit). In these situations, a modal dialog box is required. A modal dialog box is one to which the user must respond before the application will continue. While the modal dialog box is in operation, interaction with all other objects is inhibited.

A modal dialog box is simply achieved by calling ⎕DQ with just the name of the corresponding Form in its argument. This can be done from within a callback function or indeed from any point in an application. To make the local ⎕DQ terminate, you may specify an action code of 1 for an event. Alternatively, if you wish to make exclusive use of callback functions to process events, you can cause the ⎕DQ to terminate by erasing the Form from a callback function.

For example, suppose that you want the user to close the dialog box by clicking an "OK" button. You would specify the Event property for the Button as:

      ('Event' 'Select' 'EXIT')

... and the function EXIT is simply...

     ∇ EXIT Msg;BTN;Form
[1]   ⍝ Terminate modal ⎕DQ by erasing Form
[2]    OBJ←⍕⊃Msg
[3]    Form←(¯1+OBJ⍳'.')↑OBJ ⍝ Get Form name
[4]    ⎕EX Form
     ∇

Note that this function is fairly general, as it gets the name of the Form from the name of the object that generated the event.

The MsgBox and FileBox Objects

The MsgBox and FileBox objects are standard MS-Windows dialog boxes and are strictly modal. The following discussion refers to the way a MsgBox is used, but applies equally to a FileBox.

The MsgBox is a pop-up modal dialog box with a title bar (defined by the Caption property), an icon (defined by the Style property), some text (defined by the Text property) and up to three buttons (defined by the Btns property).

The MsgBox does not appear on the screen when you create it with ⎕WC. Instead, it pops up ONLY when you call ⎕DQ with the name of the MsgBox as its sole right argument. Furthermore, the MsgBox automatically pops down when the user clicks on any one of its buttons; you don't actually have to enable any events to achieve this. For example:

      'ERR' ⎕WC 'MsgBox' 'Input Error' '' 'Error'

creates an invisible MsgBox with the title (Caption) 'Input Error', no text, and a Style of 'Error'. This gives it a "Stop sign" icon. When you want to issue an error message to your user, you simply call a function (let's call it ERRMSG) which is defined as follows:

     ∇ ERRMSG Msg
[1]   ⍝ Displays 'ERR' message box
[2]    ERR.Text←Msg ⍝ Put Msg in box
[3]   ⎕DQ 'ERR'
     ∇

Note that ⎕DQ will terminate automatically when the user clicks one of the buttons in the MsgBox object.

In this case we were not interested in the particular button that the user pressed. If you are interested in this information, you can enable special events associated with these buttons. For details, see the description of the MsgBox and FileBox objects in the Object Reference.


Multi-Threading with Objects

The following rules apply when using threads and objects together.

  1. All events generated by an object are reported to the thread that owns the object and cannot be detected by any other threads. A thread owns an object if it has created it or inherited it. If a thread terminates without destroying an object, the ownership of the object and its events passes to the parent thread.
  2. The Root object '.' and the Session object ⎕SE are owned by thread 0. Events on these objects will be only be detected and processed by ⎕DQ running in thread 0, or by the implicit ⎕DQ that runs in the Session during development.
  3. Several threads may invoke ⎕DQ concurrently. However, each thread may only use ⎕DQ on objects that it owns. If a thread attempts to invoke ⎕DQ on an object owned by another thread, it will fail with DOMAIN ERROR.
  4. Any thread may execute the expression ⎕DQ '.', however:
    1. In thread 0, the expression ⎕DQ '.' will detect and process events on the Root object and on any Forms and other top-level objects owned by thread 0 or created by callbacks running in thread 0. The expression will terminate if there are no active and visible top level objects and there are no callbacks attached to events on Root.
    2. In any other thread, the expression ⎕DQ '.' will detect and process events on any Forms and other top-level objects owned by that thread or created by callbacks running in that thread. The expression will terminate if there are no active and visible top level objects owned by that thread.

  5. A thread may use ⎕NQ to post an event to an object owned by another thread, or to invoke the default processing for an event, or to execute a method in such an object. This means that the following uses of ⎕NQ are allowed when the object in question is owned by another thread:
          ⎕NQ object event...
      0 ⎕NQ object event...
      2 ⎕NQ object event...
      2 ⎕NQ object method...
      3 ⎕NQ ole_object method...
      4 ⎕NQ activexcontrol event...

    The only use of ⎕NQ that is prohibited in these circumstances is

          1 ⎕NQ object event...

    which will generate a DOMAIN ERROR.

  6. While a thread is waiting for user response to a strictly modal object such as a MsgBox, FileBox, Menu or Locator object, any other threads that are running remain suspended. APL is not able to switch execution to another thread in these circumstances.


The Co-ordinate System

Each object has a Coord property that determines the units in which its Posn and Size properties are expressed. For full details, see Coord.

Coord may be set to one of the following values :

'Inherit' | this means that the object assumes the same co-ordinate system as its parent. This is the default for all objects except the Root object.
'Prop' | the position and size of the object are expressed as a percentage of the dimensions of its parent.
'Pixel' | The position and size of the object are expressed in pixels, which are interpreted as either 'ScaledPixel' or 'RealPixel' according to the value of the DYALOG_PIXEL_TYPE parameter.
'ScaledPixel' | The position and size of the object are expressed in pixels but these metrics are scaled according to the user's chosen scaling factor.
'RealPixel' | The position and size of the object are expressed in pixels.
'User' | the position and size of the object are expressed in units defined by the YRange and XRange properties of the object's parent.
'Cell' | the position and size of the object are expressed in cell coordinates (applies only to Grid and its graphical children).

By default, the value of Coord for the Root object is 'Prop'. For all other objects, the default is 'Inherit'. This means that the default co-ordinate system is a proportional one.

You can change Coord from one value to another as you require. It only affects the units in which Size and Posn are currently expressed. The physical position and size are unaffected. Note that if you set Posn and/or Size in the same ⎕WC or ⎕WS statement as you set Coord, it is the old value of Coord that is applied.

The co-ordinate system is also independent of the way in which objects are reconfigured when their parent is resized. This is perhaps not immediately obvious, as it might be expected that objects which are specified using Pixel co-ordinates will be unaffected when their parent is resized. This is not necessarily the case as the manner in which objects respond to their parent being resized is determined independently by the AutoConf and Attach properties.

The User co-ordinate system is useful not only to automate scaling for graphics, but also to perform scrolling. This is possible because XRange and YRange define not just the scale along each axis, but also the position of the origin of the co-ordinate system in the parent window.


High DPI Support

Modern high resolution screens present some practical challenges to a Graphical User Interface that was designed when lower-resolution screens were the norm. When you increase resolution you inherently decrease the size of each pixel (assuming same display size). By decreasing the size of each pixel the content shown on the display appears smaller. When display Dots-Per-Inch (DPI) gets sufficiently dense this shrinking effect can make content hard to see and user interface components such as menus and buttons, difficult to click/tap.

Also, people have different preferences and Windows enables the user to change the DPI setting.

To address this issue, the Desktop Window Manager, which is enabled in Windows Vista and above, automatically scales up windows and their content to match the current DPI setting.

The problem with this approach is that, because the scaling is implemented by bitmap stretching, application user-interfaces windows tend to look fuzzy and/or distorted.

DPI-Awareness

To prevent the DWM from stretching its user-interface, a Windows application can declare itself to be DPI-Aware. If so, the application is expected to handle DPI issues itself. Whether it does so by scaling GUI components according to the DPI in use, or not, is up to the application itself. If an application chooses to register itself as DPI-aware, but fails to scale its GUI components on a high DPI device, they will simply appear physically smaller on the screen.

An application can declare itself as being DPI-Aware by making a system call or by making a declaration in the optional XML manifest file that may be associated with its .exe.

Dyalog APL will register itself as being DPI-Aware on startup if the value of the AUTODPI parameter is 1. This is the default, so in a standard developer installation, Dyalog APL itself and all Dyalog applications driven by the development and run-time versions of Dyalog are by default registered as DPI-Aware, so DPI scaling by the DWM is disabled.

This can be changed by setting the AUTODPI parameter to 0 (or by removing it) or using a declaration in a manifest file. See Enabling DWM Scaling.

Coord Property

Dyalog APL includes a mechanism to automatically scale a pixel coordinate user-interface according to the DPI setting. This works by introducing two new coordinate types named ScaledPixel and RealPixel and by changing the way that the existing Pixel coordinate type is interpreted.

ScaledPixel means that the number of pixels specified will be automatically scaled by Dyalog APL according to the user's chosen display scaling factor. ScaledPixel also means that Dyalog will automatically de-scale coordinate values reported by ⎕WG and coordinate values in event messages.

RealPixel means that Dyalog APL will precisely honour the number of pixels you specify and will apply no scaling. GUI windows and components will simply appear physically smaller on higher DPI devices.

The Dyalog Session uses Coord 'ScaledPixel' and all the GUI components of the Session are therefore DPI-scaled by Dyalog itself.

Pixel Coordinates and DYALOG_PIXEL_TYPE

Dyalog Versions prior to Version 14.1 did not support ScaledPixel and RealPixel options; just Pixel. Rather than force users to change all pixel coordinate types in legacy applications, Dyalog provides a parameter named DYALOG_PIXEL_TYPE whose value is either ScaledPixel or RealPixel. If the value of the Coord property is 'Pixel' this is interpreted as meaning whichever value is specified by DYALOG_PIXEL_TYPE.

If the DYALOG_PIXEL_TYPE parameter is not specified (the default), it defaults to RealPixel. So by default, Coord 'Pixel', will be treated as RealPixel and your Dyalog APL GUI application will simply appear physically smaller on higher DPI devices.

DYALOG_PIXEL_TYPE may be set to ScaledPixel by ticking the check-box on the General Tab of the Configuration Dialog box labelled Enable DPI Scaling of GUI application.

If this check-box is cleared the DYALOG_PIXEL_TYPE parameter will be removed from the current user's registry.

Using ScaledPixel coordinates, if you specify an Edit object to be 80 units wide and 20 units high, and the user's scaling factor is 150%, Dyalog will automatically draw it 120 pixels wide and 30 pixels high. You won't have to change any of your code that handles the Edit, it will just appear larger on the screen than if it hadn't been scaled. Similarly, if you use the ScaledPixel coordinate type for the Font object, the font used to draw text in the object will automatically be scaled for you.

Font Object

The Font object has a Coord property which may be set to 'Pixel', 'ScaledPixel' or 'RealPixel' when the object is created, but may not subsequently be changed. Note that the Font object does not support other Coord values. 'Pixel' is treated as 'ScaledPixel' or 'RealPixel' as discussed above.

If you are using 'ScaledPixel', this means that your fonts will also be scaled up automatically, as well as the sizes of the controls in which they are used.

Set Dyalog Pixel Type (2035⌶)

This function provides the means to set the meaning of Coord 'Pixel' programmatically and dynamically. This function affects the way that Pixel coordinates are subsequently treated. For further information, see Set Dyalog Pixel Type.

Enabling DWM Scaling

The DPI-Aware scaling features provided by Dyalog APL are designed to allow you to deploy GUI applications that look attractive in most situations, whatever the screen resolution and scaling factor is in use.

However, if you wish to ignore these facilities and fall back on Windows DWM scaling, you may do so as follows.

If you wish to enable DWM scaling in your application, you can either remove or set to zero the AUTODPI parameter. For example, the command line to start a run-time application might be:

dyalogrt.exe myruntime.dws AUTODPI=0

This will prevent Dyalog from registering your application as DPI-Aware in start-up.

Another way to enable DWM scaling is to use a manifest file. Note that if you disable DWM scaling for the development version of Dyalog APL, the appearance of the Session window may be imperfect.

Using a Manifest

A Windows application can declare itself to be DPI-aware or not using a declaration in the optional XML manifest file associated with its .exe. If you want your Dyalog APL application to be automatically scaled by the DWM, you may use a manifest file to override the call that Dyalog itself makes to register itself as being DPI-Aware.

This is done by setting the XML entity dpiAware to the value false as illustrated by the skeleton manifest file listed below.

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
 <asmv3:application>
   <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
     <dpiAware>false</dpiAware>
   </asmv3:windowsSettings>
 </asmv3:application>
</assembly>

If dpiAware appears in the manifest file, its value take precedence over the value of the AUTODPI parameter, whether it is specified implicitly by omission (it defaults to 1) or is specified in the registry or on the command line.

Naming a Manifest File

The name of the manifest file is the full name of the application file followed by an optional resource id (if omitted, the default is 1) and the extension .manifest. If your application runs courtesy of the dyalogrt.exe or dyalogrt.dll, the name of the manifest file should be one of:

   dyalogrt.exe.<resource ID>.manifest
   dyalogrt.dll.<resource ID>.manifest

If you have exported your application as an executable called example.exe or as a dll called example.dll, it should be one of:

   example.exe.<resource ID>.manifest
   example.dll.<resource ID>.manifest


Colour

Colours are specified using the FCol (foreground colour) and BCol (background colour) properties. Graphical objects have an additional FillCol (fill colour) property.

A single colour may be specified in one of two ways, either as a negative integer that refers to one of a set of standard Windows colours, or as a 3-element numeric vector. The latter specifies a colour directly in terms of its red, green and blue intensities which are measured on the scale of 0 (none) to 255 (full intensity). Standard Windows colours are:

Colour Element |  | Colour Element
0 | Default | ¯11 | Active Border
¯1 | Scroll Bars | ¯12 | Inactive Border
¯2 | Desktop | ¯13 | Application Workspace
¯3 | Active Title Bar | ¯14 | Highlight
¯4 | Inactive Title Bar | ¯15 | Highlighted Text
¯5 | Menu Bar | ¯16 | Button Face
¯6 | Window Background | ¯17 | Button Shadow
¯7 | Window Frame | ¯18 | Disabled Text
¯8 | Menu Text | ¯19 | Button Text
¯9 | Window Text | ¯20 | Inactive Title Bar Text
¯10 | Active Title Bar Text | ¯21 | Button Highlight

A colour specification of 0 (which is the default) selects the appropriate background or foreground colour defined by your current colour scheme for the object in question. For example, if you select yellow as your MS-Windows Menu Bar colour, you will get a yellow background in Menu and MenuItem objects as the default if BCol is not specified.

To select a colour explicitly, you specify its RGB components as a 3-element vector. For example:

(255 0 0) = red | ( 0 255 0) = green
(255 255 0) = yellow | (192 192 192) = grey
( 0 0 0) = black | (255 255 255) = white

Note that the colour actually realised depends upon the capabilities of the device in question and the current contents of the Windows colour map.

A colour specification of ⍬ (zilde) selects a transparent colour.


Fonts

In keeping with the manner in which fonts are managed by Microsoft Windows and other GUI environments, Dyalog APL treats fonts as objects which you create (load) using ⎕WC and erase (unload) using ⎕EX or localisation.

A Font object is created and assigned a name using ⎕WC. This name is then referenced by other objects via their FontObj properties. For example to use an Arial bold italic font of height 32 pixels in two Labels:

     'A32' ⎕WC 'Font' 'ARIAL' 32 0 1 0 700

     'F.L1' ⎕WC 'Label' 'Hello' (20 10) ('FontObj' 'A32')
     'F.L2' ⎕WC 'Label' 'World' (20 10) ('FontObj' 'A32')

If a font is referenced by more than one Form, you should create the Font as a top-level object, as in the above example. However, if the font is referenced by a single Form, you may make the Font object a child of that Form. The font will then automatically be unloaded when you erase the Form with which it is associated.

Compatibility Note:

In the first release of Dyalog APL/W (Version 6.2), fonts were referenced directly by the FontObj property. The above example would have been achieved by:

      'F.L1' ⎕WC 'Label' 'Hello' (10 10)
                 ('FontObj' 'ARIAL' 32 0 1 0 700)

      'F.L2' ⎕WC 'Label' 'World' (20 10)
                 ('FontObj' 'ARIAL' 32 0 1 0 700)

Although this original mechanism continues to be supported, it is recommended that you use the method based on Font objects which supersedes it.


Drag and Drop

Dyalog APL/W provides built-in support for drag/drop operations through the Dragable property. This applies to all objects for which drag/drop is appropriate.

The default value of Dragable is 0 which means that the object cannot be drag/dropped. To enable drag/drop, you can set it to 1 or 2. A value of 1 means that the user drags a box that represents the bounding rectangle of the object. In general, a value of 2 means that the user drags the outline of the object itself, whether or not it is rectangular. However, there are two exceptions. For a Text object, ('Dragable' 2) means that the user drags the text itself. For an Image object that contains an Icon, ('Dragable' 2) means that the user drags the icon itself, and not just its outline.

If Dragable is 1 or 2, the user may drag/drop the object using the mouse.

When the user drops an object, the default processing for the event is:

  1. If the object is dropped over its parent, it is moved to the new location.
  2. If the object is dropped over an object other than its parent, the dragged object remains where it is.

If you enable the DragDrop event (11) on all eligible objects, you can control what happens explicitly. If an object is dropped onto a new parent, you can move it by first deleting it and then recreating it. Note that you must give it a new name to reflect its new parentage. Note too that the DragDrop event reports co-ordinates relative to the object being dropped on, so it is easy to rebuild the object in the correct position and with the correct size.

An alternative to using the built-in drag/drop operation is to do it yourself with the Locator object. This is no less efficient and has the advantage that you can choose which mouse button you use. It can also be used to move a group of objects. However, the Locator only supports a rectangular or elliptical outline.


Debugging

Four features are built into the system to assist in developing and debugging GUI applications.

Firstly, if you execute ⎕WC and/or ⎕WS statements from the Session or by tracing a function, they have an immediate effect on the screen. Thus you can see immediately the visual result of an expression, and go back and edit it if it isn't quite what you want.

Secondly, if you use ⎕WC with an existing name, the original object is destroyed and then re-created. This allows you to repeatedly edit and execute a single statement until it gives the effect you desire.

Thirdly, if you TRACE a ⎕DQ statement, any callback functions that are invoked will be traced as they occur. This is invaluable in debugging. However, callbacks invoked by certain "raw" events, for example MouseMove, can be awkward to trace as the act of moving the mouse pointer to the Trace window interferes with the operation in the object concerned.

Finally, ⎕NQ can be used to artificially generate events and sequences of events in a controlled manner. This can be useful for developing repeatable test data for your application.


Creating Objects using ⎕NEW

With the introduction of Classes in Version 11.0, you may manipulate Dyalog GUI objects as Instances of built-in (GUI) Classes. This approach supplements (but does not replace) the use of ⎕WC, ⎕WS and so forth.

To create a GUI object using ⎕NEW, the Class is given as the GUI Object name and the Constructor Argument as a vector of (Property Name / Property Value) pairs. For example, to create a Form:

      F1←⎕NEW 'Form' (⊂'Caption' 'Hello World')

Notice however that only perfectly formed name/value pairs are accepted. The highly flexible syntax for specifying Properties by position and omitting levels of enclosure, that is supported by ⎕WC and ⎕WS, is not provided with ⎕NEW.

Naturally, you may reference and assign Properties in the same way as for objects created using ⎕WC:

      F1.Size
50 50
      F1.Size←20 30

Callbacks to regular defined functions in the Root or in another space, work in the same way too. If function FOO merely displays its argument:

     ∇ FOO M
[1]    ⎕←M
     ∇

      F1.onMouseUp←'#.FOO'
#.[Form]  MouseUp  78.57142639 44.62540...

Note that the first item in the event message is a ref to the Instance of the Form.

To create a control such as a Button, it is only necessary to run ⎕NEW inside a ref to the appropriate parent object. For example:

  B1←F1.⎕NEW 'Button' (('Caption' '&OK')('Size' (10 10)))

As illustrated in this example, it is not necessary to assign the resulting Button Instance to a name inside the Form (F1 in this case). However, it is a good idea to do so that refs to Instances of controls are expunged when the parent object is expunged. In the example above, expunging F1 will not remove the Form from the screen because B1 still exists as a ref to the Button. So, the following is safer:

 F1.B1←F1.⎕NEW'Button'(('Caption' '&OK')('Size' (10 10)))

Or perhaps better still,

 F1.(B1←⎕NEW 'Button'(('Caption' '&OK')('Size' (10 10))))

Note that as ⎕NEW provides no facility to name a GUI object, the Event property should use the onEvent syntax so that a callback function (or the result of ⎕DQ) receives a ref to the object. Otherwise, without the onEvent syntax, the first element of the argument to a callback function will contain a character vector such as '[Form].[Button]' which merely describes the type of the object but does not identify the object itself.

      cap←'Caption' 'Push Me'
      ev← 'Event' ('onSelect' 'foo')
      F.(B←⎕NEW'Button'#.(pos cap ev))


Native Look and Feel

Native Look and Feel is a Dyalog option that affects the appearance of the controls provided by the Dyalog GUI Interface and those used by the Dyalog Session. It is implemented by the XPLookAndFeel parameter.

Most of the Dyalog controls (with the notable exception of the Dyalog Grid) are standard Windows user-interface components provided by the Windows Common Controls library comctl32.dll. Successive versions of Windows have introduced new versions of the Windows Common Control Library which typically provide additional features as well as certain differences in appearance. However, each version of Windows continues to support older versions of the Common Control Library as well as the latest one. The decision as to which is loaded is made at run-time.

A second factor that affects the appearance of user-interface controls is the application of Visual StylesSee msdn.microsoft.com for details. 1 and Themes. These features enable users to tailor the UI to accommodate their individual needs and preferences. From Windows 8 onwards, the default appearance of certain Common Controls is overridden by the Visual Styles in use. However, this applies only if Native Look and Feel is enabled.

If Native Look and Feel is enabled, Windows loads the latest version of comctl32.dll (and potentially other Windows dlls) that is appropriate for the version of Windows in use. If Native Look and Feel is disabled, an earlier version may be loaded. The specific version that is loaded is not determined by Dyalog, but by Windows.

The Dyalog for Microsoft Windows Object Reference Guide identifies which features require Native Look and Feel to be enabled. It documents the typical appearance of controls with Native Look and Feel disabled but does not specify how the appearance of controls is affected by enabling Native Look and Feel, which is in any case affected by the Visual Styles selected by the user.

The following pictures illustrate the appearance of a simple Button created with and without Native Look and Feel under Windows 10.

The next shows the appearance of ToolButttons with Style Buttons under Windows 10 with Native Look and Feel disabled. The appearance is the same in earlier versions of Windows.

When Native Look and Feel is enabled, the buttons become transparent and Windows applies the Visual Styles associated with the current theme. This in turn implies that with Native Look and Feel enabled the Styles Button and FlatButton have the same appearance.


Gestures

Introduction

Gestures are user interactions that are most commonly generated by touching and moving fingers on the screen, although other means (e.g. touch pad, stylus) may be used to perform the same operations.

The following Gestures are supported by Dyalog APL:

Gesture | Description
Pan | The user touches one or two fingers on the screen and drags or swipes them.
Zoom | The user touches two fingers on the screen and moves them towards each other (zoom out) or away from each other (zoom in).
Rotate | The user touches two fingers on the screen and then twists them as if turning a knob.
Tap | The user taps (touches briefly) one or two fingers on the screen.
Press and Tap | The user presses one finger on the screen, then taps the screen with a second finger, while the first finger remains in contact with the screen.

Gesture Events

Gestures generate GUI events, which are summarised in the table below.

Apart from GestureTwoFingerTap, which generates a single event, Gestures generate a series of events of the same type. The first of these is flagged as a starting event. Then there are a series of one or more continuation events, followed finally by one that is flagged as the final event in the series. Each series consists of events of the same type and no other type of event will be reported between the start and end of that series.

Event | Description
GesturePan | One or more of these events are generated by a Pan Gesture.
GestureRotate | One or more of these events are generated by a Rotate Gesture.
GestureZoom | One or more of these events are generated by a Zoom Gesture.
GesturePressAndTap | This event is generated by a Press and Tap Gesture.
GestureTwoFingerTap | This event is generated by a Tap Gesture using two fingers.

Handling Gestures

Gestures do not in themselves do anything by default, but if left unhandled, may generate other events which do do something by default. For example, an unhandled Pan Gesture on a scrollbar will, by default, cause it to scroll.

An application can choose to handle Gesture events in a specifically application-dependent manner or choose to ignore them, relying on objects to respond to mouse or scroll events (which are generated by unhandled Gesture events) as appropriate.

In Dyalog APL, a Gesture event is handled by attaching a callback function which responds to the event in some way. The result of the callback function is important. The value 0 tells the Operating System that the application has handled (consumed) the event and instructs Windows NOT to take any further action. The value 1 means that the application has not taken action and instructs Windows to do whatever it would normally do in response to the Gesture; for example, to treat it as a mouse or scroll operation.

If you attach a callback to the GesturePan event which responds by, for example, moving the object, the callback should return 0. See also: High-Priority Callback Functions.

Inertia

When a Pan gesture is made, the operating system may generate additional GesturePan events depending upon the speed with which the Gesture has been made. For example, if the user makes a short but rapid swiping motion with a finger, inertia generates GesturePan events over a greater distance than the finger was actually in contact with the screen. Information as to whether or not the event was generated by inertia is provided in the event message.


Introduction

This tutorial illustrates how to go about developing a GUI application in Dyalog APL/W. It is necessarily an elementary example, but illustrates what is involved. The example is a simple Temperature Converter. It lets you enter a temperature value in either Fahrenheit or Centigrade and have it converted to the other scale.


Some Concepts

Objects

Objects are GUI components such as Forms, Buttons and Scrollbars. You create objects using the system function ⎕WC. Its left argument is a name for the object; its right argument specifies the object type and various properties. Objects are created in a hierarchy.

Properties

Properties specify the appearance and behaviour of an object. For example, the Caption property specifies the text that appears on a Button or the title that appears in the title bar on a Form. When you create an object with ⎕WC, its right argument specifies its properties. You can also set properties using ⎕WS. This lets you dynamically alter the appearance and behaviour of an object as required.

Events

Events are things that happen in objects as a result (usually) of some action by the user. For example, when the user clicks a MenuItem, it generates a Select event. Similarly, when the user focuses on an object, it generates a GotFocus event.

Callback Functions

Callback Functions are APL functions that you can associate with a particular event in a particular object. Interaction with the user is controlled by the system function ⎕DQ. This function performs all of the routine tasks involved in driving the GUI interface. However, its main role is to invoke your callback functions for you as and when events occur.

That's enough theory for now ... let's see how it all works in practice.


Creating a Form

The first task is to create a Form which is to act as the main window for our application. We will call the Form 'TEMP' and give it a title (Caption) of "Temperature Converter".

We will position the Form 68% down and 50% along the screen. This will avoid it interfering with the APL Session Window, and make development easier.

The Form will have a height equal to 30% of the height of the screen, and a width of 40% of the screen width.

      TITLE←'Temperature Converter'
      'TEMP' ⎕WC 'Form' TITLE (68 50)(30 40)


Adding a Fahrenheit Label

We are going to need two edit fields to input and display temperatures and two labels to identify them.

Let's create the "Fahrenheit" label first. It doesn't really matter what we call it because we won't need to refer to it later. Nevertheless, it has to have a name. Let's call it LF. We will place it at (10,10) but we don't need to specify its Size; ⎕WC will make it just big enough to fit its Caption.

      'TEMP.LF' ⎕WC'Label' 'Fahrenheit'(10 10)


Adding a Fahrenheit Edit Field

Now let's add the edit field for Fahrenheit. We will call it F and place it alongside the label, but 40% along. Initially the field will be empty. We will make it 20% wide but let its height default. ⎕WC will make it just big enough to fit the current font height. As the field is to handle numbers, we will set its FieldType to 'Numeric'.

'TEMP.F' ⎕WC 'Edit' '' (10 40)(⍬ 20)('FieldType' 'Numeric')


Adding a Centigrade Label & Edit Field

Now we need to add a corresponding Centigrade label and edit field. We'll call these objects LC and C respectively, and place them 40% down the Form.

'TEMP.LC' ⎕WC'Label' 'Centigrade' (40 10)
'TEMP.C' ⎕WC 'Edit' '' (40 40)(⍬ 20)('FieldType' 'Numeric')


Adding Calculate Buttons

Our Temperature Converter must work both ways; from Fahrenheit to Centigrade and vice versa. There are a number of different ways of making this happen.

A simple approach is to have two buttons for the user to press; one for Fahrenheit to Centigrade, and one for Centigrade to Fahrenheit. We will call the first one F2C and place it alongside the Fahrenheit edit field. The caption on this button will be 'F->C'. When the user presses the button, we want our application to calculate the centigrade temperature. For this we need a callback function. Let's call it f2c. Notice how you associate a callback function with a particular event. In this case, the Select event. This event is generated by a Button when it is pressed.

(The statement below is broken into two only so as to fit on the page)

      FB←'Button' 'F->C' (10 70)('Event' 'Select' 'f2c')
      'TEMP.F2C'⎕WC FB

Notice that it is not necessary to specify the Size of the button; the default size fits the Caption nicely. Now let's add the Centigrade to Fahrenheit button. This will be called C2F and have an associated callback function c2f. We could have chosen to have a single callback function associated with both buttons, which would save a few lines of code. Having separate functions is perhaps clearer.

Again, the statement is split into two only to make it fit onto the page.

      FC←'Button' 'C->F' (40 70)('Event' 'Select' 'c2f')
      'TEMP.C2F'⎕WC FC


Closing the Application Window

Then we need something to allow our user to terminate our application. He will expect the application to terminate when he closes the window. We will implement this by having a callback function called QUIT which will simply call ⎕OFF, i.e.

     ∇ QUIT
[1]   ⎕OFF
     ∇

We can associate this with the Close event on the Form TEMP. This event will be generated when the user closes the window from its System Menu

      TEMP.onClose←'QUIT'

Although here we have used assignment to set the Event property, we could just as easily have defined it when we created the Form by adding ('Event' 'Close' 'QUIT') to the right argument of ⎕WC.


Adding a Quit Button

Finally, we will add a "Quit" button, attaching the same QUIT function as a callback, but this time to the Select event which occurs when the user presses it.

Instead of having a default sized button, we will make it nice and big, and position it centrally.

To make the statement fit on the page, it is split into three. The Posn and Size properties are explicitly named for clarity.

      QB←'Button' '&Quit' ('Posn' 70 30)
      QB,←('Size' ⍬ 40)('Event' 'Select' 'QUIT')
      'TEMP.Q' ⎕WC QB

Notice how the ampersand (&) in the Caption is used to specify the mnemonic (short-cut) key. This can be used to press the button instead of clicking the mouse.


The Calculation Functions

So far we have built the user-interface, and we have written one callback function QUIT to terminate the application. We now need to write the two functions f2c and c2f which will actually perform the conversions. First let's tackle f2c.

A callback such as this one performs just one simple action. This does not depend upon the type of event that called it (there is only one), so the function has no need of arguments. Neither does it need to do anything fancy, such as preventing the event from proceeding. It need not therefore return a result. The header line, which includes the local variables we will need, is then...

   [0]  f2c;F;C

The first thing the function must do is to obtain the contents of the Fahrenheit edit field which is called TEMP.F. As we have defined the FieldType as 'Numeric', this is easily done by querying its Value property...

   [1]  F ← TEMP.F.Value

Next, we need to calculate Centigrade from Fahrenheit...

   [2]  C ← (F-32) × 5÷9

... and finally, display the value in the Centigrade edit field. As we have also defined this as a numeric field, we can just set its Value property using assignment.

   [3]  TEMP.C.Value←C

So our completed f2c callback function is...

      ∇ f2c;F;C
   [1]  F ← TEMP.F.Value
   [2]  C ← (F-32) × 5÷9
   [3]  TEMP.C.Value←C
      ∇

which can be simplified to:

      ∇ f2c
   [1]    TEMP.C.Value←(TEMP.F.Value-32)×5÷9
      ∇

The Centigrade to Fahrenheit callback function c2f looks very similar:

      ∇ c2F
   [1]    TEMP.F.Value←32+TEMP.C.Value×9÷5
      ∇


Testing the Application

Before we test our application, it would be a good idea to )SAVE the workspace. If you remember, the QUIT callback calls ⎕OFF, so if we don't want to lose our work...

      )SAVE TEMP
TEMP saved ...

Note that the GUI objects we have created are all saved with the workspace. You don't have to re-build them every time you )LOAD it again.

If this was a Run-Time application, we would have to use ⎕DQ to run it. However, as it is not, we can just go ahead and use it from the Session. Click on the Fahrenheit edit field and enter a number (say 212). Now click on the "F->C" button. The Temperature Converter window should look like the picture below.

If you have mis-typed any of the functions in this example, you may get an error. If this happens, don't worry; simply correct the error as you would with any other APL application, and type →⎕LC.

If you got a VALUE ERROR error, you have probably mis-spelt the name of the callback function. If so, you can fix it using ⎕WS to reset the appropriate Event property.

Don't click the "Quit" button or close the window (yet). If you do so your APL session will terminate.

If you want to follow what is happening you can use the Tracer. This requires a statement to trace, so we will use ⎕DQ just as you would in a real application. To do this, type ⎕DQ '.' in the Session window, then, instead of pressing Enter (to execute it), press Ctrl+Enter (to Trace it). Having done this, enter your data into one of the edit fields and click the "F->C" or "C->F" buttons as before. When you do so, your callback function will pop-up in a Trace Window. Step it through (if in doubt, see the section on the Tracer) and watch how it works. When the callback has finished, its Trace window disappears. Don't forget, you are running a ⎕DQ. To terminate it, press Ctrl+Break or select Interrupt from the Action menu.


Making the Enter Key Work

Ok, so the basic application works. Let's look at what we can do to improve it.

The first thing we can do is to let the user press the Enter key to make the system re-calculate, rather than having to click on a button. There are a number of alternatives, but we will do it using the Default property of Buttons.

In any Form, you can allocate a single Button to be the Default Button. In simple terms, pressing Enter anywhere in the Form has the same effect as clicking the Default Button. Let's do this for the "F->C" Button :

      TEMP.F2C.Default←1

Now type a number into the Fahrenheit field and then press the Enter key. As you will see, this fires the Default Button labelled "F->C". The only problem with this is that the user cannot run the calculation the other way round using the Enter key. We need some mechanism to switch which Button is the Default one depending upon which field the user typed in.

This is easily achieved by making use of the GotFocus event. This is generated when the user puts the cursor into the edit field prior to typing. So all we need do is attach a callback to set the Default Button whenever a GotFocus event occurs in either edit field. We could use two separate callbacks or we could make use of the fact that you can make APL supply data of your choice to a callback when it is fired. This is supplied as its left argument.

The first of the next two statements attaches the callback function 'SET_DEF' to the GotFocus event in the Fahrenheit edit field. It also specifies that when APL runs the callback, it should supply the character vector 'TEMP.F2C' to SET_DEF as its left argument. 'TEMP.F2C' is of course the name of the Button which we want to make the Default one. The second statement is identical, except that it instructs APL to supply the name of the Centigrade to Fahrenheit Button 'TEMP.C2F'

      TEMP.F.onGotFocus ← 'SET_DEF' 'TEMP.F2C'
      TEMP.C.onGotFocus ← 'SET_DEF' 'TEMP.C2F'

Where the callback 'SET_DEF' is defined as...

     ∇ BTN SET_DEF MSG
[1]    BTN ⎕WS'Default' 1
     ∇

Now let's test the application again. Try typing numbers in both fields and pressing enter each time.


Introducing a ScrollBar

Another way to improve the application would be to allow the user to input using a slider or scrollbar. Let's create one called 'TEMP.S' ...

      SCR←'Scroll' ('Range' 101)('Event' 'Scroll' 'C2F')
      'TEMP.S' ⎕WC SCR

The range of a scrollbar goes from 1 to the value of the Range property. Setting Range to 101 will give us a range of 1-101. You will see in a moment why we need to do this. The Scroll event will be generated whenever the user moves the scrollbar. We have associated it with the callback function 'C2F' which we will define as follows:

     ∇ C2F MSG
[1]   ⍝ Callback for Centigrade input via scrollbar
[2]    TEMP.C.Value←101-4⊃MSG
[3]    TEMP.F.Value←32+TEMP.C.Value÷5÷9
     ∇

The Event message MSG contains information about the Scroll event. Its 4th element contains the requested thumb position. As we want to go from 0 at the top, to 100 at the bottom, we need to subtract this value from 101. This is done in line 2 of the function. C2F[3] calculates the corresponding Fahrenheit value.

Try moving the scrollbar and see what happens...


Adding a Menu

It would also be helpful if you could use the scrollbar to calculate in the reverse direction, from Fahrenheit to Centigrade. Let's add this facility, and give you the ability to choose to which scale the scrollbar applies through a menu.

To create a menu structure in a bar along the top of a Form (as opposed to a floating or pop-up menu) we first need to create a MenuBar object. This type of object has very few properties, and we need only specify its name, 'TEMP.MB'.

      'TEMP.MB' ⎕WC 'MenuBar'

Notice that, at this stage, there is no change in the appearance of the Form.

Then we can add a menu with the Caption 'Scale'. The name of the menu is 'TEMP.MB.M'. Adding the first menu causes the MenuBar to become visible.

      'TEMP.MB.M' ⎕WC 'Menu' '&Scale'

Note that the ampersand (&) allows the user to select the menu quickly by pressing "Alt+S".

Now we can add the two options to the menu. Note that the MenuBar and Menu objects do not represent final choices, they merely specify a path to a choice which is represented by the MenuItem object. When either of these is chosen, we want to execute a callback function that will make the necessary changes to the scrollbar. The statements to create each of these MenuItems are broken into 3 only to fit them onto the page.

First we create the Centigrade MenuItem...

      C←'MenuItem' '&Centigrade'
      C,←('Checked' 1)('Event' 'Select' 'SET_C')
      'TEMP.MB.M.C' ⎕WC C

Setting the Checked property to 1 will cause a tick mark to appear against this option, indicating that it is the current one in force.

Then the Fahrenheit MenuItem...

      F←'MenuItem' '&Fahrenheit'
      F,←('Checked' 0)('Event' 'Select' 'SET_F')
      'TEMP.MB.M.F' ⎕WC F

Notice that as the default value of Checked is 0, we didn't really have to set it explicitly for Fahrenheit. Nevertheless, it will do no harm to do so, and improves clarity.

The SET_C callback function is defined as follows:

     ∇ SET_C
[1]   ⍝ Sets the scrollbar to work in Centigrade
[2]    TEMP.S.Range←101
[3]    TEMP.S.onScroll←'C2F'
[4]    TEMP.MB.M.C.Checked←1
[5]    TEMP.MB.M.F.Checked←0
     ∇

Line [2] simply sets the Range property of the scrollbar to be 101, and line [3] makes C2F the callback function when the scrollbar is moved. Lines [4] and [5] ensure that the tick mark is set on the chosen option.

The SET_F function is very similar...

     ∇ SET_F
[1]   ⍝ Sets the scrollbar to work in Fahrenheit
[2]    TEMP.S.Range←213
[3]    TEMP.S.onScroll←'F2C'
[4]    TEMP.MB.M.F.Checked ← 1
[5]    TEMP.MB.M.C.Checked ← 0
     ∇

and of course we need F2C to make the scrollbar work in Fahrenheit.

     ∇ F2C Msg;C;F
[1]   ⍝ Callback for Fahrenheit input via scrollbar
[2]    TEMP.F.Value←213-4⊃Msg
[3]    TEMP.C.Value←(TEMP.F.Value-32)×5÷9
     ∇


Running from Desktop

Now that we have a final working application, it would be nice to add it as a shortcut, so that the user can run it from the Start Menu or from the Desktop, like any other application.

First we need to define ⎕LX so that the application starts automatically.

      ⎕LX ← '⎕DQ''.'''

or, to avoid so many confusing quotes...

      ⎕LX ← ⍞
⎕DQ '.'

Next, it would be a good idea to clear the edit fields and ensure that the scrollbar is in its default position:

      'TEMP.F' ⎕WS 'Text' ''
      'TEMP.C' ⎕WS 'Text' ''
      'TEMP.S' ⎕WS 'Thumb' 1

Then we must )SAVE the workspace in a suitable directory to which we have write-access ...

      )SAVE c:\MyWS\TEMP
c:\MyWS\TEMP.dws saved Wed Jun  1 14:53:48 2016

... and exit APL

      )OFF

The next step is to add the application to the Desktop. This is done in the normal way, i.e.

Right-click on the Desktop and choose "New" followed by "Shortcut".

Browse to the Dyalog program and add the name of the workspace to the command line.

Select "Next" and give the application a name, then select "Finish".

The resulting icon is shown below. Note that although by default you will get a standard Dyalog APL icon, you could of course select another one from elsewhere on your system.

Clicking on this icon will start your application. Notice that the APL Session Window will NOT appear at any stage unless there is an error in your code. All the user will see is your "Temperature Converter" dialog box.


Using ⎕NEW instead of ⎕WC

From Version 11 onwards, it is possible to use ⎕NEW to create Instances of the built-in GUI Classes. The following function illustrates this approach using the Temperature Converter example described previously.

     ∇ TempConv;TITLE;TEMP
[1]    TITLE←'Temperature Converter'
[2]    TEMP←⎕NEW'Form'(('Caption'TITLE)('Posn'(10 10))
                       ('Size'(30 40)))
[3]
[4]    TEMP.(MB←⎕NEW⊂'MenuBar')
[5]    TEMP.MB.(M←⎕NEW'Menu'(,⊂'Caption' '&Scale'))
[6]    TEMP.MB.M.(C←⎕NEW'MenuItem'
                 (('Caption' '&Centigrade')('Checked' 1)))
[7]    TEMP.MB.M.(F←⎕NEW'MenuItem'
                 (,⊂('Caption' '&Fahrenheit')))
[8]
[9]    TEMP.(LF←⎕NEW'Label'(('Caption' 'Fahrenheit')
                            ('Posn'(10 10))))
[10]   TEMP.(F←⎕NEW'Edit'(('Posn'(10 40))('Size'(⍬ 20))
                          ('FieldType' 'Numeric')))
[11]
[12]   TEMP.(LC←⎕NEW'Label'(('Caption' 'Centigrade')
                            ('Posn'(40 10))))
[13]   TEMP.(C←⎕NEW'Edit'(('Posn'(40 40))('Size'(⍬ 20))
                          ('FieldType' 'Numeric')))
[14]
[15]   TEMP.(F2C←⎕NEW'Button'(('Caption' 'F->C')
                             ('Posn'(10 70))('Default' 1)))
[16]   TEMP.(C2F←⎕NEW'Button'(('Caption' 'C->F')
                              ('Posn'(40 70))))
[17]   TEMP.(Q←⎕NEW'Button'(('Caption' '&Quit')
                            ('Posn'(70 30))('Size'(⍬ 40))
                            ('Cancel' 1)))
[18]
[19]   TEMP.(S←⎕NEW'Scroll'(⊂('Range' 101)))
[20]
[21]   TEMP.MB.M.C.onSelect←'SET_C'
[22]   TEMP.MB.M.F.onSelect←'SET_F'
[23]   TEMP.F2C.onSelect←'f2c'
[24]   TEMP.F.onGotFocus←'SET_DEF'
[25]   TEMP.C2F.onSelect←'c2f'
[26]   TEMP.C.onGotFocus←'SET_DEF'
[27]   TEMP.onClose←'QUIT'
[28]   TEMP.Q.onSelect←'QUIT'
[29]   TEMP.S.onScroll←'c2f_scroll'
[30]
[31]   ⎕DQ'TEMP'
     ∇

For brevity, only a couple of the callback functions are shown here.

     ∇ f2c
[1]    TEMP.C.Value←(TEMP.F.Value-32)×5÷9
     ∇

     ∇ c2f_scroll MSG
[1]   ⍝ Callback for Centigrade input via scrollbar
[2]    TEMP.C.Value←101-4⊃MSG
[3]    c2f
     ∇


Temperature Converter Class

You may create user-defined Classes based upon Dyalog GUI objects as illustrated by the Temperature Converter Class which is listed overleaf.

To base a Class on a Dyalog GUI object, you specify the name of the object as its Base Class. For example, the Temperature Converter is based upon a Form:

      :Class Temp: 'Form'

Being based upon a top-level GUI object, the Temperature Converter may be used as follows:

      T1←⎕NEW Temp(⊂'Posn'(68 50))

Temperature Converter Example

:Class Temp: 'Form'
    ∇ Make pv;TITLE
      :Access Public
      TITLE←'Temperature Converter'
      :Implements Constructor :Base (⊂'Caption' TITLE),pv,
                                   ⊂('Size' (30 40))
      MB←⎕NEW⊂'MenuBar'
      MB.(M←⎕NEW'Menu'(,⊂'Caption' '&Scale'))
      MB.M.(C←⎕NEW'MenuItem'(('Caption' '&Centigrade')
                             ('Checked' 1)))
      MB.M.(F←⎕NEW'MenuItem'(,⊂('Caption' '&Fahrenheit')))
      LF←⎕NEW'Label'(('Caption' 'Fahrenheit')
                     ('Posn'(10 10)))
      F←⎕NEW'Edit'(('Posn'(10 40))('Size'(⍬ 20))
                   ('FieldType' 'Numeric'))
      LC←⎕NEW'Label'(('Caption' 'Centigrade')
                     ('Posn'(40 10)))
      C←⎕NEW'Edit'(('Posn'(40 40))('Size'(⍬ 20))
                   ('FieldType' 'Numeric'))
      F2C←⎕NEW'Button'(('Caption' 'F->C')('Posn'(10 70))
                       ('Default' 1))
      C2F←⎕NEW'Button'(('Caption' 'C->F')('Posn'(40 70)))
      Q←⎕NEW'Button'(('Caption' '&Quit')('Posn'(70 30))
                     ('Size'(⍬ 40))('Cancel' 1))
      S←⎕NEW'Scroll'(⊂('Range' 101))
      MB.M.C.onSelect←'SET_C'
      MB.M.F.onSelect←'SET_F'
      F2C.onSelect←'f2c'
      F.onGotFocus←'SET_DEF'
      C2F.onSelect←'c2f'
      C.onGotFocus←'SET_DEF'
      onClose←'QUIT'
      Q.onSelect←'QUIT'
      S.onScroll←'c2f_scroll'
    ∇

    ∇ f2c
      C.Value←(F.Value-32)×5÷9
    ∇
    ∇ c2f
      F.Value←32+C.Value×9÷5
    ∇
    ∇ c2f_scroll MSG
      ⍝ Callback for Centigrade input via scrollbar
      C.Value←101-4⊃MSG
      c2f
    ∇

    ∇ f2c_scroll Msg
      ⍝ Callback for Fahrenheit input via scrollbar
      F.Value←213-4⊃Msg
      f2c
    ∇

    ∇ Quit
      Close
    ∇
    ∇ SET_DEF MSG
      (⊃MSG).Default←1
    ∇
    ∇ SET_C
      ⍝ Sets the scrollbar to work in Centigrade
      S.Range←101
      S.onScroll←'c2f_scroll'
      MB.M.C.Checked←1
      MB.M.F.Checked←0
    ∇
    ∇ SET_F
      ⍝ Sets the scrollbar to work in Fahrenheit
      S.Range←213
      S.onScroll←'f2c_scroll'
      MB.M.F.Checked←1
      MB.M.C.Checked←0
    ∇
:EndClass ⍝ Temp

Notice that the :Implements Constructor statement of its Constructor Make:

:Implements Constructor :Base (⊂'Caption' TITLE),pv,
                             ⊂('Size' (30 40))

passes on the application-specific property list (pv) given as its argument, but (in this case) specifies Caption and Size as well. The order in which the properties are specified in the :Base call ensures that the former will act as a default (and be overridden by an application-specific Caption requested in pv), whereas the specified Size of(30 40) will override whatever value of Size is requested by the host application in pv.

Other Instances can co-exist with the first:

      T2←⎕NEW Temp(('Caption' 'My Application')
                   ('Posn'(10 10))


Dual Class Example

The Dual Class example is based upon the example used to illustrate how you may build an ActiveX Control in Dyalog APL (see The Dual Control Tutorial), but re-engineered as an internal Dyalog APL Class. The full listing of the Dual Class script is provided overleaf.

This version of Dual is based upon a SubForm:

      :Class Dual: 'SubForm'

The Dual Control requires a GUI parent but several Instances can co-exist, quite independently, in the same parent.

For example, function RUN creates a Form and 3 Instances of Dual; one to convert Centigrade to Fahrenheit, one to convert Fahrenheit to Centigrade, and the third to convert centimetres to inches.

     ∇ RUN;F;D1PROPS;D2PROPS;D3PROPS
[1]
[2]    F←⎕NEW'Form'(('Caption' 'Dual Instances')
                    ('Coord' 'Pixel')('Size'(320 320)))
[3]
[4]    D1PROPS←('Caption1' 'Centigrade')
               ('Caption2' 'Fahrenheit')
[5]    D1PROPS,←('Intercept' 32)('Gradient'(9÷5))
                ('Value1' 0)('Range'(0 100))
[6]    F.D1←F.⎕NEW Dual(('Coord' 'Pixel')('Posn'(10 10))
                        ('Size'(100 300)),D1PROPS)
[7]
[8]    D2PROPS←('Caption1' 'Fahrenheit')
               ('Caption2' 'Centigrade')
[9]    D2PROPS,←('Intercept'(-32×5÷9))('Gradient'(5÷9))
                ('Value1' 0)('Range'(0 212))
[10]   F.D2←F.⎕NEW Dual(('Coord' 'Pixel')('Posn'(110 10))
                        ('Size'(100 300)),D2PROPS)
[11]
[12]   D3PROPS←('Caption1' 'Centimetres')
               ('Caption2' 'Inches')
[13]   D3PROPS,←('Intercept' 0)('Gradient'(÷2.54))
                ('Value1' 0)('Range'(0 100))
[14]   F.D3←F.⎕NEW Dual(('Coord' 'Pixel')('Posn'(210 10))
                        ('Size'(100 300)),D3PROPS)
[15]
[16]   ⎕DQ'F'
     ∇

Dual's Constructor Make first splits its constructor arguments into those that apply to the Dual Class itself, and those that apply to the SubForm. Its :Implements Constructor statement then passes these on to the Base Constructor, together with an appropriate setting for EdgeStyle.

     :Implements Constructor :Base BaseArgs,
                                   ⊂'EdgeStyle' 'Dialog'

Dual Class Example

:Class Dual: 'SubForm'
    :Include GUITools
    :Field Private _Caption1←''
    :Field Private _Caption2←''
    :Field Private _Value1←0
    :Field Private _Value2←0
    :Field Private _Range←0
    :Field Private _Intercept←0
    :Field Private _Gradient←1
    :Field Private _Height←40

    ∇ Create args;H;W;POS;SH;CH;Y1;Y2;BaseArgs;MyArgs;
                  Defaults
      :Access Public
      MyArgs BaseArgs←SplitNV args
      :Implements Constructor :Base BaseArgs,
                                    ⊂'EdgeStyle' 'Dialog'
      ExecNV_ MyArgs ⍝ Set Flds named _PropertyName
                                      MyArgs
      Coord←'Pixel'
      H W←Size
      POS←2↑⌊0.5×0⌈(H-_Height)
      CH←⊃GetTextSize'W'
      'Slider'⎕WC'TrackBar'POS('Size'_Height W)
      Slider.(Limits AutoConf)←_Range 0
      Slider.(TickSpacing TickAlign)←10 'Top'
      Slider.onThumbDrag←'ChangeValue'
      Slider.onScroll←'ChangeValue'
      Y1←POS[1]-CH+1
      Y2←POS[1]+_Height+1
      'Caption1_'⎕WC'Text'_Caption1(Y1,0)('AutoConf' 0)
      'Caption2_'⎕WC'Text'_Caption2(Y2,0)('AutoConf' 0)
      'Value1_'⎕WC'Text'(⍕_Value1)(Y1,W)('HAlign' 2)
                        ('AutoConf' 0)
      CalcValue2
      'Value2_'⎕WC'Text'(⍕_Value2)(Y2,W)('HAlign' 2)
              ('AutoConf' 0)
      onConfigure←'Configure'
    ∇

    :Property Caption1, Caption2
    :Access Public
        ∇ R←Get arg
          R←(arg.Name,'_')⎕WG'Text'
        ∇
        ∇ Set arg
          (arg.Name,'_')⎕WS'Text'arg.NewValue
        ∇
    :EndProperty

    :Property Value1
    :Access Public
        ∇ R←Get
          R←_Value1
        ∇
        ∇ Set arg
          ⎕NQ'Slider' 'Scroll' 0 arg.NewValue
        ∇
    :EndProperty

    :Property Intercept, Gradient, Range, Height, Value2
    :Access Public
        ∇ R←Get arg
          R←⍎'_',arg.Name
        ∇
    :EndProperty

    ∇ CalcValue2
      _Value2←_Intercept+_Gradient×_Value1
    ∇

    ∇ ChangeValue MSG
      ⍝ Callback for ThumbDrag and Scroll
      _Value1←⊃¯1↑MSG
      CalcValue2
      Value1_.Text←⍕_Value1
      Value2_.Text←⍕_Value2
    ∇

    ∇ Configure MSG;H;W;POS;CH;Y1;Y2
      2 ⎕NQ MSG
      H W←Size
      POS←2↑⌊0.5×(H-_Height)
      CH←⊃GetTextSize'W'
      Slider.(Posn Size)←POS(_Height W)
      Y1←POS[1]-CH+1
      Y2←POS[1]+_Height+1
      Caption1_.Points←1 2⍴Y1,0
      Caption2_.Points←1 2⍴Y2,0
      Value1_.Points←1 2⍴Y1,W
      Value1_.Points←1 2⍴Y2,W
    ∇

:EndClass ⍝ Dual

The utilities contained in in the GUITools Namespace are as follows:

     ∇ r←SplitNV args;m
[1]   ⍝ Parse Name,Value Pairs
[2]   ⍝ Return pairs for this class in 1st element,
        others in 2nd element
[3]    m←(⎕NC⊃¨args)∊2.2 2.3 ⍝ Fields/Properties
                               in derived class
[4]    r←(m/args)((~m)/args)
     ∇
      ∇ExecNV_∇
     ∇ r←ExecNV_ args;n;v
[1]   ⍝ Set Properties using Name,Value Pairs
[2]    n v←↓⍉↑args
[3]    n←'_',¨n
[4]    ⍎(⍕,n,⊂'n'),'←v,0'
     ∇


Introduction

Graphical output is performed using the following objects:

Graphical Output
Circle | draws circles, arcs and pie charts
Ellipse | draws ellipses
Marker | draws a series of polymarkers
Poly | draws lines
Rect | draws rectangles
Image | displays or prints Bitmaps, Icons and Metafiles
Text | displays or prints graphical text

These graphical objects can be drawn in (i.e. be the children of) a wide range of other objects including a Form, Static, Printer and Bitmap.

Additional graphical resources are provided by the following objects. These are unusual in that they are not visible except when referenced as the property of another object:

Resource
Font | loads a font
Bitmap | defines a bitmap
Icon | defines an icon
Metafile | loads a Windows Metafile

Graphical objects are created, like any other object, using ⎕WC and have properties that can be changed using ⎕WS and queried using ⎕WG. Graphical objects also generate certain events.


Drawing Lines

To draw a line you use the Poly object. The following example draws a line in a Form from the point (y=10, x=5) to the point (y=90, x=60) :

      'F'      ⎕WC 'Form' 'Drawing Lines' ('Size' 25 50)
      'F.Line' ⎕WC 'Poly' ((10 90)(5 60))

In the above example, the points are specified as a 2-element nested vector containing y-coordinates and x-coordinates respectively. You can also use a 2-column matrix, e.g.

      'F.Line'⎕WC'Poly'(4 2⍴90 5 5 50 90 95 90 5)

Notice that because the second example replaced the object F.Line, the original line drawn in the first example has been erased.

In common with the position and size of other GUI objects, y-coordinates precede x-coordinates. Graphical software typically uses (x,y) rather than (y,x) but the latter is consistent with the order in which coordinates are specified and reported for all other objects and events. The Dyalog APL GUI support allows you to freely mix graphical objects with other GUI components (for example, you can use the graphical Text object in place of a Label) and this (y,x) consistency serves to avoid confusion.

When a graphical object in a screen object is erased its parent is restored to the appearance that it had before that graphical object was created. Thus:

      'F.Line' ⎕WC 'Poly' (2 2⍴10 5 50 10)
      ⎕EX 'F.Line'

first draws a line and then removes it. The following expression clears all graphical objects (and any other non-graphical ones too) from a parent object 'F':

      ⎕EX ⎕WN'F'

Similarly, objects automatically disappear when a function in which they are localised exits.

Erasing graphical objects that have been drawn on a Printer has no effect. Once drawn they cannot be undrawn.


Drawing in a Bitmap

A bitmap is an invisible resource (in effect, an area of memory) that is only displayed on the screen when it is referenced by another object. Any of the seven graphical objects (Circle, Ellipse, Image, Marker, Poly, Text and Rect) can be drawn in a bitmap (represented by a Bitmap object), using exactly the same ⎕WC syntax as if you were drawing in a Form, Static or Printer. However, drawing in a Bitmap is, like drawing on a Printer, an operation that cannot be "undone".

This facility allows you to construct a picture using lines, circles, text etc. and then later display it or save it as a bitmap.


Multiple Graphical Items

All graphical output objects (Circle, Ellipse, Image, Marker, Poly, Text and Rect) permit nested arguments so that you can draw several items with a single object. This feature has several advantages. Firstly, it allows you to treat related graphical items as a single object with a single name. This reduces the potential number of objects in existence and reduces the number of program statements needed to draw them. For example, sets of tick marks or grid lines do not have to be drawn separately, but can be represented by one object. Furthermore, because a set of lines can be embodied in a single object, you can erase them, replace them or drag/drop them as a unit. A further consideration is performance. A set of graphical items represented by a single object will normally be drawn faster than if each item was represented by separate objects.

For example, the following statements draw two separate rectangles; a red one at (y=10, x=20) and a blue one at (y=50, x=60). Both rectangles are size (30,30).

      RED BLUE ← (255 0 0)(0 0 255)
      'F.R1' ⎕WC 'Rect' (10 20)(30 30) ('FCol' RED)
      'F.R2' ⎕WC 'Rect' (50 60)(30 30) ('FCol' BLUE)

The next statement achieves the same result, but uses only one object:

      'F.R' ⎕WC 'Rect' ((10 50)(20 60)) (30 30)
                        ('FCol' RED BLUE)

The rectangles drawn by both these sets of statements are shown below (blue and red have been replaced by black for clarity).

The capability to specify more than one graphical item as a single object is particularly useful with the Text object as it allows you to display or print several text items (at different positions and in different colours if you wish) in a single statement. For example, the following expressions display a set of "labels" in a Form 'F1':

      LAB←'Name' 'Age' 'Address'
      POS←3 2⍴10 10 10 60 30 10
      'F1.LABS' ⎕WC 'Text' LAB POS


Unnamed Graphical Objects

When using the seven graphical output objects, you can optionally omit the final part of the name. For example, the following expression is valid:

      'F.' ⎕WC 'Poly' (2 2⍴10 5 50 10)

When you create a named object, all of the properties pertaining to that object are stored internally in your workspace. A polyline consisting of a large number of points thus takes up a significant amount of memory. However, this is necessary because the APL interpreter needs the information in order to redraw the object when another window is placed over it and then moved away again (exposure) or when the user resizes the Form in which it is displayed.

When you create an unnamed graphical object, the object is drawn, but its properties are not remembered internally, thus conserving workspace. This has two consequences. Firstly, you cannot subsequently modify or query the object's properties; you must name an object if you are ever going to refer to it again. Secondly, the object cannot automatically be redrawn (by APL) when it is exposed or resized. Instead, you must control this yourself using the Expose event.

Unnamed graphical objects are useful in the following circumstances:

  • For output to a Printer.
  • When you are very short of workspace.
  • When you are sure that the window you are drawing in will not need to be redrawn, for example, when you are working "full-screen".
  • For drawing in a Bitmap or a Metafile.
  • For creating bitmaps in an ImageList


Bitmaps and Icons

Bitmaps and icons are implemented as separate objects that you can create and destroy. Once you have created such an object you can reference it as many times as you wish. For example, you can use the same bitmap in several Buttons or associate the same icon with several Forms.

The Bitmap and Icon objects can be created in one of two ways. They are either loaded from an existing file or they are defined from APL arrays.

The files concerned must be in the appropriate Windows format for the object (.BMP or .ICO files) which can be edited by a standard Windows utility such as Paintbrush. The following example creates a Bitmap object from the CARS.BMP bitmap file which is supplied in the WS sub-directory:

      ROOT←2 ⎕NQ'.' 'GetEnvironment' 'dyalog'
      'CARS' ⎕WC 'Bitmap' (ROOT,'\WS\CARS')

Then you can use the Bitmap to fill the background of a Form by:

      'F1' ⎕WC 'Form' ('Picture' CARS 1)('Size' 25 50)

The "1" in the expression specifies that the Bitmap is to be used to "tile" the background of the Form. The result is shown in the illustration below. You can also position the Bitmap in the top-left (0) or centre (3) of the Form, or even have the Bitmap scaled automatically (2) to fit exactly in the Form. These settings are useful for displaying pictures. You can explore these facilities using the BMVIEW function in the UTIL workspace.

Instead of creating Bitmap and Icon objects from file, you can define them using APL arrays. These arrays specify the individual pixels that make up the picture or shape of the object in question.

There are two ways to define a Bitmap object from APL arrays. The first method, which is limited to colour palettes of 16 or 256 colours is to supply two arrays; one containing the colour indices for every pixel in the bitmap, and one containing the colour map. The colour map specifies the colours (in terms of their red, green and blue components) corresponding to the indices in the first array. For example, the following expressions create a 32 x 32 Bitmap from the arrays PIX and CM:

      ⍴PIX  ⍝ colour index (in CM) of each pixel
32 32
      ⍴CM   ⍝ 16-row matrix of RGB values
16 3
      'BM' ⎕WC 'Bitmap' ('Bits' PIX)('CMap' CM)

The reason that this method is restricted to 256 colours is that the CMap array containing the colour map is, of necessity, the same size as the colour palette. Even for a relatively modest 16-bit colour palette, the size of the array would be 65536 x 3.

The second method, which applies to all sizes of colour palette, is to use a single array that represents each pixel by a number that is an encoding of the red, green and blue components. The formula used to calculate each pixel value is:

      256⊥RED GREEN BLUE

where RED, GREEN and BLUE are integers in the range 0-255.

Thus the example above can be achieved using a single array CBITS as follows:

      CBITS←(256⊥⍉CMAP)[⎕IO+PIX]
      'BM' ⎕WC 'Bitmap' ('CBits' CBITS)

While it is possible to define bitmaps by creating appropriate APL arrays, it is likely that you will load them from file, e.g.

      'BM' ⎕WC 'Bitmap' (ROOT,'\WS\CARS')
      PIX CM ← 'BM' ⎕WG 'Bits' 'CMap'


Metafiles

A Windows metafile is a mechanism for representing a picture as a collection of graphics commands. Once a metafile has been created, the picture that it represents can be drawn repeatedly from it. Metafiles are device-independent, so the picture can be reproduced on different devices. Unlike bitmaps, metafiles can be scaled accurately and are therefore particularly useful for passing graphical information between different applications. Note that some other applications only support placeable metafiles. See RealSize property for details.

Creating a Metafile Object

In Dyalog APL, a Windows metafile is represented by the Metafile object. This is created in much the same way as a Bitmap object. That is, you can either make a Metafile object from an existing .WMF file, or you can create an empty one and then draw onto it using Poly, Text and other graphical objects. For example, to create a Metafile object called Tigger from the j0332364.wmf metafile that comes with Microsoft Office, you can execute the following:

   Dir←'C:\Program Files (x86)\Microsoft Office\MEDIA\CAGCAT10\'
   'Tigger'⎕WC'Metafile'(Dir,'j0332364.wmf')

If instead you wanted to create a metafile drawing from scratch, you could do so as follows. Notice that there is no need to assign names to the graphical objects drawn onto the Metafile.

     'METADUCK'  ⎕WC 'Metafile' ''
     'METADUCK.' ⎕WC 'Poly' DUCK
     'fnt'⎕WC'Font' 'Arial' 72
     'METADUCK.'⎕WC'Text' 'Quack'(45 60)('FontObj' 'fnt')

Drawing a Metafile Object

A Metafile object is drawn by specifying either the object itself or its name as the Picture property of another object. This causes the Metafile to be drawn in that object and scaled to fit exactly within its boundaries.

The following statement creates a Form containing the Metafile object Tigger.

    'F1'⎕WC'Form' ('Size' 25 50) ('Picture' Tigger)

The next statement replaces the Picture with the Metafile object METADUCK.

      F1.Picture←METADUCK


Picture Buttons

Picture buttons in toolbars are most conveniently represented by ToolButtons in ToolControls (see Chapter 4). Pictures on stand-alone buttons or buttons used in the (superseded) ToolBar object, may be created using Bitmap, Icon and Metafile objects and there are two different methods provided. The first (and the simplest) is to use the Picture property which applies to all 3 types of image,(Bitmap, Icon or Metafile). The second method is to use the BtnPix property. This requires rather more effort, and only draws Bitmaps, and not Icons or Metafiles. However, the BtnPix property gives you total control over the appearance of a Button which the Picture property does not.

Using the Picture Property

The Picture property overlays a Bitmap, Icon or Metafile on top of a standard pushbutton. The following example uses an icon which is included with Dyalog APL.

     ∇ PictureProperty;dyalog
[1]    dyalog←2 ⎕NQ'.' 'GetEnvironment' 'dyalog'
[2]    'spider'⎕WC'Icon'(dyalog,'\ws\arachnid.ico')
[3]    'F'⎕WC'Form' 'Using the Picture Property'('Coord' 'Pixel')
[4]    'F.B'⎕WC'Button'('Size' 40 40)
[5]    F.B.Picture←spider 3
     ∇

Notice that (by definition) an icon is 32 x 32 pixels in size. To allow space for the pushbutton borders you have to make the Button at least 40 x 40 pixels. The "3" means put the 'spider' in the centre of the button.

When you press a Button which has its Picture property set like this, APL automatically shifts the overlaid image down and to the right by 1 pixel. This complements the change in appearance of the button borders and achieves a "pressed-in" look. When you release the button, APL shifts the image back again.

The Picture property therefore provides a very simple mechanism for implementing a "tool-button", especially if you already have a bitmap or icon file that you want to use.

However, the Picture property has certain limitations. Firstly, you cannot alter the "pressed-in" look of the Button which is determined automatically for you. You might want the Button to change colour when you press it, and you cannot achieve this with the Picture property. Secondly, the appearance of the Button is unchanged when you make it inactive (by setting its Active property to 0).

Note that if you use the Picture property on Radio or Check buttons, the buttons assume pushbutton appearance although their radio/check behaviour is unaffected.

Using the BtnPix Property

You can obtain complete control over the appearance of a Button by using the BtnPix property; however this entails more work on your part.

BtnPix allows you to associate three bitmaps with a Button, i.e.

  • one for when the Button is in its normal state
  • one for when it is pressed/selected
  • one for when it is inactive

For example, if you have created three Bitmap objects called UP, DOWN and DEAD, you define the Button as follows:

      'F.B' ⎕WC 'Button' ('BtnPix' UP DOWN DEAD)

APL subsequently displays one of the three Bitmap objects according to the state of the Button; i.e. UP for its normal state (State 0), DOWN for its pressed/selected state (State 1) or DEAD when it is inactive (Active 0).

The BtnPix property requires that you use Bitmap objects; it doesn't work for Icons. This is because icons are normally at least partly transparent. However, it is very easy to convert an icon file to a Bitmap object. First you create an Icon object from the icon (.ICO) file. Next you read the icon's pattern definition (Bits property) and colour map (CMap property) into the workspace. Then finally, you create a Bitmap from these two arrays.

The following example illustrates how you can make a Button from icons supplied with Windows.

Load an icon:

      'T1'⎕WC'Icon'('Shell32.dll' ¯13)

Read its CBits:

      CBits ← T1.CBits

Now define a Bitmap from this variable, (replacing the T1 object):

      'T1' ⎕WC 'Bitmap' ('CBits' CBits)

Now make a second Bitmap:

      'T2'⎕WC'Icon'('Shell32.dll' ¯14)
      'T2'⎕WC'Bitmap'('CBits'T2.CBits)

Now define the Button. Notice that the third (inactive) bitmap is optional.

      'F.B' ⎕WC 'Button' ('BtnPix' 'T1' 'T2')

The pictures below show the button in its normal and pressed states.


Using Icons

You have seen how icons can be displayed using the Picture property. Other uses of icons are described below.

Firstly, you can associate an icon with a Form or so that the icon is displayed (by Windows) when the Form is minimised. This is done using the IconObj property. For example, the following expressions would associate the UK Flag icon distributed with Visual Basic with the Form 'F1'. This icon would then be displayed when 'F1' is minimised.

      'star'⎕WC'Icon'('Shell32.dll' ¯43)
      'F1' ⎕WC 'Form' ('IconObj' star)

The IconObj property also applies to the Root object '.'. This defines the icon to be displayed for your application as a whole when the user toggles between applications using Alt+Tab. It is used in conjunction with the Caption property which determines the description of your application that is shown alongside the icon, e.g.

      'MYIcon' ⎕WC 'Icon' ...
      '.' ⎕WS ('IconObj' MYIcon) ('Caption' 'My System')

An icon can be displayed using the Image object. This object is used to position one or more Icon objects (or Bitmap objects) in a Form or Static. It can also be used to draw an icon on a Printer. If you make the Image dragable, you will be able to drag/drop the icon. The following example displays a dragable Icon at (10,10) in a Form. It also associates the callback function 'Drop' with the DragDrop event so that this function is called when the user drag/drops the icon.

      'F1' ⎕WC 'Form' ('Event' 'DragDrop' 'Drop')
      'star'⎕WC'Icon'('Shell32.dll' ¯43)
      'F1.I' ⎕WC 'Image' (10 10) ('Picture' star)
       F1.I.Dragable←2

Notice that setting Dragable to 2 specifies that an object is fully displayed while it is being dragged. Setting Dragable to 1 causes only the bounding rectangle around the object to be dragged.


ToolControl and ToolButton Objects

The ToolControl and ToolButton Objects

The ToolControl object is normally used in conjunction with ToolButtons, although it may also act as a parent for other objects, including a MenuBar.

A ToolButton may display a Caption and an Image, although both are optional. Images for individual ToolButtons are not defined one-by-one, but instead are defined by an ImageList which contains a set of bitmaps or icons.

The ImageListObj property of the ToolControl specifies the name of one or more ImageList objects to be used. The ImageIndex properties of each of the ToolButtons specifies which of the images in each ImageList object apply to which of the ToolButtons.

Standard Bitmap Resources

Typically, you will want your ToolControls to provide standard Windows buttons and the easiest way to achieve this is to utilise the standard Windows bitmaps that are contained in COMCTL32.DLL. There are three main sets of bitmaps, each of which is provided in two sizes, small (16x16) and large (24 x 24).

Resource number 120 (IDB_STD_SMALL_COLOR) and 121 (IDB_STD_LARGE_COLOR) contain the following set of assorted bitmap images.

Resource number 124 (IDB_VIEW_SMALL_COLOR) and 125 (IDB_VIEW_LARGE_COLOR) contain a set of bitmaps relating to different views of information. These are used, for example in the Windows Explorer tool bar

Resource number 130 (IDB_HIST_SMALL_COLOR) and 131 (IDB_HIST_LARGE_COLOR) contain another useful set of bitmaps

COMCTL32.DLL also contains individual bitmaps in resources 132-134.

Dyalog Bitmap Resources

Another three sets of useful bitmaps are to be found in the DyaRes DLL file. These bitmaps are used in the Dyalog APL/W Session tool buttons. Note that if you include these bitmaps in a run-time application, you will have to ship DyaRes DLL with it.

The normal set of bitmaps associated with the Session buttons may be created using the statement:

      'bm'⎕wc'Bitmap' ('dyares150_64.dll' 'tb_normal')

The bitmaps used when the buttons are highlighted may be created using the statement.

      'bm'⎕wc'Bitmap' ('dyares150_64.dll' 'tb_hot')

The bitmaps used when the buttons are inactive may be created using the statement

      'bm'⎕wc'Bitmap' ('dyares150_64.dll' 'tb_inactive')

Note that in the Dyalog Session, if Native Look and Feel is enabled, these bitmaps are overridden by a single set of images designed to operate with the user's chosen theme and Visual Styles. For further information, see Native Look and Feel.

Creating ImageLists for ToolButtons

You may use up to three ImageList objects to represent ToolButton images. These will be used to specify the pictures of the ToolButton objects in their normal, highlighted (sometimes termed hot) and inactive states respectively.

The set of images in each ImageList is then defined by creating unnamed Bitmap or Icon objects as children.

When creating an ImageList, it is a good idea to set its MapCols property to 1. This means that standard button colours used in the bitmaps will automatically be adjusted to take the user's colour preferences into account.

When you create each ToolButton you specify its ImageIndex property, selecting up to three pictures (normal, highlighted and inactive) to be displayed on the button.

If you specify only a single ImageList, the picture on the ToolButton will be the same in all three cases. However, the appearance of the buttons themselves change when the button is highlighted or pressed, and in many situations this may be sufficient behaviour.

The following example illustrates how a simple ToolControl can be constructed using standard Windows bitmaps. Notice that the Masked property of the ImageList is set to 0; this is necessary if the ImageList is to contain bitmaps, as opposed to icons. Secondly, because the bitmaps are in this case size 16 x 16, it is unnecessary to specify the Size property of the ImageList which is, by default, also 16 x 16.

'F'⎕WC'Form' 'ToolControl'('Size' 10 40)
'F.TB'⎕WC'ToolControl'
'F.TB.IL'⎕WC'ImageList'('Masked' 0) ('MapCols' 1)
'F.TB.IL.'⎕WC'Bitmap'('ComCtl32' 120)⍝ STD_SMALL
'F.TB'⎕WS'ImageListObj' 'F.TB.IL'
'F.TB.B1'⎕WC'ToolButton' 'New'('ImageIndex' 7)
'F.TB.B2'⎕WC'ToolButton' 'Open'('ImageIndex' 8)
'F.TB.B3'⎕WC'ToolButton' 'Save'('ImageIndex' 9)

The Style Property

The overall appearance of the ToolButton objects displayed by the ToolControl is defined by the Style property of the ToolControl itself, rather than by properties of individual ToolButtons.

Note that the Style property may only be set when the ToolControl is created using ⎕WC and may not subsequently be changed using ⎕WS.

Style may be 'FlatButtons', 'Buttons', 'List' or 'FlatList'. The default Style is of a ToolControl is 'FlatButtons', as is the first example above. The following examples illustrate the other three styles:

The Divider Property

You will notice that, in the above examples, there is a thin groove drawn above the ToolControl. The presence or absence of this groove is controlled by the Divider property whose default is 1. The following picture illustrates the effect of setting Divider to 0.

The MultiLine Property

The MultiLine property specifies whether or not ToolButtons (and other child controls) are arranged in several rows (or columns) when there are more than would otherwise fit.

If MultiLine is 0 (the default), the ToolControl object clips its children and the user must resize the Form to bring more objects into view.

Note that you may change MultiLine dynamically, using ⎕WS.

'F'⎕WC'Form' 'ToolControl: MultiLine 0'
'F.TB'⎕WC'ToolControl'('Style' 'List')

'F.TB.IL'⎕WC'ImageList'('Masked' 0)('Size' 24 24)
'F.TB.IL.'⎕WC'Bitmap'('ComCtl32' 121)⍝ STD_LARGE
'F.TB'⎕WS'ImageListObj' 'F.TB.IL'

'F.TB.B1'⎕WC'ToolButton' 'Cut'('ImageIndex' 1)
'F.TB.B2'⎕WC'ToolButton' 'Copy'('ImageIndex' 2)
'F.TB.B3'⎕WC'ToolButton' 'Paste'('ImageIndex' 3)
'F.TB.B4'⎕WC'ToolButton' 'Undo'('ImageIndex' 4)
'F.TB.B5'⎕WC'ToolButton' 'Redo'('ImageIndex' 5)
'F.TB.B6'⎕WC'ToolButton' 'Delete'('ImageIndex' 6)

If we set MultiLine to 1, the ToolButtons are instead displayed in several rows:

The Transparent Property

The Transparent property (default 0) specifies whether or not the ToolControl is transparent. Note that Transparent must be set when the object is created using ⎕WC and may not subsequently be changed using ⎕WS.

If a ToolControl is created with Transparent set to 1, the visual effect is as if the ToolButtons (and other controls) were drawn directly on the parent Form as shown below.

'F'⎕WC'Form' 'ToolControl: Transparent 1)'
ROOT←'C:\Program Files\Dyalog\Dyalog APL 13.1 Unicode\'
'F.BM'⎕WC'Bitmap'(ROOT,'\WS\BUBBLES')
'F'⎕WS'Picture' 'F.BM' 1

'F.TB'⎕WC'ToolControl'('Style' 'Buttons')('Transparent'1)
'F.TB.IL'⎕WC'ImageList'('Masked' 0)('Size' 24 24)
'F.TB.IL.'⎕WC'Bitmap'('ComCtl32' 121)⍝ STD_LARGE
'F.TB'⎕WS'ImageListObj' 'F.TB.IL'

'F.TB.B1'⎕WC'ToolButton' 'New'('ImageIndex' 7)
'F.TB.B2'⎕WC'ToolButton' 'Open'('ImageIndex' 8)
'F.TB.B3'⎕WC'ToolButton' 'Save'('ImageIndex' 9)

Radio buttons, Check buttons and Separators

The Style property of a ToolButton may be 'Push', 'Check', 'Radio', 'Separator' or 'DropDown'.

Push buttons (the default) are used to generate actions and pop in and out when clicked.

Radio and Check buttons are used to select options and have two states, normal (out) and selected (in). Their State property is 0 when the button is in its normal (unselected state) or 1 when it is selected.

A group of adjacent ToolButtons with Style 'Radio' defines a set in which only one of the ToolButtons may be selected at any one time. The act of selecting one will automatically deselect any other. Note that a group of Radio buttons must be separated from Check buttons or other groups of Radio buttons by ToolButtons of another Style.

Separator buttons are a special case as they have no Caption or picture, but appear as a thin vertical grooves that are used only to separate groups of buttons.

The following example illustrates how two groups of radio buttons are established by inserting a ToolButton with Style 'Separator' between them. This ToolControl could be used to control the appearance of a ListView object. The first group is used to select the view (Large Icon, Small Icon, List or Report), and the second is used to sort the items by Name, Size or Date. In the picture, the user has selected Small Icon View and Sort by Date.

'F'⎕WC'Form' 'ToolControl: Radio Buttons'
'F.TB'⎕WC'ToolControl'

'F.TB.IL'⎕WC'ImageList'('Masked' 0)
'F.TB.IL.'⎕WC'Bitmap'('ComCtl32' 124)⍝ VIEW_SMALL
'F.TB'⎕WS'ImageListObj' 'F.TB.IL'

'F.TB.B1'⎕WC'ToolButton' 'Large'('ImageIndex' 1)('Style' 'Radio')
'F.TB.B2'⎕WC'ToolButton' 'Small'('ImageIndex' 2)('Style' 'Radio')
'F.TB.B3'⎕WC'ToolButton' 'List'('ImageIndex' 3)('Style' 'Radio')
'F.TB.B4'⎕WC'ToolButton' 'Details'('ImageIndex' 4)('Style' 'Radio')

'F.TB.S1'⎕WC'ToolButton'('Style' 'Separator')

'F.TB.B5'⎕WC'ToolButton' 'Name'('ImageIndex' 5)('Style' 'Radio')
'F.TB.B6'⎕WC'ToolButton' 'Size'('ImageIndex' 6)('Style' 'Radio')
'F.TB.B7'⎕WC'ToolButton' 'Date'('ImageIndex' 7)('Style' 'Radio')

Notice that the appearance of the Separator ToolButton is less obvious when the ToolControl Style is Buttons or List, but the radio grouping effect is the same:

Drop-Down buttons

It is possible to define ToolButtons that display a drop-down menu from which the user may choose an option. This is done by creating a ToolButton with Style 'DropDown'.

A ToolButton with Style 'DropDown' has an associated popup Menu object which is named by its Popup property. There are two cases to consider.

If the ShowDropDown property of the parent ToolControl is 0, clicking the ToolButton causes the popup menu to appear. In this case, the ToolButton itself does not itself generate a Select event; you must rely on the user selecting a MenuItem to specify a particular action.

If the ShowDropDown property of the parent ToolControl is 1, clicking the dropdown button causes the popup menu to appear; clicking the ToolButton itself generates a Select event, but does not display the popup menu.

'F'⎕WC'Form' 'ToolControl: Dropdown Buttons'
'F.TB'⎕WC'ToolControl'('ShowDropDown' 1)

:With 'F.FMENU'⎕WC'Menu' ⍝ Popup File menu
    'NEW'⎕WC'MenuItem' '&New'
    'OPEN'⎕WC'MenuItem' '&Open'
    'CLOSE'⎕WC'MenuItem' '&Close'
:EndWith

:With 'F.EMENU'⎕WC'Menu' ⍝ Popup Edit menu
    'CUT'⎕WC'MenuItem' 'Cu&t'
    'COPY'⎕WC'MenuItem' '&Copy'
    'PASTE'⎕WC'MenuItem' '&Paste'
 :EndWith

'F.TB.B1'⎕WC'ToolButton' 'File'('Style' 'DropDown')('Popup' 'F.FMENU')
'F.TB.B2'⎕WC'ToolButton' 'Edit'('Style' 'DropDown')('Popup' 'F.EMENU')

A MenuBar as the child of a ToolControl

As a special case, the ToolControl may contain a MenuBar as its only child. In this case, Dyalog APL/W causes the menu items to be drawn as buttons, even under Windows 95.

Although nothing is done to prevent it, the use of other objects in a ToolControl containing a MenuBar, is not supported.

'F'⎕WC'Form' 'ToolControl with MenuBar'
'F.TB'⎕WC'ToolControl'

:With 'F.TB.MB'⎕WC'MenuBar'
    :With 'File'⎕WC'Menu' 'File'
        'New'⎕WC'MenuItem' 'New'
        'Open'⎕WC'MenuItem' 'Open'
        'Close'⎕WC'MenuItem' 'Close'
    :EndWith

    :With 'Edit'⎕WC'Menu' 'Edit'
        'Cut'⎕WC'MenuItem' 'Cut'
        'Copy'⎕WC'MenuItem' 'Copy'
        'Paste'⎕WC'MenuItem' 'Paste'
    :EndWith

:EndWith

Providing User Customisation

It is common to allow the user to switch the appearance of a ToolControl dynamically. This may be done using a pop-up menu. In addition to providing a choice of styles, the user may switch the text captions on and off.

The ShowCaptions property specifies whether or not the captions of ToolButton objects are drawn. Its default value is 1 (draw captions).

ToolButtons drawn without captions occupy much less space and ShowCaptions provides a quick way to turn captions on/off for user customisation.

The following functions illustrate how this was achieved.

     ∇ Example
[1]    'F'⎕WC'Form' 'ToolControl: User Options'
[2]    'F.TB'⎕WC'ToolControl'
[3]    'F.TB'⎕WS'Event' 'MouseDown' 'TC_POPUP'
[4]
[5]    'F.TB.IL'⎕WC'ImageList'('Masked' 0)('Size' 24 24)
[6]    'F.TB.IL.'⎕WC'Bitmap'('ComCtl32' 121)⍝ STD_LARGE
[7]    'F.TB'⎕WS'ImageListObj' 'F.TB.IL'
[8]
[9]    'F.TB.B1'⎕WC'ToolButton' 'Cut'('ImageIndex' 1)
[10]   'F.TB.B2'⎕WC'ToolButton' 'Copy'('ImageIndex' 2)
[11]   'F.TB.B3'⎕WC'ToolButton' 'Paste'('ImageIndex' 3)
[12]   'F.TB.B4'⎕WC'ToolButton' 'Undo'('ImageIndex' 4)
[13]   'F.TB.B5'⎕WC'ToolButton' 'Redo'('ImageIndex' 5)
[14]   'F.TB.B6'⎕WC'ToolButton' 'Delete'('ImageIndex' 6)
     ∇

     ∇ TC_POPUP MSG;popup;TC;STYLE;SHOW;MULTI;OPTION
[1]    ⍝ Popup menu on ToolControl
[2]    :If (2≠5⊃MSG) ⍝ Right mouse button ?
[3]        :Return
[4]    :EndIf
[5]
[6]    TC←'#.',⊃MSG
[7]    STYLE SHOW MULTI←TC ⎕WG'Style' 'ShowCaptions'
                              'MultiLine'
[8]
[9]    :With 'popup'⎕WC'Menu'
[10]       'FlatButtons'⎕WC'MenuItem' '&Flat Buttons'
                          ('Style' 'Radio')
[11]       'Buttons'⎕WC'MenuItem' '&Buttons'
                          ('Style' 'Radio')
[12]       'List'⎕WC'MenuItem' '&List'('Style' 'Radio')
[13]       'FlatList'⎕WC'MenuItem' 'Fla&t List'
                          ('Style' 'Radio')
[14]       STYLE ⎕WS'Checked' 1
[15]       'sep'⎕WC'Separator'
[16]       'ShowCaptions'⎕WC'MenuItem' '&Show Text'
                           ('Checked'SHOW)
[17]       'MultiLine'⎕WC'MenuItem' '&MultiLine'
                           ('Checked'MULTI)
[18]
[19]       ('MenuItem'⎕WN'')⎕WS¨⊂'Event' 'Select' 1
[20]
[21]       :If 0=⍴MSG←⎕DQ''
[22]           :Return
[23]       :EndIf
[24]
[25]       :Select OPTION←⊃MSG
[26]       :CaseList 'FlatButtons' 'Buttons' 'List'
                     'FlatList'
[27]           TC ⎕WS'Style'OPTION
[28]       :Else
[29]           TC ⎕WS OPTION(~TC ⎕WG OPTION)
[30]       :EndSelect
[31]
[32]   :EndWith
     ∇


CoolBar and CoolBand Objects

The CoolBar and CoolBand Objects

A CoolBar contains one or more bands (CoolBands). Each band can have any combination of a gripper bar, a bitmap, a text label, and a single child object.

Using the gripper bars, the user may drag bands from one row to another, resize bands in the same row, and maximise or minimise bands in a row. The CoolBar therefore gives the user a degree of control over the layout of the controls that it contains.

A CoolBand may not contain more than one child object, but that child object may itself be a container such as a ToolControl or a SubForm.

The following example illustrates a CoolBar containing two CoolBands, each of which itself contains a ToolControl.

'F'⎕WC'Form' 'CoolBar Object with ToolControls'
'F.IL'⎕WC'ImageList'('Masked' 0)('MapCols' 1)
'F.IL.'⎕WC'Bitmap'('ComCtl32' 120)⍝ STD_SMALL

'F.CB'⎕WC'CoolBar'

:With 'F.CB.C1'⎕WC'CoolBand'
    'TB'⎕WC'ToolControl'('ImageListObj' '#.F.IL')
    'TB.B1'⎕WC'ToolButton' 'New'('ImageIndex' 7)
    'TB.B2'⎕WC'ToolButton' 'Open'('ImageIndex' 8)
    'TB.B3'⎕WC'ToolButton' 'Save'('ImageIndex' 9)
:EndWith

:With 'F.CB.C2'⎕WC'CoolBand'
    'TB'⎕WC'ToolControl'('ImageListObj' '#.F.IL')
    'TB.B1'⎕WC'ToolButton' 'Cut'('ImageIndex' 1)
    'TB.B2'⎕WC'ToolButton' 'Copy'('ImageIndex' 2)
    'TB.B3'⎕WC'ToolButton' 'Paste'('ImageIndex' 3)
    'TB.B4'⎕WC'ToolButton' 'Undo'('ImageIndex' 4)
    'TB.B5'⎕WC'ToolButton' 'Redo'('ImageIndex' 5)
:EndWith

The user may move band 2 into row 1 by dragging the gripper bar:

CoolBar: FixedOrder Property

FixedOrder is a property of the CoolBar and specifies whether or not the CoolBar displays CoolBands in the same order. If FixedOrder is 1, the user may move bands which have gripper bars to different rows, but the band order is static. The default is 0.

CoolBand: GripperMode Property

GripperMode is a property of a CoolBand and specifies whether or not the CoolBand has a gripper bar which is used to reposition and resize the CoolBand within its parent CoolBar. GripperMode is a character vector with the value 'Always' (the default), 'Never' or 'Auto'. If GripperMode is 'Always', the CoolBand displays a gripper bar even if it is the only CoolBand in the CoolBar. If GripperMode is 'Never', the CoolBand does not have a gripper bar and may not be directly repositioned or resized by the user. If GripperMode is 'Auto', the CoolBand displays a gripper bar only if there are other CoolBands in the same CoolBar.

CoolBar: DblClickToggle Property

If it has a gripper bar, the user may maximise one of the bands in a row, causing the other bands to be minimised. The action required to do this is defined by the DblClickToggle property which is a property of the CoolBar.

If DblClickToggle is 0 (the default), the user must single-click the gripper bar. If DblClickToggle is 1, the user must double-click the gripper bar. These actions toggle a child CoolBand between its maximised and minimised state. The following picture shows the first CoolBand maximised.

The next picture shows the second CoolBand maximised.

CoolBar: VariableHeight/BandBorders Properties

These two properties affect the appearance of the CoolBar.

The VariableHeight property specifies whether or not the CoolBar displays bands in different rows at the minimum required height (the default), or all the same height.

The BandBorders property specifies whether or not narrow lines are drawn to separate adjacent bands. The default is 0 (no lines).

The following example uses simple controls (as opposed to container controls) as children of the CoolBands and illustrate the effect of these properties on the appearance of the CoolBar.

'F'⎕WC'Form' 'CoolBar Object with simple controls'
'F.CB'⎕WC'CoolBar'

:With F.CB.C1'⎕WC'CoolBand'
    'E1'⎕WC'Edit' 'Edit1'
:EndWith

:With 'F.CB.C2'⎕WC'CoolBand'
    'C1'⎕WC'Combo'('One' 'Two' 'Three')('SelItems' 0 1 0)
:EndWith

:With 'F.CB.C3'⎕WC'CoolBand'
    'E2'⎕WC'Edit'(3 5⍴'Edit2')('Style' 'Multi')
:EndWith

If the CoolBands are arranged in the same row, the height of the row expands to accommodate the largest one as shown below.

The picture below illustrates the effect of setting VariableHeight to 0.

The picture below shows the effect on appearance of setting BandBorders to 1.

CoolBand: ChildEdge Property

ChildEdge is a property of a CoolBand and specifies whether or not the CoolBand leaves space above and below the object that it contains.

If the ChildEdge property of each CoolBand had been set to 1 in the above example, then the result would show wider borders between each band.

CoolBand: Caption and ImageIndex Properties

The Caption and ImageIndex properties of a CoolBand are used to display an optional text string and picture in the CoolBand.

The picture is defined by an image in an ImageList object whose name is referenced by the ImageListObj property of the parent CoolBar. The following example illustrates how this is done.

'F'⎕WC'Form' 'CoolBand Caption and ImageIndex'
'F.IL'⎕WC'ImageList'('Masked' 0)('MapCols' 1)
'F.IL.'⎕WC'Bitmap'('ComCtl32' 120)⍝ STD_SMALL

'F.CB'⎕WC'CoolBar'('ImageListObj' 'F.CB.IL')
'F.CB.IL'⎕WC'ImageList'('Masked' 1)('MapCols' 1)
'F.CB.IL.'⎕WC'Icon'('' 'aplicon')
'F.CB.IL.'⎕WC'Icon'('' 'editicon')

:With 'F.CB.C1'⎕WC'CoolBand' 'File'('ImageIndex' 1)
 'TB'⎕WC'ToolControl'('ImageListObj' '#.F.IL')('Divider' 0)
 'TB.B1'⎕WC'ToolButton' 'New'('ImageIndex' 7)
 'TB.B2'⎕WC'ToolButton' 'Open'('ImageIndex' 8)
 'TB.B3'⎕WC'ToolButton' 'Save'('ImageIndex' 9)
:EndWith

:With 'F.CB.C2'⎕WC'CoolBand' 'Edit'('ImageIndex' 2)
 'TB'⎕WC'ToolControl'('ImageListObj' '#.F.IL')('Divider' 0)
 'TB.B1'⎕WC'ToolButton' 'Cut'('ImageIndex' 1)
 'TB.B2'⎕WC'ToolButton' 'Copy'('ImageIndex' 2)
 'TB.B3'⎕WC'ToolButton' 'Paste'('ImageIndex' 3)
 'TB.B4'⎕WC'ToolButton' 'Undo'('ImageIndex' 4)
 'TB.B5'⎕WC'ToolButton' 'Redo'('ImageIndex' 5)
:EndWith

Note that the Caption and image are displayed when the CoolBand is minimised as shown below:

CoolBand: Size, Posn, NewLine, Index Properties

The Size property of a CoolBand is partially read-only and may only be used to specify its width; because the height of a CoolBand is determined by its contents. Furthermore, the Size property may only be specified when the CoolBand is created using ⎕WC.

The position of a Cool Band within a CoolBar is determined by its Index and NewLine properties, and by the position and size of preceding CoolBand objects in the same CoolBar. The Posn property is read-only.

The Index property specifies the position of a CoolBand within its parent CoolBar, relative to other CoolBands and is ⎕IO dependent. Initially, the value of Index is determined by the order in which the CoolBands are created. You may re-order the CoolBands within a CoolBar by changing its Index property with ⎕WS.

The NewLine property specifies whether or not the CoolBand occupies the same row as an existing CoolBand, or is displayed on a new line within its CoolBar parent.

The value of NewLine in the first CoolBand in a CoolBar is always ⎕IO, even if you specify it to be 0. You may move a CoolBand to the previous or next row by changing its NewLine property (using ⎕WS) from 1 to 0, or from 0 to 1 respectively.

If you wish to remember the user's chosen layout when your application terminates, you must store the values of Index, Size and NewLine for each of the CoolBands. When your application is next started, you must re-create the CoolBands with the same values of these properties.

CoolBands with SubForms

The CoolBand object itself may contain only a single child object. However, if that child is a SubForm containing other objects, the CoolBand can appear to manage a group of objects. A similar effect can be obtained using a ToolBar or ToolControl.

The following example illustrates this technique. Note that the SubForms are disguised by setting their EdgeStyle and BCol properties. In addition, their AutoConf properties are set to 0 to prevent resizing of the child controls when the CoolBands are resized.

'F'⎕WC'Form' 'CoolBar with SubForms'('Size' 25 50)
'F'⎕WS'Coord' 'Pixel'

'F.CB'⎕WC'CoolBar'

:With 'F.CB.C1'⎕WC'CoolBand'
    'S'⎕WC'SubForm'('Size' 30 ⍬)('EdgeStyle' 'Default')
                   ('BCol' ¯16)('AutoConf' 0)
    'S.E1'⎕WC'Edit' 'Edit 1'(2 2)(⍬ 60)
    'S.C1'⎕WC'Combo'('One' 'Two')''(2 70)(⍬ 60)
:EndWith

:With 'F.CB.C2'⎕WC'CoolBand'
    'S'⎕WC'SubForm'('Size' 30 ⍬)('EdgeStyle' 'Default')
                   ('BCol' ¯16)('AutoConf' 0)
    'S.E1'⎕WC'Edit' 'Edit 2'(2 2)(⍬ 60)
    'S.C1'⎕WC'Combo'('One' 'Two')''(2 70)(⍬ 60)
:EndWith


TabControl and TabButton Objects

The TabControl and TabButton Objects

The TabControl object provides access to the standard Windows NT tab control.

The standard tab control is analogous to a set of dividers in a notebook and allows you to define a set of pages that occupy the same area of a window or dialog box. Each page consists of a set of information or a group of controls that the application displays when the user selects the corresponding tab.

A special type of tab control displays tabs that look like buttons. For example, the Windows 98 taskbar is such a tab control.

To implement a multiple page tabbed dialog, illustrated below, you should create a Form, then a TabControl with Style 'Tabs' (which is the default) as a child of the Form.

'F'⎕WC'Form' 'TabControl: Default'('Size' 25 50)
'F.TC'⎕WC'TabControl'

Individual tabs or buttons are represented by TabButton objects which should be created as children of the TabControl object. Optional captions and pictures are specified by the Caption and ImageIndex properties of the individual TabButton objects themselves.

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')
'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

Next, create one or more pairs of TabButton and SubForm objects as children of the TabControl. You associate each SubForm with a particular tab by setting its TabObj property to the name of the associated TabButton object. Making the SubForms children of the TabControl ensures that, by default, they will automatically be resized correctly. (You may alternatively create your SubForms as children of the main Form and establish appropriate resize behaviour using their Attach property.)

'F.TC.T1'⎕WC'TabButton' 'One'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Two'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Three'('ImageIndex' 3)
'F.TC.S1'⎕WC'SubForm'('TabObj' 'F.TC.T1')
'F.TC.S2'⎕WC'SubForm'('TabObj' 'F.TC.T2')
'F.TC.S3'⎕WC'SubForm'('TabObj' 'F.TC.T3')

Style, FlatSeparators and HotTrack Properties

The Style property determines the overall appearance of the tabs or buttons in a TabControl and may be 'Tabs' (the default), 'Buttons' or 'FlatButtons'.

A TabControl object with Style 'Buttons' or 'FlatButtons' may be used in a similar way (i.e. to display a set of alternative pages), although buttons in this type of TabControl are more normally used to execute commands. For this reason, these styles of TabControl are borderless.

If Style is 'FlatButtons', the FlatSeparators property specifies whether or not separators are drawn between the buttons. The following example illustrates the effect of setting FlatSeparators to 1.

The HotTrack property specifies whether or not the tabs or buttons in a TabControl object (which are represented by TabButton objects), are automatically highlighted by the mouse pointer.

The Align Property

The Align property specifies along which of the 4 edges of the TabControl the tabs or buttons are arranged. Align also controls the relative positioning of the picture and Caption within each TabButton. Align may be Top (the default), Bottom, Left or Right.

If Align is 'Top' or 'Bottom', the tabs or buttons are arranged along the top or bottom edge of the TabControl and the picture is drawn to the left of the Caption.

'F'⎕WC'Form' 'TabControl: Align Bottom'('Size' 25 50)
'F.TC'⎕WC'TabControl'('Align' 'Bottom')

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'One'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Two'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Three'('ImageIndex' 3)

'F.S1'⎕WC'SubForm'('TabObj' 'F.TC.T1')
'F.S2'⎕WC'SubForm'('TabObj' 'F.TC.T2')
'F.S3'⎕WC'SubForm'('TabObj' 'F.TC.T3')

If Align is 'Left' or 'Right', the tabs or buttons are arranged top-to-bottom along the left or right edge of the TabControl as shown below.

The MultiLine Property

The MultiLine property of a TabControl determines whether or not your tabs or buttons will be arranged in multiple flights or multiple rows/columns.

The default value of MultiLine is 0, in which case, if you have more tabs or buttons than will fit in the space provided, the TabControl displays an UpDown control to permit the user to scroll them.

If MultiLine is set to 1, the tabs are displayed in multiple flights.

If the TabControl has Style 'Buttons' and MultiLine is set to 1, the buttons are displayed in multiple rows.

The ScrollOpposite Property

The ScrollOpposite property specifies that unneeded tabs scroll to the opposite side of a TabControl, when a tab is selected. This only applies when MultiLine is 1.

The following example illustrates a TabControl with ScrollOpposite set to 1, after the user has clicked Third Tab. Notice that, in this example, the SubForms have been created as children of the TabControl. This is necessary to ensure that they are managed correctly in this case.

'F'⎕WC'Form' 'TabControl: ScrollOpposite'
'F.TC'⎕WC'TabControl' ('ScrollOpposite' 1)('MultiLine' 1)

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'First Tab'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Second Tab'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Third Tab'('ImageIndex' 3)
'F.TC.T4'⎕WC'TabButton' 'Fourth Tab'('ImageIndex' 1)

If MultiLine is 1, the way that multiple flights of tabs or rows/columns of buttons are displayed is further defined by the Justify property which may be 'Right' (the default) or 'None'.

The Justify Property

If Justify is 'Right' (which is the default), the TabControl increases the width of each tab, if necessary, so that each row of tabs fills the entire width of the tab control. Otherwise, if Justify is empty or 'None', the rows are ragged as shown below.

'F'⎕WC'Form' 'TabControl: MultiLine Tabs, Justify None'
'F.TC'⎕WC'TabControl'('MultiLine' 1)('Justify ' 'None')
'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')
'F.TC'⎕WS'ImageListObj' 'F.TC.IL'
'F.TC.T1'⎕WC'TabButton' 'First Tab'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Second Tab'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Third Tab'('ImageIndex' 3)
'F.TC.T4'⎕WC'TabButton' 'Fourth Tab'('ImageIndex' 1)

The next picture illustrates the effect of Justify 'None' on a TabControl with Style 'Buttons'.

The TabSize and TabJustify Properties

By default, the size of the tabs may vary from one row to another. Fixed size tabs may be obtained by setting the TabSize property.

If fixed size tabs are in effect, the positions at which the picture and Caption are drawn within each TabButton is controlled by the TabJustify property which may be 'Centre'(the default), 'Edge', or 'IconEdge'.

'F'⎕WC'Form' 'TabControl: TabJustify Centre'
'F.TC'⎕WC'TabControl'('Style' 'Buttons')('TabSize'⍬ 30)

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')
'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'One'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Two'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Three'('ImageIndex' 3)

If TabJustify is set to 'Edge' then the picture and text on the TabButton are justified along the side defined by the Align property (default 'Top').

'F'⎕WC'Form' 'TabControl: TabJustify Edge'('Size' 10 40)
'F.TC'⎕WC'TabControl'('Style' 'Buttons')
                     ('TabJustify' 'Edge')('TabSize'⍬ 30)

etc.

If, instead, the TabJustify property is set to 'IconEdge' then the text is centred and only the icons are justified.

The TabFocus Property

The TabFocus property specifies the focus behaviour for the TabControl object.

TabFocus is a character vector that may be 'Normal' (the default), 'Never' or 'ButtonDown'.

If TabFocus is 'Normal', the tabs or buttons in a TabControl do not immediately receive the input focus when clicked, but only when clicked a second time. This means that, normally, when the user circulates through the tabs, the input focus will be given to the appropriate control in the associated SubForm. However, if the user clicks twice in succession on the same tab or button, the TabControl itself will receive the input focus.

If TabFocus is 'ButtonDown', the tabs or buttons in a TabControl receive the input focus when clicked.

If TabFocus is 'Never', the tabs or buttons in a TabControl never receive the input focus. This allows the user to circulate through a set of tabbed SubForms without ever losing the input focus to the TabControl itself.


StatusBar Object

The StatusBar Object

Like the Toolbar, the StatusBar object is also a container that manages its children. However, the StatusBar may contain only one type of object, namely StatusFields. By default, the StatusBar is a flat grey object, positioned along the bottom edge of a Form, upon which the StatusFields are drawn as sunken rectangles. StatusFields display textual information and are typically used for help messages and for monitoring the status of an application. They can also be used to automatically report the status of the Caps Lock, Num Lock, Scroll Lock, and Insert keys

The following example illustrates a default StatusBar containing three StatusFields. Notice how the StatusFields are positioned automatically.

'TEST'⎕WC'Form' 'Simple StatusBar'
'TEST' ⎕WS'BCol' (255 255 255)
'TEST.SB'⎕WC'StatusBar'
'TEST.SB.S1'⎕WC'StatusField' 'Field1:' 'text1'
'TEST.SB.S2'⎕WC'StatusField' 'Field2:' 'text2'
'TEST.SB.S3'⎕WC'StatusField' 'Field3:' 'text3'

A Default StatusBar

The following example illustrates a scrolling StatusBar. The fourth StatusField extends beyond the right edge of the StatusBar and, because HScroll is ¯2, a mini scrollbar appears.

'TEST'⎕WC'Form' 'Scrolling StatusBar'
                ('BCol' (255 255 255))

'TEST.SB'⎕WC'StatusBar'('HScroll' ¯2)

'TEST.SB.S1'⎕WC'StatusField' 'Field1:' 'text1'
'TEST.SB.S2'⎕WC'StatusField' 'Field2:' 'text2'
'TEST.SB.S3'⎕WC'StatusField' 'Field3:' 'text3'
'TEST.SB.S4'⎕WC'StatusField' 'Field4:' 'text4'

A Scrolling StatusBar

As an alternative to single-row scrolling StatusBar, you can have a multi-line one. Indeed, this is the default if you omit to specify HScroll. However, you do have to explicitly set the height of the StatusBar to accommodate the second row.

'TEST'⎕WC'Form' 'Multi Line StatusBar'
                ('BCol' (255 255 255))

'TEST.SB.S1'⎕WC'StatusField' 'Field1:' 'text1'
'TEST.SB.S2'⎕WC'StatusField' 'Field2:' 'text2'
'TEST.SB.S3'⎕WC'StatusField' 'Field3:' 'text3'
'TEST.SB.S4'⎕WC'StatusField' 'Field4:' 'text4'

A Multi-line StatusBar

Using StatusFields

There are basically three ways of using StatusFields. Firstly, you can display information in them directly from your program by setting their Caption and/or Text properties. For example, if you are executing a lengthy calculation, you may wish to display the word "Calculating ..." as the Caption of a StatusField and, as the calculations proceed, display (say) "Phase 1" followed in due course by "Phase 2", and so forth. You can also use StatusFields to display application messages, including warning and error messages, where the use of a MsgBox is inappropriate.

The second major use of a StatusField is to display hints which you do by setting the HintObj property of an object to the name of the StatusField. Used in this way, a StatusField automatically displays context sensitive help when the user places the mouse pointer over an object. This topic is described in Chapter 5.The third use of a Status Field is to monitor the status of the keyboard. This is achieved by setting its Style property to one of the following keywords:

Keyword | Meaning
CapsLock | Monitors state of Caps Lock key
ScrollLock | Monitors state of Scroll Lock key
NumLock | Monitors state of Num Lock key
KeyMode | Monitors the keyboard mode (APL/ASCII) (Classic Edition only)
InsRep | Monitors the state of the Insert/Replace toggle key

The following example illustrates different uses of the StatusField object. The first StatusField F.SB.S1 is used for context-sensitive help by making it the HintObj for the Form F. The second StatusField F.SB.S2 is simply used to display application status; in this case "Ready ...". The third and fourth StatusField objects monitor the status of the Insert and Caps Lock keys respectively. Note that whilst the Caps Lock, Num Lock and Scroll Lock keys have a recognised state, the Insert key does not. Initially, APL sets the key to "Ins" and then toggles to and from "Rep" whenever the key is pressed. To discover which mode the keyboard is in, you should use ⎕WG to read the value of the Text property of the StatusField.

'F'⎕WC'Form' 'Using StatusFields'('Coord' 'Pixel')

'F.SB'⎕WC'StatusBar'

'F.SB.S1'⎕WC'StatusField'('Size'⍬ 150)
'F'⎕WS'HintObj' 'F.SB.S1'

'F.SB.S2'⎕WC'StatusField' 'Ready ...'
'F.SB.S3'⎕WC'StatusField'('Style' 'InsRep')('Size'⍬ 50)
'F.SB.S4'⎕WC'StatusField'('Style' 'CapsLock')('Size'⍬ 50)

'F.L'⎕WC'List'WINES(0 0)(F.Size×0.8 1)('Hint' 'Choose a Wine')


Using Hints

All of the GUI objects supported by Dyalog APL that have a visible presence on the screen have a Hint property and a HintObj property. Quite simply, when the user moves the mouse pointer over the object the contents of its Hint property are displayed in the object referenced by its HintObj property. When the user moves the mouse pointer away from the object, its Hint disappears. If an object has a Hint, but its HintObj property is empty, the system uses the HintObj defined for its parent, or for its parent's parent, and so forth up the tree. If there is no HintObj defined, the Hint is simply not displayed. This mechanism has two useful attributes:

  1. it allows you to easily define a single region for help messages for all of the controls in a Form, but still provides the flexibility for using different message locations for different controls if appropriate.
  2. to enable or disable the display of hints all you typically have to do is to set or clear the HintObj property on the parent Form

The object named by HintObj may be any object with either a Caption property or a Text property. Thus you can use the Caption on a Label, Form, or Button or the text in an Edit object. If you use a StatusField object which has both Caption and Text properties, the Text property is employed. If you set HintObj to the name of an object which possesses neither of these properties, the hints will simply not be displayed. The following example illustrates the use of a StatusField for displaying hints.

Example: Using a StatusField for Hints

This example illustrates the use of a StatusField object to display hints. .

    'Test'⎕WC 'Form' 'Using Hints'('HintObj' 'Test.SB.H')

    'Test.MB' ⎕WC 'MenuBar'
    'Test.MB.F' ⎕WC 'Menu' '&File'
    HINT ← 'Creates a new empty document'
    'Test.MB.F.New' ⎕WC 'MenuItem' '&New' ('Hint' HINT)

    'Test.SB' ⎕WC 'StatusBar'
    'Test.SB.H' ⎕WC 'StatusField' ('Size' ⍬ 98)

Using a StatusBar to display Hints

Example: Using an Edit Object for Hints

You can display a much larger amount of information using a multi-line Edit object as shown in this example.

     'Test'⎕WC 'Form' 'Using Hints' ('HintObj' 'Test.ED')
      'Test.MB' ⎕WC 'MenuBar'
      'Test.MB.F' ⎕WC 'Menu' '&File'
      HINT ← 100⍴'Creates a new empty document '
      'Test.MB.F.New' ⎕WC 'MenuItem' '&New' ('Hint' HINT)
      'Test.ED' ⎕WC 'Edit' ('Style' 'Multi')

Displaying Hints in an Edit object


Using Tips

Tips work in a very similar way to Hints. Most of the GUI objects that have a visible presence on the screen have a Tip property and a TipObj property. Exceptions are Menus, MenuItems and other pop-up objects. The TipObj property contains the name of a TipField object. This is a special kind of pop-up object whose sole purpose is to display tips. When the user moves the mouse pointer over the object the corresponding TipField appears displaying the object's Tip. When the mouse pointer moves away from the object, the TipField disappears. If an object has a Tip, but its TipObj property is empty, the system uses the TipObj defined for its parent, or for its parent's parent, and so forth up the tree. If there is no TipObj defined, the Tip is simply not displayed. Normally, you need only define one TipField for your application, but if you want to use different colours or fonts for individual tips, you may define as many different TipFields as you require. Again, it is very simple to turn tips on and off.

Example

This example shows how easy it is to associate a tip with an object, in this case a Button.

      'Test'⎕WC 'Form' 'Using Tips'('TipObj' 'Test.Tip')
      'Test.Tip' ⎕WC 'TipField'
      'Test.B' ⎕WC 'Button' '&Ok' ('Tip' 'Press Me')

Using Tips


Hints and Tips Combined

There is no reason why you cannot provide Hints and Tips. The next example shows how an object, in this case a Combo, can have both defined.

Example

      'Test'⎕WC 'Form' 'Using Hints and Tips'

      'Test.SB' ⎕WC 'StatusBar'
      'Test.SB.H' ⎕WC 'StatusField' ('Size' ⍬ 98)
      'Test' ⎕WS 'HintObj' 'Test.SB.H'

      'Test.Tip' ⎕WC 'TipField'
      'Test' ⎕WS 'TipObj' 'Test.Tip'

      'Test.C' ⎕WC 'Combo' WINES
      'Test.C' ⎕WS 'Hint' 'Select your wine from this
                           list'
      'Test.C' ⎕WS 'Tip' 'Wine Cellar'

Hints and Tips Combined


Defining Overall Appearance

By default, the Grid inherits its font from the parent Form, or ultimately, from the Root object. This defaults to your Windows System font.

You can change the font for the Grid as a whole using its FontObj property. This font will be used for the row titles, column titles and for the data. You can separately define the font for the data using the CellFonts property. Thus, for example, if you wanted to use Helvetica 12 for the titles and Arial 10 for the data, you could do so as follows:

      'Test.G'  ⎕WS 'FontObj' 'Helvetica' 12

      'Test.CF' ⎕WC 'Font' 'Arial' 10
      'Test.G'  ⎕WS 'CellFonts' 'Test.CF'

The FCol and BCol properties specify the foreground and background colours for the text in the data cells. The default colour scheme is black on white. FCol and BCol may define single colours which refer to all the cells, or a set of colours to be applied to different cells

The colour of the gridlines is specified by GridFCol. To draw a Grid with no gridlines, set GridFCol to the same colour as is defined by BCol.

If the Grid is larger than the space occupied by the data cells, GridBCol specifies the colour used to fill the area between the end of the last column of data and the right edge of the Grid, and between the bottom row of data and the bottom edge of the Grid.

The ClipCells property determines whether or not the Grid displays partial cells. The default is 1. If you set ClipCells to 0, the Grid displays only complete cells and automatically fills the space between the last visible cell and the edge of the Grid with the GridBCol colour.

The following example shows a default Grid (ClipCells is 1) in which the third column of data is in fact incomplete (clipped), although this is by no means apparent to the user.

This second picture shows the effect on the Grid of setting ClipCells to 0 which prevents such potential confusion.


Row and Column Titles

Row and column titles are defined by the RowTitles and ColTitles properties, each of which is a vector of character arrays. An element of RowTitles and ColTitles may be a character vector specifying a 1-row title, or a matrix or vector of vectors which specify multi-row titles.

The height of the area used to display column titles is specified by the TitleHeight property. The width of the area used to display row titles is defined by the TitleWidth property. The alignment of text within the title cells is defined by RowTitleAlign and ColTitleAlign and the colour of the text is specified by RowTitleFCol and ColTitleFCol.

Multi-level titles are also possible and are defined by the RowTitleDepth and ColTitleDepth properties. An example of what can be achieved is shown below.

     ∇ HierarchicalTitles;Q1;Q2;Q3;Q4;TITLES;CDEPTH
[1]    'F'⎕WC'Form' ''('Size' 313 362)('Coord' 'Pixel')
[2]    F.Caption←'Hierarchical Titles'
[3]    'F.G'⎕WC'Grid'(?12 6⍴100)(0 0)F.Size
[4]    F.G.(TitleWidth TitleHeight CellWidths)←120 60 40
[5]    Q1←'Q1' 'Jan' 'Feb' 'Mar'
[6]    Q2←'Q2' 'Apr' 'May' 'Jun'
[7]    Q3←'Q3' 'Jul' 'Aug' 'Sep'
[8]    Q4←'Q4' 'Oct' 'Nov' 'Dec'
[9]    TITLES←(⊂'2013'),Q1,Q2,Q3,Q4
[10]   CDEPTH←0,16⍴1 2 2 2
[11]   F.G.(RowTitles RowTitleDepth)←TITLES CDEPTH
[12]   F.G.RowTitleAlign←'Centre'
[13]   TITLES←'Wine' 'Red' 'White'
[14]   TITLES,←'Champagne' 'Red' 'White' 'Rose'
[15]   TITLES,←⊂↑'Beer' ' and' 'Cider'
[16]   CDEPTH←0 1 1 0 1 1 1 0
[17]   F.G.(ColTitles ColTitleDepth)←TITLES CDEPTH
     ∇


Displaying and Editing Values in Grid Cells

The Grid can display the value in a cell directly (as illustrated by The components of the Grid object on page 1) or indirectly via an associated object. You do not (as you might first expect) define input and validation characteristics for the cells directly, instead you do so indirectly through associated objects. Objects are associated with Grid cells by the Input property. If a cell has an associated object, its value is displayed and edited using that object. Several types of object may be associated with Grid cells, including Edit, Label, Button (Push, Radio and Check), and Combo objects. You can use a single associated object for the entire Grid, or you can associate different objects with individual cells.

Edit and Label objects impose formatting on the cells with which they are associated according to the values of their FieldType and Decimal properties (for numbers, dates and time) and their Justify property (for text). In addition, Label objects protect cells (because a Label has no input mechanism), while Edit objects impose input validation. If you use an Edit object with a FieldType of Numeric, the user may only enter numbers into the corresponding cells of the Grid. For both Edit and Label objects, the FieldType and Decimals properties of the object are used to format the data displayed in the corresponding cells of the Grid. For example, if the FieldType property of the associated object is Date, the numeric elements in Values will be displayed as dates.

Numeric cells may also be formatted using the FormatString property which applies ⎕FMT format specifications to the data. The AlignChar property permits formatted data to be aligned in a column. For example, you can specify that numbers in a column are aligned on their decimal points.

Combo objects can be used to allow the user to select a cell value from a set of alternatives. Radio and Check Buttons may be used to display and edit Boolean values.

Associated Edit, Label and Combo objects may be external to the Grid (for example, you can have the user type values into a companion edit field) or they may be internal. Internal objects (which are implemented as children of the Grid) float from cell to cell and allow the data to be changed in-situ. Button, Spinner and TrackBar objects may only be internal.

Using a Floating Edit Field

If the Edit object specified by Input is owned by (i.e. is a child of) the Grid itself, the Edit object floats from cell to cell as the user moves around the Grid. For example, if the user clicks on the cell addressed by row 4, column 3, the Edit object is automatically moved to that location and the data in that cell is copied into it ready for editing. When the user moves the focus away from this cell, the data in the Edit object is copied back into it (and into the corresponding element of the Values property) before the Edit object is moved away to the new cell location. This mechanism provides in-situ editing. Continuing the example illustrated by The components of the Grid object on page 1, in-situ editing could be achieved as follows:

      'Test.G.ED' ⎕WC 'Edit' ('FieldType' 'Numeric')
      'Test.G'    ⎕WS 'Input' 'Test.G.ED'

In-situ editing provides two input modes; Scroll and InCell. In Scroll mode the cursor keys move from one cell to another. In InCell mode, the cursor keys move the cursor a character at a time within the cell; to switch to a new cell, the user must press the Tab key or use the mouse. The InputMode property allows you to control the input mode directly or to allow the user to switch from one to another. In the latter case, the user does so by pressing a key defined by the InputModeKey property or by double-clicking the left mouse button.

Using a Fixed Edit Field

A different style of editing may be provided by specifying the name of an external Edit object that you have created. This can be any Edit object you wish to use; it need not even be owned by the same Form as the Grid. In this case, the Edit object remains stationary (wherever you have positioned it), but as the user moves the focus from cell to cell, the cell contents are copied into it and made available for editing. The current cell is identified by a thick border. When the user shifts the focus, the data is copied out from the Edit object into the corresponding cell before data in the newly selected one is copied in. Continuing the example illustrated by The components of the Grid object on page 1, external editing could be achieved as follows:

      'Test.ED'   ⎕WC 'Edit' ('FieldType' 'Numeric')
      'Test.G'    ⎕WS 'Input' 'Test.ED'

Using Label Objects

If Input specifies a Label object, it too may either be a child of the Grid or an external Label. A Label is useful to format cell data (through its FieldType property) and to protect cells from being changed

If the Label is a child of the Grid, it floats from cell to cell in the same way as a floating Edit object. However, unlike the situation with other objects, the row and column titles are not indented to help identify the current cell. If the Label is borderless (which is the default) and has the same font and colour characteristics of the cells themselves, the user will receive no visual feedback when a corresponding cell is addressed, even though the current cell (reflected by the CurCell property) does in fact change. Therefore, if you want to protect the data by using a Label and you want the user to be able to identify the current cell, you should give the Label a border, a special colour scheme or a special font.

Using Combo Objects

A Combo object is used to present a list of choices for a cell. Although you may use an external Combo, internal Combos are more suitable for most applications. If different cells have different sets of choices, you can create several Combo objects, each with its own set of Items and associate different cells with different Combos through the CellTypes property. Alternatively, you can use a single Combo and change Items dynamically from a callback on the CellMove event. In all cases, the value in the cell corresponds to the Text property of the Combo.

If you use a floating Combo, the appearance of the non-current cells depends upon the value of the ShowInput property. If ShowInput is 0 (the default), the non-current cells are drawn in the standard way as if there were no associated input object. If ShowInput is 1, the non-current cells are given the appearance of a Combo, although the system does not actually use Combos to do so. Furthermore, there is a subtle difference in behaviour. If ShowInput is 0, the user must click twice to change a value; once to position the Combo on the new cell and again to drop its list box. If ShowInput is 1, the user may drop the list box with a single click on the cell.

Note that ShowInput may be a scalar that applies to the whole Grid, or a vector whose elements applies to different cells through the CellType property.

The following Grid uses two internal Combo objects for the Job Title and Region columns, but with ShowInput set to 0. Only the current cell has Combo appearance.

     ∇ Employees;Surname;JobTitle;Region;Salary;DATA;Jobs;Regions
[1]    'F'⎕WC'Form' ''('Size' 126 401)('Coord' 'Pixel')
[2]    F.Caption←'Employee DataBase'
[3]    Surname←'Brown' 'Jones' 'Green' 'Black' 'White'
[4]    JobTitle←'Manager' 'Project Leader' 'Consultant'
[5]    JobTitle,←'Programmer' 'Assistant'
[6]    Region←'South' 'South' 'South' 'East' 'Central'
[7]    Salary←64000 43250 45000 30000 4000
[8]    DATA←↑[0.5]Surname JobTitle Region Salary
[9]    'F.G'⎕WC'Grid'DATA(0 0)F.Size
[10]   Jobs←JobTitle
[11]   Regions←'North' 'South' 'East' 'West' 'Central'
[12]   'F.G.JobTitle'⎕WC'Combo'Jobs
[13]   'F.G.Region'⎕WC'Combo'Regions
[14]   'F.G.Salary'⎕WC'Label'('FieldType' 'Currency')
[15]   F.G.Input←'' 'F.G.JobTitle' 'F.G.Regions' 'F.G.Salary'
[16]   F.G.CellTypes←(⍴F.G.Values)⍴1 2 3 4
[17]   F.G.TitleWidth←0
[18]   F.G.ColTitles←'Surname' 'Job Title' 'Region' 'Salary'
     ∇

The same Grid with ShowInput set to 1 is illustrated below. In this case, all of the cells associated with Combo objects have Combo appearance.

      F.G.ShowInput
0
      F.G.ShowInput←1

Using Radio and Check Button Objects

Radio and Check Buttons behave in a similar way to Combo objects except that they may only be used internally. The value in the cell associated with the Button must be 0 or 1 and corresponds to the Button's State property. The value is toggled by clicking the Button.

If ShowInput is 0, the user must click twice to change a value; once to position the (floating) Button on the cell, and a second time to toggle its state. If ShowInput is 1, the user may change cell values directly with a single click. Note that this may be undesirable in certain applications because the user cannot click on a cell without changing its value.

By default, the value of the EdgeStyle property for a Radio or Check Button which is created as the child of a Grid is 'None', so you must set EdgeStyle explicitly to 'Plinth' if a 3-dimensional appearance is required.

You can refine the appearance of the Radio or Check Button using its Align property. This may be set to 'Left', 'Right' or 'Centre' (and 'Center'). The latter causes the symbol part of the Button (the circle or checkbox) to be centred within the corresponding Grid cell(s) but should only be used if the Caption property is empty.

The following illustrates different values for the Align property using Check Buttons.

     ∇ AlignedCheckBoxes;CStyle
[1]    'F'⎕WC'Form' 'Aligned Check Boxes in a Grid'
[2]    'F.G'⎕WC'Grid'(¯1+?10 3⍴2)(0 0)(100 100)('ShowInput' 1)
[3]    CStyle←('Style' 'Check')('EdgeStyle' 'Plinth')
[4]    'F.G.C1'⎕WC'Button' 'Left',CStyle,('Align' 'Left')
[5]    'F.G.C2'⎕WC'Button' '',CStyle,('Align' 'Centre')
[6]    'F.G.C3'⎕WC'Button' 'Right',CStyle,('Align' 'Right')
[7]
[8]    'F.G'⎕WS'Input'('F.G.C1' 'F.G.C2' 'F.G.C3')
[9]    'F.G'⎕WS'CellTypes'(10 3⍴1 2 3)
     ∇


Specifying Individual Cell Attributes

The FCol, BCol, CellFonts and Input properties can be used to specify attributes of individual cells. One possible design would be for these properties to be matrices like the Values property, each of whose elements corresponded to a cell in the Grid. However, although conceptually simple, this design was considered to be wasteful in terms of workspace, especially as it is unlikely that every cell will require a totally individual set of attributes. Instead, FCol, BCol, CellFonts and Input either specify a single attribute to be applied to all cells, or they specify a vector of attributes which are indexed through the CellTypes property. This design is slightly more complex to use, but minimises the workspace needed to represent cell information.

CellTypes is an integer matrix of the same size as Values. Each number in CellTypes defines the type of the corresponding cell, where type means a particular set of cell attributes defined by the BCol, FCol, CellFonts and Input properties.

If an element of CellTypes is 0 or 1, the corresponding cell is displayed using the normal value of each of the FCol, BCol, CellFonts and Input properties. The normal value is either the value defined by its first element or, if the property has not been specified, its default value.

If an element of CellTypes is greater than 1, the corresponding element of each of the FCol, BCol, CellFonts and Input properties is used. However, if a particular property applies to all cells, you need only specify one value; there is no need to repeat it. This mechanism is perhaps best explained by using examples.

Example 1

Suppose that you want to use a Grid to display a numeric matrix DATA and you want to show elements whose value exceeds 150 with a grey background. Effectively, there are 2 different types of cell; normal white ones and dark grey ones. This can be achieved as follows:

DATA←?12 3⍴300
 'F'⎕WC'Form' 'Example 1'
 'F.G'⎕WC'Grid'DATA(0 0)F.Size
 'F.G'⎕WS'CellTypes'(1+DATA>150)
 'F.G'⎕WS'BCol'(192 192 192)(128 128 128)

CellTypes[] is either 1 or 2, according to whether the value in the corresponding cell is 150 or less. So the cells whose value is 150 or less use BCol[1] which is 255 255 255 (white) whereas those cells whose value is >150 use BCol[2] which is 192 192 192 (grey).

Example 2

Continuing on from the first example, suppose that in addition, you want to show values that exceed 200 with a white background, but using a bold font. Now you have 3 types of cell; white background with normal font, grey background with normal font, and white background with bold font. This can be done as follows:

 CT←(DATA>200)+1+DATA>100
 'F.G'⎕WS'CellTypes'CT
 COL←(255 255 255)(192 192 192)(255 255 255)
 'F.G'⎕WS'BCol'COL
 'Normal'⎕WC'Font' 'Arial' 16
 'Bold'⎕WC'Font' 'Arial' 16('Weight' 1000)
 'F.G'⎕WS'CellFonts' 'Normal' 'Normal' 'Bold'

In this example, there are three different sets of attributes, selected according to where the value in CellTypes[] is 1, 2 or 3.

  1. Normal font + white background (255 255 255)
  2. Normal font + grey background (192 192 192)
  3. Bold font + white background (255 255 255)

The value in CellTypes is given by the expression (DATA>200)+1+DATA>100, so cells whose value is:

  • less than 100 use CellFonts[1] and BCol[1]
  • between 100 and 200 use CellFonts[2] and BCol[2]
  • between 100 and 200 use CellFonts[3] and BCol[3]

Example 3

This is a more complex example that introduces different uses of the Input property to handle numeric and date cells. Suppose that you wish to display the names, date of birth, and salaries of some people. The user may edit the salary and date of birth, but not the name. Salaries in excess of $19,999 are to be shown in bold

This means that we need 4 types of cell; the "names" cells, the "date of birth" cells, the cells containing salaries below $20,000 and those cells containing $20,000 or more. The Input property must specify 3 different objects; a Label for the protected "names" cells, an Edit object for the "date" cells, and a different Edit object for the salaries. The CellFonts property must specify the two different fonts required; normal and bold.

 'F'⎕WC'Form' 'Example 3'
 'F.G'⎕WC'Grid'('Posn' 0 0)F.Size
 'F.G'⎕WS'Values'(↑[0.5]NAMES BIRTHDATES SALARIES)

 CT←1,2,[1.5]3+SALARIES>19999
 'F.G'⎕WS'CellTypes'CT

 'F.G.Name'⎕WC'Label'('FontObj' 'Normal')
 'F.G.Date'⎕WC'Edit'('FieldType' 'Date')
 'F.G.Sal'⎕WC'Edit'('FieldType' 'Currency')
 INPUTS←'F.G.Name' 'F.G.Date',2⍴⊂'F.G.Sal'
 'F.G'⎕WS'Input'INPUTS

 'Normal'⎕WC'Font' 'Arial' 16
 'Bold'⎕WC'Font' 'Arial' 16('Weight' 1000)
 FONTS←(3⍴⊂'Normal'),⊂'Bold'
 'F.G'⎕WS'CellFonts'FONTS


Drawing Graphics on a Grid

You may draw graphics on a Grid by creating graphical objects (Circle, Ellipse, Image, Marker, Poly, Rect and text) as children of the Grid.

For the Grid (but only for the Grid) the Coord property may be set to 'Cell' as an alternative to 'Prop', 'Pixel' or 'User'. This allows you to easily position graphical objects relative to individual cells or ranges of cells. The origin of the Grid (0,0) is deemed to be the top left corner of the data (i.e. the area inside the row and column titles). In Cell co-ordinates, the value (1,1) is therefore the bottom right corner of the first cell. Regardless of the coordinate system, graphical objects scroll with the data.

The following example illustrates how to draw a box around the cells in rows 2 to 4 and columns 3 to 6.

 'F'⎕WC'Form' 'Graphics on a Grid'('Coord' 'Pixel')
 'F.G'⎕WC'Grid'(?10 10⍴100)(0 0)F.Size('CellWidths' 40)
 'F.G.L'⎕WC'Rect'(1 2)(3 4)('LWidth' 4)('Coord' 'Cell')

The OnTop property of the graphical object controls how it is drawn relative to the grid lines and cell text. For graphical objects created as a child of a Grid, OnTop may be 0, 1 or 2.

0 | Graphical object is drawn behind grid lines and cell text
1 | Graphical object is drawn on top of grid lines but behind cell text
2 | Graphical object is drawn on top of grid lines and cell text

The following example shows the effect of the OnTop property on how an Image is drawn on a Grid.

'F'⎕WC'Form' 'Graphics on a Grid'('Coord' 'Pixel')
 'F.G'⎕WC'Grid'(?10 10⍴100)(0 0)F.Size('CellWidths' 40)
 DyalogDir←2 ⎕NQ'.' 'GetEnvironment' 'Dyalog'
 'F.M'⎕WC'Metafile'(DyalogDir,'\WS\DOLLAR')
 'F.G.I'⎕WC'Image'(0 0)('Size' 10 10)('Coord' 'Cell')

 'F.G.I'⎕WS('Picture' 'F.M')('OnTop' 0)

      F.G.I.OnTop←1

      F.G.I.OnTop←2


Controlling User Input

The Grid object is designed to allow you to implement simple applications with very little programming effort. You merely present the data to be edited by setting the Values property and then get it back again once the user has signalled completion. The validation imposed by the associated Edit object(s) will prevent the user from entering invalid data and your program can leave the user interaction to be managed entirely by APL. However, for more sophisticated applications, the Grid triggers events which allow your program to respond dynamically to user actions.

Moving from Cell to Cell

When the user moves from one cell to another, the Grid generates a CellMove event. This reports the co-ordinates (row and column) of the newly selected cell. The CellMove event serves two purposes. Firstly, it allows you to take some special action when the user selects a particular cell. For example, you could display a Combo or List object to let the user choose a new value from a pre-defined set, then copy the selected value into the cell. Secondly, the CellMove event provides the means for you to position the user in a particular cell under program control, using ⎕NQ.

Changing Standard Validation Behaviour

Input validation is provided by the Edit object associated with a cell. By default, the built-in validation will prevent the user from leaving the cell should the data in that cell be invalid. For example, if the FieldType is 'Date' and the user enters 29th February and a non-leap year, APL will beep and not allow the user to leave the cell until a valid date has been entered If you wish instead to take some other action, for example display a message box, you should use the CellError event. This event is generated immediately the user attempts to move to another cell when the data in the current cell is invalid. The event is also generated if the user selects a MenuItem, presses a Button or otherwise changes the focus away from the current cell.

The CellError event reports the row and column number of the current cell, the (invalid) text string in that cell, the name of the object to which the user has transferred attention or the co-ordinates of the new cell selected. The default action of the event is to beep, so to disable the beep your callback function should return a 0. If you wish to allow the user to move to a different cell, you must do so explicitly by generating a CellMove event using ⎕NQ or by returning a CellMove event as the result of the callback.

Reacting to Changes

If enabled, the Grid object generates a CellChange event whenever the user alters data in a cell and then attempts to move to another cell or otherwise shifts the focus away from the current cell. This allows you to perform additional validation or to trigger calculations when the user changes a value. The CellChange event reports the co-ordinates of the current cell and the new value, together with information about the newly selected cell or the external object to which the focus has changed.

The default action of the CellChange event is to replace the current value of the cell with the new one. If you wish to prevent this happening, your callback function must return a 0. If in addition you wish the focus to remain on the current cell, you must do this explicitly by using the CellMove event to reposition the current cell back to the one the user has attempted to leave.

Restoring User Changes

The Grid object supports an Undo method which causes the last change made by the user to be reversed. This method can only be invoked under program control using ⎕NQ and cannot be directly generated by the user. If you want to provide an undo facility, it is recommended that you attach a suitable callback function to a MenuItem or a Button. To perform an undo operation, the callback function should then generate an Undo event for the Grid object.

Updating Cell Data

You can change the entire contents of the Grid by resetting its Values property with ⎕WS. However, this will causes the entire Grid to be redrawn and is not to be recommended if you only want to change one cell or just a few cells.

You can change the value in a particular cell by using ⎕NQ to send a CellChange event to the Grid. For example, if you want to alter the value in row 2 column 3 of the Grid object called Test.G to 42, you simply execute the following statement :

      ⎕NQ 'Test.G' 'CellChange' 2 3 42

To update an entire row or column of data you can use the RowChange and ColChange events. For example, to change all 12 columns of row 500 to the 12-element vector TOTAL, you could execute :

      ⎕NQ 'Test.G' 'RowChange' 500 TOTAL

Deleting Rows and Columns

You can delete a row or column by using ⎕NQ to send a DelRow or DelCol message to the Grid object. For example, the following statement deletes the 123rd row from the Grid object Test.G. Note that if you have specified it, the corresponding element of RowTitles is removed too.

      ⎕NQ 'Test.G' 'DelRow' 123

Inserting Rows and Columns

You can insert or add a row or column using the AddRow or AddCol method. You must specify the following information.

row or column number
title (optional)
height or width (optional)
undo flag (optional)
resize flag (optional)
title colour (optional)
gridline type (optional)

The event message must specify the number of the row or column you wish to insert. This is index-origin dependent and indicates the number that the row or column will have after it has been inserted. For example, if ⎕IO is 1 and you wish to insert a row between the 10th and 11th rows, you specify the number of the row to be inserted as 11. If you wish to insert a new column before the first one, you specify a column number of 1. To append a row or column to the end of the Grid, you should specify 1 + the current number of rows or columns.

If you have specified RowTitles or ColTitles, the message may include a title for the new row or column and this will be inserted in RowTitles or ColTitles as appropriate. If you fail to supply a new title, an empty vector will be inserted in RowTitles or ColTitles for you. If you are using default row and column headers and you have not specified RowTitles or ColTitles, any title you supply will be ignored. In this case the rows and columns will be re-labelled automatically.

If you have set CellHeights or CellWidths to a vector, the AddRow or AddCol event message may include the height or width of the new row or column being inserted. If you fail to supply one or you specify a value of ¯1 the default value will apply. Note that setting the height or width to 0 is allowed and will cause the new row or column to be invisible. If CellHeights or CellWidths has not been specified or is a scalar, the new row or column will be given the same height or width as the others and any value that you specify is ignored.

The undo flag indicates whether or not the insertion will be added to the undo stack and may therefore be subsequently undone. Its default value is 1.

If the data in the Grid is entirely numeric, the new row or column will be filled with zeros. If not, it will be filled with empty character vectors. If you want to set the row or column data explicitly, you should invoke the ChangeRow or ChangeCol immediately after the AddRow or AddCol event. The ChangeRow and ChangeCol event require just the row or column number followed by the new data.

The following example adds a new row entitled "Chateau Latour" to a Grid object called Test.G. The first statement adds a new row between rows 122 and 123 (it becomes row 123) of the Grid. It will be of default height (or the same as all the other rows) and the change may not be undone (the undo flag is 0). The second statement sets the data in the new row to the values defined by the vector LATOUR_SALES.

      ⎕NQ 'Test.G' 'AddRow' 123 'Chateau Latour' ¯1 0
      ⎕NQ 'Test.G' 'ChangeRow' 123 LATOUR_SALES


TreeView Feature

Introduction

The Grid can display a TreeView like interface in the row titles and automatically shows and hides row of data as the user expands and contracts nodes of the tree.

RowTreeDepth property

The tree structure is specified by the RowTreeDepth property. This is either a scalar 0 or an integer vector of the same length as the number of rows in the grid. RowTreeDepth is similar to the Depth property of the TreeView object.

Each element of RowTreeDepth specifies the depth of the corresponding row of the Grid. A value of 0 indicates that the row is a top-level row. A value of 1 indicates that the corresponding row is a child of the most recent row whose RowTreeDepth is 0; a value of 2 indicates that the corresponding row is a child of the most recent row whose RowTreeDepth is 1, and so forth.

The picture below illustrates the initial appearance of a Grid with TreeView behaviour. Notice that at first only the top-level rows are displayed.

The tree structure is defined on TreeGrid[26]. In this example, the Grid has top-level rows (RowTreeDepth of 0) that contain annual totals. The second-tier rows (RowTreeDepth of 1), contain quarterly totals, while the third-tier rows (RowTreeDepth of 2) contain monthly figures.

     ∇ TreeGrid;SIZE;YR;YRS;DATA;MDATA;QDATA;YDATA;IX
[1]    SIZE←126 381
[2]    'F'⎕WC'Form' 'Grid: TreeView Feature'
                    ('Coord' 'Pixel')
[3]    F.Size←SIZE
[4]    'F.MB'⎕WC'MenuBar'
[5]    'F.MB.View'⎕WC'Menu' 'View'
[6]    'F.MB.View.Expand1'⎕WC'MenuItem' 'Expand Years'
[7]    'F.MB.View.Expand1'⎕WS'Event' 'Select'
                             '⍎F.G.RowSetVisibleDepth 1'
[8]    'F.MB.View.Expand2'⎕WC'MenuItem' 'Expand All'
[9]    'F.MB.View.Expand2'⎕WS'Event' 'Select'
                             '⍎F.G.RowSetVisibleDepth 2'
[10]   'F.MB.View.Collapse'⎕WC'MenuItem' 'Collapse All'
[11]   'F.MB.View.Collapse'⎕WS'Event' 'Select'
                              '⍎F.G.RowSetVisibleDepth 0'
[12]   'F.G'⎕WC'Grid'('Posn' 0 0)SIZE
[13]   F.G.(TitleWidth CellWidths←80 60)
[14]   YR←'Q1' 'Jan' 'Feb' 'Mar' 'Q2' 'Apr' 'May' 'Jun'
[15]   YR,←'Q3' 'Jul' 'Aug' 'Sep' 'Q4' 'Oct' 'Nov' 'Dec'
[16]   YRS←'2000' '2001' '2002' '2003' '2004'
[17]   F.G.RowTitles←⊃,/(⊂¨YRS),¨⊂YR
[18]   MDATA←12 5⍴5/100+⍳12
[19]   YDATA←+⌿MDATA
[20]   QDATA←(3+/[1]MDATA)[1 4 7 10;]
[21]   MDATA←((⍴YR)⍴0 1 1 1)⍀MDATA
[22]   MDATA[1 5 9 13;]←QDATA
[23]   YDATA←YDATA,[1]MDATA
[24]   DATA←⊃,[1]/1 1.1 1.2 1.3 1.4×⊂YDATA
[25]   F.G.Values←DATA
[26]   F.G.RowTreeDepth←(⍴F.G.RowTitles)⍴0,(⍴YR)⍴1 2 2 2
     ∇

When the user clicks on one of the nodes indicated by a "+" symbol, the Grid automatically expands to display the rows at the next level below that node. At the same time, an Expanding event is generated. In the next picture, the user has clicked on the 2001 node and, below that, the Q3 node.

RowSetVisibleDepth Method

The Grid provides a RowSetVisibleDepth method that provides tier-level control over which rows are displayed.

The value of its argument is an integer that specifies the depth of rows to be displayed. The Grid displays all rows whose RowTreeDepth values are less than or equal to this value. In the example, this method is called by items on the View menu.

The next picture shows how the Grid is displayed after choosing Expand Years from the View menu. Notice that, as specified by TreeGrid[6] this menu item simply executes the RowSetVisibleDepth method with an argument of 1.

Similarly, the Expand All item executes RowSetVisibleDepth 2, as specified by TreeGrid[7] and this causes the Grid to display all rows up to and including RowTreeDepth of 2 as shown below.

Note that the Collapse All item executes RowSetVisibleDepth 0, which causes only the top-level rows to be displayed.

You may open specific nodes by invoking the Expanding event as a method.

Fine control over the appearance of the tree is provided through the RowTreeImages and RowTreeStyle properties. See Object Reference for further details.


Grid Comments

Introduction

Grid comments are implemented in a manner that is consistent with the way comments are handled in Microsoft Excel.

If a comment is associated with a cell, a small red triangle is displayed in its top right corner. When the user rests the mouse pointer over a commented cell, the comment is displayed as a pop-up with an arrow pointing back to the cell to which it refers. The comment disappears when the mouse pointer is moved away. This is referred to as tip behaviour.

It is also possible to display and hide comments under program control. A comment window displayed under program control does not (normally) disappear automatically when the user moves the mouse, but instead must be hidden explicitly. It is therefore possible to have several comments visible.

Implementation

Because comments are typically sparse, this facility is implemented by a small set of methods rather than as a property, and comments are stored internally in data structures that minimise storage space. The following methods and events are provided.

Event/Method | Number | Description
AddComment | 220 | Associates a comment with a cell
DelComment | 221 | Deletes the comment associated with a particular cell
GetComment | 222 | Retrieves the comment associated with a given cell
ShowComment | 223 | Displays a comment either as a pop-up or on-top window
HideComment | 224 | Hides a comment
ClickComment | 225 | Reported when user clicks the mouse on a comment window

A comment is described by its text content and the size of the window in which it appears. The text may optionally be Rich Text (RTF) such as that produced by the value of the RTFText property of a RichEdit object. The size of the window is specified in pixels.

AddComment Method

This method is used to add a new comment. For example, the following statement associates a comment with the cell at row 2, column 1; the text of the comment is "Hello", and the size of the comment window is 50 pixels (high) by 60 pixels (wide).

      2 ⎕NQ'F.G' 'AddComment' 2 1 'Hello' 50 60

The height and width of the comment window, specified by the last 2 elements of the right argument to ⎕NQ are both optional. If the cell already has an associated comment, the new comment replaces it.

Note that just before the comment is displayed, the Grid generates a ShowComment event which gives you the opportunity to (temporarily) change the text and/or window size of a comment dynamically.

DelComment Method

This method is used to delete a comment. For example, the following expression removes the comment associated with the cell at row 2, column 1.

      2 ⎕NQ'F.G' 'DelComment' 2 1

If the row and column number are omitted, all comments are deleted.

GetComment Method

This method is used to retrieve the comment associated with a cell. For example, the following expression retrieves the comment associated with the cell at row 3, column 1.

      ⎕←2 ⎕NQ 'F.G' 'GetComment' 3 1
 1 3  Hello  175 100

If there is no comment associated with the specified cell, the result is a scalar 1.

ShowComment Event/Method

If enabled, a Grid will generate a ShowComment event when the user rests the mouse pointer over a commented cell. You may use this event to modify the appearance of the comment dynamically.

You may display the comment associated with a particular cell under program control by generating a ShowComment event using ⎕NQ. By default, a comment displayed under program control does not exhibit tip behaviour but remains visible until it is explicitly removed using the HideComment method.

Note that a comment will only be displayed if the specified cell is marked as a commented cell.

HideComment Event/Method

If enabled, a HideComment event is generated just before a comment window is hidden as a result of the user moving the mouse-pointer away from a commented cell.

Invoked as a method, HideComment is used to hide a comment that has previously been displayed by ShowComment. For example, the following expression hides the comment associated with the cell at row 2, column 1.

      2 ⎕NQ'F.G' 'HideComment' 2 1

ClickComment Event

If enabled, a ClickComment event is generated when the user clicks the mouse in a comment widow. The event message reports the co-ordinates of the cell. The result of a callback function (if any) is ignored.


Multiple Document Interface Applications

The multiple-document interface (MDI) is a document-oriented interface that is commonly used by word-processors, spreadsheets and other applications that deal with documents. An MDI application allows the user to display multiple documents at the same time, with each document displayed in its own window. Document windows are implemented as child forms that are contained within a parent form. When a child form is minimised, its icon appears on the parent form instead of on the desktop. An example MDI application is illustrated below.

Child forms displayed within an MDIClient

In general, the parent form in an MDI application may also contain tool bars and status bars and potentially other objects. This means that not all of the internal area of the parent form is available. To allow for this and to distinguish MDI behaviour from that of simple child forms, Dyalog APL/W uses an MDIClient object.

The MDIClient object is a container object that effectively specifies the client area within the parent Form in which the SubForms are displayed. The MDIClient object also imposes special MDI behaviour which is quite different from that where a SubForm is simply the child of another Form.

By default, the MDIClient occupies the entire client area within its parent Form. This is the area within the Form that is not occupied by ToolBars and StatusBars. In most applications it is therefore not necessary to specify its Posn and Size properties, although you may do so if you want to reserve additional space in the parent Form for other objects.

To Create an MDI Application

  1. Create a Form (this will be the parent form for the application).
  2. Add MenuBar, ToolBar and StatusBar objects as appropriate as children of the parent Form.
  3. Create an MDIClient object as a child of the parent Form.
  4. Create the application's SubForms as children of the MDIClient, not as children of the parent Form.


MDI Behaviour

  • All child forms are displayed within the MDIClient. Forms may be moved and resized but they are restricted to the MDIClient and will be clipped if they extend beyond it.
  • When a child form is minimised, its icon appears on the MDIClient rather than on the desktop.
  • When a SubForm is maximised, its Caption is combined with the Caption of the parent Form, i.e. the parent of the MDIClient object and is displayed in the parent Form's title bar. In addition, the SubForm's system menu and restore button are displayed in the parent Form's MenuBar.
  • You cannot hide a SubForm. Setting its Visible property to 0 has no effect.
  • A SubForm does not display its MenuBar. Instead, it is displayed in place of the parent Form's MenuBar when the SubForm has the focus.

The effect of maximising a SubForm


Menus in MDI Applications

A feature of MDI behaviour is that SubForms do not display menu bars. However, if you create a MenuBar object for a SubForm, that object will be displayed as the menu bar of the parent Form whenever the SubForm has the focus. If there are no SubForms or if the SubForm with the focus does not own a MenuBar, the MenuBar of the parent Form is displayed. This mechanism provides one way of achieving the desired effect, namely that the menu bar displayed is appropriate for the type of document represented by the SubForm that has the focus. However, if you have a large number of SubForms of the same type (i.e. which share the same menu bar) you must defined identical MenuBar objects for all of them.

An alternative approach is to define separate MenuBar objects as children of the parent Form, only one of which is visible. Then you simply attach a callback function to the GotFocus event for each SubForm that makes the appropriate MenuBar visible. This approach means that you need only define MenuBar objects for each different type of SubForm, rather than for every one.

It is possible to mix these techniques, so that the MenuBar displayed is either the result of your callback function making it visible, or because a SubForm has its own MenuBar object defined and received the focus.

Note that when the user maximises a SubForm, its system menu button and restore button are displayed in the parent Form's menu bar. It is therefore essential that you ensure that your application provides such a menu bar at all times. Otherwise, when your user maximises a SubForm there is no way to reverse it.


Defining a Window Menu

Most MDI applications incorporate a Window menu. This is a special menu that displays the captions of all open SubForms as shown below. The caption of the SubForm which currently has the focus is checked and the user can switch focus to another SubForm by selecting it from the Window menu.

The Window menu

The task of updating the Window menu with the names of the SubForms is performed for you by Dyalog APL/W. You nominate the menu to be used for this purpose by setting the MDIMenu property of the appropriate MenuBar object. For example, if your MenuBar is called F1.MB and the menu you want to use as the Window menu is called F1.MB.WM, you would type the following:

      'F1.MB' ⎕WS 'MDIMenu' 'WM'

Notice that the name you specify is just the name of the menu itself, not its full pathname. If you have several MenuBars in your application, you must specify the MDIMenu property separately for each one.


Arranging Child Forms and Icons

Another common feature of MDI applications is that the user can ask for the SubForms to be displayed in a particular way, or that any SubForm icons are arranged in an orderly fashion. This is implemented in Dyalog APL/W by your application invoking an method using ⎕NQ. The MDIClient recognises three different methods, namely MDICascade (110), MDITile (111) and MDIArrange (112).

The MDICascade method causes the child forms to be arranged in an overlapping manner. The MDITile method causes them to be tiled, either horizontally or vertically. Finally, the MDIArrange method arranges any child form icons in an orderly fashion. The most convenient way to provide these actions is to attach a Callback function to appropriate MenuItems. The callback function is called with different left arguments according to the MenuItem selected. The following code snippet illustrates this technique.

The following lines define callbacks for each of the MenuItem objects in the Menu F1.MB.WM. Each one uses the callback function MDI_ARRANGE, but with a left argument corresponding to the message that must be sent to the MDIClient to cause the desired action. For example, clicking the MenuItem named F1.MB.WM.Vert runs MDI_ARRANGE with a left argument of (111 1)

'F1.MB.WM.CASCADE' ⎕WS 'Event' 30 'MDI_ARRANGE' 110
'F1.MB.WM.HORZ'    ⎕WS 'Event' 30 'MDI_ARRANGE' (111 0)
'F1.MB.WM.VERT'    ⎕WS 'Event' 30 'MDI_ARRANGE' (111 1)
'F1.MB.WM.ARRANGE' ⎕WS 'Event' 30 'MDI_ARRANGE' 112

The MDI_ARRANGE function uses its left argument to construct a message for the MDIClient object, in this case F1.MDI, and returns it as a result. This causes the desired action.

     ∇ MSG←M MDI_ARRANGE MSG
[1]    MSG←(⊂'F1.MDI'),M
     ∇

An alternative approach which does not require a callback function is to use ⎕NQ

'F1.MB.WM.CASCADE' ⎕WS 'Event' 30 '⍎⎕NQ ''F1.MDI 110'''
'F1.MB.WM.HORZ'    ⎕WS 'Event' 30 '⍎⎕NQ ''F1.MDI 111 0'''
'F1.MB.WM.VERT'    ⎕WS 'Event' 30 '⍎⎕NQ ''F1.MDI 111 1'''
'F1.MB.WM.ARRANGE' ⎕WS 'Event' 30 '⍎⎕NQ ''F1.MDI 112'''


Introduction

Dyalog APL supports dockable Forms, SubForms, CoolBands and ToolControls.

If an object is dockable, the user may drag it to a different position within the same container, drag it out of its current container and drop it onto a different container, or drop it onto the desktop as a free-floating window. An undocked object can subsequently be redocked in its original container or in another.

For example, a SubForm can be dragged from one Form and docked into another. Or a CoolBand can be dragged out of its CoolBar and turned into a top-level Form on the desktop.

With the exception of ToolControls, when a dockable object is docked or undocked, the full Name and Type of the object change according to the following table.

 | Parent Object
Dockable Object | Form F1 | SubForm F1.S1 | CoolBar F1.CB1 | Root (.)
Form F2 | SubForm F1.F2 | SubForm F1.S1.F2 | CoolBand F1.CB1.F2 | Form F2
Form F1.F2 | SubForm F1.F2 | SubForm F1.S1.F2 | CoolBand F1.CB1.F2 | Form F1.F2
SubForm F2.S2 | SubForm F1.F2 | SubForm F1.S1.F2 | CoolBand F1.CB1.F2 | Form S2
CoolBand F2.CB2.C2 | SubForm F1.C2 | SubForm F1.S1.C2 | CoolBand F1.CB1.C2 | Form C2

For example, a top-level Form F2 when docked in another top-level Form F1, becomes a SubForm named F2.F1.

;

Similarly, a CoolBand named F2.CB2.C2 when dragged from its CoolBar F2.CB2 and dropped over the desktop, becomes a top-level Form named C2.

Notice how the node name of the object remains the same, but its full pathname changes as it is moved from one parent object to another.

When an object changes Type in this way, the values of all its properties for its original Type are remembered, and these are automatically restored when the object reverts back to its original Type. Since an object can change Type between Form, SubForm, and CoolBand, it follows that there are effectively 3 different sets of properties associated with the object. However, only one set of properties (the set associated with the object's current Type) is visible and accessible (to the programmer) at any one time.


Docking Events

An object (the client) may be docked in another object (the host) if the Dockable property of the client is set to 'Always' and the name of the client is included in the host object's DockChildren property. This property defines the list of names that the host will accept. Docking a Form or re-docking an already docked object behave in essentially the same way.

DockStart Event

The user picks up a client object by depressing the left mouse button over its title bar or client area and dragging. As soon as the mouse is moved, the object generates a DockStart event At this stage, the entire operation may be cancelled by a callback function on DockStart that returns 0.

Once a docking operation has begun, the outline of the object is displayed as a rectangle that moves with the mouse.

DockMove Event

When the client object is dragged over a suitable host object (one that will accept it as a child), the host object generates a series of DockMove events. Each DockMove event reports the edge along which the client object will be docked, namely Top, Bottom, Left, Right or None, and a corresponding rectangle

.

When the mouse pointer approaches an edge of the host, the rectangle changes to describe a docking zone indicating where the object will be docked in the host.

A callback function on DockMove that returns 0 will prevent the outline rectangle changing to indicating a docking zone and will prevent the client from being docked.

A callback function on DockMove can also return a result that modifies the position and size of the rectangle that is actually displayed for the user. This in turn will affect the zone occupied by the client when it becomes docked. For example, you can use this to control its size.

DockRequest Event

When the user releases the mouse pointer, the client object generates a DockRequest event. A callback function on DockRequest may return 0 to abort the operation, or may modify the requested docking zone in the host. In the case of a ToolControl, the callback is used to action the docking operation.

DockAccept Event

In response to a successful DockRequest event, the host object generates a DockAccept event. A callback on DockAccept may also be used to abort the operation or to modify the docking zone. The DockAccept event reports the new name for the client object which it will assume as a child of the host.

Furthermore, if the DockAccept callback actions the event before completing, the docking operation will take place immediately, rather than being deferred until the callback has completed. This allows you to set properties on the newly docked object.

DockEnd Event

Finally, the docked client object (whose name has now changed) will generate a DockEnd event. This is reported for information only and a DockEnd callback function cannot cancel or modify the docking operation. The DockEnd event may however be used to set properties for the newly docked client.

If the user releases the mouse elsewhere than over an accepting host object, the DockEnd event is reported by the client object itself. If appropriate, this will be followed by a Configure event and the client will simply move to a new location without changing its docking status.

DockCancel Event

If at any stage the user presses the Esc key, the operation is aborted and the client object generates a DockCancel event.


Docking a Form inside another

The following example illustrates the effect of docking one Form in another.

      'Host' ⎕WC 'Form' 'Host'
      Host.DockChildren←'Client'

      'Client' ⎕WC 'Form' 'Client'
      Client.Dockable←'Always'

Notice that a dockable Form is indistinguishable in appearance between any other top-level Form except that it has additional items in its pop-up context (right mouse button) menu as shown.

The following picture shows the effect of dragging the Client Form to the top edge of the Host, just before the mouse button is released.

The next picture shows the result after docking. The Client Form has become a SubForm (white is the default background colour for a SubForm) called Host.Client.

The third picture illustrates the effect of docking the Client on the left-hand edge.

The following picture shows the Client Form docked as a SubForm along the right edge of the Host Form.

It is also possible to dock a Form into an already docked Form.

      'Client2' ⎕WC 'Form' 'Second Client'
      Client2.Dockable←'Always'

which we can make dockable in both the Host Form and the Host.Client SubForm:

Host.DockChildren Host.Client.DockChildren←⊂'Client2'

The next picture shows Client2 about to be docked in the Client SubForm:

And finally, after it has been docked.


Docking a Form into a CoolBar

The following example illustrates the effect of docking a Form into a CoolBar.

     ∇ FormToCoolBand
[1]    'il'⎕WC'ImageList'('Masked' 0)('MapCols' 1)
[2]    'il.'⎕WC'Bitmap'('ComCtl32' 120)⍝ STD_SMALL
[3]
[4]    'host'⎕WC'Form' 'Host'
[5]    host.Coord←'Pixel'
[6]    host.Size←140 375
[7]    'host.cb'⎕WC'CoolBar'
[8]    host.cb.DockChildren←'file' 'edit'
[9]
[10]   :With 'host.cb.file'⎕WC'CoolBand'
[11]       Caption←'File'
[12]       Dockable←'Always'
[13]       'tb'⎕WC'ToolControl'('ImageListObj' '#.il')
[14]       'tb.b1'⎕WC'ToolButton' 'New'('ImageIndex' 7)
[15]       'tb.b2'⎕WC'ToolButton' 'Open'('ImageIndex' 8)
[16]       'tb.b3'⎕WC'ToolButton' 'Save'('ImageIndex' 9)
[17]   :EndWith
[18]
[19]   :With 'edit'⎕WC'Form' 'Edit' ('Coord' 'Pixel')
[20]       Size←100 200
[21]       Dockable←'Always'
[22]       Coord←'Pixel'
[23]       'tb'⎕WC'ToolControl'('ImageListObj' '#.il')
[24]       'tb.b1'⎕WC'ToolButton' 'Cut'('ImageIndex' 1)
[25]       'tb.b2'⎕WC'ToolButton' 'Copy'('ImageIndex' 2)
[26]       'tb.b3'⎕WC'ToolButton' 'Paste'('ImageIndex' 3)
[27]       'tb.b4'⎕WC'ToolButton' 'Undo'('ImageIndex' 4)
[28]       'tb.b5'⎕WC'ToolButton' 'Redo'('ImageIndex' 5)
[29]   :EndWith
     ∇

The following picture shows the effect of dragging the client Form to the CoolBar in the host, just before the mouse button is released.

The next picture shows the result after docking. The client Form has become a CoolBand called host.cb.edit.


Undocking a SubForm or a CoolBand

When a SubForm or a CoolBand is undocked, it becomes a Form.

The object may either become a Form that is a child of Root, or a Form that remains the child of the Form from where it was undocked. Such an object will always appear on top of its parent, even when undocked.

This behaviour is controlled by the UndocksToRoot Property.

Note that a Form or a CoolBand object may be undocked if its Dockable property is set to 'Always'; the DockChildren property does not apply to the Root object.

The Root object does not provide DockMove events, but the docked object will generate a DockRequest event when the user releases the mouse button over the desktop. This may be used to disable or modify the operation.


Docking and Undocking a ToolControl

Docking and undocking a ToolControl is handled rather differently from docking and undocking a Form or CoolBand.

When you undock a ToolControl from a Form or SubForm, it cannot remain a ToolControl object, because a ToolControl cannot be a child of Root. Furthermore, its Type cannot simply change to Form because a Form cannot be a parent of a ToolButton. In fact, a ToolButton may only be the child of a ToolControl.

Therefore, when a dockable ToolControl is undocked, no action is taken; you have to perform the various operations yourself.

Typically, you would create a new Form to contain the ToolControl and only the ToolControl), and then delete the original.

The new Form should be dockable in the original parent (of the ToolControl), but a callback should intercept this operation and re-instate the ToolControl as a direct child of the host.

Effectively, when you undock a ToolControl, you need to insert a new (floating) Form between the Host Form and the ToolControl. Then when you re-dock it, you need to remove the (floating) Form from the hierarchy.

The following example illustrates the procedure.

The following function creates a Form containing a dockable ToolControl. The ToolControl can be undocked, becoming a floating toolbar, and then docked back into the original Form.

     ∇ DockableToolControl
[1]    'IL'⎕WC'ImageList'('Masked' 0)
[2]    'IL.'⎕WC'Bitmap'('ComCtl32' 120)⍝ STD_SMALL
[3]    :With 'Host'⎕WC'Form' 'Host'
[4]        Coord←'Pixel'
[5]        Size←50 300
[6]        DockChildren←'Floater'
[7]        onDockAccept←'#.DOCK'
[8]        onDockMove←'#.DOCKMOVE'
[9]        :With 'TC'⎕WC'ToolControl'
[10]           Dockable←'Always'
[11]           onDockRequest←'#.UNDOCK'
[12]           ImageListObj←'#.IL'
[13]           'B1'⎕WC'ToolButton' 'New'('ImageIndex' 7)
[14]           'B2'⎕WC'ToolButton' 'Open'('ImageIndex' 8)
[15]           'B3'⎕WC'ToolButton' 'Save'('ImageIndex' 9)
[16]       :EndWith
[17]   :EndWith
     ∇

The picture below shows the initial appearance of the Host Form and its ToolControl.

Because the ToolControl is dockable, the user may pick it up and drag it out of its parent Form as shown below.

When the user drops the ToolControl outside the Host Form, it (the ToolControl) generates a DockRequest event which is attached to the UNDOCK callback function. This function, creates a new Form called Floater, makes a copy of the ToolControl as a child of Floater, and then expunges the original ToolControl from the Host Form. The function, and the results of the operation, are shown below. The following points should be noted.

  • The UNDOCK callback returns 0 to prevent APL from taking any further action (the default action after a successful DockRequest is to generate a DockAccept event, which in this case is undesirable).
  • The Floater Form is created as a child of the Host Form so that it always floats above it in the window stacking order.
  • The Floater Form is made dockable so that it can be re-docked back into Host.
  • The (new) ToolControl is made non-dockable, so that the user cannot drag it out of Floater.

     ∇ R←UNDOCK MSG
[1]    R←0
[2]    :With 'Host.Floater'⎕WC'Form'
[3]        Caption←'Floating ToolControl'
[4]        Dockable←'Always'
[5]        Coord←'Pixel'
[6]        'TC'⎕WC⊃MSG
[7]        TC.Dockable←'Never'
[8]        Size←TC.Size
[9]        Posn←#.Host.Posn+2↑7⊃MSG
[10]   :EndWith
[11]   ⎕EX'#.Host.TC'
     ∇

The user may dock the ToolControl back into Host by dragging the Floater Form into it.

The DOCKMOVE callback function, shown below, prevents the ToolControl (represented by its parent Floater) from being docked anywhere except along the top edge.

     ∇ R←DOCKMOVE MSG
[1]   ⍝ Only allow docking along Top edge
[2]    R←MSG[4]∊'Top' 'None'
     ∇

The picture below illustrates the moment just before the user releases the mouse button to dock Floater back into Host.

At this point, the Host Form generates a DockAccept event and the callback function DOCK is invoked. This function recreates the ToolControl as a child of Host (making it dockable once more), and then expunges the Floater Form.

     ∇ R←DOCK MSG
[1]    R←0
[2]    :With ⊃MSG
[3]        'TC'⎕WC ⎕OR(3⊃MSG).TC
[4]        TC.Dockable←'Always'
[5]    :EndWith
[6]    ⎕EX'#.Host.Floater'
     ∇

Once again, the result of the callback function is 0 to tell APL that you have dealt with the situation and it is to take no further action.


Introduction

OLE Automation is an inter-process communication mechanism created by Microsoft, based on a subset of Component Object Model (COM).

See (for example) https://en.wikipedia.org/wiki/OLE_Automation.

OLE Automation allows you to drive one application from another and to mix code written in different programming languages. In practical terms, this means that you may write a subroutine to perform calculations in (say) C++ and use the subroutine directly in Visual Basic 4 or Excel. Equally, you could write the code in Visual Basic and call it from C++. Dyalog APL/W is a fully subscribed member of this code-sharing club.

OLE Automation is, however, much more than just a mechanism to facilitate cross-application macros because it deals not just with subroutine calls but with objects. An object is a combination of code and data that can be treated as a unit. Without getting too deeply into the terminology, an object defines a class; when you work with an object you create one or more instances of that class.

There are two types of OLE object involved; OLE servers and ActiveX controls. There are two types of OLE server; in-process and out-of-process. In-process OLE servers and ActiveX controls are implemented as dynamic link libraries that are loaded into a host-process at run-time. Out-of-process OLE Servers are implemented as separate processes which may even run on a separate computer in a network.

Dyalog can act as a host for OLE servers and ActiveX controls, and you may also create OLE servers and ActiveX controls in Dyalog that can be hosted by other applications, including Microsoft Office programs.

Architectural Issues

32-bit and 64-bit dynamic link libraries are compatible only with programs compiled for the same architecture, but a 64-bit process cannot load a 32-bit DLL and a 32-bit process cannot load a 64-bit DLL.

This means that the 64-bit Dyalog interpreter can only access a 64-bit in-process OLE servers and ActiveX Controls and the 32-bit Dyalog interpreter can only access 32-bit in-process COM servers and ActiveX controls.

Similarly, an in-process OLE server (dll) or ActiveXControl (ocx) saved by the 64-bit Dyalog interpreter cannot be used by a 32-bit application, and one saved by the 32-bit Dyalog interpreter cannot be used by a 64-bit application. If you try to do so, the application will generate an error. For example, if you were try to load the cfiles.dll or loan.dll saved as an in-process OLE server by the 64-bit Dyalog interpreter into a 32-bit version of Microsoft Excel, it would fail; as would a 32-bit Dyalog dll in a 64-bit version of Excel.

This restriction does not apply to out-of-process OLE servers, which are implemented as separate processes.

Hosting OLE Servers and ActiveX Controls

This chapter describes how Dyalog APL can drive other applications using OLE Automation. In these circumstances, Dyalog APL is acting as an OLE client. The following chapters describe how you can build OLE servers and ActiveX controls in Dyalog.

An ActiveX control can be instantiated as a GUI object within a Dyalog APL Form, whereas an OLE Server either has no GUI component, or is a separate object. Otherwise, the two are very similar.

You can obtain lists of the OLE Servers and ActiveX Controls installed on your computer from the OLEServers and OLEControls properties of the system object '.'. These lists are obtained from your Windows Registry and therefore contain only those OLE objects that are correctly installed. Each OLE Server and OLE Control is identified by its name and class identifier. Either may be used to access it.

The list of COM servers reported by the OLEServers and OLEControls properties of Root return only those COM objects that can be accessed from that version of the Dyalog interpreter. See Architectural Issues.


Using an OLE Server

You can access an OLE Automation Server (also known as COM Server) using the OLEClient object. When you create an OLEClient, you specify the name of the Server as the ClassName property for the object.

For example:

    EX←⎕NEW 'OLEClient' (⊂'ClassName' 'Excel.Application')

or, using ⎕WC

   'EX'⎕WC'OLEClient' 'Excel.Application'

The effect of both statements is to create an object EX, which is connected to an instance of the of the Excel.Application Class, an OLE Server. The OLE Server instance may be in-process or out-of-process. If it is in-process, the code and data associated with the instance are loaded into the same address space as the Dyalog APL process. In the latter case, the instance represents a separate Windows process on your computer or, on an entirely different computer in the network.

When APL connects to an out-of-process OLE Server in this way, you can specify whether you wish to connect to an existing (running) instance of the Server, or start a new copy of the Server. This is done using the InstanceMode property.


Loading an ActiveX Control

An ActiveX or OLE Control is in fact a type of Dynamic Link Library (DLL) which must be loaded before it can be used. This is done by creating an OCXClass object using ⎕WC or ⎕NEW.

For example, if you have an OLE Control named "Microsoft Office Chart 9.0 ", you can load it with the following statements (which are split here only to prevent text wrap)

      NAME←' Microsoft Office Chart 9.0 '
      MOC←⎕NEW 'OCXClass' (⊂'ClassName' NAME)

or, using ⎕WC

      'MOC' ⎕WC 'OCXClass' NAME

The right argument is a character string containing the name or class identifier of the ActiveX Control. The left argument is an arbitrary name of your own choosing by which you will subsequently refer to the Control class.

Using an OLE Control

Having created an OCXClass object, you may use an OLE Control by creating an instance of it from its class. The instance must be created as the child of a Form. For example:

      'F' ⎕WC 'Form'
      'F.MM' ⎕WC 'MOC' ⍝ Instance of MOC

Although you can obtain general information about an OLE Control from both the class (represented by the OCXClass object) and any instance, you may only query and manipulate a control through an instance.


Type Information

In general, it is a requirement that all COM objects provide Type Information. This is commonly provided in a type library file (extension .TLB) or is included in the object's .EXE or .DLL file. Type Information includes the names of the methods, events and properties exported by the object, together with descriptions of the arguments to each method and descriptions of the data types of each property. Type Information is necessary for the COM object to be properly recognised by object browsers and by application development systems.

When you load a COM object, APL by default reads all of the Type Information associated with the top-level object into the workspace. In addition, it reads the Type Information for all other objects in the same object hierarchy, and the Type Information for any other COM objects that are used or referenced by it. This Type Information is retained in the workspace when you )SAVE it. When you reattach an OLEClient or OCXClass to the same object, there is no need for the Type Information to be re-read.

Dyalog APL uses the Type Information to expose the names, data types and arguments of all the methods, events and properties provided by the object, and those of all the other sub-objects in the object hierarchy.

Dyalog APL also uses the Type Information to validate the arguments you supply to methods (both the number and the data types) and the values you assign to properties. For example, if a method is defined to take an argument VT_I4, Dyalog APL will issue a DOMAIN ERROR if you invoke the method with a character argument. Internally, Dyalog APL also uses the Type Information to convert between APL arrays and OLE data types.

The operation to read the Type Information may take several seconds, possibly minutes, and the Type information may occupy a considerable amount of workspace. Nevertheless, the availability of the Type information in the active workspace greatly assists development and optimises run-time performance.

Late Binding

In some circumstances it may be desirable to avoid the process of reading the Type information in its entirety (known as early binding), and instead use a different approach whereby Type information is obtained only when it is needed, i.e. when a particular property, method or event is referenced. This is called late binding and is specified by setting the LateBind property of the OLEClient object to 1 when you create it. When this scheme is used, APL only reads the Type information for properties and methods that are actually used, although the benefit of having all the Type information held in the workspace is lost.

Missing Type Information

Not all COM objects provide Type information, or do so in non-standard ways.

In these cases, if LateBind is set to 0, APL will fail to obtain any Type information, the OLEClient object will be created without it and its associated namespace will be empty. If LateBind is set to 1, the alternative mechanism using late binding will probably not work either.

There are however other ways in which the methods, properties and events provided by the COM object may be accessed from APL.

The first approach is to provide APL with the equivalent information using the SetPropertyInfo and SetMethodInfo methods of the OLEClient object. Corresponding mechanisms are provided for defining Events.

The last resort is to rely on a secondary form of late binding Prior to Version 14.0, this was the only form of late binding provided by Dyalog APL. 1in which APL requires only that the COM object confirms the existence of a given name as one that it exports, and then accesses it using a general mechanism. For further information, see Using OLE Objects without Type Information.

Identifying Properties, Methods and Events

You can obtain the names of all the properties, methods, and events exposed by a COM object by executing the system function ⎕NL, with the appropriate argument, inside the namespace that is associated with an instance of the object. Note that the result of ⎕NL is a vector of character vectors. If Type Information is unobtainable, the list of items reported by ⎕NL will be empty. See the section entitled OLE Objects without Type Information later in this Chapter.

For example:

     DB←⎕NEW'OLEClient' (⊂'ClassName' 'DAO.DBEngine.120')
     DB.⎕NL ¯2 ⍝ Properties
 AutoBrowse  ChildList  ClassID  ClassName  Data
      DefaultPassword  DefaultType  DefaultUser
      Errors  Event  EventList  Handle  HelpFile
      IniPath  InstanceMode  KeepOnClose  LastError
      Locale  LoginTimeout  MethodList  PropList
      Properties  QueueEvents  SystemDB  Type
      TypeList  Version  Workspaces

      DB.⎕NL ¯3 ⍝ Methods
 BeginTrans  CommitTrans  CompactDatabase
      CreateDatabase  CreateWorkspace  ISAMStats  Idle
      OpenConnection  OpenDatabase  RegisterDatabase
      RepairDatabase  Rollback  SetOption

Pre-Version 11 Behaviour

In previous versions of Dyalog APL, you could obtain this information from the PropList, MethodList and EventList properties of the object. Note that these 3 properties are internally generated by Dyalog APL and are not exported by the object itself. You could also obtain this information by executing the system commands )PROPS, )METHODS and )EVENTS inside the namespace that is associated with an instance of the object.

For backwards compatibility, these capabilities are retained when ⎕WX is 0 or 1.

For example:

      ⎕WX←1
      'DB'⎕WC'OLEClient' 'DAO.DBEngine.120'
      )CS DB
#.[OLEClient]

      )METHODS
BeginTrans      CommitTrans     CompactDatabase
CreateDatabase  CreateWorkspace ISAMStats       Idle
OpenConnection  OpenDatabase    RegisterDatabase
RepairDatabase  Rollback        SetOption

      )PROPS
AutoBrowse      ChildList       ClassID ClassName
Data    DefaultPassword DefaultType     DefaultUser
Errors  Event   EventList       Handle  HelpFile
IniPath InstanceMode    KeepOnClose     LastError
Locale  LoginTimeout    MethodList      PropList
Properties      QueueEvents     SystemDB        Type
TypeList        Version Workspaces

Or, for example, using an ActiveX Control:

      NAME←'Microsoft Office Chart 11.0'
      'MOC'⎕WC'OCXClass'NAME
      'F' ⎕WC'Form'
      'F.MOC' ⎕WC 'MOC' ⍝ Instance of MOC
      )CS F.MOC
#.F.MOC
      )PROPS
AllowFiltering  AllowGrouping   AllowLayoutEvents
AllowPointRenderEvents  AllowPropertyToolbox    AllowRenderEvents
AllowScreenTipEvents    AllowUISelection        Attach  AutoConf
Border  Bottom  BuildNumber     CanUndo ChartLayout ...

Using the Property Sheet

The simplest way to obtain further information about an OLE property, method or event is to display its Property Sheet.

To do this, change space to the namespace that represents the object, type the name (or place the cursor over the name) of the property, method or event in question, press the right mouse button and select Properties from the context menu.

The information displayed for the OpenDatabase method that is provided by the DAO.DBEngine OLE object is shown below.

Using the Workspace Explorer

You can also obtain information using the Workspace Explorer.

If you have created an instance of an object, you can navigate to it using the Explorer and then browse its Events, Methods and Properties. The picture below illustrates the effect of browsing the object DB that is connected to DAO.DBEngine.120.

To obtain detailed information about a specific property, event, or method, just open the appropriate folder and select the name you want. The details will be displayed in the list view pane.

The same information can be obtained by browsing the Loaded Libraries folder. This folder will be displayed if the View/Type Libraries menu item is checked and the appropriate library has been loaded. The library will be loaded if you have ever created an instance of the object in this workspace. Alternatively, you may navigate to the information using the Registered Library folder.

GetPropertyInfo Method

You can also obtain information about the properties exposed by a COM object, using the GetPropertyInfo method. Note that this is a Dyalog APL method, added to the object, and not a native method provided by the object itself.

For example, the DAO.DBEngine OLE object exposes a property called Version. You can discover the meaning of the Version property as follows:

      GetPropertyInfo 'Version'
  VT_BSTR

Or, using ⎕NQ

      +2 ⎕NQ ''  'GetPropertyInfo' 'Version'
  VT_BSTR

This tells you that the property value is a character string (VT_BSTR) that contains the version number of the database engine.

      Version
3.51

GetMethodInfo Method

You can also obtain information about the methods exposed by an OLE object, using the GetMethodInfo method. Note that this is a Dyalog APL method, added to the object, and not a native method provided by the object itself.

For example, the DAO.DBEngine OLE object exposes a method called OpenDatabase. You can obtain information about the OpenDatabase method as follows:

      ↑GetMethodInfo 'OpenDatabase'
             Database
 Name        VT_BSTR
 [Options]   VT_VARIANT
 [ReadOnly]  VT_VARIANT
 [Connect]   VT_VARIANT

This tells you that the method opens a specified database and that the result is of type Database. Furthermore, the function takes up to four arguments, the first of which (called Name) is a character string (VT_BSTR). The remaining 3 arguments (called Exclusive, ReadOnly and Connect) are optional (their names are surrounded by []) and of type VT_VARIANT.

GetEventInfo Method

Let's use the Windows Media Player as an example. First we must load the Control by creating an OCXClass object using ⎕NEW.

  wmp←⎕NEW'OCXClass'(⊂'ClassName' 'Windows Media Player')
  'f'⎕WC'Form'
  'f.wmp'⎕WC'wmp'

Next we can find out what events it supports using ⎕NL ¯8.

      wmp.⎕NL ¯8
Buffering  Click  DblClick  Disconnect  DisplayModeChange
       DVDNotify  EndOfStream  Error  KeyDown  KeyPress
     KeyUp  MarkerHit  MouseDown  MouseMove  MouseUp  New
     Stream  OpenStateChange  PlayStateChange  PositionCh
      ange  ReadyStateChange  ScriptCommand  Warning

Then, we can obtain information about a particular event (or events) by invoking a GetEventInfo method. Note that in the case of the Windows Media Control it is necessary to query the instance of the control (f.wmp) as opposed to the instance of the OCXClass (wmp). For example, you can ask it about its MouseDown event. The result is a vector, each element of which is a 2-element vector of character vectors.

      ⍴INFO←⊂f.wmp.GetEventInfo'MouseDown'
5

The first element contains a description of the event and the data type of its result (few events generate results, so this is usually VT_VOID), i.e.

      ⊃INFO
Sent when a mouse button is pressed  VT_VOID

Subsequent elements describe the name and data type of each of the parameters to the event. These are the items that will appear as the third and subsequent elements of the event message that is passed as the right argument to a callback function or returned as the result of ⎕DQ. In this case:

      ↑1↓INFO
 Button      VT_I2
 ShiftState  VT_I2
 x           VT_COORD
 y           VT_COORD

This information tells us that the first parameter Button is a 2-byte integer value which (presumably) is the number of the mouse button that the user has pressed. The second parameter Shift is also a 2-byte integer and (presumably) reports the keyboard shift state. The third and fourth parameters X and Y are of data type VT_COORD.

Obtaining On-line Help

You can display the help topic associated with a property, method, or event by selecting Help from its context menu or using the help button in its property sheet.

Note that the name of the object's help file is provided by its HelpFile property.

For example, in the case of the DAO.DBEngine OLE object:

      ⎕WG'HelpFile'
C:\PROGRA~1\COMMON~1\MICROS~1\OFFICE12\dao360.chm

For Office 2000 applications, you will need to install the MSDN to obtain the appropriate help files.


Methods

When you create an instance of a COM object, the methods and the properties are directly accessible from the corresponding namespace.

Calling Methods

You invoke a method in an OLE object as if it were an APL function in your workspace.

If a method takes no parameters, you must invoke it as if it were niladic.

If a method takes parameters, you must call it as if it were monadic. Each element of its argument corresponds to each of the method's parameters.

If a method takes a parameter declared as a string (VT_BSTR) you must call it with an enclosed character vector.

Note: In previous versions of Dyalog APL, a character vector was automatically enclosed if required. For backwards compatibility you may select old or new behaviour using ⎕WX. If ⎕WX is 3 (the default) you must enclose a single string argument. IF ⎕WX is 0 or 1, you may supply a simple character vector.

For example, the OpenDatabase method in the DAO.DBEngine OLE server may be called with a single parameter that specifies the name of the database to be opened. You may call it from APL with either of the following two expressions:

     OpenDatabase 'c:\example.mdb' ⍝only if ⎕WX is 0 or 1
     OpenDatabase ⊂'c:\example.mdb'⍝any value of ⎕WX

Arrays and Pointers

Many parameters to OLE methods are specified by pointers. If, for example, the parameter type is VT_BSTR, it means that the calling routine must supply a pointer to (i.e. the address of) a character string.

Similarly, if the parameter type is defined to be VT_VARIANT, it means that the parameter is the address of an arbitrary array (the VT_VARIANT data type actually maps nicely onto a Dyalog APL nested array).

The rule is that if a pointer is required, APL will provide it automatically; you do not have to do so. Instead, all you do is supply the value.

Optional Parameters

Methods are often defined to have optional parameters. For example the parameters defined for the OpenDatabase method provided by the DAO.DBEngine OLE object are:

 Name         VT_BSTR
 [Exclusive]  VT_VARIANT
 [ReadOnly]   VT_VARIANT
 [Connect]    VT_VARIANT

To call the corresponding APL function, you may supply a nested array that contains 1,2, 3or 4 elements corresponding to these parameters.

The parameters to some methods are all optional. This means that the method may be called with or without any parameters. As APL does not support this type of syntax, the special value ⍬ (zilde) is used to mean "0 parameters".

For example, the parameters for the Idle method provided by DAO.DBEngine are defined to be:

 [Action]  VT_VARIANT

This means that the method takes either no arguments or one argument. To call it with no argument, you must use ⍬ (zilde), for example:

      Idle ⍬

Note that you cannot therefore call a function in an APL server with a single argument that is an empty numeric vector.

Output Parameters

You may encounter parameters whose data type is defined explicitly as a pointer to something else, for example VT_PTR to VT_UI4 specifies a pointer to an unsigned 4-byte integer.

In these cases, it usually means that the calling routine is expected to pass an address into which the OLE method will place a value.

When you invoke the method you must use data of the type pointed to.

The result of the method is then a vector containing the result defined for the method, followed by the (new) values of the output parameters. This is similar to the mechanism used by ⎕NA.

Named Parameters

Visual Basic syntax allows you to specify parameters by position or by name; rather like ⎕WC and ⎕WS. For example the parameters defined for the OpenDatabase method provided by the DAO.DBEngine OLE object are:

 Name         VT_BSTR
 [Exclusive]  VT_VARIANT
 [ReadOnly]   VT_VARIANT
 [Connect]    VT_VARIANT

You could call this method from Visual Basic using the syntax:

Set Db = OpenDatabase(Name:="c:\example.mdb",_
                      ReadOnly:=True)

You may do the same thing from Dyalog APL, using ⎕WS syntax. For example, the equivalent call from APL would be:

      OpenDatabase('Name' 'c:\example.mdb')('ReadOnly' 1)

Note that you may only use named parameters if they are supported by the method. Many methods do not allow them.

Methods that return Objects

Object hierarchies in OLE are not static, but are created dynamically by calling methods that return objects as their result.

If the data type of the result of a method is a pre-defined object type, or VT_DISPATCH or VT_COCLASS, or VT_PTR to VT_DISPATCH or VT_PTR to VT_COCLASS, the result returned to APL is a namespace. If the result is assigned to a name, the value associated with that name becomes a namespace reference. For example, GetMethodInfo tells us that the syntax for the OpenDatabase method provided by the OLE object DAO.DBEngine is as follows:

      ↑ DB.GetMethodInfo 'OpenDatabase'
 Opens a specified database  VT_DISPATCH
 Name                        VT_BSTR
 [Exclusive]                 VT_VARIANT
 [ReadOnly]                  VT_VARIANT
 [Connect]                   VT_VARIANT

The data-type of the result is VT_DISPATCH, so it returns an object; indeed the help for the method tells us that it returns a Database object. The function could be called from APL as follows:

      DB←OpenDatabase ⊂'example.mdb'

Alternatively, you may simply use the result as an argument to a defined function or as the argument to ⎕CS or :With, thereby switching into the namespace returned by the method. For example:

      :With OpenDatabase ⊂'example.mdb'

      :EndWith

Notice that in both these cases, the namespace associated with the result of the OpenDatabase method is unnamed. Assigning the result of OpenDatabase to DB does not set the namespace name to DB, it merely assigns a namespace reference to DB.

To preserve compatibility with previous versions of Dyalog APL that did not support namespace references, a method that returns an object may be called with the name of the (new) namespace as its left argument. Note that OLE methods do not themselves accept left arguments, so this extension does not conflict with OLE conventions.

      'DB' OpenDatabase ⊂'example.mdb'

This expression creates a new namespace called DB associated with a new object in the OLE Server. Note that if you invoke the OpenDataBase method in this way, its result is a number that represents the Dispatch Interface of the new object. This is done to preserve compatibility with previous versions of Dyalog APL.


Properties

By default, Properties exposed by a COM object behave in the same way as Properties exposed by Dyalog APL Classes.

To query the value of a property, you simply reference it. To set the value of the property, you assign a new value to it. If the Property is an Indexed Property, you may use indexing to set or retrieve the value of a particular element.

Note that in previous versions of Dyalog APL, indexed Properties of COM objects were exposed as Methods and for backwards compatibility this behaviour may be retained by setting ⎕WX to 0 or 1 (the default value is 3). See Language Reference.

If the old (pre-Version 11.0) behaviour is selected., indexed properties are exposed as methods and you treat the property as if it were an APL function. To obtain the value of the property, you must call it monadically, specifying the required index (or other information) as the argument. To set the value of the property, you must call it dyadically, specifying the required index (or other information) as the right argument and the new value as the left argument.

The data type of the variable is reported by the GetPropertyInfo method. Conversion between APL data types and OLE data types is performed automatically.

If you attempt to set the value of a property to an something with an inappropriate data type, APL will generate a DOMAIN ERROR.

If you set the value to something of the correct data type, APL will pass it through the OLE interface. However, the OLE object may itself reject the new value. In this case, APL will also generate a DOMAIN ERROR. However, the OLE error information may be obtained from the LastError property of the object or Root. The error is also displayed in the Status Window.

Note that if ⎕WX is 0 or 1, )PROPS and PropList report the names of all of the properties of an object, regardless of whether the property is implemented as a variable or as a function. You can tell whether or not the property takes an argument (and therefore behaves as a function) from its property sheet, using GetPropertyInfo, or from the documentation for the object in question.

Properties as Objects

Dyalog APL permits an object hierarchy to be represented by a namespace hierarchy. In other words, the relationship between one object and another is a parent-child relationship whereby one object owns and contains another.

Visual Basic has no such mechanism and the relationship between objects has to be specified in another way. This is commonly done using properties. For example, an object view of a bicycle could be a hierarchy consisting of a bicycle object that contains a Frame object, a FrontWheel object and a RearWheel object. In Visual Basic, you could represent this hierarchy as a Bicycle object having Frame, FrontWheel and RearWheel properties which are (in effect) pointers to the sub-objects. The properties are effectively used to tie the objects together.

An extension of this idea is the Visual Basic Collection object. This is a special type of object, that is somewhat similar to an array. It is used where one object may contain several objects of the same type. For example, a Wheel object could contain a Spokes collection object which itself contains a number of individual Spoke objects. Collection objects are usually implemented as properties.

When you reference the value of an object property, you will get a namespace.

Using the bicycle analogy, you could recreate the object hierarchy in the APL workspace as follows:

      'BIKE'  ⎕WC'OLEClient' 'EG.Bicycle'
      FRONT ← BIKE.FrontWheel
      REAR ← BIKE.RearWheel

The result would be three namespaces, one named BIKE, and two unnamed namespaces referenced by FRONT and REAR. Each contains the specific properties, methods and events exposed by the three corresponding objects.

Note however, that in this example BIKE, FRONT and REAR are all top-level namespaces; a proper parent/child representation can be achieved by making FRONT and REAR child namespaces of BIKE, for example:

      BIKE.FRONT ← BIKE.FrontWheel
      BIKE.REAR ← BIKE.RearWheel

or

      :With BIKE
          FRONT ← FrontWheel
          REAR ← RearWheel
      :EndWith

This example illustrates that when you work with an OLE object, you have a choice whether to represent an object hierarchy as a namespace tree or just as a collection of otherwise unrelated namespaces.


Events

Events generated by OLE objects are provided via an event sink which is simply an interface that defines a collection of events that may be generated by the object. Objects may support more than one event sink and may or may not define them in a type library.

By default, events generated by COM objects are processed like all other events in Dyalog APL.

This means that if you attach a callback function to an event in an instance of an OCXClass object, the events are queued up when they are received and then processed one-by-one, by ⎕DQ, from the internal queue. This is the mechanism used to process all events in Dyalog APL and it has many advantages:

  • Events are handled in an orderly manner
  • An event cannot interrupt a callback that is processing a previous event
  • Incoming events are held up so that you can trace a callback function

The disadvantage of this approach is that, for internal reasons, your APL callback function is unable to return a result to the ActiveX control, or to modify any of the arguments supplied by the event. This is a severe problem if the COM object relies on callbacks to control certain aspects of its functionality.

The QueueEvents property allows you to change the normal behaviour so that it is possible for a callback function to return a result to a COM object.

If QueueEvents is 1, which is the default, the result (if any) of your callback function is not passed back to the COM object but is discarded. Thus you cannot, for example, inhibit or modify the default processing of the event by the COM object.

If instead you set QueueEvents to 0, the callback function attached to the event is executed immediately, even if there are other APL events before it in the internal event queue. The result of your callback function is then passed back to the COM object which may use it to inhibit or modify its normal event processing.

See QueueEvents for further details.


Using OLE Objects without Type Information

Even if an OLE Object fails to provide Type Information, either using early or late binding, you will still be able to access its methods and properties using a secondary form of late binding or SetMethodInfo and SetPropertyInfo as follows.

Secondary Late Binding Prior to Version 14.0, this was the only form of late binding provided by Dyalog APL. 1

If you refer to a name inside the OLEClient namespace that would otherwise generate a VALUE ERROR, and there is no Type information available for that name, APL asks the COM object if it has a member (method or property) of that name.

The mechanism permits APL to determine only that the member is exported; it says nothing about its type (method or property) nor its syntax. If the response from the COM object is positive, APL therefore makes the most general assumption possible, namely:

  • That the member is a method
  • That it may take up to 16 optional arguments
  • That each argument is input/output (i.e. specified via a pointer)
  • That the method returns a result.

This means that if you know, from its documentation or another source, that a COM object provides a certain Method or Property, you may therefore access that member by simply calling a function of that name in the OLEClient namespace. Note that any parameters you pass will be returned in the result, because APL assumes that all parameters are input/output. Furthermore, APL will be unable to check the validity of the parameters you specify because it does not know what data types are expected.

SetMethodInfo and SetPropertyInfo

The SetMethodInfo and SetPropertyInfo methods provide a mechanism for you to precisely specify the missing Type Information for the methods and properties that you wish to use. See Object Reference for further details.

Note that whether you use late binding or SetMethodInfo/SetPropertyInfo, any sub-object namespaces that you create by invoking the methods and properties in the top-level object, will also have no visible methods and properties. Therefore, if the Type Information is missing, Late Binding or SetMethodInfo and SetPropertyInfo must be used to access all the methods and properties that you wish to use, wherever they occur in the object hierarchy.

Events

When type library information is available, Dyalog APL automatically connects the appropriate event sinks and establishes the EventList property for the object when it is created. However, if the COM object does not declare its event sinks in a type library, or if the LateBind property were set to 1, it is necessary to connect to them manually. To support these cases, the following methods are used. These apply to top-level COM objects and to the namespaces associated with any other COM objects exposed by them.

Method | Description
OLEListEventSinks | Returns the names of any event sinks currently attached to an object. An event sink is a set of events grouped (for convenience) by a COM object.
OLEAddEventSink | Attaches the namespace associated with an object to a specific event sink that it supports. If successful, new event names will appear in the EventList property of the namespace. This is the only way to access events from an event sink that is not described in the object's Type Information.
OLEDeleteEventSink | Removes the events associated with a particular event sink from the EventList property of the namespace associated with an object.


Collections

A collection is a special type of object that represents a set of other objects. Collections are typically implemented as properties. For example, the Excel Sheet object has a property named Sheets whose value is a collection object that represents a set of worksheets. Collections typically have a property called Count, which tells you how many objects there are, and a Default Property named Item that provides access to each member of the set. Item typically accepts a number or a name as an index and returns a reference to an object.

For example, if a workbook contains two worksheets named "P&L" and "2002 Sales" respectively, they might be accessed as follows:

      S1←Sheets.Item[1]
      S1.Name
P&L
      S2←Sheets.Item ['2002 Sales']
      S2.Index
2

Note that in old versions of Dyalog APL (pre-Version 11.0) the Item property was exposed as a method. This old behaviour may be select by setting ⎕WX to 0 or 1 when you create the object. In which case:

      S1←Sheets.Item 1
      S1.Name
P&L
      S2←Sheets.Item '2002 Sales'
      S2.Index
2

Note that some collections work in origin 0 and some in origin 1; there is no way to tell which applies except from the documentation. Furthermore, collections are used for all sorts of purposes, and may not necessarily permit the instantiation of more than one member of the set at the same time. Collections are not the same as arrays.

As mentioned above, the Item property is typically the Default Property (see Language reference) of a Collection, so indexing may be applied directly to the Collection object.

      Sheets[1 2].Name
 P&L  2002 Sales

The :For - :EndFor control structure provides a convenient way to enumerate through the members of a collection without using the Item property. For example, the following code snippet accumulates the values in an Excel worksheet collection.

      DATA←0⍴⊂0 0⍴0
      :For S :In Sheets  ⍝ Enumerate SHEETS collection
          DATA,←⊂S.UsedRange.Value2
      :EndFor


Null Values

COM methods and properties frequently return null values for which there is no direct equivalent in the APL language. Instead, the system constant ⎕NULL is used to represent a null value.

The following spreadsheet contains a number of empty cells.

Using the Excel.Application COM object, the contents of the spreadsheet can be obtained as follows:

      'EX'⎕WC'OLEClient' 'Excel.Application'
      WB←EX.Workbooks.Open 'simple.xls'

      WB.Sheets[1].UsedRange.Value2
 [Null]  [Null]  [Null]  [Null]  [Null]
 [Null]    Year  [Null]  [Null]  [Null]
 [Null]    1999    2000    2001    2002
 [Null]  [Null]  [Null]  [Null]  [Null]
 Sales      100      76     120     150
 [Null]  [Null]  [Null]  [Null]  [Null]
 Costs       80      60     100     110
 [Null]  [Null]  [Null]  [Null]  [Null]
 Margin      20      16      20      40

To determine which of the cells are filled, you can compare the array with ⎕NULL.

      ⎕NULL≢¨WB.Sheets[1].UsedRange.Value2
0 0 0 0 0
0 1 0 0 0
0 1 1 1 1
0 0 0 0 0
1 1 1 1 1
0 0 0 0 0
1 1 1 1 1
0 0 0 0 0
1 1 1 1 1

⎕NULL should also set the values of COM properties to null.


Additional Interfaces

Most COM objects and their sub-objects provide information about their methods and properties through the IDispatch interface which is the normal interface used for OLE Automation. When you create an instance of an OLEClient object or an OCXClass object, Dyalog APL uses this interface to gain the information it requires.

If an object does not provide an IDispatch interface, or if an object provides additional functionality through other interfaces, it is possible to access the object's functionality using the OLEQueryInterface method.

In addition, if an object exposes sub-objects using an interface other than IDispatch, you may access these sub-objects using the OLEQueryInterface method..

See OLEQueryInterface for further details.


Writing Classes based on OLEClient

You may define APL Classes (See Language Reference) based upon the OLEClient object. For example:

:Class Excel: 'OLEClient'
    ∇ ctor wkbk
      :Access Public
      :Implements Constructor :Base ,⊂('ClassName' 'Excel.Application')
      Workbooks.Open ⊂wkbk
    ∇
:EndClass ⍝ Excel
      XL←⎕NEW Excel 'f:\help11.0\days.xls'
      XL.Workbooks[1].Sheets[1].UsedRange.Value2
   From      To    Days  Hours
  38790   38791       0   3.25
  38792   38792  [Null]   2.25
  38793   38793  [Null]   2.5
  38799   38799  [Null]   5
  38800   38800  [Null]   3
 [Null]  [Null]  [Null]  16


Introduction

This chapter describes how you can write an OLE Automation Server in Dyalog APL.

OLE objects are represented in Dyalog APL by namespaces. There is a direct correspondence between the object model and Dyalog APL namespace technology, a correspondence that is thoroughly exploited in the implementation of OLE Automation.

An OLE object is simply a collection of methods (code that performs tasks) and properties (data that affects behaviour). An object corresponds directly to a Dyalog APL namespace which contains functions that do things and variables that affect things. Furthermore, OLE objects are hierarchical in nature; objects may contain sub-objects just as namespaces may contain sub-namespaces. To complete the picture, an OLE Server is an application that provides (exposes) one or more OLE objects. Thus an OLE Server corresponds directly to a workspace that contains one or more namespaces.

However, when you access an OLE object, you do so by creating an instance of its class and you may work with several instances at the same time. Furthermore, several applications may access the same OLE object at the same time, each with its own set of instances. Each instance inherits its methods (functions) and the initial values of its properties from the class. However, different property values will soon be established in different instances so they must be maintained separately.

Dyalog APL/W includes the capability for a namespace to spawn instances of itself. Initially, a new instance is simply a pointer to the original namespace (not a copy), but as soon as anything in it is changed, the new value is recorded separately. Thus instance namespaces will typically share functions but maintain separate sets of data.

Out-of-Process and In-Process OLE Servers

Dyalog APL allows you to create both out-of-process OLE Servers and in-process OLE Servers. An out-of-process OLE Server runs as a completely separate Windows program that communicates with one or more client programs. An in-process OLE Server is implemented as a Dynamic Link Library (DLL) that is loaded into the client process and becomes part of its address space.

Writing an APL OLE Server

The following steps are required to create an OLE Automation Server in Dyalog APL/W:

  1. On Windows 7 or later, you must start Dyalog APL with Administrator privileges (right-click the desktop icon and choose Run as administrator). This is necessary to register an OLE server.
  2. Create a workspace containing an OLEServer namespace. This namespace represents an OLE Object and may contain as many functions and variables as you want to provide the functionality you require. It may also contain other OLEServer namespaces to represent sub-objects in an object hierarchy.
  3. For each of the functions and variables that you wish to expose as methods and properties of your object, you must declare the data types of their parameters and results. You can do this manually, using the COM Properties tab of the Object Properties dialog box, or by invoking the SetFnInfo and SetVarInfo methods. Note that non-exported functions and variables, sub-namespaces and defined operators may be used internally, but are not available directly to an OLE Automation client. It is also possible to generate events from an OLEServer. The mechanism is the same as for an ActiveXControl and is described in the next chapter.
  4. Select Export from the Session File menu and choose in-process or out-of-process COM Server as you prefer.

Deploying an APL OLE Server

An in-process Dyalog COM Server uses the dynamic-link library version of the Dyalog interpreter which must be present in the same directory as your .dll, so you must copy the appropriate version there. You may use either the Development DLL or the Run-Time DLL. If you choose to use the Development DLL, you will also need to copy the DyaRes DLL which it uses.

An out-of-process Dyalog COM Server consists of your workspace and the associated type library (.tlb) file which is created when you export it. The workspace requires the Development EXE or the Run-Time EXE, which must be in the same directory as your workspace and type library file.

Rules for Exported Functions

There are certain fundamental differences between OLE syntax and APL syntax.

For example, OLE methods may take any number of arguments whereas APL is confined to two; a left and a right.

Secondly, some of the arguments or even all of the arguments to an OLE method may be optional. You cannot however call a monadic APL function with no arguments; in APL there is a clear distinction between niladic functions and functions that take an argument.

Furthermore, the number and type of the arguments for each OLE method must be registered in advance so that OLE knows how to call it.

These factors mean that certain rules must be adopted so that APL can register your APL functions as OLE methods.

  1. Exported APL functions must be niladic or monadic defined functions; dyadic functions, dfns, derived functions and operators are not allowed. However, ambivalent functions may be called (monadically) by OLE.
  2. Character arrays whose rank is greater than 1 are passed as 1-byte integer arrays. This means that 1-byte integer matrices and higher-rank arrays will always be converted to character arrays.
  3. An exported APL function may not be called with an empty numeric vector (zilde) as its single argument. Zilde is used by an APL client to call a non-niladic OLE method with no arguments.
  4. If an exported APL function is called with more than one parameter, its argument will be a nested vector. If it is called with a single parameter that is a character vector or an array whose rank is greater than 1, the argument supplied to the APL function will be a simple array. Effectively, a 1-element nested array received from an OLE Client is disclosed.

The main advantage of an in-process OLE Server is that communication between the client application and the OLE Server is fast. Communication between clients and out-of-process OLE Servers has to go through a separate OLE layer in Windows that incurs a certain overhead. Another advantage is that in-process OLE Servers are simpler to administer and simpler to install.

The main disadvantages of in-process OLE Servers is that there can only be one client per server and they do not support DCOM directly.

ClassID, TypeLibID and other properties

Windows COM objects are identified using a system of Globally Unique Identifiers (GUIDs). When you create an OLEServer object using ⎕WC, APL creates a number of GUIDs and allocates them to the OLE Server. One of these is a Class Identifier (often abbreviated to CLSID) that will uniquely identify your OLE object. This is stored in the ClassID property of the OLEServer. Another GUID identifies the Dispatch interface of the object but is not available via a property.

An out-of-process COM server requires a separate Type Library file. This is a binary file that describes the methods (functions) and properties (variables) exposed by the OLEServer namespace(s) in the workspace. The Type Library is identified by a GUID and by its file name. The file name (which is constructed from the workspace name with a .TLB extension) is stored in the TypeLibFile property of the OLEServer namespace. The GUID is generated when it is first needed and is stored in the TypeLibFileID property of the OLEServer namespace. Note that if the workspace contains several OLEServer objects, their TypeLibFile and TypelLibID properties all have the same values.


In-process OLE Servers

Exporting

When you use File/Export to create an in-process OLE Server, the following steps are performed.

APL first saves your workspace to a temporary file. Then it creates a temporary Type Library File that describes each of the OLEServer objects in the workspace. Next, it creates a Dynamic Link Library (DLL) file (whose name defaults to the name of your workspace but with a .DLL extension) by merging the workspace saved in the temporary file with the file dllstub.dll. Finally, it registers your OLE Server by updating the Windows Registry. Your OLE Server DLL is self-contained and is independent of your workspace. The temporary files are then deleted.

Execution

In-process OLEServers are hosted (executed) by the Dyalog APL DLL. If you export your OLE Server with Runtime application checked, it will be bound with the run-time version, If this checkbox is cleared, your OLE Server will be bound by the development version.

If an in-process OLE Server, that is bound with the run-time Dyalog APL DLL generates an untrapped error, an OLE Automation error will be reported.

If an in-process OLE Server, that is bound with the development Dyalog APL DLL generates an untrapped error, the APL Session will appear and you can use it to debug the problem and continue. Note that at this point, the development DLL will load your Session file so that all of your session tools are available during debugging. If your Session file runs any initialisation code that references external files, remember that this code will be executed in the current working directory of the host process.

For further details, see Dyalog for Microsoft Windows Installation and Configuration Guide.

Registering and Unregistering In-Process OLE Servers

During development, an in-process OLE Server is automatically registered when you create it using File/Export.

The Windows utility regsvr32.exe should be used to register an in-process OLE Server independently, or to install a runtime in-process OLE Server on a target computer. For example:

C:\WINDOWS\System32>regsvr32 c:\MyWS\mysvr.dll

regsvr32 should also be used (with the /u flag) to unregister an in-process OLE Server. For example:

C:\WINDOWS\System32>regsvr32 /u c:\MyWS\mysvr.dll

Note that in both cases, regsvr32 actually starts the OLE Server. This in turn loads the appropriate Dyalog APL DLL. If you are using the development DLL, note that if your session start-up code fails for any reason, the regsvr32 process will hang and have to be terminated using the Task Manager.


Out-of-process OLE Servers

Exporting

When you use File/Export to create an out-of-process OLE Server, the following steps are performed.

APL first creates a single Type Library File that describes all of the OLEServer objects in the workspace. It then registers your OLE Server by updating the Windows Registry with, among other things, the names and ClassIDs of your workspace and Type Library file.

Note that the type information is taken from your active workspace and not the saved workspace. It is up to you to ensure that your saved workspace (which will actually be used when the OLE Server is invoked) is kept in step.

For example, if you were subsequently to remove the OLEServer objects from your workspace and re-save it, or save a completely different workspace with the same pathname, your OLE Server would fail to start because the Type Library and Registry and no longer synchronised with your workspace.

Execution

An out-of-process OLE Server is implemented by a separate Dyalog APL process (DYALOG.EXE or DYALOGRT.EXE) that loads your workspace when it starts.

If an out-of-process OLE Server, that is bound with the run-time Dyalog APL program, generates an untrapped error, an OLE Automation error will be reported.

If an out-of-process OLE Server, that is bound with the development Dyalog APL program, generates an untrapped error, the APL Session will appear and you can use it to debug the problem and continue. In previous versions of Dyalog APL, the visibility of the APL Session for debugging was controlled by the ShowSession property. Setting ShowSession to 1 will cause the Session to be displayed immediately, when the OLE Server is started. However, setting ShowSession to 0 will not prevent the Session from appearing if an untrapped APL error occurs.

Registering and Unregistering

During development, an out-of-process OLE Server is automatically registered when you create it using File/Export.

An out-of-process OLEServer may also be registered by calling its OLERegister method. This performs the same tasks as File/Export, but without any user-interaction. OLERegister is the recommended way to install an out-of-process OLEServer on a target computer as a run-time application.

An out-of-process OLEServer may be unregistered by calling its OLEUnRegister method.

Registry Entries

This section describes the entries that are written into the Windows Registry when APL registers an out-of-process OLEServer.

All registry entries are written as sub-keys of the primary key HKEY_LOCAL_MACHINE\SOFTWARE\Classes of which HKEY_CLASSES_ROOT is an alias. Four separate entries are created, although only the first of these applies to top-level OLEServers.

  1. A sub-key named dyalog.xxxx where xxxx is the name of the OLEServer. This has a sub-key named CLSID whose Default value is a GUID corresponding to the ClassID property of the OLEServer.
  2. A sub-key named CLSID\xxxx where xxxx is the GUID corresponding to the value of the ClassID property of the OLEServer. The Default value of this sub-key is the name of the OLEServer, and the sub-key itself contains sub-keys, namely DyalogDispInterface, DyalogEventInterface, InProcHandler32, LocalServer32, ProgID, TypeLib, and VersionIndependentProgID.
    1. DyalogDispInterface and DyalogEventInterface have their Default values set to the GUID for the Interface entry (see Paragraph 4). This GUID is generated internally by the registration of the Type Library.
    2. InProcHandler32 has the Default value "OLE32.DLL".
    3. LocalServer32 has its Default value set to the command line that is required to start the OLEServer. This is the full path-name of the appropriate DYALOG.EXE or DYALOGRT.EXE followed by the full path-name of the corresponding workspace plus any options that were specified in the Create bound file dialog box.
    4. ProgID has its Default value set to "dyalog.xxxx" where "xxxx" is the name of the OLEServer.
    5. TypeLib has its Default value set to the GUID corresponding to the TypeLibID property of the OLEServer.
    6. VersionIndependentProgID has its Default value set to "dyalog.xxxx" where "xxxx" is the name of the OLEServer (same as ProgID).
    7. Note that for a sub-object (an OLEServer that is a child of another OLEServer) only the InProcHandler32 key is required, although the other entries are created and are in fact redundant.
  3. A sub-key named TypeLib\xxxx where xxxx is the GUID corresponding to the value of the TypeLib property of the OLEServer. This contains a sub-key named 1.0 (which refers to its version number). The Default value of 1.0 is "Type Library for xxxx" where "xxxx" is the name of the OLEServer. 1.0 contains three further sub-keys named 0, FLAGS and HELPDIR.
    1. 0 (this identifies the language id; 0 refers to all languages) contains a sub-key named win32 whose Default value is the full path-name of the Type Library file associated with the OLE object; i.e. the value of the TypeLibFile property of the OLEServer.
    2. FLAGS has a Default value of "0".
    3. HELPDIR has its Default value set to the full path-name of the directory in which the corresponding workspace is saved.
  4. Sub-keys named Interface\xxxx where xxxx is the GUID referenced by the value of DyalogDispInterface and DyalogEventInterface described in paragraph 2. The Default values of these sub-keys is "xxxxdisp" where "xxxx" is the name of the OLEServer. You may identify the correct Interface sub-key by searching the registry for this string. It has three sub-keys named ProxyStubClsid, ProxyStubClsid32, and TypeLib.
    1. ProxyStubClsid has a Default value of a GUID that references an interface of type PSDispatch.)
    2. ProxyStubClsid32 (same as ProxyStubClsid).
    3. TypeLib has two values. Its Default value is the GUID identified by the TypeLib property of the OLEServer object, or, for a child OLEServer, the TypeLib property if its parent OLEServer. Its Version value is "1.0".


The LOAN Workspace

LOAN.DWS contains a single namespace called Loan which is used to calculate monthly repayments on a loan. As supplied, LOAN is a pure APL workspace. You will have to turn it into an OLE Server, and declare a method and a property, before you can use it.

The Loan namespace contains a single function CalcPayments and a variable PeriodType.

The CalcPayments function takes a 5-element numeric vector as an argument whose elements specify:

  1. loan amount
  2. maximum number of periods for repayment
  3. minimum number of periods for repayment
  4. maximum annual interest rate
  5. minimum annual interest rate

CalcPayments also uses the "global" variable PeriodType which specifies whether the periods (above) are years or months. This is done solely to illustrate how another application can manipulate an APL object via its variables (properties) as well as by calling its functions (methods).

CalcPayments returns a matrix. The first row contains the period numbers (from min to max). The first column contains the interest rates (from min to max in steps of 0.5%). Other elements contain the monthly repayments for the corresponding number of periods and interest rates.

Using CalcPayments

The following session transcript illustrates how the CalcPayments function is used.

      )LOAD LOAN
C:\...\samples\ole\loan.dws saved ...

      )OBS
  Loan
      )CS Loan
#.Loan
      )FNS
CalcPayments
      )VARS
PeriodType

      CalcPayments 10000 5 3 6 3
0     3           4           5
3   290.8120963 221.3432699 179.6869066
3.5 293.0207973 223.5600105 181.9174497
4   295.2398501 225.7905464 184.1652206
4.5 297.4692448 228.0348608 186.4301924
5   299.708971  230.2929357 188.7123364
5.5 301.959018  232.5647523 191.0116217
6   304.2193745 234.8502905 193.3280153

The CalcPayments Function

     ∇ PAYMENTS←CalcPayments X;LoanAmt;LenMax;LenMin;IntrMax;
                IntrMin;PERIODS;INTEREST;NI;NM;PER;INT
[1]   ⍝ Calculates loan repayments
[2]   ⍝ Argument X specifies:
[3]        ⍝   LoanAmt     Loan amount
[4]        ⍝   LenMax      Maximum loan period
[5]        ⍝   LenMin      Minimum loan period
[6]        ⍝   IntrMax     Maximum interest rate
[7]        ⍝   IntrMin     Minimum interest rate
[8]   ⍝ Also uses the following global variable (for illustration)
[9]        ⍝   PeriodType  Type of period;1 = years, 2 = months
[10]
[11]   LoanAmt LenMax LenMin IntrMax IntrMin←X
[12]
[13]   PER←PERIODS←¯1+LenMin+⍳1+LenMax-LenMin
[14]   PERIODS←PERIODS×12 1[PeriodType]
[15]   INT←INTEREST←0.5×¯1+(2×IntrMin)+⍳1+2×IntrMax-IntrMin
[16]   INTEREST←INTEREST÷100×12 1[PeriodType]
[17]
[18]   NI←⍴INTEREST
[19]   NM←⍴PERIODS
[20]
[21]   PAYMENTS←(LoanAmt)×((NI,NM)⍴NM/INTEREST)÷1-1÷(1+INTEREST)∘.*PERIODS
[22]   PAYMENTS←PER,[1]PAYMENTS
[23]   PAYMENTS←(0,INT),PAYMENTS
     ∇

Registering Loan as an OLE Server

To use this example, you must first

  1. Convert the Loan namespace into an OLEServer object.
  2. Declare the COM properties for CalcPayments and PeriodType.
  3. Create an in-process or out-of-process server and register the Loan object on your system.

Please perform the following steps:

On Windows 7 or later, you must start Dyalog APL with Administrator privileges (right-click the desktop icon and choose Run as administrator). This is necessary to register an OLE server.

)LOAD the loan workspace from the samples\ole sub-directory

      )LOAD samples\ole\loan
samples\ole\loan saved ...
      )OBS
Loan

Execute the following statement to make Loan an OLEServer object:

      Loan.⎕WC 'OLEServer'

Next, change space into the Loan namespace and use ⎕NL to display the names of the two objects therein:

      )cs Loan
#.Loan
      ⎕NL 2 3
CalcPayments
PeriodType

Right-click over the name CalcPayments and select Properties from the pop-up menu. This brings up the Properties dialog box for Loan.CalcPayments. Click on the COM Properties tab, check the Exported box and then fill in the names and data types of its parameters as illustrated below.

The picture above shows the COM properties that are required to export function CalcPayments as a method. The function is declared to require 5 parameters of type VT_I4 (integers) and return a result of type VT_ARRAY of VT_R8 (an array of floating-point numbers).

The names you choose for the parameters will be visible in an object browser and certain other programming environments.

Do the same for the PeriodType variable so that it is exported as a property.

The picture above shows the COM properties to export variable PeriodType as a property. The property is declared to be of type VT_I4 (integer).

Rename and save the workspace to avoid overwriting the original:

      )WSID c:\MyWS\myloan
was C:\Program Files\Dyalog\Dyalog APL-64 15.0 Unicode\Samples\ole\loan.dws
      )SAVE
c:\MyWS\myloan.dws saved...

Finally, to create your OLE Server, choose Export from the Session File menu and complete the Create bound file dialog box as shown below. In this case, the OLE Server is created as an in-process server, bound to the development version of the Dyalog APL DLL (because the Runtime application checkbox is cleared)

Using Loan from Excel

Start Excel and load the spreadsheet Loan.xlsm from the Dyalog APL sub-directory samples\ole.

The Payments button fires a simple macro that uses the APL dyalog.Loan object to perform repayment calculations. To run the example enter data into the cells as shown below, then click Payments. When you do so, Excel runs the Calc macro and this causes OLE to initialise the dyalog.Loan OLE Server

The Calc macro actually calculates the repayments matrix by calling the CalcPayments method in the dyalog.Loan object; i.e. it runs the CalcPayments function in the Loan namespace.

How it Works

Sub Calc()
    Dim APLLoan As Object
    Dim Payments As Variant
    Set APLLoan = CreateObject("dyalog.Loan")
    LoanAmt = Cells(1, 3).Value
    LenMax = Cells(2, 3).Value
    LenMin = Cells(3, 3).Value
    IntrMax = Cells(4, 3).Value
    IntrMin = Cells(5, 3).Value
    APLLoan.PeriodType = 1
    Payments = APLLoan.CalcPayments(LoanAmt, LenMax,
                           LenMin, IntrMax, IntrMin)
    For r = 0 To UBound(Payments, 1)
        For c = 0 To UBound(Payments, 2)
            Cells(r + 1, c + 5).Value = Payments(r, c)
        Next c
    Next r
End Sub

The statement:

Dim APLLoan As Object

declares a (local) variable called APLLoan to be of type Object

The next statement:

Set APLLoan = CreateObject("dyalog.Loan")

creates an instance of dyalog.Loan associated with this variable.

Effectively, when the macro is run, Excel asks OLE to provide the external object called dyalog.Loan.

If you exported Loan as an out-of-process OLE Server, OLE starts the appropriate version (development or run-time) of Dyalog APL with your workspace MYLOAN. If you exported Loan as an in-process OLE Server, OLE loads MYLOAN.DLL into your Visual Basic application which in turn loads the appropriate Dyalog APL DLL. In either case, an instance of the Loan namespace is connected to the Excel macro as an Object.

The next statement to notice is:

APLLoan.PeriodType = 1

In Excel terms, this statement sets the PeriodType property of the APLLoan object to the value 1. What actually happens, is that the APL variable PeriodType in the corresponding running instance of the Loan namespace is set to 1.

Finally, the following statement:

Payments = APLLoan.CalcPayments(LoanAmt, LenMax, LenMin,
                                IntrMax, IntrMin)

calls the APL function CalcPayments and receives the result.

In Excel terms, this statement invokes the CalcPayments method of the APLLoan object. In practice, it calls the CalcPayments APL function with the specified argument and puts the result in the local variable Payments. Note that the conversion between the result of the function (a Dyalog APL floating-point matrix) and the corresponding Excel data type is performed automatically for you.

Notice that the APLLoan variable is local to the Calc macro. This means that the dyalog.Loan object is loaded every time that Calc is run and is unloaded when it terminates.

Using Loan from Dyalog APL

It is of course possible to use Dyalog APL as both an OLE Automation client and an OLE Automation Server.

To use the dyalog.Loan object, start Dyalog APL and then enter the following expressions in the Session window.

      'LN'⎕WC'OLEClient' 'dyalog.Loan'
      )OBS
LN
      )CS LN
#.LN
      )METHODS
CalcPayments
      )PROPS
AutoBrowse      ChildList       ClassID ClassName       Data    Event   EventList       Handle  HelpFile
InstanceMode    KeepOnClose     LastError       LateBind        Locale  MethodList      PeriodType      PropList
QueueEvents     Type    TypeList

      CalcPayments 10000 5 3 6 3
0     3           4           5
3   290.8120963 221.3432699 179.6869066
3.5 293.0207973 223.5600105 181.9174497
4   295.2398501 225.7905464 184.1652206
4.5 297.4692448 228.0348608 186.4301924
5   299.708971  230.2929357 188.7123364
5.5 301.959018  232.5647523 191.0116217
6   304.2193745 234.8502905 193.3280153

The statement:

      'LN'⎕WC'OLEClient' 'dyalog.Loan'

causes APL to ask OLE to provide the external object called dyalog.Loan. This name will have been recorded in the registry by Dyalog APL when you saved the MYLOAN workspace.

If you exported Loan as an out-of-process OLE Server, OLE starts a second Dyalog APL process (development or run-time) with your workspace MYLOAN. There are now two separate copies of Dyalog APL running; one is the client, the other the server.

If you exported Loan as an in-process OLE Server, OLE loads MYLOAN.DLL into the Dyalog APL program which in turn loads the appropriate Dyalog APL DLL. These DLLs are both are loaded into the same address space as the original APL process. In effect, you have two copies of APL (and two workspaces) running as a single program.

Note that in both cases, the mapping between the corresponding functions and variables is direct. Effectively, the client namespace LN is an instance of the server namespace Loan.


Implementing an Object Hierarchy

Despite the close correspondence between the object model and Dyalog APL namespace technology, there is one significant difference. OLE does not support object hierarchies in the sense that one object contains or owns another.

Instead you must implement object hierarchies using properties that refer to other objects and/or methods that return objects as results.

It is not possible to pass Dyalog APL namespace hierarchies through OLE because OLE does not support them. If you want to write an OLE Automation Server in APL that implements an object hierarchy, you must follow the OLE conventions for doing so.

You can pass an instance of a Dyalog APL OLEServer namespace to an OLE client as a ⎕OR, which can be the result of a function or the value of a variable. In order to be recognised as an OLE object, the namespace must be of type OLEServer.

In fact, when you export a workspace containing one or more OLEServer objects, any child OLEServer objects that they contain are registered too.

The CFILES Workspace (samples\ole\cfiles.dws) illustrates the use of an object hierarchy.


The cfiles Workspace

cfiles.dws contains a single OLEServer namespace called CFiles which implements a basic object-oriented interface to Dyalog APL component files.

This example allows an OLE Client, such as Excel, to read and write APL component files. It is deliberately over-simplified but illustrates how an object hierarchy may be implemented.

The workspace contains the function Make which converts the namespaces CFiles and CFiles.File into OLEServers and defines the COM properties for their methods. All you then have to do is to export it as a COM Server.

The CFiles OLEServer namespace contains functions GetFile and OpenFile and a sub-namespace called File which is also an OLEServer. This namespace contains functions FREAD, FREPLACE, FAPPEND and FSIZE.

The |GetFile function just returns the full pathname of the supplied samples\ole\test.dcf component file which may be used to test the OLEServer. The other functions are described in detail later in this section.

To use this Server, an OLE Client requests an instance of the dyalog.CFiles object.

To open a component file, an OLE Client calls OpenFile with the name of the file as its argument. This function opens the file and returns, not a file tie number as you might expect, but an instance of the File namespace which is associated with the file. As far as the client is concerned, this is a subsidiary OLE object of type dyalog.File.

To perform file operations, the client invokes the FREAD, FREPLACE, FAPPEND and FSIZE methods (functions) of the File object.

A more sophisticated example might expose each component as a subsidiary object too.

Registering CFiles as an OLE Server

In order to explore the use of an APL OLE Server using the cfiles workspace as an example, you must register the CFiles object on your system.

On Windows 7 or later, you must start Dyalog APL with Administrator privileges (right-click the desktop icon and choose Run as administrator). This is necessary to register an OLE server.

)LOAD the cfiles workspace from the samples\ole sub-directory

      )LOAD cfiles
C:\Program Files (x86)\Dyalog\Dyalog APL 15.0 Unicode\...

To implement this workspace as an OLEServer, run "Make"
Then click File/Export from the Session menu

Make         ⍝ Converts CFiles and CFiles namespaces
             ⍝ to OLEServers
             ⍝ and exports their functions as methods
             ⍝ then renames this ws

You are running as administrator ...

      Make
Making OLEServers ...
... Done
Workspace is now mycfiles with empty ⎕LX

      )OBS
CFiles
      CFiles.Type
OLEServer

You should now save your workspace in a personal directory to which you have write access. This will allow you to export CFiles as either an in-process or out-of-process OLE Server.

      )WSID c:\MyWS\mycfiles.dws
was mycfiles.dws
      )SAVE
c:\MyWS\mycfiles.dws saved Wed Jun  1 13:53:56 2016

Then select Export from the Session File menu and create either an in-process or out-of-process OLE Server.

The GetFile Function

     ∇ r←GetFile
[1]    r←2 ⎕NQ'.' 'GetEnvironment' 'DYALOG'
[2]    r,←'\samples\ole\test.dcf'
     ∇

GetFile simply returns the full pathname of the test.dcf component file.

The OpenFile Function

     ∇ FILE←OpenFile NAME;F;TIE
[1]   ⍝ Makes a new File object
[2]    TIE←1+⌈/0,⎕FNUMS
[3]    NAME ⎕FSTIE TIE
[4]    File.TieNumber←TIE
[5]    File.Name←NAME
[6]    FILE←⎕OR'File'
     ∇

OpenFile takes the name of an existing component file and opens it exclusively using ⎕FTIE.

It returns an instance of the File namespace that is associated with the file through the variable TieNumber. This is global to the File namespace.

OpenFile[4]sets the variable TieNumber in the File namespace to the tie number of the requested file.

OpenFile[5]sets the variable Name in the File namespace to the name of the requested file. This is not actually used.

OpenFile[6]creates an instance of the File namespace using ⎕OR and returns it as the result.

Note that there is a separate instance of File for every file opened by every OLE Client that is connected. Each knows its own TieNumber and Name.

The COM Properties dialog box for OpenFile is shown below. The function is declared to take a single parameter called FileName whose data type is VT_BSTR (a string). The result of the function is of data type VT_DISPATCH. This data type is used to represent an object.

The FSIZE Function

     ∇ R←FSIZE
[1]    R←⎕FSIZE TieNumber
     ∇

FSIZE returns the result of ⎕FSIZE for the file associated with the current instance of the File namespace.

The COM Properties dialog box for FSIZE is shown below. The function is declared to take no parameters. The result of the function is of data type VT_VARIANT. This data type is used to represent an arbitrary APL array.

The FREAD Function

     ∇ R←FREAD N
[1]    R←⎕FREAD TieNumber,N
     ∇

FREAD returns the value in the specified component read from the file associated with the current instance of the File namespace.

The COM Properties dialog box for FREAD is shown below. The function is declared to take a single parameter called Component whose data type is VT_I4 (an integer). The result of the function is of data type VT_VARIANT. This data type is used to represent an arbitrary APL array.

The FAPPEND Function

     ∇ R←FAPPEND DATA
[1]    R←DATA ⎕FAPPEND TieNumber
     ∇

FAPPEND appends a component onto of the file associated with the current instance of the File namespace.

The COM Properties dialog box for FAPPEND is shown below. The function is declared to take a single parameter called Data whose data type is VT_VARIANT. This data type is used to represent an arbitrary APL array. The result of the function is of data type VT_I4 (an integer).

The FREPLACE Function

     ∇ FREPLACE ID;I;DATA
[1]    I DATA←ID
[2]    DATA ⎕FREPLACE TieNumber,I
     ∇

FREPLACE replaces the specified component of the file associated with the current instance of the File namespace.

The COM Properties dialog box for FREPLACE is shown below. The function is declared to take two parameters. The first is called Component and is of data type VT_I4 (integer). The second parameter is called Data and is of data type VT_VARIANT. This data type is used to represent an arbitrary APL array. The result of the function is of data type VT_VOID, which means that the function does not return a result.

Using CFiles from Excel

Start Excel and load the spreadsheet cfiles.xlsm from the Dyalog APL sub-directory samples\ole.

Please note that to simplify the Excel code, only components containing matrices (such as those contained in samples\ole\test.dcf) are handled. Components containing scalars, vectors, higher-rank arrays and complex nested arrays are not supported.

Depending upon your configuration settings, it is likely that the macros in cfiles.xlsm are disabled when the spreadsheet is loaded, as shown above. If so, click the Options button and enable them. The security warning is then removed as shown below.

The next step is to enter the name of your component file. A sample file named test.dcf is provided in the samples\ole sub-directory. To get the pathname of this sample file, click Get File Name. The result is shown below:

The next step is to open the file by clicking the Open button. This runs the FOpen procedure. Note that if this step is critical; otherwise any attempt to read or write to the file will fail. When the file is opened, the size of the file is displayed as shown below.

Finally, to read a component, enter the component number, move the input focus to a different cell, and then and click Read. This runs the FRead procedure.

To replace a component, first enter the component number. Then type some data elsewhere on the spreadsheet and select it. Now click Replace. This runs the FReplace procedure.

To append a component, enter some data elsewhere on the spreadsheet and select it. Now click Append. This runs the FAppend procedure.

The FOpen Procedure

Public CF As Object
Public File As Object

Dim Data As Variant

Sub FOpen()
    Set CF = CreateObject("dyalog.cfiles")
    f = Cells(1, 2).Value
    Set File = CF.OpenFile(f)
    Call FSize
End Sub

In the declaration section, the first statement declares a global variable CF to be of data type Object. This variable will be connected to the dyalog.CFiles OLE Server object. The second statement declares a global variable File to be of data type Object. This variable will be connected to the dyalog.File OLE Server object. The third statement declares a global variable Data to be of data type Variant. This is equivalent to a nested array. This variable will be used for the component data.

The statement:

Set CF = CreateObject("dyalog.cfiles")

causes OLE to start Dyalog APL and obtain an instance of the dyalog.CFiles OLE Server object which is then associated with the variable CF. Because this variable is global, the OLE Server remains in memory and available for use.

The statement

f = Cells(1, 2).Value

gets the name of the file to be opened and puts it into the (local) variable f.

Finally, the statement:

Set File = CF.OpenFile(f)

calls the OpenFile function and stores the result (which is an object) in the global variable File.

The FRead Procedure

Sub FRead()
    c = Cells(4, 2).Value
    Data = File.FREAD(c)
    For r = 0 To UBound(Data, 1)
        For c = 0 To UBound(Data, 2)
            Cells(r + 6, c + 2).Value = Data(r, c)
        Next c
    Next r
End Sub

The statement:

c = Cells(4, 2).Value

gets the number of the component to be read and stores it in the (local) variable c.

The statement:

Data = File.FREAD(c)

calls the FREAD function in the instance of the File namespace that is connected to the (global) Excel variable File. The result is stored in the variable Data.

The remaining statements copy the data from Data into the spreadsheet.

The FReplace Procedure

Sub FReplace()
    c = Cells(4, 2).Value
    Data = Selection.Value
    Call File.FReplace(c, Data)
    Call Fsize()
End Sub

The statement:

c = Cells(4, 2).Value

gets the number of the component to be replaced and stores it in the (local) variable c.

The statement:

Data = Selection.Value

gets the contents of the selected range of cells and stores it in the variable Data. This will be a 2-dimensional matrix.

The statement:

Call File.FReplace(c, Data)

calls the FREPLACE function in the instance of the File namespace that is connected to the (global) Excel variable File.

The FAppend Procedure

Sub FAppend()
    Dim Rslt As Variant
    Data = Selection.Value
    Rslt = File.FAppend(Data)
    Call Fsize()
End Sub

The statement:

Data = Selection.Value

gets the contents of the selected range of cells and stores it in the variable Data. This will be a 2-dimensional matrix.

The statement:

Rslt = File.FAppend(Data)

calls the FAPPEND function in the instance of the File namespace that is connected to the (global) Excel variable File. The result of this function is ignored.


Configuring an out-of-process OLEServer for DCOM

Introduction

When you register an out-of-process OLEServer using File/Export or OLERegister, Dyalog APL automatically updates the Windows registry so that your OLEServer is immediately accessible to an OLE client application running on the same computer.

If you wish to make the same object accessible to client applications running on different computers (using distributed COM, or DCOM) you have to install additional registry entries on the server and on each of the clients.

Once you have established these registries entries, you should be able to access the OLEServer from Windows 95 or NT client computers in exactly the same way as if it were local; the client applications need not know where the server is located. In most cases, these additional registry entries are sufficient. However, the NT and DCOM security considerations may require the use of dcomcnfg.exe (a Microsoft utility) to set additional values. For example, if you get E_ACCESSDENIED errors when connecting from the client you may need to run dcomcnfg.exe on the server computer to assign the appropriate launch and access permissions for the OLEServer object.

The additional registry entries are described below. You may add these to the registry directly (using regedit.exe) or by running the functions provided in the DCOMREG.DWS workspace.

DCOM Registry Entries for the Server

On the computer upon which you want the OLEServer to be run, you must add the following registry entries.

  1. A key under HKEY_CLASSES_ROOT\AppID whose name corresponds to the CLSID of your OLEServer object as reported by the value of its ClassID property. The (Default) value of this key should be the name of the server object. In addition, you must define a RunAs entry which specifies the manner in which a client application runs your server. The simplest choice is Interactive User which specifies that the client application is treated like a normal user.

    2. For example, if you had saved an OLEServer namespace called Loan (c.f. samples\loan.dws), whose ClassID property had the value {B80E9D40-2090-11D1-8F93-0020AFABD95D} the entries would be:

    HKEY_CLASSES_ROOT\AppID\{B80E9D40-2090-11D1-8F93-0020AFABD95D}

    (Default)=dyalog.Loan

    RunAs=Interactive User

  2. An AppID entry to the HKEY_CLASSES_ROOT\CLSID key. (Note that this key will itself have been created by Dyalog APL/W when you saved the workspace) Once again, CLSID refers to the value of your OLEServer's ClassID property. The value of the AppID entry is the (same) CLSID.

    3. Using the same example as above, the entry would be:

    HKEY_CLASSES_ROOT\{B80E9D40-2090-11D1-8F93-0020AFABD95D}

    AppID={B80E9D40-2090-11D1-8F93-0020AFABD95D}

DCOM Registry Entries for the Client

On each of the computers from which you wish to call the OLEServer object as a client, you must add the following entries.

  1. Two keys under HKEY_CLASSES_ROOT that identify the object (locally) and associate it with your OLEServer Note that the local name of the object is arbitrary and may be different on each client.

    2. HKEY_CLASSES_ROOT\dyalog.ServerName

    HKEY_CLASSES_ROOT\dyalog.ServerName\CLSID

    CLSID is again the CLSID of the OLEServer object (this must be the same as that of the server machine). dyalog.ServerName can be replaced with whatever name you want clients to use to refer to this object

  2. Under HKEY_CLASSES_ROOT\AppID, a key whose name corresponds to the CLSID of your server object. The (Default) value of this key should be the name of the OLE server object (its name on the server computer). In addition, the key should contain a RemoteServerName entry whose value is the name of the server computer. For example:

    3. HKEY_CLASSES_ROOT\AppID\{B80E9D40-2090-11D1-8F93-0020AFABD95D}

    (Default)=dyalog.Loan

    RemoteServerName=ntsvr

DCOMREG Workspace

The workspace DCOMREG.DWS contains a single namespace called reg that contains three functions to help register an out-of-process OLE Server for DCOM.

RegDCOMServer

This function should be run on the server computer and is called as follows:

      RegDCOMServer ServerName CLSID

Where ServerName is a character string containing the (full) name of the OLEServer (e.g. dyalog.Loan) and CLSID is a character string containing the CLSID of the server (the value of it ClassID property). For example:

      )LOAD LOAN
.\LOAN saved ...
      )COPY DCOMREG
DCOMREG saved ...

      CLSID ←('Loan' ⎕WG 'ClassID')
      reg.RegDCOMServer 'dyalog.Loan' CLSID

RegDCOMClient

This function should be run on each of the client computers and is called as follows:

      machine RegDCOMClient ServerName CLSID

Where machine is a character vector specifying the name of the (NT) server computer, ServerName is a character vector containing the (full) name of the OLEServer (e.g. dyalog.Loan) and CLSID is a character string containing the CLSID of the server (the value of it ClassID property). For example:

      CLSID←'{B80E9D40-2090-11D1-8F93-0020AFABD95D}'
      'NTSVR' reg.RegDCOMClient 'dyalog.Loan' CLSID

Config

This niladic function simply invokes the dcomcnfg.exe utility using ⎕CMD.


Calling an OLE Function Asynchronously

Introduction

Functions exported by an OLEServer are executed (by the underlying OLE technology) in a synchronous manner. This means that the OLE client must wait for the function to complete before it can continue processing.

In certain cases the client may not be interested in a result from a function and it may be desirable for client not to have to wait. For example, if a function updates files or performs a printing task, it would be nice for the client application to continue while the server performs this task in background, or indeed (using DCOM) on another computer.

For an out-of-process OLE Server, this can be achieved by having the function that is called directly by the client post an event (using ⎕NQ) onto the event queue and then return. When the function terminates, APL will take the next event from the queue and take the appropriate action. If the event has an associated callback function, APL will invoke it. Note that this happens immediately after the original function has terminated and a result (if any) has been returned to the client. This means that the APL OLEServer continues processing at the same time as the client application.

Note however that while the OLEServer is processing, further OLE requests will be queued. For example, if the client were to call the same function again immediately, the function would not be invoked until the original processing has finished and the client would therefore wait (note that OLE itself will actually time-out after a certain period). Nevertheless, this technique is an effective way to offload batch processing tasks to a second (background) APL process or to one running on a different computer.

The OLEASYNC Workspace

The OLEASYNC workspace illustrates this technique. It contains a single namespace called Async which exports 2 functions (methods), PRINT and ASYNC and two variables (properties) ERRCODE and COPIES.

The first function, PRINT, prints a specified number of test pages in the background. PRINT does not actually do any printing. All it does is to associate a second function PRINT_CB as a callback on a user-defined event 3001 (the choice of 3001 is purely arbitrary). It then posts an event 3001 onto the queue and returns 0 as its result.

The function also illustrates the use of :Trap. Should either of the statements on lines [3] and [4] fail, the function terminates cleanly and returns ⎕DM instead.

      ∇ R←PRINT N
[1]    ⍝ Prints N test pages "in background"
[2]    :Trap 0
[3]        '.'⎕WS'Event' 3001 'PRINT_CB'N
[4]        ⎕NQ'.' 3001
[5]        (R ERRCODE)←0
[6]    :Else
[7]        (R ERRCODE)←⎕DM ⎕EN
[8]    :EndTrap
     ∇

The actual printing is performed by PRINT_CB after PRINT has returned to the client and while the client itself continues processing. It too uses :Trap to terminate cleanly should an error occur.

      ∇ N PRINT_CB MSG;PR;I;M
[1]    ⍝ Callback function : prints N test pages
[2]    :Trap 0
[3]        'PR'⎕WC'Printer'
[4]        :For I :In ⍳N
[5]            'PR.'⎕WC'Text'(20 60⍴'Testing')(0 0)
[6]            1 ⎕NQ'PR' 'NewPage'
[7]        :EndFor
[8]        ERRCODE←0
[9]    :Else
[10]       ERRCODE←⎕EN
[11]   :EndTrap
     ∇

Note that the client can (later) query ERRCODE to find out whether or not the operation succeeded. Indeed, referencing ERRCODE will synchronise the client and server because the server will have to wait until PRINT_CB completes before it can service the request for the value of ERRCODE.

The ASYNC function illustrates a slightly different approach and may be used to execute any expression asynchronously. It simply associates its argument (a character vector) as an expression to be executed when (user-defined) event 3001 occurs. It then posts this event onto the queue as before.

      ∇ R←ASYNC CMD
[1]    ⍝ Executes expression CMD "asynchronously"
[2]    :Trap 0
[3]        '#.Async'⎕WS'Event' 3001 'DO'CMD
[4]        ⎕NQ'#.Async' 3001
[5]        (R ERRCODE)←0
[6]    :Else
[7]        (R ERRCODE)←⎕DM ⎕EN
[8]    :EndTrap
     ∇

The callback function DO is invoked (later) when the event 3001 is processed from the event queue. This happens immediately after the function ASYNC has returned its result to the client workspace. DO simply executes its left argument, which is the string that was supplied as the right argument to ASYNC.

      ∇ CMD DO MSG
[1]    :Trap 0
[2]        ⍎CMD
[3]        ERRCODE←0
[4]    :Else
[5]        ERRCODE←⎕EN
[6]    :EndTrap
     ∇

You may wonder why it is necessary to use a callback function as opposed to an execute expression. In particular, why not have ASYNC[3] as follows?

[3]        '#.Async'⎕WS'Event' 3001 '⍎CMD'

The reason is that whilst a callback will execute in the instance of the OLEServer namespace connected to this client (which is what we want), an execute expression will be executed in the master OLEServer namespace itself.

The namespace contains a fourth function called LPR which is designed to be called via ASYNC using an expression such as ASYNC 'LPR'.

      ∇ LPR;PR;I
[1]    :Trap 0
[2]        'PR'⎕WC'Printer'
[3]        :For I :In ⍳COPIES
[4]            'PR.'⎕WC'Text'(20 60⍴'Testing')(0 0)
[5]            1 ⎕NQ'PR' 'NewPage'
[6]        :EndFor
[7]        ERRCODE←0
[8]    :Else
[9]        ERRCODE←⎕EN
[10]   :EndTrap
     ∇

Note that the number of copies to be printed is defined by the (global) variable COPIES whose default value is 1. This is done only to illustrate that LPR called via DO runs in the correct instance of the OLEServer (using your value of COPIES) as opposed to in the master OLEServer namespace itself.

Testing dyalog.Async

Load OLEASYNC and then register dyalog.Async as an OLE object by doing the following:

      Async.⎕WC 'OLEServer'
      'Async'⎕WS'ExportedFns' ('PRINT' 'ASYNC')
      'Async'⎕WS'ExportedVars' ('ERRCODE' 'COPIES')

Rename the workspace to avoid overwriting the original and )SAVE it.

      )WSID c:\MyWS\MYASYNC
was C:\Program Files\Dyalog\Dyalog APL-64 15.0 Unicode\Samples\ole\oleasync.dws
      )SAVE
c:\MyWS\MYASYNC.dws saved Wed Jun  1 14:11:01 2016

Finally, register the OLE Server using File/Export. Note that dyalog.Async will only work as an out-of-process OLE Server.

Now clear the workspace and test dyalog.Async using Dyalog APL as an OLE client application. You could also try calling it from Excel. Note that the results from the functions PRINT and ASYNC are returned immediately.

      )CLEAR
clear ws
      'TEST' ⎕WC 'OLEClient' 'dyalog.Async'

      TEST.PRINT 3
0
      TEST.ERRCODE
0
      TEST.COPIES←2
      TEST.COPIES
2
      TEST.ASYNC 'LPR'
0
      TEST.ASYNC 99 ⍝ Wrong !
0
      TEST.ERRCODE
11


Introduction

An ActiveX Control is basically a user-defined control that may be included in GUI applications and Web Browsers.

This chapter describes how you write ActiveX Controls in Dyalog APL/W.

A Dyalog APL ActiveX Control can be used by any other application that supports ActiveX. Such applications include Microsoft Visual Basic, Microsoft Excel, Microsoft Internet Explorer, Netscape Navigator with the NCompass ScriptActive Plug-In and of course Dyalog APL itself.

This chapter also includes a tutorial which teaches you how to:

  • Create an ActiveX control in Dyalog APL
  • Define and Export Properties, Methods and Events
  • Include your ActiveX control in a Visual basic application
  • Run your ActiveX control from a Web Browser.

The examples described in this Chapter were developed and tested using the 32-bit version of Dyalog APL 15.0 Unicode and Microsoft Visual Studio Community 2015. Note that the Visual Studio IDE does not support 64-bit ActiveX controls, so you cannot run the tutorial using the 64-bit version of Dyalog.


Overview

What is an ActiveX Control ?

An ActiveX Control is a dynamic link library that represents a particular type of COM object. When an ActiveX Control is loaded by a host application, it runs in-process, i.e. it is part of the host application's address space. Furthermore, an ActiveX Control typically has a window associated with it, which normally appears on the screen and has a user interface.

An ActiveX Control is usually stored in file with the extension .OCX. The functionality provided by the control can be supplied entirely by functions in that file alone, or can be provided by other dynamic link libraries that it loads and calls, i.e. an ActiveX Control can be stand-alone or can rely on one or more other dynamic link libraries.

What is a Dyalog APL ActiveX Control ?

An ActiveX Control written using Dyalog APL is also a file with a .OCX extension. The file combines a small dynamic link library stub and a workspace. The functionality of the control is provided by the functions and variables in the workspace combined with the dynamic link library version of Dyalog APL.

Note that an ActiveX Control written in Dyalog APL is a GUI object that has a visible appearance and a user interface.

To write an ActiveX Control in Dyalog APL, you use ⎕WC to create an ActiveXControl object, as a child of a Form. An ActiveXControl is a container object, akin to a Group or a SubForm, that may contain a whole range of other controls such as Edit, Combo, Button and Grid objects. You may populate your ActiveXControl with other objects at this stage and save them in the workspace. However, you may prefer to create these sub-objects when an instance of the ActiveXControl is created. This happens when your control is loaded by a host application.

All the functions and variables that represent methods and properties through which the ActiveXControl object exports its functionality, reside within the ActiveXControl namespace.

You may turn a workspace containing one or more ActiveXControl objects into an installable OCX file by selecting the Export menu item from the Session File menu.

Note that a single OCX file can therefore contain a number of ActiveX Controls.

When a Dyalog APL ActiveX Control is loaded by a host application, functions in the stub load the appropriate Dyalog APL dynamic link library (DyalogDLL for short) into the host application. Note that the Dyalog dll must either be on the system PATH or be in the same directory as the OCX file.

The Dyalog dll copies the appropriate parts of the workspace from the .OCX. If the same host application starts a second (different) ActiveX Control written in Dyalog APL, the appropriate parts of the second workspace are merged with the first. For further details, see the section entitled Workspace Management.

The Dyalog APL DLL

ActiveXControls are hosted (executed) by the Dyalog APL DLL. For further details, see COM Objects and the Dyalog APL DLL.

Instance Creation

When a host application creates an instance of an ActiveXControl object, the new instance generates a Create event. It is recommended that you make any GUI objects that you need within the ActiveXControl at this stage, rather than making them in advance and saving them in the workspace.

The reason for this is that until an instance of an ActiveXControl is created, its Size and ambient properties are not known. Ambient properties include the font (which may affect the size and position of the internal controls) and background and foreground colours. These are specified by the host application and should normally be honoured by the ActiveXControl. Although when you are developing an ActiveXControl it will have a specific size, the size of an instance of the object cannot be predicted in advance because it is determined by the host application. This alone is sufficient reason to delay the creation of sub-objects inside the ActiveXControl until the Create event occurs.

In addition to the Create event, ActiveXControl objects support a PreCreate event. This event is always generated before a Create event and signals the creation of a newly cloned namespace. However, it is reported before the host application has assigned it a window. You may therefore not use the PreCreate event to create sub-objects, but you may use it for other initialisation tasks if applicable. Many host applications distinguish between design mode, when the user may just place controls in a GUI framework, and run mode when the controls become fully active. Some applications, such as Microsoft Access, do not require the control to appear fully in design mode, but instead represent the control by a simple rectangle or bitmap. In these cases, the ActiveXControl will generate a PreCreate event in design mode and not generate a Create event until run-time. Others, like Visual Basic, require that the control appears in design mode as it would appear in the final application. In these cases, the Create event follows immediately after PreCreate.

Properties, Methods and Events

Typically, an ActiveX Control provides Properties, Methods and Events that allow the control to be configured and controlled by a host application.

The information about the properties, methods and events exported by an ActiveX Control is normally stored in its .OCX file. The information includes the name of each property and its data type, and the name and data type of each method and each of its arguments. The information for an event is similar to that for a method. In addition to these obligatory items, it is possible to include help strings and help ids which provide on-line documentation for the host application programmer

Dyalog APL provides facilities for you to specify all this information in one of two ways; using dialog boxes or by calling methods.

Firstly, the Properties dialog box for an ActiveXControl object includes three additional tabs named COM Properties, COM Functions and COM Events. These dialog boxes allow you to export variables as properties, to export functions as either properties or methods, and to export events. In addition, the individual Properties dialog boxes for all the functions and variables in an ActiveXControl namespace have an additional COM Properties tab which performs the same function. Examples of these dialog boxes are provided in the tutorial section of this chapter.

Secondly, the ActiveXControl object provides three (internal) methods that allow you to specify this information by executing APL statements. These methods are named SetVarInfo, SetFnInfo and SetEventInfo and examples of their use is given in the tutorial.

Generating Events

Events that are generated by Dyalog APL GUI objects inside an ActiveXControl are purely internal events and are not detectable by a host application. However, an ActiveXControl object may generate an arbitrary event for a host application using ⎕NQ with a left argument of 4.

An external event must have a name (numbers are not allowed) and may include one or more parameters that supply additional information. The name of the event and the name and data types of each of its parameters must be defined in advance using the COM Events tab of the Properties dialog box of the ActiveXControl object, or by calling its SetEventInfo method.

For example, the Dual control described in the tutorial has an event called ChangeValue1. This event supplies a parameter named Value1 that has a data type of VT_PTR to VT_I4 (pointer to an integer). The Dual control generates the event for the host application by executing the statement:

      4 ⎕NQ '' 'ChangeValue1' Value1

where Value1 is the new value of its internal Slider control.

A host application may choose to ignore an event generated by an ActiveXControl, or it may attach a callback function that performs some action in response to the event. A callback function in the host application receives the parameters supplied by the event as parameters to the function. If the host application is Dyalog APL itself, the callback function receives the parameters as part of the event message.

A host application callback function may not return a result. However, it may modify any of the parameters that were supplied as part of the event message if those parameters are defined as pointers (VT_PTR to xxx).

The result of 4 ⎕NQ is therefore a vector whose elements correspond to the pointer parameters in the order they were specified. The result does not contain elements for parameters that were not exported as pointers and may therefore be empty. In the above example, the result of 4 ⎕NQ is a 1-element vector containing the, possibly modified, value of Value1.


The Dual Control Tutorial

The ActiveX control we will use in this example is deliberately an extremely simple one; so that the intricacies of the control itself do not get in the way of the principles involved. In practice, there are actually very few restrictions concerning the complexity of the ActiveX control, and it is perfectly possible to package complete multiple-window Dyalog APL applications in this way.

Your ActiveX control will be called a Dyalog Dual Control and is based on the Dyalog APL TrackBar object.

The Dual control allows the user to enter a number using a slider, whilst displaying its value in two different units. For example, you could use it to enter a temperature value which is displayed in both Centigrade and Fahrenheit units. Equally, the same control could be used to enter a measurement of length which is concurrently displayed in centimetres and inches.

Methods

None. (The Dual control provides no methods.)

Properties

The Dual control provides the following properties:

Property | Description
Caption1 | A text string that describes the primary units. This is displayed in the top left corner of the object.
Caption2 | A text string that describes the secondary or derived units. This is displayed in the bottom left corner of the object.
Value1 | The current value of the control measured in primary units
Value2 | The current value of the control measured in secondary units.
Intercept | Used to derive Value2 from Value1
Gradient | Used to derive Value2 from Value1
Min | The minimum value of Value1
Max | The maximum value of Value1

Value2 is derived from Value 1 using the expression:

      Value2←Intercept+Gradient×Value1

Events

Your Dual control will generate a ChangeValue1 event whenever the user alters Value1 using the slider.

The event message will contain a single parameter (the new value) which may be modified by the host application.

In other words, every time the value in the control changes, the host application may detect this as an event and has the opportunity to override the user.

Your Dual control will also generate a ChangeValue2 event whenever the derived value in the control (Value2) changes. This event is reported for information only.

Introducing the Dual Control

To save time, the basic APL code for the Dual control has already been written. Two workspaces are provided in the samples\activex sub-directory named dualbase.dws and dualfns.dws. You will use these workspaces to build the ActiveX control yourself.

Preparing a Working Directory

To run this tutorial you will need to save files to a directory on your computer to which you have write access. This example uses a directory named c:\MyWS.

The directory is required to store the workspace and ActiveXControl, Dual.ocx as you develop them..

A Dyalog ActiveXControl uses the dynamic-link library version of the Dyalog interpreter which must be present in the same directory as the .ocx, so you must copy the appropriate version here before you can start the tutorial. You may use either the Development DLL or the Run-Time DLL. If you choose to use the Development DLL, you will also need to copy the DyaRes DLL which it uses.

For the names of these files corresponding to the version of Dyalog that you are using, see Files.

Start Dyalog as Administrator

Under Windows 7 and later you have to have administrator privileges to register a COM component. Therefore you must run Dyalog as administrator. If you fail to do this, the registration process will fail. If so, you can continue the process where you left off by closing Dyalog, restarting as administrator, and reloading the workspace.

Getting Started

Load the samples\activex\dualbase.dws workspace:

      )LOAD dualbase
C:\Program Files (x86)\Dyalog\Dyalog APL 15.0 Unicode\...

Run the function TEST and observe how the 2 Dual controls behave.

View the function TEST and observe how 2 separate instances of the Dual namespace F.D1 and F.D2 have been created using ⎕OR and ⎕NS.

Using the Dyalog APL Workspace Explorer, open up the various namespaces. See how F.D1 and F.D2 are clones of Dual.

Open the function Dual.Create and see how the individual components of the control are defined.

Close the Form F.

Changing Dual into an ActiveX Control

Change the name of the workspace to Dual in a directory to which you have write-access:

      )WSID c:\MyWS\Dual

Make a new namespace called F

      )NS F

Using the Workspace Explorer, move the Dual namespace into F, so that Dual is a child namespace of F.

Now edit the function F.Dual.Create and make the following changes:

Remove all references to the local variable POSITION. This change is required because an ActiveX control has no say in its position within its parent. (Hint: use the Search/Replace dialog to remove all occurrences of POSITION+)

Remove the right argument, SIZE and change Create[1] from:

      H W←SIZE

to

      H W←Size

This change allows the control to fit itself within the space allocated by the host application.

Change Create[4] from:

      CH←⊃##.GetTextSize 'W'

to

      CH←⊃GetTextSize 'W'

The original code was designed to pick up the character height from the parent Form. The ActiveXControl object does this automatically via its own GetTextSize method.

After making these changes, the Create function should be as follows:

     ∇ Create;H;W;POS;SH;CH;Y1;Y2
[1]    H W←Size
[2]    SH←40 ⍝ Default TrackBar height
[3]    POS←2↑⌊0.5×0⌈(H-SH)
[4]    CH←⊃GetTextSize'W'
[5]    'Slider'⎕WC'TrackBar'(POS)('Size'SH W)
[6]    Slider.(Limits AutoConf)←(Min,Max)0
[7]    Slider.(TickSpacing TickAlign)←10 'Top'
[8]    Slider.onThumbDrag←'ChangeValue'
[9]    Slider.onScroll←'ChangeValue'
[10]   Y1←POS[1]-CH+1
[11]   Y2←POS[1]+SH+1
[12]   'Cap1'⎕WC'Text'Caption1(Y1,0)('AutoConf' 0)
[13]   'Cap2'⎕WC'Text'Caption2(Y2,0)('AutoConf' 0)
[14]   'V1'⎕WC'Text'(⍕Value1)(Y1,W)
                    ('HAlign' 2)('AutoConf' 0)
[15]   CalcValue2
[16]   'V2'⎕WC'Text'(⍕Value2)(Y2,W)
                    ('HAlign' 2)('AutoConf' 0)
     ∇

Open the function F.Dual.Build. This function turns the Dual's parent namespace into a Form (an ActiveXControl requires a parent Form) and turns Dual itself into an ActiveXControl. It then attaches functions Create and Configure as callbacks on the Create and Configure events of the ActiveXControl object itself.

     ∇ Build
[1]    ##.⎕WC'Form'('Coord' 'Pixel')('KeepOnClose' 1)
[2]    ⎕WC'ActiveXControl'('Size' 80 200)
                          ('KeepOnClose' 1)
[3]    ⎕WS'Event' 'Create' 'Create'
[4]    ⎕WS'Event' 'Configure' 'Configure'
[5]    ⎕NQ'' 'Create'
     ∇

Run function F.Dual.Build. You should see a Form containing a single instance of the Dual control. Please resist any temptation to play with it at this stage; we want it to be in its default state for when we save it.

Type the following expression; note that the ClassID, which uniquely identifies your control (and so will not be the same as that shown below), is allocated when you create the ActiveXControl object.

        F.Dual.ClassID
{002F9614-50F7-4F3B-BB0B-FA3316964E78}

Save the workspace (c:\MyWS\Dual.dws).

From the Session File menu, select Export, choose where you want to save your OCX, and then click Save. It is a good idea to clear the Runtime application checkbox so that you can debug the control if anything goes wrong.

Testing the Dual Control

This section describes how you can test and exercise the Dual control using any appropriate version of Microsoft Visual Studio, such as Microsoft Visual Studio Community 2015, and language (e.g. Visual Basic) of your choice. This tool is henceforth referred to herein as VB.

  • Start VB and create a new Windows Forms Application Project.
  • Click the right mouse button in the General section of the Toolbox window and select Choose Items ... from the pop-up menu. In the Choose Toolbox Items dialog box, click the COM Components tab.
  • Locate the control named Dyalog Dual Control, enable its check box and click OK. This adds a tool for the Dual control to the VB Toolbox.
  • Click on the new tool and drag it onto your Form. An instance of the Dual control will appear.
  • Repeat this step to position a second instance of the Dual control on your VB Form.
  • Click the Start Debugging button.
  • Exercise the two Dual controls.
  • Click the Stop Debugging button.
  • Click on one of the Dual controls and scroll through its Property list. Notice that all the properties listed are standard VB ones; there are no properties (or indeed methods and events) exported. We will learn how to do this next.

Close but do not save the project.

Defining and Exporting Properties

Back in the Dyalog Session, change space into the F.Dual namespace.

      )CS F.Dual

The properties we wish to export are:

Caption1 | Description of the primary set of units
Caption2 | Description of the secondary set of units
Value1 | The primary value in the control
Min | Minimum for Value1
Max | Maximum for Value1
Intercept | Used to derive the secondary value (Value2)
Gradient | Used to derive the secondary value (Value2)

Although we could export all these properties as variables, it is generally more useful to employ Get and Put functions. The reason for this is that there is no mechanism to detect when the host application changes a property/variable; nor is there any mechanism to prevent it assigning an inappropriate value. The Get and Put functions you need are listed below. To save you time, you can copy them in from the workspace samples\activex\dualfns.dws.

      )COPY dualfns
C:\Program Files (x86)\Dyalog\Dyalog APL 15.0 Unicode\...
     ∇ R←GetCaption1
[1]    R←Caption1

     ∇ SetCaption1 C
[1]    Cap1.Text←Caption1←C

     ∇ R←GetCaption2
[1]    R←Caption2

     ∇ SetCaption2 C
[1]    Cap2.Text←Caption2←C

     ∇ R←GetIntercept
[1]    R←Intercept

     ∇ SetIntercept I
[1]    Intercept←I
[2]    CalcValue2
[3]    V2.Text←⍕Value2

     ∇ R←GetGradient
[1]    R←Gradient

     ∇ SetGradient G
[1]    Gradient←G
[2]    CalcValue2
[3]    V2.Text←⍕Value2

     ∇ R←GetValue1
[1]    R←Value1

     ∇ SetValue1 V
[1]    1 ⎕NQ'' 'ChangeValue'V

The Get functions need no explanation; they simply return the value of the corresponding variable. The Set functions assign a new value to the corresponding variable and update the control accordingly. SetValue1 does this by enqueuing a Scroll event to the Slider, which in turn invokes the ChangeValue callback.

Display the Object Properties dialog box for the function GetCaption1. (Hint: use the Workspace Explorer).

Select the COM Properties tab. As you have not yet defined any OLE attributes, the default display is as follows:

Check the Exported option button.

Change the data type for the Result to VT_BSTR (a text string).

Check the Prop Get radio button to indicate that this is a Property Get function and enter the name of the property (Caption1) to which it applies.

Note that it is not necessary for the property name referenced by the Get and Put functions to correspond to a variable name, although in this case it does.

The final COM Properties dialog box for GetCaption1 should appear as follows. Click OK to save your changes.

Now do the same for the SetCaption1 function. This function takes an argument which it expects to be a character vector. It must therefore be defined as having a single parameter of data type VT_BSTR; the parameter name is unimportant. However, you must ensure that the Optional button is unchecked.

In APL terms, the function does not return a result. However, in OLE terms the result is defined to be of type VT_VOID. Alternatively, you may just leave this field empty.

The OLE properties for SetCaption1 should appear as follows:

An alternative way to define the syntax for exported functions is to use the COM Functions tab in the Properties dialog box for the ActiveXControl object itself. (Hint: using the Workspace Explorer, open F so that its contents, Dual, are displayed in the right-hand list, select Dual, then click Props). The COM Functions tab should appear as follows:

The right-hand Combo box allows you to view and edit their syntax for the exported functions you have already defined. The left-hand Combo box displays the list of other non-exported functions that are defined in the ActiveXControl.

Select GetCaption2 from the left-hand Combo box, and then click Add. The dialog box will change to display the default syntax for GetCaption2. Alter the Result data type to VT_BSTR, select Prop Get, and enter the name of the property, Caption2, so that the dialog box appears as follows:

The third way to define the syntax for exported functions is to use the SetFnInfo method of the ActiveXControl object. This allows you to export functions using APL code, which in some circumstances may be more convenient than filling in dialog boxes.

The SetFnInfo method requires the name of the function, its syntax, a help id, a code which specifies its type (0 = method, 2 = property get, 4 = property put) and, if appropriate, the name of the property to which it applies, i.e.

      SetFnInfo fn syntax helpid type property

The function syntax is a nested array whose first element defines the function's result and whose subsequent elements define each of its parameters. Each syntax specifier is a single character string that defines a data type, or a pair of character strings. If so, the first string for the result defines a help string, and the first string for each parameter defines its name.

The following table describes the information we must specify for each of the functions to be exported:

Table 52: Exported Functions

Function | Result | Parameter |  | Get/Put | Property
 |  | Name | Type
GetCaption1 | VT_BSTR |  |  | Get (2) | Caption1
GetCaption2 | VT_BSTR |  |  | Get(2) | Caption2
GetGradient | VT_R8 |  |  | Get(2) | Gradient
GetIntercept | VT_R8 |  |  | Get(2) | Intercept
GetValue1 | VT_I4 |  |  | Get(2) | Value1
SetCaption1 | VT_VOID | Caption1 | VT_BSTR | Put(4) | Caption1
SetCaption2 | VT_VOID | Caption2 | VT_BSTR | Put(4) | Caption2
SetGradient | VT_VOID | Gradient | VT_R8 | Put(4) | Gradient
SetIntercept | VT_VOID | Intercept | VT_R8 | Put(4) | Intercept
SetValue1 | VT_VOID | Value1 | VT_I4 | Put(4) | Value1

From this table we can easily construct the corresponding SetFnInfo statements. For example, the statement for GetCaption1 is:

      SetFnInfo 'GetCaption1' 'VT_BSTR' ¯1 2 'Caption1'

Note that ¯1 in the 3rd element of the right argument specifies that there is no help id.

Open the function F.Dual.EXPORT; this contains statements to export all of the Get and Put functions we need.

Run the function and save the workspace.

      )CS
#
      F.Dual.EXPORT
            )SAVE
c:\MyWS\Dual.dws saved Mon Aug  1 14:52:14 2016

Then, re-export the workspace, updating your .OCX file with all the new information.

Setting Properties from VB

Start VB and create a new Windows Forms Application Project.

If the Dyalog Dual Control is not already in the Toolbox, click the right mouse button in the General section of the Toolbox window and select Choose Items ... from the pop-up menu. In the Choose Toolbox Items dialog box, click the COM Components tab.

Locate the control named Dyalog DUAL Control, enable its check box and click OK. This adds a tool for the Dual control to the VB Toolbox.

Click on the Dyalog Dual tool and drag it onto your Form. An instance of the Dual control will appear.

In the Properties dialog box, change the default Dual1 properties to the following:

Caption1 | Centimetres
Caption2 | Inches
Gradient | 0.3937
Intercept | 0

Double-click the left mouse button over your Form (Form1). This will bring up the code editor dialog box. Edit the Form1_Load() subroutine, entering the program statements shown below. This code will be run when VB starts your application and loads the Form Form1. It illustrates how you can change the properties of your Dyalog APL ActiveX control dynamically.

Now test your application by clicking Start Debugging. When you have finished, click Stop Debugging.

Close but do not save the project. This is necessary to allow you to rebuild the Dual ActiveX control which is (currently) loaded in your VB application. Otherwise, Dyalog will be unable to overwrite the .ocx file.

Defining and Exporting Events

Back in Dyalog, using the Workspace Explorer, open the callback function F.Dual.ChangeValue and alter ChangeValue[2] from:

    Value1←⊃¯1↑MSG

to

    Value1←⊃4 ⎕NQ '' 'ChangeValue1' (⊃¯1↑MSG)

Then close the function. Previously, the ChangeValue function simply accepted the new value (of the TrackBar thumb) that it received as the last element of the event message. Now it generates an external ChangeValue1 event for the host application using 4 ⎕NQ. The host may in turn modify the new value which is returned as the result of the expression. Thus not only can Dyalog APL generate events which are detectable by the host application, it can also accept modifications.

Again using the Workspace Explorer, open the Properties dialog box for the Dual object itself and select the COM Events tab.

Enter the name of the event ChangeValue1 into the edit box labelled Name.

Click Add

Click the right mouse button over the Result row and select Insert

In the column labelled Param Name enter Value1, then change the Type to VT_I4 and the Modifier to VT_PTR. This defines a parameter named Value1 that supplies a pointer to an integer. The fact that it is a pointer means that the (integer) parameter may be modified by the host application.

The final appearance of this dialog box should be as follows:

Click OK, change back to the root space, and save the workspace.

      )CS #
      )SAVE

Select File/Export and rebuild your OCX file.

Using Events from VB

Back in VB, create a new Windows Application Project.

Check that the Dyalog DUAL Control tool is available in the ToolBox.

If not:

  • click the right mouse button in the General section of the Toolbox window and select Choose Items ... from the pop-up menu. In the Choose Toolbox Items dialog box, click the COM Components tab.
  • locate the control named Dyalog DUAL Control, set its check box on and click OK. This adds a tool for the Dual control to the VB Toolbox.

Click on the Dyalog DUAL Control tool and drag it onto your Form. An instance of the Dual control will appear.

Select the label tool and add a label object (Label1) to the Form. Select its Font property and change it to 14-point bold.

View the code window and choose the object AxDual1 and its only event ChangeValue1. Enter a line of code to set the Caption property of the Label object Label1 to the String equivalent of the event parameter Value1.

Enter the following code, and then close the code window, i.e.

Label1.Text = Str(e.Value1)

Start the application using Start Debugging. Exercise the Dual control and observe that VB updates the Label1 control in response to the ChangeValue1 events. When you have finished, select Stop Debugging.

In the code window, add the following line of code to the AxDual1_ChangeValue subroutine:

e.Value1=2 * (e.Value1\2)

Start the application using Start Debugging. Exercise the Dual control and observe that now the slider moves in increments of 2. When you have finished, select Stop Debugging


Introduction

Introduction to DDE

Dynamic Data Exchange (DDE) is a protocol supported by Microsoft Windows that enables two applications to communicate with one another and to exchange data.

DDE has largely been superseded by COM, but continues to be supported by Dyalog APL for backwards compatibility. For new applications, use COM.

Two applications exchange information by having a conversation. In any conversation, there is a client, which is the application that initiates the conversation, and a server; the application that is responding to the client. An application may partake in several conversations at the same time, and may play the server role in some and the client role in others. Indeed, it is perfectly reasonable for two applications to have two conversations in which each acts as the server in one and the client in another.

Most conversations are effectively one-way in that data flows from the server to the client. However, conversations are potentially bi-directional and it is possible for the client to send data to the server. This is often described as poking data.

To initiate a DDE conversation, the client application must specify the name of the server and the subject of the conversation, called the topic. The combination of application and topic uniquely identifies the conversation. In most applications that support DDE, the topic is the "document name". For example, Microsoft Excel recognises the name of a spreadsheet file (.XLS or .XLC) as a topic.

During a conversation, the client and server exchange information concerning one or more items. An item identifies a particular piece of data. For example, Microsoft Excel recognises cell references (such as R1C1) as data items in a conversation. Throughout a conversation, the client may specify how it wishes to be updated when the data in the server changes. There are three alternatives. Firstly, the client can explicitly request the value of an item as and when it needs it. This is described as a cold link. Alternatively, a client may ask the server to supply it with the value of a particular item whenever its value changes. This is called a hot link.

Finally, it may ask the server to notify it whenever the value of an item changes, to which the client may respond by asking for the new value or not. This is termed a warm link.

In addition to providing a means for exchanging data, DDE provides a mechanism for one application to instruct another application to execute a command. This is implemented by sending a DDE_EXECUTE message. It is important to understand that the effect of the command is local to the application in which it is executed, and that the recipient of the message does not return a result to the originating application. It does not work like the APL execute function.


Shared Variable Principles

Shared Variables are part of the APL standard, although strictly speaking as an optional facility. They provide a comprehensive mechanism for communicating between two APL workspaces, or between APL and a co-operating non-APL application. Despite some conflicts between Shared Variable concepts and DDE, this standard APL mechanism has overriding advantages as the basis for a DDE interface. The main benefit is that Shared Variables provide a general basis for developing communications using a variety of protocols, of which DDE is but a single example. Dyalog APL communications are not therefore designed for and limited to DDE, but can be extended to other protocols which are appropriate in different environments.

Most mainframe APL users will already be familiar with Shared Variables and will need no introduction to their concepts. New APL users, or those whose experience has been only of PC-based interpreters, may find the following introduction helpful.

Introduction

It is easiest to consider Shared Variables between two APL workspaces. A Shared Variable is simply a variable that is common to and visible in two workspaces. Once a variable is shared, its value is the same in both workspaces. Communication is achieved by one workspace assigning a new value to the variable and then the other workspace referencing it. Although there is no explicit send or receive, it is perhaps easier to think of things in this way. When you assign a value to a shared variable, you are in effect transmitting it to your partner. When you reference a shared variable, you are in fact receiving it from your partner.

This discussion of shared variables will refer to the terms set and use. The term set means to assign a (new) value to a variable, i.e. its name appears to the left of an assignment arrow. The term use means to refer to the value of a variable, i.e. its name appears to the right of an assignment arrow.

Sharing a Variable

Variables are shared using the system function ⎕SVO. This is a dyadic function whose right argument specifies the name (or a matrix of names) of the variable, and whose left argument identifies the partner with whom the variable is to be shared. In mainframe APL, you identify the partner by its processor id. For example, the following statement means that you offer to share the variable X with processor 123.

      123 ⎕SVO 'X'

A single ⎕SVO by one workspace is not however sufficient to make a connection. It is necessary that both partners make an offer to share the variable. Thus if you are process 345, your partner must complete the coupling by making an equivalent shared variable offer, e.g.

      345 ⎕SVO 'X'

The coupling process is symmetrical and there is no specific order in which offers must be made. However, there is a concept known as the degree of coupling which is returned as the result of ⎕SVO. The degree of coupling is simply a count of the number of processes which currently have the variable "on offer". When the first process offers to share the variable, its ⎕SVO will return 1. When the second follows suit, its ⎕SVO returns 2. The first process can tell when coupling is complete by calling ⎕SVO monadically at a later point, as illustrated below.

Process 345 | Process 123
123 ⎕SVO 'X' |
1 |
 | 345 ⎕SVO 'X'
 | 2
⎕SVO 'X' |
2 |

In this example, both partners specified exactly whom they wished to share with. These are termed specific offers. It is also possible to make a general offer, which means that you offer to share a particular variable with anyone. Coupling can be established by any other processor that offers to share the same variable with you, but notice that the other processor must make a specific offer to couple with your general one. The rule is in fact, that sharing may be established by matching a specific offer with another specific offer, or by matching a specific offer with a general offer. Two general offers cannot establish a connection.

The State Vector

One of the interesting things about Shared Variables, is that both APL workspaces are equal partners. Either of them is allowed to change the value of a shared variable, thus communication is two way. In any communication of this sort, it is essential to have a mechanism to keep things in step. If not, it is possible for one partner to miss something or to receive the same message twice. In some applications this doesn't matter. For example, if one APL workspace is simply monitoring the current value of a particular currency, it does not matter that a second workspace doesn't see all of the fluctuations as they occur. It is important only that the latest value can be referenced when it is needed. Contrast this with a trading application in which the trading workspace registers each transaction with a second workspace which monitors and stores the transactions on a database. Clearly in this case it is essential that each and every transaction is properly communicated and recorded.

Synchronisation is provided by two system functions, ⎕SVS and ⎕SVC. ⎕SVS reports the current value of a shared variable's State Vector. This provides information concerning the state of the variable from each partner's point of view. The second function, ⎕SVC, allows you and your partner to specify interlocking that enforces the level of synchronisation required by your application.

Each shared variable has a state vector which indicates which partner has set a value of which the other is still ignorant, and which partner is aware of the current value. The current state of a shared variable is reported by the monadic system function ⎕SVS. Its argument is the name of the shared variable. Its result is a 4-element Boolean vector which specifies the current state vector, i.e.

      state ← ⎕SVS name

The state vector will have one of the following values:

0 0 0 0 | The variable is not shared
0 0 1 1 | Both partners know the current value
1 0 1 0 | You have set the value, but your partner has yet to use it.
0 1 0 1 | Your partner has set the variable but you have not yet used it.

It may not be immediately apparent as to how the information provided by ⎕SVS can be used. The answer, as we will see later, is that communications generates events. That is to say, when your partner sets a shared variable to a new value or references a value that you have set, an event is generated telling you that something has happened. ⎕SVS is then used to determine what has happened (set or use) and, if you have several variables shared, which one of the variables has in some way changed state. A shared variable state change is thus the trigger that forces some kind of action out of the other process.

Access Control

⎕SVS is not sufficient on its own to synchronise data transfer. For example, what if the two partners both set the shared variable to a different value at exactly the same point in time ? This is the role of ⎕SVC which actually assures data integrity (if required) by imposing access controls. Its purpose is to synchronise the order in which two applications set and use the value of a shared variable.

In simple terms, ⎕SVC allows an application to inhibit its partner from setting a new value before it has read the current one, and/or to inhibit its partner from using a variable again before it has been reset.

⎕SVC is a dyadic system function. Its right argument specifies the name of the shared variable; its left argument the access control vector, i.e.

       access ⎕SVC name

The access control vector is a 4-element Boolean vector whose elements specify access control as follows:

[1] | 1 means that you cannot set the variable until your partner has used it.
[2] | 1 means that your partner cannot set the variable until you have used it.
[3] | 1 means that you cannot use the variable until your partner has set it.
[4] | 1 means that your partner cannot use the variable until you have set it.

In principle, each of the two partners maintains its own copy of the access control vector using ⎕SVC. Control is actually imposed by the effective access control vector which is the result of "ORing" the two individual ones. From your own point of view, the effective access control vector is:

   (your ⎕SVC)  ∨  (your partner's ⎕SVC)[3 4 1 2]

Whenever either of the partners attempts an operation (set or use) on a shared variable, the system consults its effective access control vector. If the vector indicates that the operation is currently permitted, it goes ahead. If however the vector indicates that the operation is currently inhibited, the operation is delayed until the situation changes.

For example, suppose that the effective access control vector is (1 0 0 1). This prevents either partner from setting the shared variable twice in a row, without an intervening use by the other. The purpose of this is to prevent loss of data. Suppose now that one workspace assigns the value 10 to the shared variable (which is called DATA), i.e.

      DATA ← 10

Then, before the partner has referenced the new value it attempts to execute the statement:

      DATA ← 20

APL will not execute the statement. Instead it will wait (indefinitely if required) until the partner has received the first value (10). Only then will the second assignment be executed and processing continued. Effectively one workspace stops and waits for the other to catch up.

Similarly, suppose that the effective access control vector is (0 0 1 1). This means that neither partner can use the variable twice in succession without an intervening set by the other. This type of control is appropriate where each set corresponds to an individual transaction, and you want to prevent transactions from inadvertently being duplicated.

Suppose now that one workspace references the shared variable (which is called DATA), i.e.

      TRANSACTION ← DATA

Then, soon after, it executes the statement again, but without an intervening set by its partner, i.e.

      TRANSACTION ← DATA

This time, the reference to DATA is inhibited, and the workspace waits (indefinitely if necessary) until the partner has assigned a new value. Only then will the second reference be executed and processing continued. Again, one workspace stops and waits for the other.

The purpose of ⎕SVC is to synchronise data transfer. It is particularly useful where timing considerations would otherwise cause data loss. However, an incorrect application which makes inappropriate use of ⎕SVC may hang.

A second type of problem can occur during the development of an application that uses shared variables. If the program is interrupted by an error, an attempt to display the value of a shared variable counts as a "use" and, if inhibited, will hang. In applications that use interlocking, it is recommended that a shared variable is explicitly "used" by making an assignment to a temporary variable which can then be referenced freely.

This is the theory; we will now see how DDE, by its very nature, imposes certain limitations in practice.


APL and DDE in Practice

The interface between Dyalog APL/W and DDE is provided by Shared Variables which are implemented as closely as possible in accordance with the APL Standard. There are however some conflicts between Shared Variables and the way in which DDE works. These impose certain restrictions.

The APL Shared Variable concept is based upon the peer-to-peer communications model where each partner has equal rights and equal control. DDE however is based upon the client-server model whereby data (normally) flows from server to the client at the client's request. This in turn has two major implications. Firstly, a client must initiate a DDE conversation. A server may only respond to a request from a client for a connection; it may not itself start a conversation. Secondly a server cannot specify to which client it wishes to communicate. In terms of the APL standard, this means that if a shared variable is to act as a server it must be made the subject of a general offer. A shared variable that is to act as a client must be the subject of a specific offer Furthermore, as in any DDE conversation there must be one server and one client, it means that two APL workspaces can share variables only if one makes a general offer and one makes a specific offer.

An APL application registers itself as a potential server, or initiates a DDE conversation as a client, by making a Shared Variable offer using ⎕SVO. The offer is either a general offer, which corresponds to a DDE server, or a specific offer which is a client.

Note that, as mentioned in the introduction, DDE does not preclude two-way data transfer, despite its insistence on a client-server relationship. Thus the establishment of a shared variable as a server or as a client does not force the data transfer to be one-way. The choice of whether APL is to act as a server or as client may in practice be determined by convenience.

APL as the Client

To initiate a DDE conversation with a server, you use ⎕SVO as follows:

      'DDE:appln|topic' ⎕SVO 'var item'

where:

appln | is the name of the server application.
topic | is the server topic (usually the name of a document).
var | is the name of the APL variable.
item | is the name of the item with which the variable is to be associated (shared).

For example, the following statement would associate the variable SALES with the block of cells R1C1 to R10C10 in an Excel spreadsheet called "Budget".

      'DDE:EXCEL|BUDGET' ⎕SVO 'SALES R1C1:R10C10'
2

Note that the result of ⎕SVO is the degree of coupling. This has the value 2 if the connection is complete (the server has responded) and 1 if it has not. In practice it is a little more complicated than this, because the result actually depends upon the type of DDE link that has been established.

In principle, the type of link is determined by the client. However, because the server may refuse to accept a particular type of link, it can actually be a result of negotiation between the two applications.

When the shared variable is offered as a client, APL always requests a warm link from the server. If the server refuses a warm link, APL instead requests the current value of the data item (a cold link), and, if the server responds, APL stores the value in the variable. In either case, the degree of coupling is set to 2 if the connection was successful.

Executing Commands in the Server

As mentioned in the Introduction, it is possible for a client to instruct a server to execute a command by sending it a DDE_EXECUTE message. This is intended to allow the client to condition the environment in which the server is operating and not (as one might first expect) to execute a command which directly returns a result. In fact the only response from a server to a DDE_EXECUTE message is a positive or negative acknowledgement, the meaning of which is application dependent.

You can establish a shared variable as a channel for sending DDE_EXECUTE messages by assigning it a surrogate name of '⍎', the APL execute symbol. After sharing, you send commands to the server as DDE_EXECUTE messages by assigning them, as character vectors, to the shared variable. Following each such assignment, the value of the shared variable is reset to 1 if the server responded with a positive acknowledgement, or 0 if it responded with a negative acknowledgement. This should be interpreted with reference to the server application documentation. Note that most applications require that commands are surrounded by square brackets but several commands may be sent at a time. The following examples use Microsoft Excel Version 2.0 as the server :

Establish a link to Excel's SYSTEM topic :

      'DDE:EXCEL|SYSTEM' ⎕SVO 'X ⍎'
2

Instruct EXCEL to open a spreadsheet file :

      X←'[OPEN(c:\mydir\mysheet.xls)]'
      X
1

Instruct EXCEL to select a range of cells :

      X←'[SELECT("R1C1:R5C10")]'
      X
1

Carry out two commands in one call :

      CMD1←'[OPEN(c:\mydir\mysheet.xls)]'
      CMD2←'[SELECT("R1C1:R5C10")]'
      X←CMD1,CMD2
      X
1

APL as the Server

A DDE conversation is initiated by a client, and not by a server. If you wish to act as a server, it is therefore necessary to register this fact with the APL interpreter so that it will subsequently respond to a client on your behalf. This is done by making a general offer using ⎕SVO as follows:

      'DDE:' ⎕SVO 'var item'

where:

var | is the name of the APL variable.
item | is the name of the item with which the variable is to be associated (shared).

Notice that in this case, the left argument to ⎕SVO specifies only the protocol, 'DDE'. APL automatically defines the application name and topic to be 'DYALOG' and ⎕WSID respectively. The DDE item is specified in the right argument as either the name of the variable, or, optionally, as its external name or surrogate.

To allow another application to act as a client, you must have previously published the name(s) of the items which are supported. For example, if your APL application provides SALES information, the following statement could be used to establish it as a server for this item:

      'DDE:' ⎕SVO 'X1 SALES'
1

In the case of a single general offer, the result of ⎕SVO will always be 1. When subsequently a client application attempts to initiate a conversation with a server with the application name 'DYALOG' and topic ⎕WSID, the APL interpreter will respond and complete the connection.

At this point, if and when the client has requested a hot or warm link to the item SALES, the degree of coupling (which is reported by using ⎕SVO monadically) becomes 2, i.e.

      ⎕SVO 'X1'
2


State and Access Control

Earlier, we have seen how shared variable state and access controls are used to ensure effective communication between two APL tasks. How do these concepts apply in the DDE environment when APL is using shared variables to communicate via DDE with both other APL workspaces, and with non-APL applications?

The initial state of a shared variable on the completion of sharing depends upon whether your variable is a server or a client. If it is a server, the initial state vector is (1 0 1 0) which means that you have set (and know) the value, but your partner has yet to use it. If the variable is acting as a client, the initial state vector is (0 1 0 1). This implies that your partner has set the value but you have yet to use it.

As your partner can be a non-APL application which does not share the concepts of set and use, it is necessary to define a rule or set of rules from which APL can reasonably infer such actions.

During a DDE conversation, the physical transfer of data from one application to another is achieved using DDE DATA messages. When a DATA message is sent, the receiving task normally returns an ACK (acknowledgement) message. APL uses the DATA and ACK messages to control Shared Variable access.

When an assignment is made to a shared variable, APL sends a DATA message to the second process. When it receives back an ACK message, APL infers that this means that the partner has used the variable. When APL receives a DATA message from the other process it infers that the partner has set the variable. However, it only responds with an ACK message when the new value of the variable is referenced by the workspace.

Let's see what this means if two APL workspaces are involved.

Server Workspace | Client Workspace
Make general offer |
X←42 |
'DDE:' ⎕SVO 'X' |
1 |
⎕SVS 'X' |
0 0 0 0 ⍝ No partner |
⎕SVC 'X' |
0 0 0 0 ⍝ No access ctl |
 | Make specific offer
 | 'DDE:DYALOG|SERVER'⎕SVO'X'
 | <--- initiate ---
ack ---> |
 | <--- please advise on change
ack ---> |
 | 2 ⍝ Offer accepted
⎕SVS 'X' | ⎕SVS 'X'
1 0 1 0⍝ I know, not he | 0 1 0 1⍝ He knows, I don't
 | Client requests data
 | Y ← X
 | <--- req ---
--- data (42) ---> |
 | <--- ack ---
⎕SVS 'X' | ⎕SVS 'X'
0 0 1 1⍝ We both know | 0 0 1 1⍝ We both know
Server changes data |
X ← 20 |
--- data has changed --> |
 | <--- ack ---
⎕SVS 'X' | ⎕SVS 'X'
1 0 1 0⍝ I know, not he | 0 1 0 1⍝ He knows, I don't
 | Client requests data
 | Y ← X
 | <--- req ---
--- data (20) ---> |
 | <--- ack ---
⎕SVS 'X' | ⎕SVS 'X'
0 0 1 1⍝ We both know | 0 0 1 1⍝ We both know

As you can see, this has the desired effect, namely that an APL workspace sets the value of a shared variable by assignment to it and uses it by reference to it. The mechanism of using the DATA and ACK messages to imply set and use also works with non-APL applications which do not (in general) support these concepts.

Access control between two APL workspaces is imposed by each workspace acting independently. Whenever either workspace changes its ⎕SVC, the information is transmitted to the other. Thus both workspaces maintain their own copy of the effective access control vector upon which to base decisions.

Server Workspace | Client Workspace
No access control | No access control
⎕SVC 'X' | ⎕SVC 'X'
0 0 0 0 ⍝ No access ctl | 0 0 0 0 ⍝ No access ctl
Client makes multiple requests for data
Y←X
Y←X
Server can set several times
X←30
X←40
Set access control
1 0 0 1 ⎕SVC 'X'
--- change in ⎕SVC -->
⎕SVC 'X' | ⎕SVC 'X'
1 0 0 1⍝ I cannot set
         until he has
         used; he cannot
         use untilI
         have set

0 1 1 0⍝ He cannot set
         until I have
         used. I cannot
         use until he
         has set
Client requests data
Y ← X
<--- req ---
(hangs waiting for data)
Server changes data
X ← 30
--- data (30) --->
<--- ack ---
Y⍝ data received
30
Server changes data
X ← 40
--- data has changed --->
<--- ack ---
Server tries to change data again
X ← 50
--- data has changed --->
(assignment hangs waiting for ack)
Y ← X⍝ use data
<--- req ---
--- data (40) --->
<--- ack ---
X⍝ assignment done | Y⍝ data received
50 | 40

Where the second process is a non-APL application, the effective access control vector is maintained only by the APL task and access control can only be imposed by APL. At first sight, it may seem impossible for APL to affect another application in this way, and indeed there are severe limitations in what APL can achieve. Nevertheless, effective access control is possible in the case when it is desirable to inhibit the partner from setting the value twice without an intervening use by the APL task.

This is simply achieved by withholding the ACK message. Thus if APL receives a DATA message from its partner at a time when a set by the partner is inhibited, APL registers the new value but withholds the acknowledgement. Only when the inhibitor is removed will APL respond with an ACK. (Users with DDESPY will observe that this is actually implemented by APL re-transmitting the DATA message to itself when the inhibitor is removed).

Assuming that the second application waits for the acknowledgement before proceeding, this will cause the desired synchronisation. Naturally, this cannot be entirely guaranteed because APL has no direct control over a non-APL program. Indeed, when an application transmits a DATA message, it can include a flag to indicate that an acknowledgement is neither expected nor required. In these circumstances, APL is powerless to impose any access control.

Note that APL does not (and cannot) have any control over successive internal references to the data by a non-APL application.

The rule for establishing your partner's initial ⎕SVC is as follows:

  • If the DDE link is a warm link, your partner's ⎕SVC is initially (0 0 0 0).
  • If the DDE link is instead a hot link, your partner's ⎕SVC is initially (1 0 0 1).

This works in practice as follows:

Server = APL, Client = APL

You made a general offer which has been accepted by another APL workspace, e.g.

      'DDE:' ⎕SVO 'DATA'

Two APL tasks always use a warm DDE link. Therefore, initially, both ⎕SVCs are (0 0 0 0). Control is (optionally) imposed by both partners subsequently setting ⎕SVC.

Server = APL, Client = another application

You made a general offer which has been accepted by another application, e.g.

      'DDE:' ⎕SVO 'DATA'

The client application establishes the strength of the link (warm or hot). If it is a warm link, the initial value of the client's ⎕SVC is (0 0 0 0) and, as the client has no means to change it itself, control may only be imposed by the server APL task. If the client establishes a hot link, its initial ⎕SVC is (1 0 0 1). As it has no means to change it, and as the APL server task cannot (by definition) change it, the client's ⎕SVC retains this setting for the duration of the conversation. (1 0 0 1) means that both partners are inhibited from setting the value of the shared variable twice in a row without an intervening use (or set) by the other. Given that the other application has requested a hot link (give me the value every time it changes) it is reasonable to assume that the application does not want to miss any values and will happily accept new data every time it is changed.

Server = another application, Client = APL

You made a specific offer to another application, e.g.

      'DDE:EXCEL|SHEET1' ⎕SVO 'DATA R1C1:R3C4'

In this case, APL as the client will request a warm DDE link. If the server fails to agree to this request, APL will ask for the current data value and, whether or not the server responds, will not establish a permanent link. Thus the only possibility for a permanent connection is a warm link. This in turn means that the server's ⎕SVC will be (0 0 0 0). Furthermore, as the server has no means to change it, it's ⎕SVC will remain (0 0 0 0) for the duration of the conversation. Control is therefore imposed solely by APL.

Terminating a Conversation

A DDE conversation is terminated by "un-sharing" the variable. This can be done explicitly using ⎕EX or ⎕SVR. It is also done automatically when you exit a function in which a shared variable is localised.


Example: Communication Between APLs

The following instructions will allow you to explore how the DDE interface can be used to communicate between two Dyalog APL/W workspaces.

Start two separate APL sessions and arrange their windows one above the other so that they do not overlap.

Select the top window and type:

      )WSID SERVER
      A←?5 5⍴100 ⋄ A
      'DDE:' ⎕SVO 'A EXTNAME'
1

The result of ⎕SVO is 1, indicating that no client has yet joined in the conversation.

Select the lower window and type:

      )WSID CLIENT
      'DDE:DYALOG|SERVER' ⎕SVO 'B EXTNAME'
      B

The result of ⎕SVO is 2 indicating that the connection with the SERVER workspace has been successfully made. Now type B. It will have the same value as A in the upper window.

Select the top window (SERVER) again and type:

      A←⌹A
      ⎕SVS 'A'
1 0 1 0

Note that the result of ⎕SVS indicates that the SERVER has set A, but the CLIENT has not yet referenced the value.

Select the lower window (CLIENT) and type:

      ⎕SVS 'B'
0 1 0 1
      B
...
      ⎕SVS 'B'
0 0 1 1

Note how, after referencing the shared variable, its state has changed.

Still in the CLIENT workspace, write the following function called FOO:

     ∇ FOO
[1]   ⍝ This function gets called on event 50 (DDE)
[2]    →(0 0 1 1≡⎕SVS'B')/0 ⍝ Exit if no change
[3]    B
     ∇

Then, to attach FOO as a callback and to "wait"...

      '.' ⎕WS 'Event' 50 'FOO'
⎕DQ '.'

Now switch to the upper window (SERVER) and type:

      A←⌹A

Type this expression repeatedly, or experiment with others. Note how changing A generates a DDE event (event number 50) on the system object '.' in CLIENT, which in turn fires the callback.

To interrupt ⎕DQ in the CLIENT, type Ctrl+Break or select "Interrupt" from the Action menu in the Session Window.


Example : Excel as the Server

The following instructions will allow you to explore the DDE interface with another application (in this case Microsoft Excel) acting as the server.

Start Excel and enter some data into (say) the cells R1C1 to R4C3 of the spreadsheet "SHEET1". The data can be character strings and/or numbers. Note that if the spreadsheet is NOT called "SHEET1", the function RUN below should be changed accordingly.

Start Dyalog APL/W (clear ws).

Size your windows so that both the Excel window and the APL Session window can be viewed comfortably at the same time.

Type the following statement in the APL Session :

      'DDE:EXCEL|SHEET1' ⎕SVO 'X R1C1:R4C3'
2

The result should be 2. If not, please check that you have typed the expression correctly, and that the name of the topic (SHEET1) corresponds to the spreadsheet name displayed by Excel.

Note that the character between "EXCEL" and "SHEET1" may be the ASCII pipe symbol or the APL stile. Also note that in some countries, you use Lnn instead of Rnn to refer to rows in Excel. You may therefore need to use the following expression instead:

      'DDE:EXCEL|SHEET1' ⎕SVO 'X L1C1:L4C3'
2

Remaining in the APL Session, type X. It is a matrix containing as many cells as you have requested in the ⎕SVO statement. If you entered any character strings, X will be nested.

Switch to your Excel window and change the data in one or more of the cells.

Switch back to the APL Session and look at X again. It will contain the new data.

Look at the state of the shared variable X using ⎕SVS. It indicates that both partners are aware of the current value of X.

      ⎕SVS 'X'
0 0 1 1

Now switch to Excel and change the data again. Repeat step 8. Note the result indicates that Excel has changed X, but you have not yet referenced it.

      ⎕SVS 'X'
0 1 0 1

Type the expressions :

      '.' ⎕WS 'EVENT' 50 1
      ⎕DQ'.'

Now switch to Excel and change the data again. Note that the ⎕DQ terminates and returns a result.

  . 50

Switch back to APL and create the following function :

      ∇ FOO MSG
   [1] 'MSG IS ' MSG
   [2] 'X IS' X
      ∇

Then type :

      '.' ⎕WS 'EVENT' 50 'FOO'
      ⎕DQ'.'

Now switch back to Excel and change the data. Note that every time you change a cell, the DDE event fires your callback function FOO. In fact the function is fired twice because it itself alters the STATE of X by referencing it. This causes a second DDE event.

Switch back to APL, and type Ctrl+Break or select "Interrupt" from the Action menu to interrupt ⎕DQ.


Example : Excel as the Client

The following instructions will allow you to explore the DDE interface with APL acting as the server to another application; in this case Microsoft Excel.

Start APL (clear ws) and type the expressions :

      )WSID MYWS
      X←12
      'DDE:' ⎕SVO 'X SALES'

The workspace MUST have a name as this is broadcast as the DDE topic. Note that it is currently essential that X contains a value before you make the offer. The result of ⎕SVO is 1, indicating that no client has yet joined in the conversation.

Start Excel (empty spreadsheet).

Size your windows so that both the Excel window and the APL Session window can be viewed comfortably at the same time. Do NOT iconify either one.

Select the Excel window and type the following formula into the first cell :

=dyalog|myws!sales

the value of X (12) will now appear in the cell.

Switch to the APL Session and type :

      ⎕SVO'X'
2

Notice that now that Excel has made the connection, the degree of coupling is 2.

Now type :

      X←34

You will immediately see the new value appear in your spreadsheet.

Create the following function in your workspace :

     ∇ FOO MSG
[1]    MSG
[2]    X←⎕AI[2]
     ∇

Then type the expressions :

      '.' ⎕WS 'EVENT' 50 'FOO'

      ⎕DQ '.'

The link between Excel and APL is a warm link (the type of link is determined by the client, so other applications may behave differently). This means that APL will send the new value of X (SALES) to Excel every time it changes. If you have DDESPY.EXE, you can verify what is happening.

To interrupt ⎕DQ, type Ctrl+Break or select "Interrupt" from the Action menu in the Session Window.


Example : APL as Compute Server for Excel

The following instructions illustrate how APL can act as a "compute server" for Microsoft Excel, using two shared variables. One variable is used to read the data from Excel; the other is used to pass back the result.

Start Excel and enter some NUMBERS into the cells R1C1 to R3C3 of the spreadsheet "SHEET1".

Start Dyalog APL/W and size your windows so that both the Excel window and the APL Session window can be viewed comfortably at the same time.

)LOAD the EXCEL workspace. This contains the following functions :

     ∇ RUN;Z;⎕WSID
[1]    Z←'DDE:EXCEL|SHEET1'⎕SVO 'DATA R1C1:R3C3'
[2]    →(2=Z)/L1
[3]    'No Excel out there ?' ⋄ →0
[4]   L1:
[5]    CALC
[6]    ⎕WSID←'EXCEL'
[7]    Z←'DDE:'⎕SVO 'RESULT ANSWER'
[8]    'Now type "=dyalog|excel!answer" into'
[9]    'cell A4 in your spreadsheet'
[10]  L2:⎕DL 1
[11]   →(2≠⎕SVO 'RESULT')/L2 ⍝Wait for Excel to connect
[12]   'Connected ...'
[13]   '.'⎕WS 'EVENT' 50 'CALLB'
[14]  ⎕DQ '.'
     ∇

     ∇ CALLB MSG
[1]   ⍝ Callback to recalculate when Excel changes DATA
[2]    →(0 0 1 1≡⎕SVS 'DATA')/0
[3]    CALC
     ∇

     ∇ CALC;⎕TRAP
[1]    ⎕TRAP←0 'C' '→ERR'
[2]    RESULT←+/,DATA
[3]    →0
[4]   ERR:RESULT←⊂⎕EM ⎕EN
     ∇

Type the following statement in the APL Session :

      RUN

Now type "=dyalog|excel!answer" into cell A4 in your spreadsheet

Follow the above instructions to establish a link from APL to cell A4 in your Excel spreadsheet. The result of the computation will be displayed.

Try changing some of the numbers in the spreadsheet and watch as APL re-calculates the sum.

Try entering a character string in cell A1. Note that APL sends back a character string containing DOMAIN ERROR.

Use Ctrl+Break or select "Interrupt" from the Action menu in the Session window to stop ⎕DQ.


Restrictions & Limitations

Although shared variables have been implemented as closely to the APL standard as is possible, certain restrictions are imposed by the nature of DDE itself.

The server cannot make an offer to a specific client. Instead, it must broadcast a "general" offer, which could be accepted by any client. Indeed neither the client nor the server can specifically identify the other task.

Dyalog APL supports Excel "Fast Table Format" for communications with Excel (and with any other application that supports this format). This imposes the following restrictions :

  • The maximum number of numbers that you can send to Excel is 8191. Any attempt to send more will result in a LENGTH ERROR. This is because APL currently tries to send all the data in a single block. Larger amounts of data can be received from Excel, because Excel will send several blocks if required. The restriction may be lifted in due course.
  • The maximum length of a character vector (which represents a string within a cell) is 255.

A client APL program can only use indexed assignment to change the value of a shared variable if it already knows the up-to-date value of the variable, i.e. if its ⎕SVS is 0 0 1 1 or 1 0 1 0. An attempt to use indexed assignment on a variable whose ⎕SVS is 0 1 0 1 will cause a NONCE error.

Consider Excel as a server and APL as client with several warm links to an Excel spreadsheet e.g.:

      'DDE:EXCEL|SHEET1' ⎕SVO 'X R1C1'
      'DDE:EXCEL|SHEET1' ⎕SVO 'Y R2C2'
      'DDE:EXCEL|SHEET1' ⎕SVO 'Z R3C3'

If R1C1 is changed in Excel, APL expects to be told only of that change. Instead, Excel tells APL that ALL the linked cells have changed.

If APL pokes a value back to R1C1, Excel again tells APL that ALL the linked cells have changed.

You must take care to avoid this problem when dealing with DDE between Excel and APL.


Introduction

This manual describes the Dyalog APL interface to the Microsoft .NET Framework. This document does not attempt to explain the features of the .NET Framework, except in terms of their APL interfaces. For information concerning the .NET Framework, see the documentation, articles and help files, which are available from Microsoft and other sources.

The .NET interface features include:

  • The ability to create and use objects that are instances of .NET Classes
  • The ability to define new .NET Classes in Dyalog APL that can then be used from other .NET languages such as C# and VB.NET.
  • The ability to write Web Services in Dyalog APL.
  • The ability to write ASP.NET web pages in Dyalog APL

.NET Classes

The .NET Framework defines a so-called Common Type System. This provides a set of data types, permitted values, and permitted operations. All cooperating languages are supposed to use these types so that operations and values can be checked (by the Common Language Runtime) at run time. The .NET Framework provides its own built-in class library that provides all the primitive data types, together with higher-level classes that perform useful operations.

Dyalog APL allows you to create and use instances of .NET Classes, thereby gaining access to a huge amount of component technology that is provided by the .NET Framework.

It is also possible to create Class Libraries (Assemblies) in Dyalog APL. This allows you to export APL technology packaged as .NET Classes, which can then be used from other .NET programming languages such as C# and Visual Basic.

The ability to create and use classes in Dyalog APL also provides you with the possibility to design APL applications built in terms of APL (and non-APL) components. Such an approach can provide benefits in terms of reliability, software management and re-usage, and maintenance.

GUI Programming with System.Windows.Forms

One of the most important .NET class libraries is called System.Windows.Forms, which is designed to support traditional Windows GUI programming. Visual Studio .NET, which is used to develop GUI applications in Visual Basic and C#, produces code that uses System.Windows.Forms. Dyalog APL allows you to use System.Windows.Forms, instead of (and in some cases, in conjunction with) the built-in Dyalog APL GUI objects such as the Dyalog APL Grid, to program the Graphical User Interface.

Web Services

Web Services are programmable components that can be called by different applications. Web Services have the same goal as COM, but are technically platform independent and use HTTP as the communications protocol with an application. A Web Service can be used either internally by a single application or exposed externally over the Internet for use by any number of applications.

ASP.NET and WebForms

ASP.NET is a new version of Microsoft Active Server Page technology that makes it easier to develop and deploy dynamic Web applications. To supplement ASP.NET, there are some important new .NET class libraries, including WebForms which allow you to build browser-based user interfaces using the same object-oriented mechanism as you use Windows.Forms for the Windows GUI. The use of these component libraries replaces basic HTML programming.

ASP.NET pages are server-side scripts, that are usually written in C# or Visual Basic. However, you can also employ Dyalog APL directly as a scripting language (APLScript) to write ASP.NET web pages. In addition, you can call Dyalog APL workspaces directly from ASP.NET pages, and write custom server-side controls that can be incorporated into ASP.NET pages.

These features give you a wide range of possibilities for using Dyalog APL to build browser-based applications for the Internet, or for your corporate Intranet.


Prerequisites

Dyalog APL Version 17.0 .NET Interface requires Version 4.0 or greater of the Microsoft .NET Framework. It does not operate with earlier versions of .NET.

For full Data Binding support (including support for the INotifyCollectionChanged interfaceThis interface is used by Dyalog to notify a data consumer when the contents of a variable, that is data bound as a list of items, changes. 1), and Syncfusion, Version 17.0 requires .NET Version 4.5.

The examples provided in the sub-directory Samples/asp.net require that IIS is installed. If IIS and ASP.NET are not present, the asp.net sub-directory will not be installed during the Dyalog installation.


Files Installed with Dyalog

NET Interface Components

The components used to support the .NET interface are summarised below. Different versions of each component are supplied according to the target platform.

  • The Bridge DLL. This is the interface library through which all calls between Dyalog APL and the .NET Framework are processed
  • The DyalogProvider DLL. This DLL performs the initial processing of an APLScript.
  • The APLScript Compiler. This is itself written in Dyalog APL and packaged as an executable.
  • The DyalogNet DLL; a subsidiary library
  • The Dyalog DLL. This is the engine that executes all APL code that is hosted by and called from another .NET application.

For a list of the files associated with each of these components, see Files.

Code Samples

The samples subdirectory contains several sub-directories relating to the .NET interface:

  • aplclasses; a sub-directory that contains examples of .NET classes written in APL.
  • aplscript; a sub-directory that contains APLScript examples.
  • asp.net; a sub-directory that is mapped to the IIS Virtual Directory dyalog.net, and contains various sample APL Web applications.
  • winforms; a sub-directory that contains sample applications that use the System.Windows.Forms GUI classes.
  • web.config: this file specifies Dyalog configuration parameters for ASP.NET. See The web.config file.


Introduction

.NET classes are implemented as part of the Common Type System. The Type System provides the rules by which different languages can interact with one another. Types include interfaces, value types and classes. The .NET Framework provides built-in primitive types plus higher-level types that are useful in building applications.

A Class is a kind of Type (as distinct from interfaces and value types) that encapsulates a particular set of methods, events and properties. The word object is usually used to refer to an instance of a class. An object is typically created by calling the system function ⎕NEW, with the class as the first element of the argument.

Classes support inheritance in the sense that every class (but one) is based upon another so-called Base Class.

An assembly is a file that contains all of the code and metadata for one or more classes. Assemblies can be dynamic (created in memory on-the-fly) or static (files on disk). For the purposes of this document, the term Assembly refers to a file (usually with a .DLL extension) on disk.


Locating .NET Classes and Assemblies

Unlike COM objects, which are referenced via the Windows Registry, .NET assemblies and the classes they contain, are generally self-contained independent entities (they can be based upon classes in other assemblies). In simple terms, you can install a class on your system by copying the assembly file onto your hard disk and you can de-install it by erasing the file.

Although classes are arranged physically into assemblies, they are also arranged logically into namespaces. These have nothing to do with Dyalog APL namespaces and, to avoid confusion, are henceforth referred to in this document as .NET namespaces.

Often, a single .NET namespace maps onto a single assembly and usually, the name of the .NET namespace and the name of its assembly file are the same; for example, the .NET namespace System.Windows.Forms is contained in an assembly named System.Windows.Forms.dll.

However, it is possible for a .NET Namespace to be implemented by more than one assembly; there is not a one-to-one-mapping between .NET Namespaces and assemblies. Indeed, the main top-level .NET Namespace, System, is spread over a number of different assembly files.

Within a single .NET Namespace there can be any number of classes, but each has its own unique name. The full name of a class is the name of the class itself, prefixed by the name of the .NET namespace and a dot. For example, the full name of the DateTime class in the .NET namespace System is System.DateTime.

There can be any number of different versions of an assembly installed on your computer, and there can be several .NET namespaces with the same name, implemented in different sets of assembly files; for example, written by different authors.

To use a .NET Class, it is necessary to tell the system to load the assembly (dll) in which it is defined. In many languages (including C#) this is done by supplying the names of the assemblies or the pathnames of the assembly files as a compiler directive.

Secondly, to avoid the verbosity of programmers having to always refer to full class names, the C# and Visual Basic languages allow the .NET namespace prefix to be elided. In this case, the programmer must declare a list of .NET namespaces with Using (C#) and Imports (Visual Basic) declaration statements. This list is then used to resolve unqualified class names referred to in the code.

In either language, when the compiler encounters the unqualified name of a class, it searches the specified .NET namespaces for that class.

In Dyalog APL, this mechanism is implemented by the ⎕USING system variable. ⎕USING performs the same two tasks that Using/Imports declarations and compiler directives provide in C# and Visual Basic; namely to give a list of .NET namespaces to be searched for unqualified class names, and to specify the assemblies which are to be loaded.

⎕USING is a vector of character vectors each element of which contains 1 or 2 comma-delimited strings. The first string specifies the name of a .NET namespace; the second specifies the pathname of an assembly file. This may be a full pathname or a relative one, but must include the file extension (.dll). If just the file name is specified, it is assumed to be located in the standard .NET Framework directory that was specified when the .NET Framework was installed (e.g. C:\windows\Microsoft.NET\Framework\v2.0.50727)

It is convenient to treat .NET namespaces and assemblies in pairs. For example:

⎕USING←'System,mscorlib.dll'
  ⎕USING,←⊂'System.Windows.Forms,System.Windows.Forms.dll'  ⎕USING,←⊂'System.Drawing,System.Drawing.dll'

Note that because Dyalog APL automatically loads mscorlib.dll (which contains the most commonly used classes in the System Namespace), it is not actually necessary to specify it explicitly in ⎕USING.

⎕USING has Namespace scope, i.e. each Dyalog APL Namespace, Class or Instance has its own value of ⎕USING that is initially inherited from its parent space but which may be separately modified. ⎕USING may also be localised in a function header, so that different functions can declare different search paths for .NET namespaces/assemblies.

If ⎕USING is empty (⎕USING←0⍴⊂''), APL will not search for .NET classes in order to resolve names which would otherwise give a VALUE ERROR.

Assigning a simple character vector to ⎕USING is equivalent to setting it to the enclose of that vector. The statement (⎕USING←'') does not empty ⎕USING, it sets it to a single empty element, which gives access to mscorlib.dll and the Bridge DLL without a namespace prefix.

Within a Class script, you may instead employ one or more :Using statements to specify the .NET search path. Each of these statements is equivalent to appending an enclosed character vector to ⎕USING.

     :Using System,mscorlib.dll
     :Using System.Windows.Forms,System.Windows.Forms.dll
     :Using System.Drawing,System.Drawing.dll

Classes also inherit from the namespace they are contained in. The statement

     :Using

Is equivalent to

     ⎕USING←0⍴⊂''

…and allows a class to clear the inherited value before appending to ⎕USING, or to state that no .NET assemblies should be loaded.

The equivalent to ⎕USING←'') is a :Using statement followed by a comma separator but no namespace prefix and no assembly name:

    :Using ,


Using .NET Classes

To create a Dyalog APL object as an instance of a .NET class, you use the ⎕NEW system function. The ⎕NEW system function is monadic. It takes a 1 or 2-element argument, the first element being a class.

If the argument is a scalar or a 1-element vector, an instance of the class is created using the constructor that takes NO argument.

If the argument is a 2-element vector, an instance of the class is created using the constructor whose argument matches the disclosed second element.

For example, to create a DateTime object whose value is the 30th April 2008:

      ⎕USING←'System'

      mydt←⎕NEW DateTime (2008 4 30)

The result of ⎕NEW is an reference to the newly created instance:

      ⎕NC ⊂'mydt'
9.2

If you format a reference to a .NET Object, APL calls its ToString method to obtain a useful description or identification of the object. This topic is discussed in more detail later in this chapter.

      mydt
30/04/2008 00:00:00

If you want to use fully qualified class names instead, one of the elements of ⎕USING must be an empty vector. For example:

      ⎕USING←,⊂''

      mydt←⎕NEW System.DateTime (2008 4 30)

When creating an instance of the DateTime class, you are required to provide an argument with two elements: (the class and the constructor argument, in our case a 3-element vector representing the date). Many classes provide a default constructor which takes no arguments. From Dyalog APL, the default constructor is called by calling ⎕NEW with only a reference to the class in the argument. For example, to obtain a default Button object, we only need to write:

      mybtn←⎕NEW Button

The above statement assumes that you have defined ⎕USING correctly; there must be a reference to System.Windows.Forms.dll, and a namespace prefix which allows the name Button to be recognised as System.Windows.Forms.Button.

The mechanism by which APL associates the class name with a class in a .NET namespace is described below.

Constructors and Overloading

Each .NET Class has one or more constructor methods. A constructor is a method which is called to initialise an instance of the Class. Typically, a Class will support several constructor methods - each with a different set of parameters. For example, System.DateTime supports a constructor that takes three Int32 parameters (year, month, day), another that takes six Int32 parameters (year, month, day, hour, minute, second), and so forth. These different constructor methods are not distinguished by having different names but by the different sets of parameters they accept.

This concept, which is known as overloading, may seem somewhat alien to the APL programmer. After all, we are used to defining functions that accept a whole range of different arguments. However, type checking, which is fundamental to the .NET Framework, requires that a method is called with the correct number of parameters, and that each parameter is of a predefined type. Overloading solves this issue.

When you create an instance of a class in C#, you do so using the new operator. This is automatically mapped to the appropriate constructor method by matching the parameters you supply to the various forms of the constructor. A similar mechanism is implemented in Dyalog APL using the ⎕NEW system function.

How the ⎕NEW System Function is implemented

When APL executes an expression such as:

      mydt←⎕NEW DateTime (2008 4 30)

the following logic is used to resolve the reference to DateTime correctly.

The first time that APL encounters a reference to a non-existent name (i.e. a name that would otherwise generate a VALUE ERROR), it searches the .NET namespaces/assemblies specified by ⎕USING for a .NET class of that name. If found, the name (in this case DateTime) is recorded in the APL symbol table with a name class of 9.6 and is associated with the corresponding .NET namespace. If not, VALUE ERROR is reported as usual. Note that this search ONLY takes place if ⎕USING has been assigned a value.

Subsequent references to that symbol (in this case DateTime) are resolved directly and do not involve any assembly searching.

If you use ⎕NEW with only a class as argument, APL will attempt to call the version of its constructor that is defined to take no arguments. If no such version of the constructor exists, the call will fail with a LENGTH ERROR.

Otherwise, if you use ⎕NEW with a class as argument and a second element, APL will call the version of the constructor whose parameters match the second element you have supplied to ⎕NEW. If no such version of the constructor exists, the call will fail with a LENGTH ERROR.

Notes

  • The value of ⎕USING is only used when an object is instantiated. Changing the value of ⎕USING has no effect on objects that have already been instantiated in the active workspace.
  • When a workspace containing .Net objects is saved, .the names of the Net objects are saved with it but they are not automatically re-instantiated when the workspace is loaded or copied. A reference to such an orphaned object will report (NULL).

Displaying a .NET Object

When you display a reference to a .NET object, APL calls the object's ToString method and displays the result. All objects provide a ToString method because all objects ultimately inherit from the .NET class System.Object. Many .NET classes will provide their own ToString that overrides the one inherited from System.Object, and return a useful description or identifier for the object in question. ToString usually supports a range of calling parameters, but APL always calls the version of ToString that is defined to take no calling parameters. Monadic format (⍕) and monadic ⎕FMT have been extended to provide the same result, and provides a quick shorthand method to call ToString in this way. The default ToString supplied by System.Object returns the name of the object's Type. This can be changed using the system function ⎕DF. For example,

     z←⎕NEW DateTime ⎕TS
     z.(⎕DF(⍕DayOfWeek),,'G< 99:99>'⎕FMT 100⊥Hour Minute)
     z
Saturday 09:17

Note that if you want to check the type of an object, this can be obtained using the GetType method, which is supported by all .NET objects.

Disposing of .NET Objects

.NET objects are managed by the .NET Common Language Runtime (CLR). The CLR allocates memory for an object when it is created, and de-allocates this memory when it is no longer required.

When the (last) reference from Dyalog APL to a .NET object is expunged by ⎕EX or by localisation, the system marks the object as unused, leaving it to the CLR to de-allocate the memory that it had previously allocated to it, when appropriate. Note that even though Dyalog has de-referenced the APL name, the object could potentially still be referenced by another .NET class.

De-allocated memory may not actually be re-used immediately and may indeed never be re-used, depending upon the algorithms used by the CLR garbage disposal.

Furthermore, a .NET object may allocate unmanaged resources (such as window handles) which are not automatically released by the CLR.

To allow the programmer to control the freeing of resources associated with .NET objects in a standard way, objects implement the IDisposable interface which provides a Dispose() method. The C# language provides a using control structure that automates the freeing of resources. Crucially, it does so however the flow of execution exits the control structure, even as a result of error handling. This obviates the need for the programmer to call Dispose() explicitly wherever it may be required.

This programming convenience is provide in Dyalog APL by the :Disposable ... :EndDisposable control structure. For further information, see Language Reference Guide: Disposable Statement.


Advanced Techniques

Shared Members

Certain .NET Classes provide methods, fields and properties, that can be called directly without the need to create an instance of the Class first. These members are known as shared, because they have the same definition for the class and for any instance of the class.

The methods Now and IsLeapYear exported by System.DateTime fall into this category. For example:

      ⎕USING←,⊂'System'

      DateTime.Now
07/11/2008 11:30:48

      DateTime.IsLeapYear 2000
1

APL language extensions for .NET objects

The .NET Framework provides a set of standard operators (methods) that are supported by certain classes. These operators include methods to compare two .NET objects and methods to add and subtract objects.

In the case of the DateTime Class, there are operators to compare two DateTime objects. For example:

      DT1←⎕NEW DateTime (2008 4 30)
      DT2←⎕NEW DateTime (2008 1 1)

     ⍝ Is DT1 equal to DT2 ?
      DateTime.op_Equality DT1 DT2
0

The op_Addition and op_Subtraction operators add and subtract TimeSpan objects to DateTime objects. For example:

      DT3←DateTime.Now
      DT3
07/11/2008 11:33:45

      TS←⎕NEW TimeSpan (1 1 1)
      TS
01:01:01

      DateTime.op_Addition DT3 TS
07/11/2008 12:34:46

      DateTime.op_Subtraction DT3 TS
07/11/2008 10:32:44

The corresponding APL primitive functions have been extended to accept .NET objects as arguments and simply call these standard .NET methods internally. The methods and the corresponding APL primitives are shown in the table below.

Note that calculations and comparisons performed by .NET methods are performed independently from the values of APL system variables (such as ⎕FR and ⎕CT).

.NET Method | APL Primitive Function
op_Addition | +
op_Subtraction | -
op_Multiply | ×
op_Division | ÷
op_Equality | =
op_Inequality | ≠
op_LessThan | <
op_LessThanOrEqual | ≤
op_GreaterThan | >
op_GreaterThanOrEqual | ≥

So instead of calling the appropriate .NET method to compare two objects, you can use the familiar APL primitive instead. For example:

      DT1=DT2
0
      DT1>DT2
1
      DT3+TS
07/11/2008 12:34:46
      DT3-TS
07/11/2008 10:32:44

Apart from being easier to use, the primitive functions automatically handle arrays and support scalar extension; for example:

      DT1>DT2 DT3
1 0

In addition, the monadic form of Grade Up (⍋) and Grade Down (⍒), and the Minimum (⌊) and Maximum (⌈) primitive functions have been extended to work on arrays of references to .NET objects. Note that the argument(s) must be a homogeneous set of references to objects of the same .NET class, and in the case of Grade Up and Grade Down, the argument must be a vector. For example:

      ⍋DT1 DT2 DT3
2 1 3
      ⌊/DT1 DT2 DT3
01/01/2008 00:00:00

Exceptions

When a .NET object generates an error, it does so by throwing an exception. An exception is in fact a .NET class whose ultimate base class is System.Exception.

The system constant ⎕EXCEPTION returns a reference to the most recently generated exception object.

For example, if you attempt to create an instance of a DateTime object with a year that is outside its range, the constructor throws an exception. This causes APL to report a (trappable) EXCEPTION error (error number 90) and access to the exception object is provided by ⎕EXCEPTION.

      ⎕USING←'System'
      DT←⎕NEW DateTime (100000 0 0)
EXCEPTION
      DT←⎕NEW DateTime (100000 0 0)

      ⎕EN
90
      ⎕EXCEPTION.Message
Year, Month, and Day parameters describe an un-representable DateTime.

      ⎕EXCEPTION.Source
mscorlib

      ⎕EXCEPTION.StackTrace
   at System.DateTime.DateToTicks(Int32 year,
                                  Int32 month,
                                  Int32 day)

   at System.DateTime..ctor(Int32 year,
                            Int32 month,
                            Int32 day)

Specifying Overloads and Casts

If a .NET function is overloaded in terms of the types of arguments it accepts, Dyalog APL chooses which overload to call depending upon the data types of the arguments passed to it. For example, if a .NET function foo() is declared to take a single argument either of type int or of type double APL would call the first version if you called it with an integer value and the second version if you called it with a non-integer value.

In some circumstances it may be desirable to override this mechanism and explicitly specify which overload to use.

A second requirement is to be able to specify to what .NET types APL should coerce arrays before calling a .NET function. For example, if a parameter to a .NET function is declared as type System.Object, it might be necessary to force the APL argument to be cast to a particular type of Object before the function is called.

Both these requirements are met by calling the function via the Variant operator ⍠. There are two options, OverloadTypes (the Principle Option) and CastToTypes. Each option takes an array of refs to .NET types, the same length as the number of parameters to the function.

OverloadTypes Examples

To force APL to call the double version of function foo() regardless of the type of the argument val:

      (foo ⍠('OverloadTypes'Double))val

or more simply:

      (foo ⍠Double)val

Note that Double is a ref to the .NET type System.Double.

      ⎕USING←'System'
      Double
(System.Double)

Taking this a stage further, suppose that foo() is defined with 5 overloads as follows:

foo()
foo(int i)
foo(double d)
foo(double d, int i)
foo(double[] d)

The following statements will call the niladic, double, (double, int) and double[] overloads respectively.

(foo ⍠ (⊂⍬)) ⍬                              ⍝ niladic
(foo ⍠ Double) 1                            ⍝ double
(foo ⍠(⊂Double Int32))1 1                   ⍝ double,int
(foo ⍠(Type.GetType ⊂'System.Double[]'))⊂1 1 ⍝ double[]

Note that in the niladic case, an enclosed empty vector is used to represent a null reference to a .NET type.

CastToTypes Example

The .NET function Array.SetValue() sets the value of a specified element (or elements) of an array. The first argument, the new value, is declared as System.Object, but the value supplied must correspond to the type of the Array in question. APL has no means to know what this is and will therefore pass the value as is, i.e. in whatever internal format it happens to be at the time. For example:

      ⎕USING←'System'

      ⍝ create a Boolean  array with 2 elements
      BA←Array.CreateInstance Boolean 2
      BA.GetValue 0 ⍝ get the 0th element
0
      ⍝ attempt to set the 0th element to 1 (AKA true)
      BA.SetValue 1 0
EXCEPTION: Cannot widen from source type to target type
either because the source type is a not a primitive type or the conversion cannot be accomplished.
test[5] BA.SetValue 1 0
       ∧

The above expression failed because APL passed the first argument 1 ,unchanged from its current internal representation, as a 1-byte integer which does not fit into a Boolean element.

To rectify the situation, APL must be told to cast the argument to a Boolean as follows:

      (BA.SetValue ⍠ ('CastToTypes'(Boolean Int32)))1 0
      BA.GetValue 0 ⍝ get the 0th element
1

Overloaded Constructors

If a class provides constructor overloads, a similar mechanism is used to specify which of the constructors is to be used when an instance of the class is created using ⎕NEW.

For example, if MyClass is a .NET class with an overloaded constructor, and one of its constructors is defined to take two parameters; a double and an int, the following statement would create an instance of the class by calling that specific constructor overload:

      (⎕NEW ⍠ (⊂Double Int32)) MyClass (1 1)


More Examples

Directory and File Manipulation

The .NET Namespace System.IO (also in the Assembly mscorlib.dll) provides some useful facilities for manipulating files. For example, you can create a DirectoryInfo object associated with a particular directory on your computer, call its GetFiles method to obtain a list of files, and then get their Name and CreationTime properties.

      ⎕USING←,⊂'System.IO'
      d←⎕NEW DirectoryInfo (⊂'C:\Dyalog')

d is an instance of the Directory Class, corresponding to the directory c:\Dyalog In this document, we will refer to the location where Dyalog APL is installed as C:\Dyalog. Your installation of Dyalog APL may be in a different folder or even on a different drive but the examples should work just the same it you replace C:\Dyalog by your folder name 1.

      d
C:\Dyalog

The GetFiles method returns a list of files; actually, FileInfo objects, that represent each of the files in the directory: Its optional argument specifies a filter; for example:

      d.GetFiles ⊂'*.exe'
 evalstub.exe  exestub.exe  dyalog.exe  dyalogrt.exe

The Name property returns the name of the file associated with the File object:

      (d.GetFiles ⊂'*.exe').Name
 evalstub.exe  exestub.exe  dyalog.exe  dyalogrt.exe

And the CreationTime property returns its creation time, which is a DateTime object:

      (d.GetFiles ⊂'*.exe').CreationTime

01/04/2004 09:37:01 01/04/2004 09:37:01 08/06/2004 ...

If you call GetFiles without an argument (in APL, with an argument of ⍬), it returns a complete list of files:

      files←d.GetFiles ⍬

Taking advantage of namespace reference array expansion, an expression to display file names and their creation times is as follows.

      files,[1.5]files.CreationTime
 relnotes.hlp       03/02/2004 11:47:02
 relnotes.cnt       03/02/2004 11:47:02
 def_uk.dse         22/03/2004 12:13:31
 DIALOGS.HLP        22/03/2004 12:13:31
 dyares32.dll       22/03/2004 12:13:40
 ...

Sending an email

The .NET Namespace System.Web.Mail provides objects for handing email.

You can create a new email message as an instance of the MailMessage class, set its various properties, and then send it using the SmtpMail class.

Please note that these examples will only work if your computer is configured to allow you to send email in this way.

      ⎕USING←'System.Web.Mail,System.Web.dll'
      m←⎕NEW MailMessage
      m.From←'tony.blair@uk.gov'
      m.To←'sales@dyalog.com'
      m.Subject←'order'
      m.Body←'Send me 100 copies of Dyalog APL now'

      SmtpMail.Send m

However, note that the Send method of the SmtpMail object is overloaded and may be called with a single parameter of type System.Web.Mail.MailMessage as above, or four parameters of type System.String:

So instead, you can just say:

      SmtpMail.Send 'tony.blair@uk.gov'
                    'sales@dyalog.com'
                    'order'
                    'Send me the goods'

Web Scraping

The .NET Framework provides a whole range of classes for accessing the internet from a program. The following example illustrates how you can read the contents of a web page. It is complicated, but realistic, in that it includes code to cater for a firewall/proxy connection to the internet. It is only 9 lines of APL code, but each line requires careful explanation.

First we need to define ⎕USING so that it specifies all of the .NET Namespaces and Assemblies that we require.

      ⎕USING←'System,System.dll' 'System.Net' 'System.IO'

The WebRequest class in the .NET Namespace System.Net implements the .NET Framework's request/response model for accessing data from the Internet. In this example we create a WebRequest object associated with the URI http://www.cdnow.com. Note that WebRequest is an example of a static class. You don't make instances of it; you just use its methods.

      wrq←WebRequest.Create ⊂'http://www.cdnow.com'

In fact (and somewhat confusingly) if the URI specifies a scheme of "http://" or "https://", you get back an object of type HttpWebRequest rather than a plain and simple WebRequest. So, at this stage, wrq is an HttpWebRequest object.

      wrq
System.Net.HttpWebRequest

This class has a Proxy property through which you specify the proxy information for a request made through a firewall. The value assigned to the Proxy property has to be an object of type System.Net.WebProxy. So first we must create a new WebProxy object specifying the hostname and port number for the firewall. You will need to change this statement to suit your own internet configuration (it may even not be necessary to do this).

      PX←⎕NEW WebProxy(⊂'http://dyagate.dyadic.com:8080')
      PX
System.Net.WebProxy

Having set up the WebProxy object as required, we then assign it to the Proxy property of the HttpRequest object wrq.

      wrq.Proxy←PX

The HttpRequest class has a GetResponse method that returns a response from an internet resource. No it's not HTML (yet), the result is an object of type System.Net.HttpWebResponse.

      wr←wrq.GetResponse
      wr
System.Net.HttpWebResponse

The HttpWebResponse class has a GetResponseStream method whose result is of type System.Net.ConnectStream. This object, whose base class is System.IO.Stream, provides methods to read and write data both synchronously and asynchronously from a data source, which in this case is physically connected to a TCP/IP socket.

      str←wr.GetResponseStream
      str
System.Net.ConnectStream

However, there is yet another step to consider. The Stream class is designed for byte input and output; what we need is a class that reads characters in a byte stream using a particular encoding. This is a job for the System.IO.StreamReader class. Given a Stream object, you can create a new instance of a StreamReader by passing it the Stream as a parameter.

      rdr←⎕NEW StreamReader str
      rdr
System.IO.StreamReader

Finally, we can use the ReadToEnd method of the StreamReader to get the contents of the page.

      s←rdr.ReadToEnd
      ⍴s
45242

Note that to avoid running out of connections, it is necessary to close the Stream:

      str.Close


Enumerations

An enumeration is a set of named constants that may apply to a particular operation. For example, when you open a file you typically want to specify whether the file is to be opened for reading, for writing, or for both. A method that opens a file will take a parameter that allows you to specify this. If this is implemented using an enumerated constant, the parameter may be one of a specific set of (typically) integer values; for example, 1=read, 2=write, 3=both read and write. However, to avoid using meaningless numbers in code, it is conventional to use names to represent particular values. These are known as enumerated constants or, more simply, as enums.

In the .NET Framework, enums are implemented as classes that inherit from the base class System.Enum. The class as a whole represents a set of enumerated constants; each of the constants themselves is represented by a static field within the class.

The next chapter deals with the use of System.Windows.Forms to create and manipulate the user interface. The classes in this .NET Namespace use enums extensively.

For example, there is a class named System.Windows.Forms.FormBorderStyle that contains a set of static fields named None, FixedDialog, Sizeable, and so forth. These fields have specific integer values, but the values themselves are of no interest to the programmer.

Typically, you use an enumerated constant as a parameter to a method or to specify the value of a property. For example, to create a Form with a particular border style, you would set its BorderStyle property to one of the members of the FormBorderStyle class, viz.

⎕USING←'System'
  ⎕USING,←⊂'System.Windows.Forms,system.windows.forms.dll'
f1←⎕NEW Form
f1.BorderStyle←FormBorderStyle.FixedDialog
FormBorderStyle.⎕NL ¯2 ⍝ List enum members
Fixed3D  FixedDialog  FixedSingle  FixedToolWindow  None
Sizable  SizableToolWindow

An enum has a value, which you may use in place of the enum itself when such usage is unambiguous. For example, the FormBorderStyle.Fixed3D enum has an underlying value is 2:

     Convert.ToInt32 FormBorderStyle.Fixed3D
2

You could set the border style of the Form f1 to FormBorderStyle.Fixed3D with the expression:

      f1.BorderStyle←2

However, this practice is not recommended. Not only does it make your code less clear, but also if a value for a property or a parameter to a method may be one of several different enum types, APL cannot tell which is expected and the call will fail.

For example, when the constructor for System.Drawing.Font is called with 3 parameters, the 3rd parameter may be either a FontStyle enum or a GraphicsUnit enum. If you were to call Font with a 3rd parameter of 1, APL cannot tell whether this refers to a FontStyle enum, or a GraphicsUnit enum, and the call will fail.


Handling Pointers with Dyalog.ByRef

Certain .NET methods take parameters that are pointers.

An example is the DivRem method that is provided by the System.Math class. This method performs an integer division, returning the quotient as its result, and the remainder in an address specified as a pointer by the calling program.

APL does not have a mechanism for dealing with pointers, so Dyalog provides a .NET class for this purpose. This is the Dyalog.ByRef class, which is a provided by an Assembly that is loaded automatically by the Dyalog APL program.

Firstly, to gain access to the Dyalog .NET Namespace, it must be specified by ⎕USING. Note that you need not specify the Assembly (DLL) from which it is obtained (the Bridge DLL), because (like mscorlib.dll) it is automatically loaded by when APL starts.

      ⎕USING←'System' 'Dyalog'

The Dyalog.ByRef class represents a pointer to an object of type System.Object. It has a number of constructors, some of which are used internally by APL itself. You only need to be concerned about two of them; the one that takes no parameters, and the one that takes a single parameter of type System.Object. The former is used to create an empty pointer; the latter to create a pointer to an object or some data.

For example, to create an empty pointer:

      ptr1←⎕NEW ByRef

Or, to create pointers to specific values,

      ptr2←⎕NEW ByRef 0
      ptr3←⎕NEW ByRef (⊂⍳10)
      ptr4←⎕NEW ByRef (⎕NEW DateTime (2000 4 30))

Notice that a single parameter is required, so you must enclose it if it is an array with several elements. Alternatively, the parameter may be a .NET object.

The ByRef class has a single property called Value.

      ptr2.Value
0
      ptr3.Value
1 2 3 4 5 6 7 8 9 10
      ptr4.Value
30/04/2000 00:00:00

Note that if you reference the Value property without first setting it, you get a VALUE ERROR.

      ptr1.Value
VALUE ERROR
      ptr1.Value
     ^

Returning to the example, we recall that the DivRem method takes 3 parameters:

  1. the numerator
  2. the denominator
  3. a pointer to an address into which the method will write the remainder after performing the division.
      remptr←⎕NEW ByRef
      remptr.Value
VALUE ERROR
      remptr.Value
      ^
      Math.DivRem 311 99 remptr
3
      remptr.Value
14

In some cases a .NET method may take a parameter that is an Array and the method expects to fill in the array with appropriate values. In APL there is no syntax to allow a parameter to a function to be modified in this way. However, we can use the Dyalog.ByRef class to call this method. For example, the System.IO.FileStream class contains a Read method that populates its first argument with the bytes in the file.

      ⎕using←'System.IO' 'Dyalog' 'System'
      fs←⎕NEW FileStream ('c:\tmp\jd.txt' FileMode.Open)
      fs.Length
25
      fs.Read(arg←⎕NEW ByRef,⊂⊂25⍴0)0 25
25
      arg.Value
104 101 108 108 111 32 102 114 111 109 32 106 111 104 110 32 100 97 105 110 116 114 101 101 10


DECF Conversion

Incoming .NET data types VT_DECIMAL (96-bit integer) and VT_CY (currency value represented by a 64-bit two's complement integer, scaled by 10,000) are converted to 126-bit decimal numbers (DECFs). This conversion is performed independently of the value of ⎕FR.

If you want to perform arithmetic on values imported in this way, then you should set ⎕FR to 1287, at least for the duration of the calculations.

Note that the .NET interface converts System.Decimal to DECFs but does not convert System.Int64 to DECFs.


Introduction

System.Windows.Forms is a .NET namespace that provides a set of classes for creating the Graphical User Interface for Windows applications.

As an alternative to the built-in Dyalog GUI, Windows Forms has been superseded by Windows Presentation Foundation which is described in the next Chapter. This section is included to support existing Dyalog applications that make use of Windows Forms.

Unless otherwise specified, all the examples described in this Chapter may be found in the samples\winforms\winforms.dws workspace.


Creating GUI Objects

GUI objects are represented by .NET classes in the .NET Namespace System.Windows.Forms. In general, these classes correspond closely to the GUI objects provided by Dyalog APL, which are themselves based upon the Windows API.

For example, to create a form containing a button and an edit field, you would create instances of the Form, Button and TextBox classes.


Object Hierarchy

The most striking difference between the Windows.Forms GUI and the Dyalog GUI is that in Windows.Forms the container hierarchy represented by forms, group boxes, and controls is not represented by an object hierarchy. Instead, objects that represent GUI controls are created stand-alone (i.e. without a parent) and then associated with a container, such as a Form, by calling the Add method of the parent’s Controls collection. Notice too that Windows.Forms objects are associated with APL symbols that are namespace references, but Windows.Forms objects do not have implicit names.


Positioning and Sizing Forms and Controls

The position of a form or a control is specified by its Location property, which is measured relative to the top left corner of the client area of its container.

Location has a data type of System.Drawing.Point. To set Location, you must first create an object of type System.Drawing.Point then assign that object to Location.

Similarly, the size of an object is determined by its Size property, which has a data type of System.Drawing.Size. This time, you must create a System.Drawing.Size object before assigning it to the Size property of the control or form.

Objects also have Top(Y) and Left(X) properties that may be specified or referenced independently. These accept simple numeric values.

The position of a Form may instead be determined by its DeskTopLocation property, which is specified relative to the taskbar. Another alternative is to set the StartPosition property whose default setting is WindowsDefaultLocation, which represents a computed best location.


Modal Dialog Boxes

Dialog Boxes are displayed modally to prevent the user from performing tasks outside of the dialog box.

To create a modal dialog box, you create a Form, set its BorderStyle property to FixedDialog, set its ControlBox, MinimizeBox and MaximizeBox properties to false, and display it using ShowDialog.

A modal dialog box has a DialogResult property that is set when the Form is closed, or when the user presses OK or Cancel. The value of this property is returned by the ShowDialog method, so the simplest way to handle user actions is to check the result of ShowDialog and proceed accordingly. Example 1 illustrates a simple modal dialog box.

Example 1

Function EG1 illustrates how to create and use a simple modal dialog box. Much of the function is self-explanatory, but the following points are noteworthy.

EG1[1-2] set ⎕USING to include the .NET Namespaces System.Windows.Forms and System.Drawing.

EG1[6,8,9] create a Form and two Button objects. As yet, they are unconnected. The constructor for both classes is defined to take no arguments, so the ⎕NEW system function is only called with a class argument.

EG1[14] shows how the Location property is set by first creating a new Point object with a specific pair of (x and y) values.

EG1[18] computes the values for the Point object for button2.Location, from the values of the Left, Height and Top properties of button1; thus positioning button2 relative to button1.

     ∇ EG1;form1;button1;button2;true;false;⎕USING;Z
[1]    ⎕USING←,⊂'System.Windows.Forms,
                 System.Windows.Forms.dll'
[2]    ⎕USING,←⊂'System.Drawing,System.Drawing.dll'
[3]    true false←1 0
[4]
[5]    ⍝ Create a new instance of the form.
[6]    form1←⎕NEW Form
[7]    ⍝ Create two buttons to use as the accept and cancel btns
[8]    button1←⎕NEW Button
[9]    button2←⎕NEW Button
[10]
[11]   ⍝ Set the text of button1 to "OK".
[12]   button1.Text←'OK'
[13]   ⍝ Set the position of the button on the form.
[14]   button1.Location←⎕NEW Point,⊂10 10
[15]   ⍝ Set the text of button2 to "Cancel".
[16]   button2.Text←'Cancel'
[17]   ⍝ Set the position of the button relative to button1.
[18]   button2.Location←⎕NEW Point,
                   ⊂button1.Left button1.(Height+Top+10)
[19]

EG1[21,23] sets the DialogResult property of button1 and button2 to DialogResult.OK and DialogResult.Cancel respectively. Note that DialogResult is an enumeration with a predefined set of member values.

Similarly, EG1[32] defines the BorderStyle property of the form using the FormBorderStyle enumeration.

EG1[38 40] defines the AcceptButton and CancelButton properties of the Form to button1 and button2 respectively. These have the same effect as the Dyalog GUI Default and Cancel properties.

EG1[42] sets the StartPosition of the Form to be centre screen. Once again this is specified using an enumeration; FormStartPosition.

[20]  ⍝ Make button1's dialog result OK.
[21]   button1.DialogResult←DialogResult.OK
[22]  ⍝ Make button2's dialog result Cancel.
[23]   button2.DialogResult←DialogResult.Cancel
[24]
[25]
[26]   ⍝ Set the title bar text of the form.
[27]   form1.Text←'My Dialog Box'
[28]   ⍝ Display a help button on the form.
[29]   form1.HelpButton←true
[30]
[31]   ⍝ Define the border style of the form to that of a
                                               dialog box.
[32]   form1.BorderStyle←FormBorderStyle.FixedDialog
[33]   ⍝ Set the MaximizeBox to false to remove the
                                             maximize box.
[34]   form1.MaximizeBox←false
[35]   ⍝ Set the MinimizeBox to false to remove the
                                             minimize box.
[36]   form1.MinimizeBox←false
[37]   ⍝ Set the accept button of the form to button1.
[38]   form1.AcceptButton←button1
[39]   ⍝ Set the cancel button of the form to button2.
[40]   form1.CancelButton←button2
[41]   ⍝ Set the start position of the form to the centre
                                            of the screen.
[42]   form1.StartPosition←FormStartPosition.CenterScreen
[43]

EG1[45 46] associate the buttons with the Form. The Controls property of the Form returns an object of type Form.ControlCollection. This class has an Add method that is used to add a control to the collection of controls that are owned by the Form.

EG1[50] calls the ShowDialog method (with no argument; hence the ⍬). The result is an object of type Form.DialogResult, which is an enumeration.

EG1[52] compares the result returned by ShowDialog with the enumeration member DialogResult.OK (note that the primitive function = has been extended to compare objects).

[44]   ⍝ Add button1 to the form.
[45]   form1.Controls.Add button1
[46]   ⍝ Add button2 to the form.
[47]   form1.Controls.Add button2
[48]
[49]   ⍝ Display the form as a modal dialog box.
[50]   Z←form1.ShowDialog ⍬
[51]   ⍝ Determine if the OK button was clicked on the
                                              dialog box.
[52]   :If Z=DialogResult.OK
[53]      ⍝ Display a message box saying that the OK
                                      button was clicked.
[54]       Z←MessageBox.Show⊂'The OK button on the form
                                             was clicked.'
[55]   :Else
[56]      ⍝ Display a message box saying that the Cancel
                                      button was clicked.
[57]       Z←MessageBox.Show⊂'The Cancel button on the
                                        form was clicked.'
[58]   :EndIf
     ∇

Warning: The use of modal forms in .NET can lead to problematic situations while debugging. As the control is passed to .NET the APL interpreter cannot regain control in the event of an unforeseen error. It is advisable to change the code to something like the following until the code is fully tested:

[52]   form1.Visible←1
[53]   :While form1.Visible ⋄ :endwhile

Example 2

Functions EG2 and EG2A illustrate how the Each operator (¨) and the extended namespace reference syntax in Dyalog APL may be used to produce more succinct, and no less readable, code.

     ∇ EG2;form1;label1;textBox1;true;false;⎕USING;Z
[1]    ⎕USING←,⊂'System.Windows.Forms,
                 System.Windows.Forms.dll'
[2]    ⎕USING,←⊂'System.Drawing,System.Drawing.dll'
[3]    true false←1 0
[4]
[5]    ⍝ Create a new instance of the form.
[6]    form1←⎕NEW Form
[7]
[8]    textBox1←⎕NEW TextBox
[9]    label1←⎕NEW Label
[10]
[11]   ⍝ Initialize the controls and their bounds.
[12]   label1.Text←'First Name'
[13]   label1.Location←⎕NEW Point (48 48)
[14]   label1.Size←⎕NEW Size (104 16)
[15]   textBox1.Text←''
[16]   textBox1.Location←⎕NEW Point (48 64)
[17]   textBox1.Size←⎕NEW Size (104 16)
[18]
[19]   ⍝ Add the TextBox control to the form's control
          collection.
[20]   form1.Controls.Add textBox1
[21]   ⍝ Add the Label control to the form's control
          collection.
[22]   form1.Controls.Add label1
[23]
[24]   ⍝ Display the form as a modal dialog box.
[25]   Z←form1.ShowDialog ⍬
     ∇

EG2A[7] takes advantage of the fact that .NET classes are namespaces, so the expression Form TextBox Label is a vector of namespace refs, and the expression ⎕NEW¨Form TextBox Label runs the ⎕NEW system function on each of them.

Similarly, EG2A[10 11 12] combine the use of extended namespace reference and the Each operator to set the Text, Location and Size properties in several objects together.

     ∇ EG2A;form1;label1;textBox1;true;false;⎕USING;Z
[1]    ⍝ Compact version of EG2 taking advantage of ref
          syntax and ¨
[2]    ⎕USING←'System.Windows.Forms,System.Windows.Forms.dll'
[3]    ⎕USING,←⊂'System.Drawing,System.Drawing.dll'
[4]    true false←1 0
[5]
[6]    ⍝ Create a new instance of the form, TextBox and Label.
[7]    (form1 textBox1 label1)←⎕NEW¨Form TextBox Label
[8]
[9]    ⍝ Initialize the controls and their bounds.
[10]   (label1 textBox1).Text←'First Name' ''
[11]   (label1 textBox1).Location←⎕NEW¨Point,¨⊂¨(48 48)(48 64)
[12]   (label1 textBox1).Size←⎕NEW¨Size,¨⊂¨(104 16)(104 16)
[13]
[14]   ⍝ Add the Label and TextBox controls to the form's
          control collection.
[15]   form1.Controls.AddRange⊂label1 textBox1
[16]
[17]   ⍝ Display the form as a modal dialog box.
[18]   Z←form1.ShowDialog ⍬
     ∇


Non-Modal Forms

Non-modal Forms are displayed using the Run method of the System.Windows.Forms.Application object. This method is designed to be called once, and only once, during the life of an application and this poses problems during APL development. Fortunately, it turns out that, in practice, the restriction is that Application.Run may only be run once on a single system thread. However, it may be run successively on different system threads. During development, you may therefore test a function that calls Application.Run, by running it on a new APL thread using Spawn (&). See Chapter 13 for further details.

DataGrid Examples

Three functions in the samples\winforms\winforms.dws workspace provide examples of non-modal Forms. These examples also illustrate the use of the WinForms.DataGrid class.

Function Grid1 is an APL translation of the example given in the help file for the DataGrid class in the .NET SDK Beta1. The original code has been slightly modified to work with the current version of the SDK.

Function Grid2 is an APL translation of the example given in the help file for the DataGrid class in the .NET SDK Beta2.

Function Grid is an APL translation of the example given in the file:

C:\Program Files\Microsoft.NET\SDK\v1.1\...
QuickStart\winforms\samples\Data\Grid\vb\Grid.vb

This example uses Microsoft SQL Server 2000 to extract sample data from the sample NorthWind database. To run this example, you must have SQL Server running and you must modify function Grid_Load to specify the name of your server.

GDIPLUS Workspace

The samples\winforms\gdiplus.dws workspace contains a sample that demonstrates the use of non-rectangular Forms. It is a direct translation into APL from a C# sample (WinForms-Graphics-GDIPlusShape) that was distributed on the Visual Studio .NET Beta 2 Resource CD.

TETRIS Workspace

The samples\winforms\tetris.dws workspace contains a sample that demonstrates the use of graphics. It is a direct translation into APL from a C# sample (WinForms-Graphics-Tetris) that was distributed on the Visual Studio .NET Beta 2 Resource CD.

WEBSERVICES Workspace

An example of a non-modal Form is provided by the WFGOLF function in the samples\asp.net\webservices\webservices.dws workspace. This function performs exactly the same task as the GOLF function in the same workspace, but it uses Windows.Forms instead of the built-in Dyalog GUI.

WFGOLF, and its callback functions WFBOOK and WFSS perform exactly the same task, with almost identical dialog box appearance, of GOLF and its callbacks BOOK and SS that are described in Chapter 7.

Note that when you run WFGOLF or GOLF for the first time, you must supply an argument of 1 to force the creation of the proxy class for the GolfService web service.


Introduction

Windows Presentation Foundation is a graphical system that includes a programmable Graphical User Interface. It is supplied as a set of Microsoft .NET assemblies and is supported on all current Windows platforms.

The WPF GUI is in many ways more sophisticated and powerful than either Dyalog APL's own built-in GUI or the GUI provided by Windows Forms.

Like any other set of .NET classes, WFP can be integrated into Dyalog APL applications via the .NET interface. Dyalog APL users may therefore develop GUI applications that are based upon WPF as an alternative to the built-in Dyalog GUI or Windows Forms.

Quite apart from its advanced GUI capabilities, WPF supports data binding. This is a complex subject, but putting it very simply, data binding allows a property of a user-interface object (such as the Text property of a TextBox object) to be bound to some data. When the data changes, the bound property of the object changes and vice versa.

Dyalog APL Version 14 includes a data binding function (2015⌶This function may remain as an I-beam or be replaced by one or more system functions in a future Version of Dyalog APL. 1) which supports data binding to APL arrays and namespaces.

A WPF GUI can be built dynamically by creating a set of component objects (using ⎕NEW) in a similar way to the Dyalog APL GUI and Windows Forms. However, the same user-interface can instead be specified statically using XAML, a text markup system that describes the GUI using XML. Along with data binding, this feature allows the application logic and the user-interface to be developed and maintained separately.

The examples described in this section are provided in the workspace WPFIntro.dws


Temperature Converter

Temperature Converter Tutorial

This tutorial illustrates how to go about developing a simple WPF application in Dyalog APL. It is functionally identical to the GUI tutorial example that illustrates how to develop a GUI application using the built-in Dyalog APL Graphical User Interface. See Interface Guide: GUI Tutorial.

Like the GUI Tutorial, this is necessarily an elementary example, but illustrates the principles that are involved. The example is a simple Temperature Converter.

The user may enter a temperature value in either Fahrenheit or Centigrade and have it converted to the other scale.

No attempt has been made to update the WPF example, in terms of its user-interface, from the original version which was developed for Windows 3. This allows a direct comparison to be made between using the WPF and using the built-in Dyalog GUI.

There are two versions provided. The first uses XAML to describe the user-interface with code to drive it. The second version is written entirely in APL code. The two versions of this example may be found in WPFIntro.dws in the namespaces UsingXAML and UsingCode respectively.


Using XAML

The functions and data for this example are provided in the workspace WPFIntro.dws in the namespace WPF.UsingXAML. To run the example:

      )LOAD wpfintro
      WPF.UsingXAML.TempConverter

Arguably the easiest way to create a WPF GUI is to define it using XAML. The XAML defines the structure, layout and appearance of the user-interface in a very concise manner. It is still necessary to write code to display the XAML and to respond to user actions, but the amount of code involved is minimal.

The XAML for the Temperature Converter is shown below.

<Window
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Name="Temp"
 Title="WPF Temperature Converter"
 SizeToContent="WidthandHeight">
  <DockPanel LastChildFill="False">
    <Menu DockPanel.Dock="Top">
        <MenuItem Header="_Scale">
            <MenuItem Name="mnuFahrenheit" Header="_Fahrenheit"
             IsCheckable="True" IsChecked="True"/>
            <MenuItem Name="mnuCentigrade" Header="_Centigrade"
             IsCheckable="True"/>
        </MenuItem>
    </Menu>
    <Grid Width="230" Margin="40,10,10,10">
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="80"/>
        <ColumnDefinition Width="60"/>
      </Grid.ColumnDefinitions>
    <Label Grid.Row="0" Grid.Column="0" Content="Fahrenheit"/>
    <Label Grid.Row="1" Grid.Column="0" Content="Centigrade"/>
    <TextBox Name="txtFahrenheit" Grid.Row="0" Grid.Column="1"
     Margin="5"/>
    <TextBox Name="txtCentigrade" Grid.Row="1" Grid.Column="1"
     Margin="5"/>
    <Button Name="btnF2C" Grid.Row="0" Grid.Column="2"
     Content="F>C" Margin="5"/>
    <Button Name="btnC2F" Grid.Row="1" Grid.Column="2"
     Content="C>F" Margin="5"/>
    <Button Name="btnQuit" Grid.Row="2" Grid.Column="1"
     Content="Quit" Margin="5"/>
    </Grid>
    <ScrollBar Name="scrTemp" DockPanel.Dock="Right"  Width="20"
     Orientation="Vertical" Minimum="1" Maximum="213">
    </ScrollBar>
  </DockPanel>
</Window>

The window defined by this XAML is illustrated in the screen image shown above. Let us examine the XAML, component by component.

Parent and Child Controls

First, notice how the structure of the GUI is defined by enclosing the child components inside the opening and closing tags of its parent. So:

<Window
...
  <DockPanel>
...
  </DockPanel>
</Window>

specifies a Window control that contains a DockPanel control.

Similarly,

    <Menu>
        <MenuItem ... >
            <MenuItem ... />
            <MenuItem ... />
        </MenuItem>
    </Menu>

defines a Menu that contains a MenuItem, that itself contains two other MenuItem objects.

Named and Un-named Controls

Secondly, notice that certain objects are named whereas others are not. For example: TextBox Name="mnuFahrenheit defines a TextBox named txtFahenheit; whereas <DockPanel ...> defines an unnamed DockPanel object.

Objects are given names so that they can be referenced from the code that displays content in the user-interface or handles the user actions. In this case, the code will read the content of the txtFahrenheit TextBox but has no need to reference the DockPanel.

The Main Window

<Window
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Name="Temp"
 Title="WPF Temperature Converter"
 SizeToContent="WidthandHeight">
...
</Window>

This extract of XAML defines a Window control; a top-level window that is equivalent to a Dyalog APL GUI Form.

The xmlns attributes define the XML namespaces (effectively the vocabulary of the xml scheme) and are mandatory in an XAML document.

The name of the TextBox is Temp, and its caption is WFP Temperature Converter. The SizeToContent property is set to "WidthandHeight", which causes the TextBox to automatically size itself to fit its content in both horizontal and vertical directions.

The DockPanel

 <DockPanel LastChildFill="False">
..
 </DockPanel>

WPF provides a number of layout controls. These are containers whose only purpose is to arrange child controls in a particular way, and to dictate how they are re-arranged when the parent window is resized. The DockPanel is one of the simplest of the WPF layout controls.

In this case, the DockPanel is controlling 3 child windows a Menu, a Grid and a ScrollBar.

The attachment of a particular child control is specified by setting its DockPanel.Dock property. By default, the last control added to a DockPanel is stretched to fill the remaining space when the window is expanded. In this case, the requirement is for a fixed-width scrollbar attached to the right edge, so the default is overridden by setting the LastChildFill property to "False".

The Menu

    <Menu DockPanel.Dock="Top">
        <MenuItem Header="_Scale">
            <MenuItem Name="mnuFahrenheit" Header="_Fahrenheit"
             IsCheckable="True" IsChecked="True"/>
            <MenuItem Name="mnuCentigrade" Header="_Centigrade"
             IsCheckable="True"/>
        </MenuItem>
    </Menu>

The above extract from the XAML defines a Menu. Setting Dock to "Top" causes the Menu as a whole to be docked, so that it appears like a menubar, along the top of the DockPanel. The Menu contains a single MenuItem labelled Scale which itself contains two sub-items labelled Fahrenheit and Centigrade respectively. The IsCheckable property specifies whether or not the user can check the MenuItem, and the IsChecked property sets and reports its checked state. The underscore characters (e.g. as in "_Scale") identify the following character as a keyboard shortcut.

The Grid

    <Grid Width="230" Margin="40,10,10,10">
    ...
    </Grid>

The Grid object is another WPF layout control that organises other controls in rows and columns. Here, the XAML defines a Grid with a width of 230; a left margin if 40, and a top, right and bottom margin of 10. As there is no explicit unit specified, the system uses the default device-independent unit (px) of 1/96th inch.

The rows and columns of a Grid are defined by collections of RowDefinition and ColumnDefinition objects.

Here the XAML specifies that the Grid contains 3 rows, each of which has a Height set to "Auto" which means that its height depends upon the height of its content.

      <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
      </Grid.RowDefinitions>

Similarly, there are 3 columns. The first column (which will contain labels) takes its width from its content, i.e. it will be just wide enough to display the longest label. The other columns for the edit boxes and buttons are specified to be 80px and 60px wide respectively. In this case, the content (TextBox and Button objects) will take their widths from that of the column.

     <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="80"/>
        <ColumnDefinition Width="60"/>
      </Grid.ColumnDefinitions>

The Label Objects(Column 1)

    <Label Grid.Row="0" Grid.Column="0" Content="Fahrenheit"/>
    <Label Grid.Row="1" Grid.Column="0" Content="Centigrade"/>

Here the XAML specifies Label objects Fahrenheit and Centigrade. Because they are defined within the <Grid> ...</Grid> tags, they are child objects of the Grid. In addition it is necessary to specify in which cells they are displayed using their Grid.Row and Grid.Column properties. Note that the cell coordinates have zero origin.

The TextBox Objects(Column 2)

    <TextBox Name="txtFahrenheit" Grid.Row="0" Grid.Column="1"
     Margin="5"/>
    <TextBox Name="txtCentigrade" Grid.Row="1" Grid.Column="1"
     Margin="5"/>

The XAML specifies two TextBox objects named txtFahrenheit and txtCentigrade respectively. Setting Margin to "5" means that a margin of 5px is applied around each edge; otherwise the text boxes would occupy the entire width of the column (80px). The effective width of each TextBox will therefore be 70px (80-2×5).

The Button Objects (Column 3)

    <Button Name="btnF2C" Grid.Row="0" Grid.Column="2"
     Content="F>C" Margin="5"/>
    <Button Name="btnC2F" Grid.Row="1" Grid.Column="2"
     Content="C>F" Margin="5"/>
    <Button Name="btnQuit" Grid.Row="2" Grid.Column="1"
     Content="Quit" Margin="5"/>

The XAML specifies three named Button controls. Note that the caption on a Button is specified by its Content property.

The ScrollBar Object

This example uses a ScrollBar which the user may scroll to input a value, either in Fahrenheit or Centigrade depending upon which of the two menu items (Fahrenheit or Centigrade) is checked.A ScrollBar is not the ideal choice of control for this type of user interation, but this example is designed to look and behave like the original Dyalog GUI example, which was written for the original version of Dyalog APL for Windows. 1

    <ScrollBar Name="scrTemp" DockPanel.Dock="Right"  Width="20"
     Orientation="Vertical" Minimum="1" Maximum="213">
    </ScrollBar>

This XAML snippet defines a ScrollBar named scrTemp.

Setting DockPanel.Dock to "Right" means that it will be docked (aligned) on the right edge of the DockPanel. It will be a vertical scrollbar, have a fixed width of 20px and a default height. The range of the ScrollBar is defined by its Minimum and Maximum properties which are set so that the ScrollBar will specify a value in Fahrenheit.

Note that in order to cause the ScrollBar to be docked (aligned) along the right edge of the DockPanel it is necessary to set LastChildFill to "False" (for the DockPanel) and Dock to "Right" (for the ScrollBar), because the value of LastChildFill (default "True") overrides the Dock value of the last defined child of the DockPanel.

Note

The XAML that defines this user-interface is at the same time both simple and complex. It is simple because (in this case) it is readily understood. It is complex because in order to write it, the user-interface designer must understand precisely how the various controls and their properties behave and work together. For these details, you should refer to the appropriate documentation and check out the large number of examples published on the internet.

The Code to display the XAML

The function TempConverter shown below contains the code needed to display and operate the user interface whose layout is defined by the XAML described above.

     ∇ TempConverter;str;xml;win;txtFahrenheit;txtCentigrade;mnuFahrenheit;mnuCentigrade;btnF2C;btnC2F;btnQuit;scrTemp;sink
[1]    ⎕USING←'System'
[2]    ⎕USING,←⊂'System.IO'
[3]    ⎕USING,←⊂'System.Windows.Markup'
[4]    ⎕USING,←⊂'System.Xml,system.xml.dll'
[5]    ⎕USING,←⊂'System.Windows.Controls.Primitives,WPF/PresentationFramework.dll'
[6]
[7]    str←⎕NEW StringReader(⊂XAML)
[8]    xml←⎕NEW XmlTextReader str
[9]    win←XamlReader.Load xml
[10]
[11]   txtFahrenheit←win.FindName⊂'txtFahrenheit'
[12]   txtCentigrade←win.FindName⊂'txtCentigrade'
[13]   mnuFahrenheit←win.FindName⊂'mnuFahrenheit'
[14]   mnuFahrenheit.onClick←'SET_F'
[15]   mnuCentigrade←win.FindName⊂'mnuCentigrade'
[16]   mnuCentigrade.onClick←'SET_C'
[17]   (btnF2C←win.FindName⊂'btnF2C').onClick←'f2c'
[18]   (btnC2F←win.FindName⊂'btnC2F').onClick←'c2f'
[19]   (btnQuit←win.FindName⊂'btnQuit').onClick←'Quit'
[20]   (scrTemp←win.FindName⊂'scrTemp').onScroll←'F2C'
[21]   sink←win.ShowDialog
     ∇

The variable XAML (a character vector) contains the XAML described previously.

Note that apart from the names given to the objects by the XAML and used by the function, the XAML and the code are independent.

TempConverter[7-8] create a XamlReader object from the character vector via StringReader and XmlTextReader objects.

[7]    str←⎕NEW StringReader(⊂XAML)
[8]    xml←⎕NEW XmlTextReader str

TempConverter[9] instantiates the XAML content by calling its Load method, which returns a reference win to the top-level control (in this case a Window) defined therein. The Window is not yet visible.

[9]    win←XamlReader.Load xml

Earlier, it was explained that objects defined by the XAML must be named in order that they can be referenced (used) by the code. The mechanism to achieve this is to call the FindName method of the Window, which returns a reference to the specified (named) object. So these statements:

[11]   txtFahrenheit←win.FindName⊂'txtFahrenheit'
[12]   txtCentigrade←win.FindName⊂'txtCentigrade'

obtain refs (in this case named txtFahrenheit and txtCentigrade) to objects named txtFahrenheit and txtCentigrade. It is convenient (but not essential) to use the same name for the ref as is used for the control.

Most of the remaining statements obtain refs to the MenuItem, Button and ScrollBar objects and attach callback functions to their Click and Scroll events respectively.

[13]   mnuFahrenheit←win.FindName⊂'mnuFahrenheit'
[14]   mnuFahrenheit.onClick←'SET_F'
[15]   mnuCentigrade←win.FindName⊂'mnuCentigrade'
[16]   mnuCentigrade.onClick←'SET_C'
[17]   (btnF2C←win.FindName⊂'btnF2C').onClick←'f2c'
[18]   (btnC2F←win.FindName⊂'btnC2F').onClick←'c2f'
[19]   (btnQuit←win.FindName⊂'btnQuit').onClick←'Quit'
[20]   (scrTemp←win.FindName⊂'scrTemp').onScroll←'F2C'

Finally the code displays the Window and hands it over to the user by calling the ShowDialog method of the top-level Window.

[21]   sink←win.ShowDialog

ShowDialog displays the Window modally; i.e. until it is closed, the user may interact only with that Window. It is equivalent to ⎕DQ win or win.Wait in the Dyalog built-in GUI.

The CallBack Functions

The callback functions are named as they are in the basic Dyalog GUI example and are remarkably similar. See Interface Guide: GUI Tutorial.

Callback function f2c which is attached to the Click event of the btnF2C button (labelled F>C) reads the character string in the txtFahrenheit TextBox, converts it to a number using Text2Num, calculates the equivalent in centigrade and then displays the result in the txtCentigrade TextBox.

     ∇ f2c;value
[1]    ⍝ Callback to convert Fahrenheit to Centigrade
[2]    :If 1=⍴,value←Text2Num txtFahrenheit.Text
[3]        txtCentigrade.Text←2⍕(value-32)×5÷9
[4]    :Else
[5]        txtCentigrade.Text←'invalid'
[6]    :EndIf
     ∇

For completeness, the Text2Num function is shown below. Note that if the user enters an invalid number, Text2Num returns an empty vector, and the callback displays the text invalid instead.

     ∇ num←Text2Num txt;val
[1]    val num←⎕VFI txt
[2]    num←val/num
     ∇

The c2f function converts from Centigrade to Fahrenheit when the user presses the button labelled C>F.

     ∇ c2f;value
[1]   ⍝ Callback to convert Centigrade to Fahrenheit
[2]    :If 1=⍴,value←Text2Num txtCentigrade.Text
[3]        txtFahrenheit.Text←2⍕32+value÷5÷9
[4]    :Else
[5]        txtFahrenheit.Text←'invalid'
[6]    :EndIf
     ∇

The callbacks F2C and C2F, one of which at a time is attached to the Scroll event of the ScrollBar object are shown below. The argument Msg contains two items, namely:

[1] | Object | a ref to the ScrollBar object
[2] | Object | a ref to an object of type System.Windows.Controls.Primitives.ScrollEventArgs

In this case the code uses the NewValue property of the ScrollEventArgs object. An alternative would be to refer to the Value property of the ScrollBar object

     ∇ F2C Msg;C;F;val
[1]   ⍝ Callback for Fahrenheit input via scrollbar
[2]    txtFahrenheit.Text←2⍕val←213-(2⊃Msg).NewValue
[3]    txtCentigrade.Text←2⍕(val-32)×5÷9
     ∇

     ∇ C2F Msg;C;F;val
[1]   ⍝ Callback for Centigrade input via scrollbar
[2]    txtCentigrade.Text←2⍕val←101-(2⊃Msg).NewValue
[3]    txtFahrenheit.Text←2⍕32+val÷5÷9
     ∇

The callbacks SET_F and SET_C which are attached to the Click events of the two MenuItem objects are shown below.

     ∇ SET_F
[1]   ⍝ Sets the scrollbar to work in Fahrenheit
[2]    scrTemp.(Minimum Maximum)←1 213
[3]    scrTemp.onScroll←'F2C'
[4]    mnuFahrenheit.IsChecked←1
[5]    mnuCentigrade.IsChecked←0
     ∇

     ∇ SET_C
[1]   ⍝ Sets the scrollbar to work in Centigrade
[2]    scrTemp.(Minimum Maximum)←1 101
[3]    scrTemp.onScroll←'C2F'
[4]    mnuCentigrade.IsChecked←1
[5]    mnuFahrenheit.IsChecked←0
     ∇

Finally, the callback function Quit which is attached to the Click event on the Quit button, simply calls the Close method of the Window:

     ∇ Quit arg
[1]    win.Close
     ∇

Notice that unlike its equivalent in the Dyalog GUI, it is not appropriate to close the Window using the expression ⎕EX 'win'. This would expunge the ref to the Window but have no effect on the Window itself.


Using Code

The functions for this example are provided in the workspace WPFIntro.dws in the namespace WPF.UsingCode. To run the example:

      )LOAD wpfintro
      WPF.UsingCode.TempConverter

The following function TempConverter performs exactly the same task of defining and manipulating the user-interface for the Temperature Converter example using XAML which was discussed previously.

The callback functions it uses are identical.

     ∇ TempConverter;⎕USING;win;dp;mnu;mnuFahrenheit;mnuCentigrade;gr;tn;rd1;rd2;rd3;rc1;rc2;rc3;l1;l2;txtFahrenheit;txtCentigrade;btnF2C;btnC2F;btnQuit;sink;mnuScale;scrTemp
[1]
[2]    ⎕USING←,⊂'System.Windows.Controls,WPF/PresentationFramework.dll'
[3]    ⎕USING,←⊂'System.Windows.Controls.Primitives,WPF/PresentationFramework.dll'
[4]    ⎕USING,←⊂'System.Windows,WPF/PresentationFramework.dll'
[5]    ⎕USING,←⊂'System.Windows,WPF/PresentationCore.dll'
[6]
[7]    win←⎕NEW Window
[8]    win.SizeToContent←SizeToContent.WidthAndHeight
[9]    win.Title←'WPF Temperature Converter'
[10]
[11]   dp←⎕NEW DockPanel
[12]   dp.LastChildFill←0
[13]
[14]   mnu←⎕NEW Menu
[15]
[16]   mnuScale←⎕NEW MenuItem
[17]   mnuScale.Header←'_Scale'
[18]   sink←mnu.Items.Add mnuScale
[19]
[20]   mnuFahrenheit←⎕NEW MenuItem
[21]   mnuFahrenheit.Header←'Fahrenheit'
[22]   mnuFahrenheit.IsCheckable←1
[23]   mnuFahrenheit.IsChecked←1
[24]   mnuFahrenheit.onClick←'SET_F'
[25]   sink←mnuScale.Items.Add mnuFahrenheit
[26]
[27]   mnuCentigrade←⎕NEW MenuItem
[28]   mnuCentigrade.Header←'_Centigrade'
[29]   mnuCentigrade.IsCheckable←1
[30]   mnuCentigrade.IsChecked←0
[31]   mnuCentigrade.onClick←'SET_C'
[32]   sink←mnuScale.Items.Add mnuCentigrade
[33]
[34]   sink←dp.Children.Add mnu
[35]   dp.SetDock mnu Dock.Top
[36]
[37]   gr←⎕NEW Grid
[38]   gr.Width←230
[39]   gr.Margin←⎕NEW Thickness(40 10 10 10)
[40]
[41]   rd1←⎕NEW RowDefinition
[42]   rd1.Height←GridLength.Auto
[43]   rd2←⎕NEW RowDefinition
[44]   rd2.Height←GridLength.Auto
[45]   rd3←⎕NEW RowDefinition
[46]   rd3.Height←GridLength.Auto
[47]   gr.RowDefinitions.Add¨rd1 rd2 rd3
[48]
[49]   rc1←⎕NEW ColumnDefinition
[50]   rc1.Width←GridLength.Auto
[51]   rc2←⎕NEW ColumnDefinition
[52]   rc2.Width←⎕NEW GridLength 80
[53]   rc3←⎕NEW ColumnDefinition
[54]   rc3.Width←⎕NEW GridLength 60
[55]   gr.ColumnDefinitions.Add¨rc1 rc2 rc3
[56]
[57]   l1←⎕NEW Label
[58]   l1.Content←'Fahrenheit'
[59]   sink←gr.Children.Add l1
[60]   gr.SetRow l1 0
[61]   gr.SetColumn l1 0
[62]
[63]   l2←⎕NEW Label
[64]   l2.Content←'Centigrade'
[65]   sink←gr.Children.Add l2
[66]   gr.SetRow l2 1
[67]   gr.SetColumn l2 0
[68]
[69]   txtFahrenheit←⎕NEW TextBox
[70]   txtFahrenheit.Margin←⎕NEW Thickness 5
[71]   sink←gr.Children.Add txtFahrenheit
[72]   gr.SetRow txtFahrenheit 0
[73]   gr.SetColumn txtFahrenheit 1
[74]
[75]   txtCentigrade←⎕NEW TextBox
[76]   txtCentigrade.Margin←⎕NEW Thickness 5
[77]   sink←gr.Children.Add txtCentigrade
[78]   gr.SetRow txtCentigrade 1
[79]   gr.SetColumn txtCentigrade 1
[80]
[81]   btnF2C←⎕NEW Button
[82]   btnF2C.Content←'F>C'
[83]   btnF2C.Margin←⎕NEW Thickness 5
[84]   btnF2C.onClick←'f2c'
[85]   sink←gr.Children.Add btnF2C
[86]   gr.SetRow btnF2C 0
[87]   gr.SetColumn btnF2C 2
[88]
[89]   btnC2F←⎕NEW Button
[90]   btnC2F.Content←'C>F'
[91]   btnC2F.Margin←⎕NEW Thickness 5
[92]   btnC2F.onClick←'c2f'
[93]   sink←gr.Children.Add btnC2F
[94]   gr.SetRow btnC2F 1
[95]   gr.SetColumn btnC2F 2
[96]
[97]   btnQuit←⎕NEW Button
[98]   btnQuit.Content←'Quit'
[99]   btnQuit.Margin←⎕NEW Thickness 5
[100]  btnQuit.onClick←'Quit'
[101]  sink←gr.Children.Add btnQuit
[102]  gr.SetRow btnQuit 2
[103]  gr.SetColumn btnQuit 1
[104]
[105]  sink←dp.Children.Add gr
[106]
[107]  scrTemp←⎕NEW ScrollBar
[108]  scrTemp.Width←20
[109]  scrTemp.Orientation←Orientation.Vertical
[110]  scrTemp.Minimum←1
[111]  scrTemp.Maximum←213
[112]  scrTemp.onScroll←'F2C'
[113]
[114]  sink←dp.Children.Add scrTemp
[115]  dp.SetDock scrTemp Dock.Right
[116]
[117]  win.Content←dp
[118]
[119]  sink←win.ShowDialog
     ∇

Although this approach appears at first sight to be considerably more verbose than using XAML (a 120-line function compared with a 21-line function and a 44-line block of XAML) each line of code performs only one very simple task, and no attempt has been made to write utility functions to perform the same task for similar controls, as might be done in a real application.

As before, let us examine the code line-by-line.

TempConverter[2-5] define ⎕USING so that the appropriate .NET assemblies are on the search-path. Note that the ScrollBar control is in System.Windows.Controls.Primitives and not System.Windows.Controls like the others.

[2]    ⎕USING←,⊂'System.Windows.Controls,WPF/PresentationFramework.dll'
[3]    ⎕USING,←⊂'System.Windows.Controls.Primitives,WPF/PresentationFramework.dll'
[4]    ⎕USING,←⊂'System.Windows,WPF/PresentationFramework.dll'
[5]    ⎕USING,←⊂'System.Windows,WPF/PresentationCore.dll'

TempConverter[8-9] creates a Window and sets its SizeToContent and Title properties as in the XAML example. Notice however that whereas using XAML the string SizeToContent="WidthandHeight" is sufficient, when using code it is necessary to get the Type right. In this case, the SizeToContent property must be set to a specific member (in this case WidthAndHeight) of the System.Windows.SizeToContent enumeration. Other members of this Type are Width, Height and Manual (the default).

[7]    win←⎕NEW Window
[8]    win.SizeToContent←SizeToContent.WidthAndHeight
[9]    win.Title←'WPF Temperature Converter'

TempConverter[11-12] create a DockPanel control and set its LastChildFill property to 0. In this case the APL value 0 is used instead of the string "False" in XAML.

[11]   dp←⎕NEW DockPanel
[12]   dp.LastChildFill←0

TempConverter[14] creates a Menu control.

[14]   mnu←⎕NEW Menu

TempConverter[16-18] create a MenuItem control with the caption Scale, and then add the control to the Items collection of the main Menu using its Add method. This illustrates one significant difference between using XAML and code. In XAML, the parent/child relationships between controls are defined by the structure and order of the XML. Using code, child controls must be explicitly added to the appropriate list of child controls managed by the parent.

[16]   mnuScale←⎕NEW MenuItem
[17]   mnuScale.Header←'_Scale'
[18]   sink←mnu.Items.Add mnuScale

TempConverter[20-25] create a MenuItem control labelled Fahrenheit. The IsCheckable and IsChecked properties are set to 1, which is equivalent to "True" in XAML. The callback function SET_F is assigned to the Click event exactly as in the XAML version of this example. The last line in this section makes the Fahrenheit MenuItem a child of the Scale MenuItem.

[20]   mnuFahrenheit←⎕NEW MenuItem
[21]   mnuFahrenheit.Header←'Fahrenheit'
[22]   mnuFahrenheit.IsCheckable←1
[23]   mnuFahrenheit.IsChecked←1
[24]   mnuFahrenheit.onClick←'SET_F'
[25]   sink←mnuScale.Items.Add mnuFahrenheit

The code used to create the Centigrade MenuItem is more or less the same.

TempConverter[34-35] adds the top-level Menu to the DockPanel. Note that in the case of a DockPanel, the list of its child controls is represented by its Children property. Furthermore, to define how it is docked this is done, using code, by the SetDock method of the DockPanel. This contrasts with the way this is achieved using XAML (DockPanel.Dock="Top"). Note too that the argument to SetDock is not just a simple string as in XAML, but a member of the System.Windows.Controls.Dock enumeration.

[34]   sink←dp.Children.Add mnu
[35]   dp.SetDock mnu Dock.Top

TempConverter[37-39] create the Grid control. Its Width property will accept a simple numeric value, but its Margin property must be given an instance of a System.Windows.Thickness structure. In this case, the ThickNess constructor is given a 4-element numeric vector that specifies its Left, Top, Right and Bottom members respectively.

[37]   gr←⎕NEW Grid
[38]   gr.Width←230
[39]   gr.Margin←⎕NEW Thickness(40 10 10 10)

TempConverter[41-47] create instances of 3 RowDefinition classes and add them to the RowDefinitions collection of the Grid. Note that whereas in XAML the Height can be specified as a string, using code it is necessary once again to use the correct Type. In this case, Height must be specified by a member of the System.Windows.GridLength structure.

[41]   rd1←⎕NEW RowDefinition
[42]   rd1.Height←GridLength.Auto
[43]   rd2←⎕NEW RowDefinition
[44]   rd2.Height←GridLength.Auto
[45]   rd3←⎕NEW RowDefinition
[46]   rd3.Height←GridLength.Auto
[47]   gr.RowDefinitions.Add¨rd1 rd2 rd3

Similarly, TempConverter[49-55] create instances of 3 ColumnDefinition classes and add them to the ColumnDefinitions collection of the Grid. Note that The Width property will not accept a simple numeric value, it must be a member of the GridLength structure. To set the Width to 80, it is necessary first to create an instance of a GridLength structure giving this value as the argument to its constructor.

[49]   rc1←⎕NEW ColumnDefinition
[50]   rc1.Width←GridLength.Auto
[51]   rc2←⎕NEW ColumnDefinition
[52]   rc2.Width←⎕NEW GridLength 80
[53]   rc3←⎕NEW ColumnDefinition
[54]   rc3.Width←⎕NEW GridLength 60
[55]   gr.ColumnDefinitions.Add¨rc1 rc2 rc3

TempConverter[57-61] create a Label control with the caption Fahrenheit. To display the Label in a Grid it is necessary to first add it to the Children collection of the Grid, and then set its position in the Grid using its SetRow and SetColumn methods. Similar code is used to create and position the second Label.

[57]   l1←⎕NEW Label
[58]   l1.Content←'Fahrenheit'
[59]   sink←gr.Children.Add l1
[60]   gr.SetRow l1 0
[61]   gr.SetColumn l1 0

TempConverter[69-73] create and position a TextBox control, in the same way as the Label controls. Notice that in this case, the constructor for the Thickness structure is given a single value that specifies all four of its Left, Top, Right and Bottom members.

[69]   txtFahrenheit←⎕NEW TextBox
[70]   txtFahrenheit.Margin←⎕NEW Thickness 5
[71]   sink←gr.Children.Add txtFahrenheit
[72]   gr.SetRow txtFahrenheit 0
[73]   gr.SetColumn txtFahrenheit 1

TempConverter[81-87] create and position a Button control. The callback function f2c is attached to the Click event in the same way as in the XAML version of this example.

[81]   btnF2C←⎕NEW Button
[82]   btnF2C.Content←'F>C'
[83]   btnF2C.Margin←⎕NEW Thickness 5
[84]   btnF2C.onClick←'f2c'
[85]   sink←gr.Children.Add btnF2C
[86]   gr.SetRow btnF2C 0
[87]   gr.SetColumn btnF2C 2

TempConverter[105] adds the Grid to the list of Children to be managed by the DockControl.

[105]  sink←dp.Children.Add gr

TempConverter[107-112] create a ScrollBar control. Its Width, Minimum and Maximum properties all accept simple numeric values. However, its Orientation property must be set to a member of the System.Windows.Controls.Orientation enumeration.

[107]  scrTemp←⎕NEW ScrollBar
[108]  scrTemp.Width←20
[109]  scrTemp.Orientation←Orientation.Vertical
[110]  scrTemp.Minimum←1
[111]  scrTemp.Maximum←213
[112]  scrTemp.onScroll←'F2C'

TempConverter[114-115] add the ScrollBar to the list of Children managed by the DockPanel, and use its SetDock method to cause it to be right-aligned.

[114]  sink←dp.Children.Add scrTemp
[115]  dp.SetDock scrTemp Dock.Right

Finally, the DockPanel is assigned to the Content property of the Window, and the Window displayed as in the XAML version of this example. Note that a Window may contain just one control.

[117]  win.Content←dp
[118]
[119]  sink←win.ShowDialog


Text Example

Example 1

This example illustrates data binding using XAML to specify the user-interface coupled with an APL function to drive it and handle the data binding.

The XAML

The XAML shown below, describes a Window containing a TextBox.

<Window
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Name="Temp"
 Title="Data Binding (Text)"
 SizeToContent="WidthandHeight">
     <TextBox Name="txt" Width="300" Margin="5"
      Text="{Binding txtSource,Mode=TwoWay,
             UpdateSourceTrigger=PropertyChanged}"/>
</Window>

It contains a data binding expression, namely:

      Text="{Binding txtSource,Mode=TwoWay,
             UpdateSourceTrigger=PropertyChanged}"

This specifies that the Text property of the TextBox is bound to a value in the Binding Source (which has yet to be defined) whose path is txtSource. The binding mode is set to TwoWay which means that any change in the TextBox will be reflected in a new value in the Binding Source, and vice-versa. The value in the Binding Source will be updated when the property (in this case the Text Property) changes.

The APL Code

The function Text which generates this example is shown below.

The argument txt is the text to be displayed initially in the TextBox. Note that the variable XAML_Text contains the XAML that describes the user-interface listed above.

     ∇ Text txt;⎕USING;str;xml;win
[1]    ⎕USING←,⊂'System.Windows.Controls,WPF/PresentationFramework.dll'
[2]    win←LoadXAML XAML
[3]    win.txtBox←win.FindName⊂'txt'
[4]
[5]    ⎕EX'txtSource'
[6]    txtSource←txt
[7]    win.txtBox.DataContext←2015⌶'txtSource'
[8]
[9]    win.Show
     ∇

The utility function LoadXAML incorporates the 3 lines of code, used to create a WPF window from XAML, that were coded in-line in previous examples in this chapter.

     ∇ win←LoadXAML xaml;⎕USING;str;xml
[1]    ⎕USING←'System.IO'
[2]    ⎕USING,←⊂'System.Windows.Markup'
[3]    ⎕USING,←⊂'System.Xml,system.xml.dll'
[4]    ⎕USING,←⊂'System.Windows.Controls,
                 WPF/PresentationFramework.dll'
[5]    str←⎕NEW StringReader(⊂xaml)
[6]    xml←⎕NEW XmlTextReader str
[7]    win←XamlReader.Load xml
     ∇

Text[1] defines the .NET search path needed to access the WPF controls.

[1]    ⎕USING←,⊂'System.Windows.Controls,WPF/PresentationFramework.dll'

Text[2-3] uses the utility function LoadXAML to load a WPF user-interface from the XAML and then uses the FindName method to obtain a reference to the object named txt.

[2]    win←LoadXAML XAML
[3]    win.txtBox←win.FindName⊂'txt'

Text[5-6] initialise a new global variable named txtSource to the value of the argument. When using a global variable as a data binding source, it is generally advisable to establish a new variable by first expunging it. This is because its binding type (the exported type of the data bound variable) is stored in the workspace along with its value, and the binding type (were it to be incorrect) may not be changed once it has been established. 1

[5]   ⎕EX'txtSource'
[6]   txtSource←txt

Text[7]creates a Binding Source object using 2015⌶ and assigns it to the DataContext property of the TextBox object. Because it is a character vector, the exported Type for the bound variable txtSource is System.String which is appropriate for the Text property of a TextBox.

[7]    win.txtBox.DataContext←2015⌶'txtSource'

Text[9] displays the Window. Note that although the APL local variable win goes out of scope when the function terminates, the Window remains visible until the user has closed it.

[9]   win.Show

Testing the Data Binding

The following expressions may be used to explore the effect of data binding.

      )LOAD wpfintro
      )CS DataBinding.Text
      Text 'Hello World'

     txtSource←⌽txtSource

Typing into the TextBox changes the value of the bound variable.

      txtSource
What is in txtSource now?


FontSize Example

Example 2

This example illustrates the use of the optional left argument to 2015⌶ to specify the data type used to export the value of the bound variable.

The XAML

The XAML shown below, describes the same Window containing a TextBox as before.

<Window
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Name="Temp"
 Title="Data Binding (FontSize)"
 SizeToContent="WidthandHeight">
     <TextBox Name="txt" Text="Hello World" Width="300"
      Margin="5"
      FontSize="{Binding sizeSource,Mode=OneWay}"/>
</Window>

This time, the data binding expression is:

      FontSize="{Binding sizeSource,Mode=OneWay}"/>

This specifies that the FontSize property of the TextBox is bound to a value in the Binding Source (which has yet to be defined) whose path is sizeSource. The binding mode is set to OneWay which means that the FontSize property depends on the data value but not vice versa. Were the FontSize to change for any external reason (which is admittedly unlikely in the case of FontSize), it would not alter the value in sizeSource to which it is bound.

The APL Code

The function FontSize is almost identical to the function Text which is described in Example 1.

     ∇ FontSize size;⎕USING;win
[1]    ⎕USING←'System'
[2]    ⎕USING,←⊂'System.Windows.Controls,WPF/PresentationFramework.dll'
[3]    win←LoadXAML XAML
[4]    win.txtBox←win.FindName⊂'txt'
[5]
[6]    ⎕EX'sizeSource'
[7]    sizeSource←size
[8]    win.txtBox.DataContext←Int32(2015⌶)'sizeSource'
[9]
[10]   win.Show
     ∇

The key difference is in FontSize[8]. Here the left argument of (2015⌶) is Int32. This means that the exported Type of the variable sizeSource will be Int32. This Type (a 32-bit integer) is required by the FontSize property of a TextBox; no other Type will do. If this were omitted, APL would export the value of the variable using a Type dependent on its internal format (most likely Int16) and the binding would fail.

[8]    win.txtBox.DataContext←Int32(2015⌶)'sizeSource'

Testing the Data Binding

      )LOAD wpfintro
      )CS DataBinding.FontSize
      FontSize 12

      sizeSource
12
      sizeSource←30


Text and FontSize using Code

Example 3

This example uses APL code to both build the user-interface (instead of using XAML) and handle the data binding. In this case both the Text and the FontSize properties are bound to APL variables. The function is shown below:

     ∇ TextFontSize(txt size);⎕USING;win;sink
[1]    ⎕USING←'System'
[2]    ⎕USING,←,⊂'System.Windows.Controls,WPF/PresentationFramework.dll'
[3]    ⎕USING,←⊂'System.Windows.Controls.Primitives,WPF/PresentationFramework.dll'
[4]    ⎕USING,←⊂'System.Windows,WPF/PresentationFramework.dll'
[5]    ⎕USING,←⊂'System.Windows,WPF/PresentationCore.dll'
[6]
[7]   ⍝ Create a Window, DockPanel and TextBox
[8]    win←⎕NEW Window
[9]    win.SizeToContent←SizeToContent.WidthAndHeight
[10]   win.Title←'Data Binding (Text and FontSize)'
[11]   win.txtBox←⎕NEW TextBox
[12]   win.txtBox.Width←350
[13]   win.Content←win.txtBox
[14]
[15]  ⍝ Define data binding from variable "txtSource"
[16]  ⍝ to the Text property of TextBox win.txtBox
[17]   ⎕EX'txtSource'
[18]   txtSource←txt
[19]   win.txtbinding←⎕NEW Data.Binding(⊂'txtSource')
[20]   win.txtbinding.Source←2015⌶'txtSource'
[21]   win.txtbinding.Mode←Data.BindingMode.TwoWay
[22]   win.txtbinding.UpdateSourceTrigger←Data.UpdateSourceTrigger.PropertyChanged
[23]   sink←win.txtBox.SetBinding TextBox.TextProperty win.txtbinding
[24]
[25]  ⍝ Define data binding from variable "sizeSource"
[26]  ⍝ to the FontSize property of TextBox win.txtBox
[27]   ⎕EX'sizeSource'
[28]   sizeSource←size
[29]   win.fntbinding←⎕NEW Data.Binding(⊂'sizeSource')
[30]   win.fntbinding.Source←Int32(2015⌶)'sizeSource'
[31]   win.fntbinding.Mode←Data.BindingMode.OneWay
[32]   sink←win.txtBox.SetBinding TextBox.FontSizeProperty win.fntbinding
[33]
[34]   win.Show
     ∇

Apart from the code that creates the controls, the only material difference between this and the previous examples is the way that the bindings are handled.

In code (as opposed to using XAML) this is done using explicit Binding objectsBinding objects are implicit in all binding operations, but are created declaratively when using XAML. 1 The code for binding the Text property to the txtSource variable is as follows:

[19]   win.txtbinding←⎕NEW Data.Binding(⊂'txtSource')
[20]   win.txtbinding.Source←2015⌶'txtSource'
[21]   win.txtbinding.Mode←Data.BindingMode.TwoWay
[22]   win.txtbinding.UpdateSourceTrigger←Data.UpdateSourceTrigger.PropertyChanged
[23]   sink←win.txtBox.SetBinding TextBox.TextProperty win.txtbinding

Line [19] creates a Binding object, passing the constructor the name of the APL variable txtSource as the Path to the binding value.

[19]   win.txtbinding←⎕NEW Data.Binding(⊂'txtSource')

Line [20] creates a Binding Source object using 2015⌶ as before, but this time assigns it to the Source property of the Binding object.

[20]   win.txtbinding.Source←2015⌶'txtSource'

Line [21] sets the Mode property of the Binding object to TwoWay (a field of the BindingMode Type). As in Example 1, this specifies two-way binding.

[21]   win.txtbinding.Mode←Data.BindingMode.TwoWay

Line [22] sets the UpdateSourceTrigger property of the Binding object to PropertyChanged (a field of the UpdateSourceTrigger Type). This causes the value in the Binding Source (in this case txtSource) to be changed whenever the property (in this case the Text property) of the TextBox changes. This will occur on every keystroke.

[22]   win.txtbinding.UpdateSourceTrigger←Data.UpdateSourceTrigger.PropertyChanged

(Note that the three types Binding, BindingMode and UpdateSourceTrigger are located in System.Windows.Data)

The code that establishes the binding between the sizeSource variable and the FontSize property is very similar.

[29]   win.fntbinding←⎕NEW Data.Binding(⊂'sizeSource')
[30]   win.fntbinding.Source←Int32(2015⌶)'sizeSource'
[31]   win.fntbinding.Mode←Data.BindingMode.OneWay
[32]   sink←win.txtBox.SetBinding
                TextBox.FontSizeProperty win.fntbinding

Note however that (as in Example 2) the left-argument to (2015⌶) specifies that the exported data type of the sizeSource variable is to be Int32.

Testing the Data Binding

      )LOAD wpfintro
      )CS DataBinding.TextFontSizeCode
      TextFontSize 'Hello World' 30

      txtSource sizeSource←(⌽txtSource) 18

As in previous examples, when the user changes the text, the new text appears in txtSource.

      txtSource
Learn to play the bouzouki!

Note

It is perhaps worth mentioning that if you want to bind two properties of the same object to two APL variables, it has to be done by writing code as shown in this example, using two separate Binding Source objects. This is because using XAML you may only associate a single Binding Source to an object.

However, this minor restriction is easily surmounted by using an APL namespace as a Binding Source as illustrated in the next Example.


Text and Fontsize using XAML

Example 4

This example uses XAML to specify the user-interface and the main components of the data binding.

The XAML

The XAML is much the same as in Example 1 and 2 except that it connects two properties Text and FontSize of the same TextBox to two Paths txtSource and sizeSource.

<Window
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Name="Temp"
 Title="Data Binding (Text and FontSize)"
 SizeToContent="WidthandHeight">
     <TextBox Name="txt" Width="350" Margin="5"
      Text="{Binding txtSource,Mode=TwoWay,
             UpdateSourceTrigger=PropertyChanged}"
      FontSize="{Binding sizeSource,Mode=OneWay}"/>
</Window>

The APL Code

The function TextFontSize is shown below.

     ∇ TextFontSize(txt size);⎕USING;str;xml;win;options
[1]    ⎕USING←'System'
[2]    ⎕USING,←⊂'System.Windows,WPF/PresentationFramework.dll'
[3]
[4]    win←LoadXAML XAML
[5]
[6]    src←⎕NS''
[7]    src.(txtSource sizeSource)←txt size
[8]    options←2 2⍴'txtSource'String'sizeSource'Int32
[9]
[10]   win.DataContext←options(2015⌶)'src'
[11]
[12]   win.Show
     ∇

Lines [6-7] create a new namespace src containg two variables txtSource and sizeSource which are initialised to the arguments of the function.

[6]    src←⎕NS''
[7]    src.(txtSource sizeSource)←txt size

Line [8] creates a local variable named options which will be used as the left argument of 2015⌶). It is a 2-column matrix. The first column is a list of the names of the variables which are to be exported by the namespace when used as a Binding Source. The second column specifies their data types.

[8]    options←2 2⍴'txtSource'String'sizeSource'Int32

Line [10] creates a Binding Source object from the namespace src and a left argument options and assigns it to the DataContext property of the Window win.

[10]   win.DataContext←options(2015⌶)'src'

An alternative would be to assign it to the DataContext property of the TextBox object, but this would require one further line of code to identify it. The reason this works is that the DataContext property of a TextBox (and many other controls) is inherited from its parent Window. This feature allows a single Binding Source namespace to be used to specify data bindings between its component variables and any number of properties of any number of controls in the same Window.

As shown before, the left argument of 2015⌶) is optional. Without it, the namespace would export all its variables using default binding types. In this case, because the binding type of sizeSource must be specified as Int32, it is necessary to use a left argument, which means specifying all the variables involved.

Testing the Data Binding

      )LOAD wpfintro
      )CS DataBinding.TextFontSizeXAML
      DB_Text_FontSize_XAML'Hello World' 30

      src.(txtSource sizeSource←(⌽txtSource) 18)

As in previous examples, when the user changes the text, the new text appears in txtSource.

      src.txtSource
Learn to play the bouzouki!


Filtered List Example

Example 5

WPF data binding provides the means to bind controls that display lists of items, such as the ListBox, ListView, and TreeView controls, to collections of data. These controls are all based upon the ItemsControl class. To bind an ItemsControl to a collection object, you use its ItemsSource property.

If the right argument of 2015⌶ names a variable, or a namespace containing a variable, that is a vector other than a simple character vector, it returns a Binding Source object that provides the necessary interfaces to bind the variable as a collection to the ItemSource property of an ItemsControl.

The APL variable will normally contain a vector of character vectors, because most ItemsControl objects deal with collections of strings. However, any APL vector other than a simple character vector will be treated in this way.

This example illustrates binding between a variable containing a vector of character vectors, to the items of a ListBox.

Incidentally, the ItemsSource property overrides the Items collection as a means to specify the content of the ItemsControl. When the ItemsSource property is set, the Items collection becomes read-only and of fixed-size. Note that the ItemsSource property supports OneWay binding by default.

The XAML

The variable XAML_FilteredList, shown below, contains XAML to specify a Window containing a StackPanel. The StackPanel control is a WPF layout control that organises child controls in a single line, by default vertically. In this example, the StackPanel contains a TextBox and, below it, a WrapPanel, and below that a TextBlock. The WrapPanel is also a layout control that organises its child controls sequentially from left to right. The WrapPanel contains two ListBox controls.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Filtered List Example"
    SizeToContent="WidthAndHeight"
    Topmost="true">
    <StackPanel>
        <TextBox Name="filter" Margin="5"
         Text="{Binding Filter,Mode=TwoWay,
                UpdateSourceTrigger=PropertyChanged}"/>
        <WrapPanel>
            <ListBox Name="all" Width="135" Height="440"
             Margin="5" ItemsSource="{Binding DyalogNames}"/>
            <ListBox Name="filtered" Width="135" Height="440"
             Margin="5" ItemsSource="{Binding FilteredList}"/>
        </WrapPanel>
        <TextBlock Text="Dyalog WPF Demo" Margin="5"/>
    </StackPanel>
 </Window>

The Code

     ∇ FilteredList;MySource;win;sink
[1]
[2]    MySource←⎕NS''
[3]    MySource.Filter←''
[4]    MySource.FilteredList←0⍴⊂''
[5]    MySource.DyalogNames←DyalogNames
[6]
[7]    win←LoadXAML XAML_FilteredList
[8]    win.DataContext←2015⌶'MySource'
[9]    (win.FindName⊂'filter').onTextChanged←
                              'FilteredList_TextChanged'
[10]   sink←win.ShowDialog
     ∇

Like the previous example, this example uses a namespace MySource containing the bound variables Filter, FilteredList and DyalogNames.

FilteredList[8] creates a Binding Source object and assigns it to the DataContext property of the Window win.

[8]    win.DataContext←2015⌶'MySource'

The DataContext property is inherited by all child controls, so they all share the same Binding Source. Their different Paths to different values in the Binding Source are specified in the XAML as follows.

The Text property of the TextBox named filter is bound to the variable Filter by the expression Text="{Binding Filter,...

        <TextBox Name="filter" Margin="5"
         Text="{Binding Filter,Mode=TwoWay,

The ItemsSource property of the ListBox named all is bound to the variable DyalogNames by the expression ItemsSource="{Binding DyalogNames}"

            <ListBox Name="all" Width="135" Height="440"
             Margin="5" ItemsSource="{Binding DyalogNames}"/>

Thirdly, the ItemsSource property of the ListBox named filtered is bound to the variable FilteredList by the expression ItemsSource="{Binding FilteredList}"

            <ListBox Name="filtered" Width="135" Height="440"
             Margin="5" ItemsSource="{Binding FilteredList}"/>

Testing the Data Binding

      FilteredList

If the user types a single character, in this case "e", into the TextBox, this fires a TextChanged event which in turn fires the callback function shown below:

     ∇ FilteredList_TextChanged a;hits
[1]    hits←(⊂MySource.Filter){∨/⍺⍷⍵}¨DyalogNames
[2]    MySource.FilteredList←hits/DyalogNames
     ∇

When the callback runs, the variable MySource.Filter, which is bound to the Text property of the TextBox, will contain "e". The function calculates a mask hits which identifies which members of the variable DyalogNames contain this string. It then assigns that subset to the variable MySource.FilteredList. This is bound to the ItemsSource property of the right-hand ListBox, so the result is as follows:

Similarly, typing "er" into the TextBox reduces the number of hits as shown below:


NetObject Example

Example 6

This example illustrates data binding using a vector of .NET objects, in this case DateTime objects.

The XAML

The XAML shown below, describes a Window containing a StackPanel, inside which is a ListBox.

<Window

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="NetObjects (DateTime) Example"
    SizeToContent="WidthAndHeight" >
    <StackPanel>
         <TextBlock Text="Dates of forthcoming Orthodox Easters"
          FontSize="18" Margin="5"/>
         <ListBox Name="EasterDates" Height="100"
          Margin="5" />
    </StackPanel>
</Window>

The APL Code

The function NetObjects is shown below.

     ∇ NetObjects;⎕USING;win;dt
[1]    ⎕USING←'System'
[2]    win←LoadXAML XAML
[3]    win.dates←win.FindName⊂'EasterDates'
[4]    dt←{⎕NEW DateTime ⍵}¨Easter
[5]    win.dates.ItemsSource←2015⌶'dt'
[6]    sink←win.ShowDialog
     ∇

NetObjects[3] uses FindName to obtain a ref to the ListBox (defined in the XAML) named EasterDates:

[3]    win.dates←win.FindName⊂'EasterDates'

The global variable Easter contains a vector of 3-element numeric vectors representing the dates of forthcoming Orthodox Easter Sundays.

      ↑Easter
2015 4 12
2016 5  1
2017 4 16
2018 4  8
2019 4 28
2020 4 19
2021 5  2
2022 4 24
2023 4 16
2024 5  5

NetObjects[4] creates a vector of DateTime objects from the global variable Easter.

[4]    dt←{⎕NEW DateTime ⍵}¨Easter

Then, NetObjects[5] creates a binding source object from this array and assigns it to the ItemsSource property of the ListBox.

[5]    win.dates.ItemsSource←2015⌶'dt'

Testing the Data Binding

      )LOAD wpfintro
      DataBinding.NETObjects.NETObjects


DateTime Example

Example 6a (Casting to DateTime)

This example is similar to Example 6 but illustrates how numeric data in ⎕TS format can be converted to DateTime type.

The XAML

The XAML shown below describes a Window containing a StackPanel, inside which is a ListBox.

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DateTimes using ⎕TS data"
    SizeToContent="WidthAndHeight" >
    <StackPanel>
         <TextBlock Text="Some High Tides at Portsmouth, England"
          FontSize="18" Margin="5"/>
         <ListBox Name="TideTimes" Height="200"
          Margin="5" />
    </StackPanel>
</Window>

The APL Code

The function Tides is shown below.

     ∇ Tides;⎕USING;win;dt;Highs
[1]    ⎕USING←'System'
[2]    win←LoadXAML XAML_Tides
[3]    win.times←win.FindName⊂'TideTimes'
[4]    Highs←(⊂2016 2 18),¨(7 9)(8 44)(19 47)(21 47)
[5]    Highs,←(⊂2016 2 19),¨(8 17)(10 12)(20 51)(22 51)
[6]    dt←7↑¨Highs
[7]    win.times.ItemsSource←DateTime(2015⌶)'dt'
[8]    sink←win.ShowDialog
     ∇

Tides[3] uses FindName to obtain a ref to the ListBox (defined in the XAML) named TideTimes:

[3]    win.times←win.FindName⊂'TideTimes'

Tides[4-5] creates a vector of integer vectors each of which species the time and date of a high tide at Portsmouth. Tides[6] extends each to 7-elements, which is required to represent a DateTime object.

Then, Tides[7] creates a binding source object from this array and assigns it to the ItemsSource property of the ListBox. Note that the left argument DateTime specifies that the data be cast to that type.

[7]    win.times.ItemsSource←DateTime(2015⌶)'dt'

Testing the Data Binding

      )LOAD wpfintro
      DataBinding.NetObjects.Tides

Tides[3] uses FindName to obtain a ref to the ListBox (defined in the XAML) named TideTimes:

[3]    win.times←win.FindName⊂'TideTimes'

Tides[4-5] creates a vector of integer vectors each of which species the time and date of a high tide at Portsmouth. Tides[6] extends each to 7-elements, which is required to represent a DateTime object.

Then, Tides[7] creates a binding source object from this array and assigns it to the ItemsSource property of the ListBox. Note that the left argument DateTime specifies that the data be cast to that type.

[7]    win.times.ItemsSource←DateTime(2015⌶)'dt'

Testing the Data Binding

      )LOAD wpfintro
      DataBinding.NetObjects.Tides


DataGrid Example

Example 7

This example illustrates data binding using a vector of namespaces.

Each row in the WPF DataGrid control is represented by an object, and each column as a property of that object. Each row in the DataGrid is bound to an object in the data source, and each column in the data grid is bound to a property of the data object.

The XAML

The XAML shown below, describes a Window containing a DockPanel, inside which is a DataGrid.

 <Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DataGrid Example" Height="500"
    SizeToContent="Width"
    Topmost="true">
    <DockPanel>
        <DataGrid Name="DG1" ItemsSource="{Binding}"
                  AutoGenerateColumns="False" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Wine"
                 Binding="{Binding Name}"/>
                <DataGridTextColumn Header="Price"
                 Binding="{Binding Price, StringFormat=C}" />
            </DataGrid.Columns>
        </DataGrid>
    </DockPanel>
 </Window>

The phrase ItemsSource="{Binding}" states that the content of the DataGrid is bound to a data source, which in this case will be inherited from the DataContext property of the parent Window.

Binding="{Binding Name}" specifies that the contents of the first column are bound to a Path named Name in the data source.

Similarly, Binding="{Binding Price, StringFormat=C}" specifies that the Path for the second column is Price (StringFormat=C merely specifies the default currency format).

The APL Code

The function Grid is shown below.

     ∇ Grid;⎕USING;MySource;win
[1]    ⎕USING←'System'
[2]    winelist←⎕NS¨(⍴Wines)⍴⊂''
[3]    winelist.Name←Wines
[4]    winelist.Price←0.01×10000+?(⍴Wines)⍴10000
[5]
[6]    win←LoadXAML XAML
[7]    win.DataContext←2015⌶'winelist'
[8]    win.Show
     ∇

The global variable Wines contains a vector of character vectors, each of which is the name of a wine. Grid[2-4] creates winelist, a vector of namespaces, of the same length, each of which contains two variables c Name and Price.

Testing the Data Binding

      )LOAD wpfintro
      )CS DataBinding.DataGrid
      Grid

Let's round the prices to the nearest $5.

 winelist.Price←5×⌊0.5+winelist.Price÷5


DataGrid Matrix Example

Example 8

This example illustrates data binding using a matrix and is practically identical to Example 7 except that it uses a matrix instead of a vector of namespaces.

Each row in the WPF DataGrid control is represented by an object, and each column as a property of that object. Each row in the DataGrid is bound to an object in the data source, and each column in the data grid is bound to a property of the data object.

The XAML

The XAML shown below, describes a Window containing a DockPanel, inside which is a DataGrid. The XAML is identical to the XAML in Example 7, except for the window caption.

 <Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DataGrid Matrix Example" Height="500"
    SizeToContent="Width"
    Topmost="true">
    <DockPanel>
        <DataGrid Name="DG1" ItemsSource="{Binding}"
                  AutoGenerateColumns="False" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Wine"
                 Binding="{Binding Name}"/>
                <DataGridTextColumn Header="Price"
                 Binding="{Binding Price, StringFormat=C}" />
            </DataGrid.Columns>
        </DataGrid>
    </DockPanel>
 </Window>

The phrase ItemsSource="{Binding}" states that the content of the DataGrid is bound to a data source, which in this case will be inherited from the DataContext property of the parent Window.

Binding="{Binding Name}" specifies that the contents of the first column are bound to a Path named Name in the data source.

Similarly, Binding="{Binding Price, StringFormat=C}" specifies that the Path for the second column is Price (the phrase StringFormat=C merely specifies the default currency format).

The APL Code

The function Grid is shown below.

     ∇ Grid;⎕USING;MySource;win;info
[1]    ⎕USING←'System'
[2]    ⎕EX'winelist'
[3]    winelist←Wines,[1.5]0.01×10000+?(⍴Wines)⍴10000
[4]    win←LoadXAML XAML
[5]    info←(⍪'Name' 'Price'),⊂Object
[6]    win.DataContext←info(2015⌶)'winelist'
[7]    win.Show
     ∇

As in Example 7, the global variable Wines contains a vector of character vectors, each of which is the name of a wine.

Grid[2-4] creates a matrix winelist, whose first column contains the names of the wines, and whose second column their (randomly generated) prices. As this is a global variable, the variable is expunged before being used in order to remove any previous data binding information that was associated with it.

Grid[5]creates the left argument for (2015⌶) which defines the names and data types of the properties which the columns of the matrix winelist will be exposed as. In this case, the names of the paths are Name and Price, and their data types are both System.Object. So the first column will be exposed as Name and the second as Price, matching the path names specified in the XAML:

            <DataGridTextColumn Header="Wine"
            Binding="{Binding Name}"/>
            <DataGridTextColumn Header="Price"
            Binding="{Binding Price, StringFormat=C}" />

Testing the Data Binding

      )LOAD wpfintro
      )CS DataBinding.DataGridMatrix
      Grid

Let's round the prices to the nearest $5.

 winelist[;2]←5×⌊0.5+winelist[;2]÷5

Using Code

The same result can be achieved using code instead of XAML as illustrated by the function GridCodeNoFmt. The function is so-named because this code is insufficient to display the second column in currency format.

     ∇ GridCodeNoFmt;⎕USING;MySource;win;info;fmt
[1]    ⎕USING←'System'
[2]    ⎕USING,←,⊂'System.Windows.Controls,WPF/PresentationFramework.dll'
[3]    ⎕USING,←⊂'System.Windows.Controls.Primitives,WPF/PresentationFramework.dll'
[4]    ⎕USING,←⊂'System.Windows,WPF/PresentationFramework.dll'
[5]    ⎕USING,←⊂'System.Windows,WPF/PresentationCore.dll'
[6]
[7]    ⎕EX'winelist'
[8]    winelist←Wines,[1.5]0.01×10000+?(⍴Wines)⍴10000
[9]    win←⎕NEW Window
[10]   win.Title←'DataGrid Matrix (Code)'
[11]   win.grid←⎕NEW DataGrid
[12]   info←(⍪'Name' 'Price'),⊂Object
[13]   win.grid.ItemsSource←info(2015⌶)'winelist'
[14]   win.grid.Height←500
[15]   win.Content←win.grid
[16]   win.SizeToContent←SizeToContent.WidthAndHeight
[17]   win.Show
     ∇

This is because by default the DataGrid generates its columns automatically with default formatting.

In order to apply special formatting to one or more columns, it is necessary to set the AutoGenerateColumns property to 0, and to generate the columns programmatically as is shown in the second version of the function, GridCode.

     ∇ GridCode;⎕USING;MySource;win;info;fmt
[1]    ⎕USING←'System'
[2]    ⎕USING,←,⊂'System.Windows.Controls,WPF/PresentationFramework.dll'
[3]    ⎕USING,←⊂'System.Windows.Controls.Primitives,WPF/PresentationFramework.dll'
[4]    ⎕USING,←⊂'System.Windows,WPF/PresentationFramework.dll'
[5]    ⎕USING,←⊂'System.Windows,WPF/PresentationCore.dll'
[6]
[7]    ⎕EX'winelist'
[8]    winelist←Wines,[1.5]0.01×10000+?(⍴Wines)⍴10000
[9]    win←⎕NEW Window
[10]   win.Title←'DataGrid Matrix (Code with Formatting)'
[11]   win.grid←⎕NEW DataGrid
[12]   info←(⍪'Name' 'Price'),⊂Object
[13]   win.grid.ItemsSource←info(2015⌶)'winelist'
[14]   win.grid.Height←500
[15]   win.grid.AutoGenerateColumns←0
[16]   win.Content←win.grid
[17]   win.SizeToContent←SizeToContent.WidthAndHeight
[18]   ⍝ Add columns and set format
[19]   win.grid.Columns.Add¨'' 'C'{
[20]       col←⎕NEW DataGridTextColumn
[21]       col.Header←⍵
[22]       col.Binding←⎕NEW Data.Binding(⊂⍵)
[23]       col.Binding.StringFormat←,⍺
[24]       col
[25]   }¨'Name' 'Price'
[26]
[27]   win.Show
     ∇

In this version of the function, lines [19-25] create the two columns Name and Price, applying currency format to the Price column.


SyncFusion Introduction

Syncfusion Libraries

Under a licensing agreement with Syncfusion, Dyalog includes the Syncfusion library of WPF controls. These may be used by Dyalog APL users to develop applications, and may be distributed with Dyalog APL run-time applications.

The Syncfusion libraries comprise a set of .NET assemblies which are supplied in the Syncfusion/4.5 sub-directory of the main Dyalog APL installation directory (for example: c:\Program Files\Dyalog\Dyalog APL-64 14.0 Unicode\Syncfusion\4.5.

Requirements

To use the Syncfusion libraries you must be using Microsoft .NET Version 4.5. See UI Guide: Configuration Dialog:.NET Framework Tab.

In addition, to use the controls contained in these assemblies it is necessary to perform one or both of the following steps.

Using XAML

If using XAML, the XAML must include the appropriate xmlns statements that specify where the Syncfusion controls are to be found. For example:

xmlns:syncfusion="clr-namespace:Syncfusion.Windows.Gauge;
                  assembly=Syncfusion.Gauge.WPF"

The above statement defines the prefix syncfusion to mean the specified Syncfusion namespace and assembly that contains the various Gauge controls. When the prefix syncfusion is subsequently used in front of a control in the XAML, the system knows where to find it. For example:

<syncfusion:CircularGauge Name="fahrenheit" Margin="10">

⎕USING

In common with all .NET types, when a Syncfusion control is loaded using XAML or using ⎕NEW it is essential that the current value of ⎕USING identifies the .NET namespace and assembly in which the control will be found. For example:

       ⎕USING,←⊂'Syncfusion.Windows.Gauge,Syncfusion/4.5/Syncfusion.Gauge.WPF.dll'

This statement tells APL to search the .NET namespace named Syncfusion.Windows.Gauge, which is located in the assembly file whose path (relative to the Dyalog installation directory) is Syncfusion/4.5/Syncfusion.Gauge.WPF.dll.


Syncfusion Circular Gauge Example

The XAML

Like most Syncfusion controls, the CircularGauge is made up of a complex structure of objects, and the XAML (see variable XAML_SF) is too extensive to describe in detail herein. It was created from the sample XAML from the Syncfusion documentation for this control entitled Essential Gauge for WPF, which may be downloaded from http://help.syncfusion.com/wpf/gauge.

The key statements in the XAML are as follows:

xmlns:syncfusion="clr-namespace:Syncfusion.Windows.Gauge;assembly=Syncfusion.Gauge.WPF"

The above statement defines the prefix syncfusion to mean the specified Syncfusion namespace and assembly. When the prefix syncfusion is subsequently used in front of a control in the XAML, the system knows where to find it.

The next two statements define CircularPointer controls (the needles on the gauges); one for the Fahrenheit gauge (named f_pointer) and one for the Centigrade gauge (named c_pointer).

 <syncfusion:CircularPointer Name="f_pointer" BorderWidth="0.3"
  PointerLength="100" PointerPlacement="Inside" PointerWidth="20"
  Value="32"/>
 <syncfusion:CircularPointer Name="c_pointer" BorderWidth="0.3"
  PointerLength="100" PointerPlacement="Inside" PointerWidth="20"
  Value="0"/

The APL Code

The following functions were used to produce the example illustrated above. The main function is SF_TC_XAML.

     ∇ SF_TC_XAML;⎕USING;win;f_pointer;c_pointer;sink
[1]
[2]    win←LoadXAML XAML_SF
[3]
[4]    f_pointer←win.FindName⊂'f_pointer'
[5]    c_pointer←win.FindName⊂'c_pointer'
[6]
[7]    f_pointer.onMouseEnter←'MouseEnter'
[8]    c_pointer.onMouseEnter←'MouseEnter'
[9]
[10]   sink←win.ShowDialog
     ∇

After creating the Window from the text in XAML_SF, the function SF_TC_XAML obtains refs to the two CircularPointer controls named f_pointer (in the Fahrenheit gauge) and c_pointer (in the Centigrade gauge). It then attaches the MouseEnter callback to each of these objects.

     ∇ MouseEnter(this ev);ptrs
[1]    ptrs←f_pointer c_pointer
[2]    ptrs.onValueChanged←(ptrs⍳this)⌽0 'TempChanged'
     ∇

In this example, the user grabs one of the gauge needles and moves it around the face of the gauge. When the user moves the mouse into one of these needles, the MouseEnter callback fires. The function MouseEnter receives the CircularPointer object that generated the event this as the first item in its argument.

The code simply attaches the callback function TempChanged to this, and disables any callback on the other CircularPointer object.

Note that if both CircularPointer objects had callbacks on TempChanged at the same time, the system would enter a callback loop.

     ∇ TempChanged(obj ev)
[1]    :Select obj
[2]    :Case f_pointer
[3]        c_pointer.Value←(obj.Value-32)×5÷9
[4]    :Case c_pointer
[5]        f_pointer.Value←32+obj.Value÷5÷9
[6]    :EndSelect
     ∇

The LoadXAML function used in this example is subtly different from previous examples.

     ∇ win←LoadXAML xaml;⎕USING;str;xml
[1]    ⎕USING←'System.IO'
[2]    ⎕USING,←⊂'System.Windows.Markup'
[3]    ⎕USING,←⊂'System.Xml,system.xml.dll'
[4]    ⎕USING,←⊂'System.Windows.Controls,WPF/PresentationFramework.dll'
[5]    ⎕USING,←⊂'Syncfusion.Windows.Gauge,Syncfusion/4.5/Syncfusion.Gauge.WPF.dll'
[6]    str←⎕NEW StringReader(⊂xaml)
[7]    xml←⎕NEW XmlTextReader str
[8]    win←XamlReader.Load xml
     ∇

In particular, it contains the all-important statement:

[5]    ⎕USING,←⊂'Syncfusion.Windows.Gauge,
                 Syncfusion/4.5/Syncfusion.Gauge.WPF.dll'

This statement tells APL to search the .NET namespace named Syncfusion.Windows.Gauge, which is located in the assembly file whose path (relative to the Dyalog installation directory) is Syncfusion/4.5/Syncfusion.Gauge.WPF.dll.


Introduction

Dyalog APL allows you to build new .NET Classes, components and controls. .NET classes created by Dyalog may be hosted by any application or programming language that supports .NET.

A component is a class with emphasis on cleanup and containment and implements specific interfaces.

A control is a component with user interface capabilities.

With one exception, every .NET Class inherits from exactly one base class. This means that it begins with all of the behaviour of the base class, in terms of the base class properties, methods and events. You add functionality by defining new properties, methods and events on top of those inherited from the base class or by overriding base class methods with those of your own.


Assemblies, Namespaces and Classes

To create a .NET class in Dyalog APL, you simply create a standard APL Class and export the workspace as a Microsoft .NET Assembly (*.dll).

.NET Classes are organised in .NET Namespaces. If you wrap your Class (or Classes) within an APL namespace, the name of that namespace will be used to identify the name of the corresponding .NET Namespace in your Assembly.

If a Class is to be based upon a specific .NET Class, the name of that .NET Class must be specified as the Base Class in the :Class statement, and the :Using statement(s) must correctly locate the base class. If not, the Class is assumed to be based upon System.Object. If you use any .NET Types within your Class, you must ensure that these too are located by :Using.

Once you have defined the functionality of your .NET classes, you are ready to save them in an assembly. This is simply achieved by selecting Export from the Session File menu.

You will be prompted to specify the directory and name of the assembly (DLL) and it will then be created and saved. Your .NET class is now ready for use by any .NET development environment, including APL itself.

When a Dyalog .NET class is invoked by a host application, it automatically loads the Dyalog DLL, the developer/debug or run-time dynamic link library version of Dyalog APL. You decide which of these DLLs is to be used according to the setting of the Runtime application checkbox in the Create bound file dialog box. Note however that the Dyalog .NET class, and all the Dyalog DLLs on which it depends, reside in the same directory as the host program.

Note that if you wish to include a Dyalog .NET class in a Visual Studio application it is recommended that you add the Bridge DLL as a reference in a Visual Studio .NET project.

If you want to repeat the most recent export after making changes to the class, you can click on the icon to the right of the save icon on the WS button bar at the top of the session. Note that the workspace itself is not saved when you do an export, so if you want the export options to be remembered you must )SAVE the workspace after you have exported it.


Getting Started

The tutorial described in this Chapter was originally designed (for Dyalog Version 10) to be exercised in a console window, with the user invoking the C# compiler directly using a command-line interface. It was originally envisaged to be run in-situ in the samples\aplclasses sub-directory.

Today, the samples\aplclasses sub-directory is read-only, and direct access to the C# compiler via a command-line interface is problematical. Another consideration is the change in requirement for dependent Dyalog DLLs, which must now reside in the same directory as the host program.

The tutorial has therefore been re-factored to use Microsoft Visual Studio, using the material unchanged from the original version.

All the examples are to be executed as simple console applications written in C# in the framework of Microsoft Visual Studio Community 2015 (hereafter referred to as VS). To run the examples as described herein, you should install VS.

Initialisation

The first step is to start VS and create a new C# Console application. You may name and store it as you like, but this tutorial chooses the name DyApp and the folder c:\, so VS creates a directory named c:\DyApp containing several other files and directories.

When the application is executed (in debug mode) by VS it will be run in the application's sub-directory bin\Debug.

It is mandatory that the Dyalog .NET class, and all the Dyalog DLLs on which it depends, reside in the same directory as the host program.

So the first step is to copy the requisite Dyalog DLLs to the bin\Debug sub-directory. These DLLs are:

  • Development DLL or Run-Time DLL (this tutorial uses the Development DLL)
  • Bridge DLL
  • DyalogNet DLL

For the names of these files corresponding to the version of Dyalog that you are using, see Files.

Following these steps, the contents of the bin\Debug sub-directory should be similar to those shown below:

Directory of c:\DyApp\bin\Debug

23/09/2016  15:17    <DIR>          .
23/09/2016  15:17    <DIR>          ..
28/07/2016  18:05           532,480 bridge150_unicode.dll
26/08/2016  13:39         7,123,968 dyalog150_unicode.dll
28/07/2016  18:05            18,944 dyalognet.dll
23/09/2016  15:17               189 DyApp.exe.config
23/09/2016  15:17            22,696 DyApp.vshost.exe
23/09/2016  15:17               189 DyApp.vshost.exe.config
30/10/2015  10:19               490 DyApp.vshost.exe.manifest

Running the Tutorial

All of the examples are provided in the Dyalog sub-directory samples\aplclasses. The source code for the Dyalog classes are workspaces named aplclasses1.dws, aplclasses2.dws etc. whilst the corresponding C# source code for hosting them is named aplfns1.cs, aplfns2.cs etc.

In order to execute each example, we will export the workspace (aplclasses1.dws, aplclasses2.dws and so forth) as a Microsoft .NET Assembly named (in all cases) aplclasses.dll to the bin\Debug sub-directory.

To start with we will replace the main program in the VS application with C# code imported from the first example aplfns1.cs, and execute it with the results displayed in a simple console window. Subsequent examples will be developed by editing this code directly or by copy/pasting code from the other C# source code files that are supplied.

Each workspace contains a .NET Namespace called APLClasses which itself contains a single .NET Class called Primitives that exports a single method called IndexGen.


Example 1

Load the workspace aplclasses1.dws from samples\aplclasses, then view the Primitives class:

      )ed ○APLClasses.Primitives The character before the name APLClasses.Primitives, ○, is typically obtained with Ctrl-O. It is used to tell the editor to edit a class1
:Class Primitives
:Using System
     ∇ r←IndexGen n
      :Access public
      :Signature Int32[]←IndexGen Int32 n
      r←⍳n
     ∇
:EndClass

Primitives contains one public method/function named IndexGen.

The public characteristics for the exported method are included in the definition of the class and its functions. Those are specified in the :Signature statement.

Its syntax is:

:Signature [return type←] fnname [arg1type [arg1name]
                                 [,argNtype [argNname]]*]

that is: The type of the result returned by the function - followed by arrow - if any, the exported name (it can be different from the APL function name but it must be provided), and, if any arguments are to be supplied, their types and optional names, each type-name pair separated from the next by a comma. In the example above the function returns an array of 32-bit integers and takes a single integer as its argument. For further details, see Signature Statement.

Note that, when the class is fixed, APL will try to find the .NET data types you have specified for the result and for the parameters. If one or more of the data types are not recognised as available .NET Types, you will be informed in the status window and APL will refuse to fix the class. If you see such a warning you have either entered an incorrect data type name, or you have not set :Using correctly, or some other syntax problem has been detected (for example the function is missing a terminating ∇. In the previous example, the only data type used is System.Int32. Since we have set :Using System, the name Int32 is found in the right place and all is well.

It should be noted that in the previous release of Dyalog APL the statements :Returns and :ParameterList were used instead of :Signature. They are still accepted for backwards compatibility but are considered deprecated. Their syntax will not be documented here but a list can be found in Appendix A.

Now you are ready to create the assembly. This is done by selecting Export… from the Session File menu. This displays the following dialog box.

This gives you the opportunity to change the name or path of the assembly. The Runtime application checkbox allows you to choose to which if the two versions of the Dyalog APL dynamic link library the assembly will be bound. In this tutorial we will use the Development version. The Isolation Mode Combo box allows you to choose which Isolation Mode you require.

  • Change the File name to aplclasses.
  • Clear the Runtime application checkbox

Finally, click Save. APL now makes the assembly and, as it does so, displays information in the Status window as shown below. If any errors occur during this process, the Status window will inform you.

aplfns1.cs

The following C# source, called samples\APLClasses\aplfns1.cs, will be used to call our Dyalog.NET Class.

The using statements specify the names of .NET namespaces to be searched for unqualified class names.

The program creates an object named apl of type Primitives by calling the new operator on that class. Then it calls the IndexGen method with a parameter of 10.

      using System;
      using APLClasses;
      public class MainClass
          {
          public static void Main()
              {
                  Primitives apl = new Primitives();
                  int[] rslt = apl.IndexGen(10);
                  for (int i=0;i<rslt.Length;i++)
                  Console.WriteLine(rslt[i]);
              }
          }

In VS, click Project/Add Existing Item and navigate to add aplfns1.cs from samples\aplclasses.

Next, using the Solution Explorer, rename aplfns1.cs to aplfns.cs and delete the dummy program program.cs. This is necessary otherwise there would be two Main() entry-points in the application.

Open aplfns.cs in the VS code editor (double -click its name in Solution Explorer) and add the following two lines of code:

      Console.Write("Press <Enter> to exit... ");
      while (Console.ReadKey().Key != ConsoleKey.Enter) { }

These allow you, the user, to view the contents of the console window before it disappears when the program ends.

Notice that APLClasses and Primitives are marked as being in error. This is because as yet, VS does not know what these are.

To resolve this issue, select Project/Add Reference... click Browse, navigate to c:\DyApp\bin\Debug and add aplclasses.dll.

The final code is shown below:

Note that it may be necessary to add the bridge dll and other dyalog dlls as references too.

Now click Start to run the program. The results are shown in a console window.


Example 2

In Example 1, we said nothing about a constructor used to create an instance of the Primitives class. In Example 2, we will show how this is done.

In fact, in Example 1, APL supplied a default constructor, which is inherited from the base class (System.Object) and is called without arguments.

Example 2 will extend Example 1 by adding a constructor that specifies the value of ⎕IO.

Load the workspace aplclasses2.dws from samples\aplclasses, then display the Primitives class:

      ↑⎕SRC APLClasses.Primitives
:Class Primitives
:Using System

    ∇ CTOR IO
      :Implements constructor
      :Access public
      :Signature CTOR Int32 IO
      ⎕IO←IO
    ∇

    ∇ R←IndexGen N
      :Access public
      :Signature Int32[]←IndexGen Int32
      R←⍳N
    ∇

:EndClass ⍝ Primitives

This version of Primitives contains a constructor function called CTOR that simply sets ⎕IO to the value of its argument. The name of this function is purely arbitrary.

Using this version, build a new .NET Assembly using File/Export… as before.

Please note that as before it is essential that the Build runtime assembly checkbox is unchecked.

aplfns2.cs

The following C# source, called samples\APLClasses\aplfns2.cs, can be used to call the new version of our APL .NET Class.

      using System;
      using APLClasses;
      public class MainClass
            {
            public static void Main()
                  {
                  Primitives apl = new Primitives(0);
                  int[] rslt = apl.IndexGen(10);

                  for (int i=0;i<rslt.Length;i++)
                  Console.WriteLine(rslt[i]);
                  }
            }

The program is the same as in the previous example, except that the code that creates an instance of the Primitives class is simply changed to specify an argument; in this case 0.

Primitives apl = new Primitives(0);

Rather than load aplfns2.cs into VS, it is simpler to just make this change in-situ as shown below.

Then click Start to build and run the modified application:


Example 2a

In Example 2, the argument to CTOR, the constructor for the Primitives class, was defined to be Int32. This means that the .NET Framework will allow a client to specify any integer when it creates an instance of the Primitives class. What happens if the client uses a parameter of 2? Clearly this is going to cause an APL DOMAIN ERROR when used to set ⎕IO.

aplfns2a.cs

The following C# source, called samples\APLClasses\aplfns2a.cs, can be used to demonstrate what happens.

      using System;
      using APLClasses;
      public class MainClass
            {
            public static void Main()
                  {
                  Primitives apl = new Primitives(2);
                  int[] rslt = apl.IndexGen(10);

                  for (int i=0;i<rslt.Length;i++)
                  Console.WriteLine(rslt[i]);
                  }
            }

The code is the same as in the previous example, except that the line that creates an instance of the Primitives class specifies an inappropriate argument 2.

Primitives apl = new Primitives(2);

Rather than load aplfns2.cs into VS, it is simpler to just make this change in-situ as shown below.

Then click Start to build and run the modified application:

… as we have built the Dyalog .NET class to use the Development DLL, the APL Session appears, and the Tracer can be used to debug the problem. You can see that the constructor CTOR has stopped with a DOMAIN ERROR. Meanwhile, the C# program is still waiting for the call (to create an instance of Primitives) to finish.

Notice that in Dyalog APL, the )SI System Command provides information about the entire calling stack, including the .NET function calls that are involved. Notice too that the CTOR function, the constructor for this APL .NET class, is running here in APL thread 1, which is associated with the system thread 9572.

In this case, debugging is simple, and you can simply type:

      IO←1
      →⎕LC

Now, the CTOR function completes, the aplfns program continues and the output is displayed.


Example 3

The correct .NET behaviour when an APL function fails with an error is to throw an exception, and this example shows how to do it.

In the .NET Framework, exceptions are implemented as .NET Classes. The base exception is implemented by the System.Exception class, but there are a number of super classes, such as System.ArgumentException and System.ArithmeticException that inherit from it.

⎕SIGNAL may be used to throw an exception. To do so, its right argument should be 90 and its left argument should be an object of type System.Exception or an object that inherits from System.Exception.

When you create the instance of the Exception class, you may specify a string (which will turn up in its Message property) containing information about the error.

aplclasses3.dws contains an improved version of the CTOR constructor function.

     ∇ CTOR IO;EX
[1]   :Access public
[2]   :Signature CTOR Int32 IO
[3]   :Implements constructor
[4]   :If IO∊0 1
[5]      ⎕IO←IO
[6]   :Else
[7]      EX←⎕NEW ArgumentException,⊂⊂'IndexOrigin must be
                                      0 or 1'
[8]      EX ⎕SIGNAL 90
[9]   :EndIf
     ∇

Load aplclasses3.dws and export a new version of aplclasses.dll as before. The Create bound dialog box should appear exactly as in Example 2 .

aplfns3.cs

The following C# source, called samples\APLClasses\aplfns3.cs, contains code to catch the exception and to display the exception message.

using System;
using APLClasses;
public class MainClass
    {
    public static void Main()
        {
try
    {
        Primitives apl = new Primitives(2);
        int[] rslt = apl.IndexGen(10);

        for (int i=0;i<rslt.Length;i++)
            Console.WriteLine(rslt[i]);
}
catch (Exception e)
    {
    Console.WriteLine(e.Message);
    }
        }

    }

Using copy/paste, merge the new code into aplfns.cs in VS, to produce the following:

Click Start to run the new version:


Example 4

This example builds on Example 3 and illustrates how you can implement constructor overloading, by establishing several different constructor functions.

By way of an example, when a client application creates an instance of the Primitives class, we want to allow it to specify the value of ⎕IO or the values of both ⎕IO and ⎕ML.

The simplest way to implement this is to have two public constructor functions CTOR1 and CTOR2, which call a private constructor function CTOR.

aplclasses4.dws contains a new version of the Primitives class with these additions:

      ∇ CTOR1 IO
[1]    :Implements constructor
[2]    :Access public
[3]    :Signature CTOR1 Int32 IO
[4]    CTOR IO 0
     ∇
     ∇ CTOR2 IOML
[1]    :Implements constructor
[2]    :Access public
[3]    :Signature CTOR2 Int32 IO,Int32 ML
[4]    CTOR IOML
     ∇
     ∇ CTOR IOML;EX
[1]    IO ML←IOML
[2]    :If ~IO∊0 1
[3]        EX←⎕NEW ArgumentException,⊂⊂'IndexOrigin must
                                               be 0 or 1'
[4]        EX ⎕SIGNAL 90
[5]    :EndIf
[6]    :If ~ML∊0 1 2 3
[7]        EX←⎕NEW ArgumentException,⊂⊂'MigrationLevel
                                    must be 0, 1, 2 or 3'
[8]        EX ⎕SIGNAL 90
[9]    :EndIf
[10]   ⎕IO ⎕ML←IO ML
     ∇

The :Signature statements for these three functions show that CTOR1 is defined as a constructor that takes a single Int32 parameter, CTOR2 is defined as a constructor that takes two Int32 parameters, and CTOR has no .NET Properties defined at all. Note that in .NET terms, CTOR is not a Private Constructor; it is simply an internal function that is invisible to the outside world.

Next, a function called GetIOML is defined and exported as a Public Method. It simply returns the current values of ⎕IO and ⎕ML.

     ∇ R←GetIOML
[1]   :Access public
[2]   :Signature Int32[]←GetIOML
[3]    R←⎕IO ⎕ML
     ∇

Load aplclasses4.dws and export a new version of aplclasses.dll as before. The Create bound dialog box should appear exactly as in Example 2 .

aplfns4.cs

samples\APLClasses\aplfns4.cscontains code to invoke the two different constructor functions CTOR1 and CTOR2 :

using System;
using APLClasses;
public class MainClass
    {
    public static void Main()
        {
        Primitives apl10 = new Primitives(1);
        int[] rslt10 = apl10.GetIOML();
        for (int i=0;i<rslt10.Length;i++)
            Console.WriteLine(rslt10[i]);

        Primitives apl03 = new Primitives(0,3);
        int[] rslt03 = apl03.GetIOML();
        for (int i=0;i<rslt03.Length;i++)
            Console.WriteLine(rslt03[i]);
        }
    }

Here the code creates two instances of the Primitives class named apl10 and apl03. The first is created with a constructor parameter of (1); the second with a constructor parameter of (0,3).

The C# compiler matches the first call with CTOR1, because CTOR1 is defined to accept a single Int32 parameter. The second call is matched to CTOR2 because CTOR2 is defined to accept two Int32 parameters.

Using copy/paste, merge the new code from aplfns4.cs into aplfns.cs in VS to produce the following:

Click Start to run the new version:


Example 5

This example takes things a stage further and illustrates how you can implement method overloading.

In this example, the requirement is to export three different versions of the IndexGen method; one that takes a single number as an argument, one that takes two numbers, and a third that takes any number of numbers. These are represented by three functions named IndexGen1, IndexGen2 and IndexGen3 respectively. Because monadic ⍳ performs all of these operations, the three APL functions are in fact identical. However, their public interfaces, as defined in their :Signature statement, are all different.

The overloading is achieved by entering the same name for the exported method (IndexGen) in the box provided, for each of the three APL functions.

aplclasses5.dws contains a new version of the Primitives class with three different versions of IndexGen as shown below:

     ∇ R←IndexGen1 N
[1]   :Access public
[2]   :Signature Int32[]←IndexGen Int32 N
[3]    R←⍳N
     ∇

This is the version we have seen before. The method is defined to take a single argument of type Int32, and to return a 1-dimensional array (vector) of type Int32.

     ∇ R←IndexGen2 N
[1]   :Access public
[2]   :Signature Int32[][,]←IndexGen Int32 N1, Int32 N2
[3]    R←⍳N
     ∇

This version is defined to take two arguments of type Int32, and to return a 2-dimensional array, each of whose elements is a 1-dimensional array (vector) of type Int32.

     ∇ R←IndexGen3 N
[1]   :Access public
[2]   :Signature Array←IndexGen Int32[] N
[3]    R←⍳N
     ∇

In principle, we could define 7 more different versions of the method, taking 3, 4, 5 etc. numeric parameters. Instead, this method is defined more generally, to take a single parameter that is a 1-dimemsional array (vector) of numbers, and to return a result of type Array. In practice we might use this version alone, but for a C# programmer, this is harder to use than the two other specific cases.

Notice also that all function use the same descriptive name, <IndexGen>.

Load aplclasses5.dws and export a new version of aplclasses.dll as before. The Create bound dialog box should appear exactly as in Example 2 .

aplfns5.cs

samples\APLClasses\aplfns5.cscontains code to invoke the three different variants of IndexGen, in the new aplclasses.dll. Notice that it uses a local sub-routine PrintArray().

      using System;
      using APLClasses;
      public class MainClass
            {
            static void PrintArray(int[] arr)
            {
                  for (int i=0;i<arr.Length;i++)
                      {
                      Console.Write(arr[i]);
                      if (i!=arr.Length-1)
                         Console.Write(",");
                      }
            }

            public static void Main()
                  {
                  Primitives apl = new Primitives(0);
                  int[] rslt = apl.IndexGen(10);
                  PrintArray(rslt);
                  Console.WriteLine("");

                  int[,][] rslt2 = apl.IndexGen(2,3);
                  for (int i=0;i<2;i++)
                           {
                           for (int j=0;j<3;j++)
                                    {
                                    int[] row = rslt2[i,j];
                                    Console.Write("(");
                                    PrintArray(row);
                                    Console.Write(")");
                                    }
                  Console.WriteLine("");
                           }

                  int[] args = new int[3];
                  args[0]=2;
                  args[1]=3;
                  args[2]=4;
                  Array rslt3 = apl.IndexGen(args);
                  Console.WriteLine(rslt3);

            }

Using copy/paste, merge the new code from aplfns5.cs into aplfns.cs in VS to produce the following:

Click Start to run the new version:

It is possible for a function to have several :Signature statements. Given that our three functions perform exactly the same operation, it might have made more sense to use a single function:

     ∇ R←IndexGen1 N
[1]   :Access public
[2]   :Signature Int32[]←IndexGen Int32 N
[3]   :Signature Int32[][,]←IndexGen Int32 N1, Int32 N2
[4]   :Signature Array←IndexGen Int32[] N
[5]    R←⍳N
     ∇


Interfaces

Interfaces define additional sets of functionality that classes can implement; however, interfaces contain no implementation, except for static methods and static fields. An interface specifies a contract that a class implementing the interface must follow. Interfaces can contain shared (known as "static" in many compiled languages) or instance methods, shared fields, properties, and events. All interface members must be public. Interfaces cannot define constructors. The .NET runtime allows an interface to require that any class that implements it must also implement one or more other interfaces.

When you define a class, you list the interfaces which it supports following a colon after the class name. The value of ⎕USING (possibly set by :Using) is used to locate Interface names.

If you specify that your class implements a certain Interface, you must provide all of the members (methods, properties, and so forth) defined for that Interface. However, some Interfaces are only marker Interfaces and do not actually specify any members.

An example is the TemperatureControlCtl2 custom control described in Chapter 10, which derives from System.Web.UI.Control. The first line of this class definition reads:

:Class TemperatureConverterCtl2: System.Web.UI.Control,
    System.Web.UI.IPostBackDataHandler,
    System.Web.UI.IPostBackEventHandler

Following the colon, the first name is the base class. Following the (optional) base class name is the list of interfaces which are implemented. The TemperatureControlCtl2 custom control implements two interfaces named IPostBackDataHandler and IPostBackEventHandler. These interfaces are required for a custom control that intends to render the HTML for its own form elements in a Web page. These interfaces define certain methods that get called at the appropriate time by the page framework when a Web page is constructed for the browser. It is therefore essential that the class implements all the methods specified by the interface, even if they do nothing.

The base class, System.Web.UI.Control, defines an optional Interface called INamingContainer. A class based on Control that implements INamingContainer specifies that its child controls are to be assigned unique ID attributes within an entire application. This is a marker interface with no methods or properties defined for it.

See these examples in Chapter 10 for further details.


Introduction

Microsoft Internet Information Services (IIS) is a comprehensive Web Server software package that allows you to publish information on your Intranet, or on the World Wide Web. IIS is included with Professional and Server versions of all recent Windows operating systems; all you need add is a network connection to run your own Web site.

IIS includes Active Server Page (ASP) technology. The basic idea of ASP is to permit web pages to be created dynamically by the web server. An ASP file is a character file that contains a mixture of HTML and scripts. When IIS receives a request for an ASP file, it executes the server-side scripts contained in the file to build the Web page that is to be sent to the browser. In addition to server-side scripts, ASP files can contain HTML (including related client-side scripts) as well as calls to components that can perform a variety of tasks such as database lookup, calculations, and business logic.

Basically, each script inside an ASP page generates a stream of HTML. The server runs the scripts and assembles the resulting HTML into a single stream (Web page) that is sent to the browser.

ASP.NET is a new version of ASP and is based upon the Microsoft .NET Framework technology. It offers significantly better performance and a host of new features including support for Web Services.


IIS Installation Dependency

During installation, Dyalog registers itself with ASP.NET as an ASP.NET programming language. Among other things, this allows ASP.NET web pages to be written in Dyalog. The Dyalog installation program also registers the Dyalog asp.net sample applications as IIS Virtual Directories.

It is not practical for the Dyalog setup.exe to perform these tasks unless IIS and ASP.NET are already installed. Furthermore, unless IIS and ASP.NET are already installed and activated on the system, the Dyalog sub-directory Samples/asp.net will not even be copied onto the system, because the samples it contains would be inoperable.

If IIS is installed after Dyalog, it is necessary to de-install and then re-install Dyalog to enable the registration of Dyalog as an ASP.NET Programming language to occur, and for the Samples/asp.net sub-directory to be copied onto the system and the samples registered as IIS Virtual Directories.


IIS Applications and Virtual Directories

IIS Applications, Virtual Directories, Application Pools

IIS supports the concept of an Application. An application is a logically separate service or web site. IIS can run any number of Applications concurrently. The files associated with an application are stored in a physical directory on disk, which is linked to an IIS Virtual Directory. The name of the Virtual Directory is the name of the Application or Web Site.

The Dyalog APL distribution contains a directory named Dyalog\Samples\asp.net and a set of sub-directories each of which contains a sample application.

During the installation of Dyalog APL, these are automatically registered as IIS Virtual Directories, under a common root. The name of the root begins dyalog.net followed by the Dyalog Version number, the edition (Unicode or classic), and the architecture (32-bit or 64-bit). For example, dyalog.net.15.0.unicode.64 Versions of Dyalog APL prior to Version 11.0 created Virtual Directories under apl.net. 1. The name of the root application is referred to henceforth as dyalog.net.

IIS applications run in application pools. An application pool is a group of one or more URLs that are served by the same worker process or set of worker processes which are separate from the worker process that services another application pool. This mechanism isolates applications from one another, providing resilience should any one application fail.

Each dyalog.net application is associated with an application pool named Dyalog APL xx (.NET v4.0 Classic The term NET v4.0 Classic refers to the name of a standard application pool on which it is based, and has nothing to do with the Classic variant of Dyalog. 2), where xx is 32 or 64) which is created if required during installation.

When you want to run the Web Services and Web Page examples, you do so by specifying the URL http://localhost/dyalog.net.xxxx/

These samples can be easily found by selecting the Documentation Centre menu item from the Help menu on the Dyalog session, and scrolling down to the Tutorials section.


Internet Services Manager

As its name suggests, Internet Services Manager is a tool for managing IIS. If you are developing Web Pages and/or Web Services, you will be using this tool a lot, and it makes sense to add it as a shortcut on your desktop.

To do this, open Control Panel, then open Administrative Tools, right-click Internet Information Services (IIS) Manager, and select Send To Desktop (create shortcut).

The dyalog.net Application

Following a successful installation of Dyalog APL, the dyalog.net Application should appear in Internet Services Manager as shown below.

Note that the golf, temp and webservices sub-directories in the dyalog.net application represent separate IIS applications.

The dyalog Application Pool will appear in the list of Applications Pools as shown below.

The Advanced Settings of the dyalog.net Application are shown below.


Introduction

A Web Service can be thought of as a Remote Procedure Call. However, it is a remote procedure call that can be made over the Internet using character-based messages.

Web Services are implemented using Simple Object Access Protocol (SOAP), Extensible Mark-up Language (XML) and Hypertext Transfer Protocol (HTTP). Web Services do not require proprietary network protocols or software. Web Service calls and responses can successfully be transmitted over the Internet without the need to specially configure firewalls.

A Web Service is a class that may be called by any program running on the computer, any program running on a computer on the same LAN, or any program running on any computer on the internet.

Web Services are hosted (i.e. executed) by ASP.NET running under Microsoft IIS. Any one Web Service sits on a single server computer and runs there under ASP.NET/IIS. The messages that invoke the Web Service, pass its arguments, and return its results, utilise standard HTTP/SOAP/XML protocols.

A Web Service consists of a single text script file, with the extension .asmx, in an IIS Virtual Directory on the server computer.

A Web Service may expose a number of Methods and Properties. Methods may be called synchronously (the calling process waits for the result) or asynchronously (the calling process invokes the method, continues for a bit, and then subsequently checks for the result of the previous call).


Web Service Scripts

Web Service (.asmx) Scripts

Web Services may be written in a variety of languages, including APLScript, the scripting version of Dyalog APL. See APLScript on page 1.

The first statement in the script file declares the language and the name of the service. For example, the following statement declares a Dyalog APL Web Service named GolfService.

<%@ WebService Language="Dyalog" Class="GolfService" %>

Note that Language="Dyalog" is specifically connected to the Dyalog APL script compiler through the application's web.config file or through the global ASP.NET system file Machine.config. Note that versions of Dyalog prior to 11.0 used Language="APL".

The syntax of this first line is common to all Web Services, regardless of the language in which they are written.

A Dyalog APL Web Service script starts with a :Class statement and ends with an :EndClass statement. These statements are directives used by the Dyalog APL script compiler and are specific to Dyalog APL.

The :Class statement declares the name of the Class (which must be the same as the name declared in the WebService statement) and the Base Class from which it inherits, which is normally System.Web.Services.WebService.

   :Class GolfService: System.Web.Services.WebService

Following the :Class statement, there may appear any number of APL expressions and function bodies. Following these there must be a :EndClass statement. Internal sub-classes (nested classes) may also be defined within the main :Class ... :EndClass block.

Because the functions usually take arguments and return results whose types must be known, the statement

   :Using System

must almost always appear immediately after the :Class statement to locate them.


Compilation

When the Web Service, specified by the .asmx file, is called for the first time, ASP.NET invokes the appropriate language compiler (in this case, the Dyalog APL Script compiler) whose job is to produce an Assembly that defines and describes a class. When the Web Service is used subsequently, the request is satisfied by creating and using an instance of the class. However, ASP.NET detects if the .asmx script has been modified, and recompiles it in this case.

The Dyalog APL Script compiler creates a DLL containing a workspace, which itself contains the Web Service class. The class contains all the functions, which are defined within the script, together with any variables that were established by expressions in the script. A single function comprises all the statements enclosed within a pair of del (∇) symbols.

For example, the following script would define a class, instances of which would run using ⎕ML←2, containing a single function FOO and a variable X.

:Class MyClass
   ⎕ML←2
   X←10
   ∇ Z←FOO Y
     Z←Y+X
   ∇
:EndClass

Note that all expressions in the class script are executed by the script compiler when it creates the assembly. They are not executed when the Web Service is invoked.

If your script contains a ⎕CY statement, it will be executed by the compiler when establishing the class. This may be used to import functions from other workspaces and obviate the need to include them in the .asmx file.


Exporting Methods

Your Web Service will be of no use unless it exports at least one method. To export a function as a method, you must include declaration statements. Such declarations may be supplied anywhere within the function body, but it is recommended that they appear together as the first block of statements in your code. All declaration statements begin with the colon (:) character and the following declaration statements are supported:

:Access WebMethod

This statement causes the function to be exported as a method and must be present.

:Signature type ← fnname type name1, type name2, ...

This statement declares the data type of the result and the arguments of the method where type may specify any valid .NET type that is supported by Web Services. Note that the assignment arrow (←) is necessary if the function returns a result.

The declaration of each parameter of the method is separated from the next by a comma. Each name may be any ASCII character string. Note that names are optional.

Add1

∇ R←Add1 args
 :Access WebMethod
 :Signature Int32←Add Int32 arg1,Int32 arg2
  R←+/args
∇

The Add1 function defined above is exported as a method named Add, that takes exactly (and only) two parameters of type Int32 and returns a result of type Int32. Armed with this definition, which is recorded in the metadata associated with the class, the .NET Framework guarantees that the method will only be called in this way.

Add2

∇ R←Add2 arg
 :Access WebMethod
 :Signature Double←Add Double[] arg1
  R←+/arg
∇

The Add2 function defined above is exported as a method that takes an array of Double and returns a result of type Double. Depending on the type of the arguments provided when the method is invoked, .NET and Dyalog APL will call Add1 or Add2 - or generate an exception if the argument does not match any of the signatures.


Web Service Data Types

In principle, Web Services are designed to support most, if not all, of the data types supported by the .NET Framework, and to support any new .NET classes that you choose to define.

In practice, the current set of data types supported by Web Services is somewhat restricted; in particular:

  • Multi-dimensional arrays are not supported; only vectors.
  • Arbitrary nested arrays are not supported.

However, despite these restrictions, it is possible to build effective Web Services, as you will see in the following examples.


Execution

When your Web Service (or Page) is invoked, ASP.NET requests an instance of the corresponding Class from the Assembly (DLL) that was created when it was compiled. The first time this happens for any Dyalog APL Web Service or Web Page, the Dyalog APL dynamic link library is loaded into the ASP.NET host process and the namespace corresponding to your Web Service class is )COPYed from the Assembly. The Dyalog APL dynamic link library then delivers an instance of this namespace to the client (calling) process. See Introduction for further details.

In general, every call on a method in a Web Service causes a new instance of the Web Server class to be created. If you need to maintain/update variables between calls, you need to write them to permanent storage.

If a client invokes a different Dyalog APL Web Service or Web Page, its class is )COPYed from its Assembly into the workspace managed by the Dyalog APL dynamic link library. When you export a class, you can select one of three Isolation Modes:

  1. Each host process has a single workspace
  2. Each AppDomain has its own workspace
  3. Each Assembly has its own workspace

In this context, "workspace" is synonymous with "Dyalog APL process": Each workspace is managed by a separate process running dyalog.dll. Under option 1, all Dyalog APL Web Services (and Web Pages) hosted by the IIS host process share the same workspace when they are invoked.

The isolation mode selected has implications for the way that you access and manage global resources such as component files. Finer isolation modes may be implemented in future versions of Dyalog APL.


Global.asax and Application and Session Objects

Global.asax, Application and Session Objects

When a Web Service runs, it has access to the Application and Session objects. These are objects provided by ASP.NET through which you can manage the execution of the Web Service. ASP.NET creates an Application object when it first starts the Application, i.e. when any client requests any Web Service or Web Page stored in the same IIS Virtual Directory. It also creates a Session object for each client process.

When the first request comes in for an ASP.NET application, ASP.NET checks for an optional file named global.asax, and if it is there it compiles it. The application's global.asax instance is then used to apply application events.

global.asax typically defines callback functions to be executed on the various Application and Session events, such as Application_Start, Application_End, Session_Start, Session_End and so forth.

Dyalog APL allows you to use APL functions in the global.asax script. This allows you to initialise your APL application when it is first invoked, and to close it down cleanly when it is terminated.

For example, you can use global.asax to tie a component file on start-up, and untie it on termination.


Sample Web Service: EG1

The first APLExample sample is supplied in samples\asp.net\webservices\eg1.asmx which is mapped via an IIS Virtual Directory to the URL:

 http://localhost/dyalog.net.15.0.unicode.32/webservices/eg1.asmx

<%@ WebService Language="Dyalog" Class="APLExample" %>

:Class APLEXample: System.Web.Services.WebService
:Using System

 ∇ R←Add args
   :Access WebMethod
   :Signature Int32←Add Int32 arg1,Int32 arg2
   R←+/args
 ∇

:EndClass

The Add function defined above is exported as a method that takes exactly (and only) two parameters of type Int32 and returns a result of type Int32.

Line [3] could in fact be coded as:

   R←args[1]+args[2]

because .NET guarantees that a client can only call the method by providing two 32-bit integers as parameters.

Testing APLExample from a Browser

If you connect to a URL that represents a Web Service, the browser displays a page that provides information about the service and the methods that it contains. In certain cases, but by no means all, the page also contains form fields that let you invoke a method from the browser.

The screen shot below shows the page displayed by Google Chrome when it is pointed at eg1.asmx. It shows that the Web Service is called APLExample, and that it exports a single method called Add. Furthermore, the Add method takes two parameters of type int, named arg1 and arg2.

The following screen shot shows the result of entering the values 23 and 19 into the form fields and then pressing the Invoke button.

In this case, the method returns an int value 42.

It is important to understand what is happening here.

Accessed in this way from a browser, a Web Service appears to be behaving like a Web Server; this is not the case.

It is simply that the browser detects that the target URL is a Web Service, and invokes an ASP+ page named DefaultSdlHelpGenerator.aspx that inspects the compiled class and returns an HTML view of the Web service.


Sample Web Service: LoanService

The LoanService sample is supplied in Dyalog\Samples\asp.net\Loan\Loan.asmx, which is mapped via an IIS Virtual Directory to the URL:

 http://localhost/dyalog.net.15.0.unicode.32/Loan/Loan.asmx

This APLScript sample defines a class named LoanService that is based upon System.Web.Services.WebService. The LoanService class defines a sub-class called LoanResult and a method called CalcPayments.

<%@ WebService Language="Dyalog" Class="LoanService" %>
:Class LoanService: System.Web.Services.WebService
:Using System
    :Class LoanResult
    :Access public
        :Field Public Int32[] Periods
        :Field Public Double[] InterestRates
        :Field Public Double[] Payments
    :EndClass

    ∇ R←CalcPayments X;LoanAmt;LenMax;LenMin;IntrMax;
                     IntrMin;PERIODS;INTEREST;NI;NM
[1]   :Access WebMethod
[2]   :Signature LoanResult←CalcPayments Int32 LoanAmt,
                        Int32 LenMax,Int32 LenMin,
                        Int32 IntrMax,Int32 IntrMin
[3]
[4]  ⍝ Calculates loan repayments
[5]  ⍝ Argument X specifies:
[6]  ⍝   LoanAmt     Loan amount
[7]  ⍝   LenMax      Maximum loan period
[8]  ⍝   LenMin      Minimum loan period
[9]  ⍝   IntrMax     Maximum interest rate
[10] ⍝   IntrMin     Minimum interest rate
[11]
[12]   LoanAmt LenMax LenMin IntrMax IntrMin←X
[13]   R←⎕NEW LoanResult
[14]   R.Periods←¯1+LenMin+⍳1+LenMax-LenMin
[15]   R.InterestRates←0.5×¯1+(2×IntrMin)+⍳1+2×
                   IntrMax-IntrMin
[16]   NI←⍴INTEREST←R.InterestRates÷100×12
[17]   NM←⍴PERIODS←R.Periods×12
[18]   R.Payments←,(LoanAmt)×((NI,NM)⍴NM/INTEREST)÷
                   1-1÷(1+INTEREST)∘.*PERIODS
     ∇
:EndClass

CalcPayments takes five integer parameters (see comments for their descriptions) and returns an object of type LoanResult.

Note that the block of APLScript that defines the sub-class LoanResult must reside between the :Class and :EndClass statements of the main class, LoanService. You may define any number of internal classes in this way.

The LoanResult class is made up only of Fields and it does not export any methods or properties. Furthermore, there are no constructor methods defined and it relies solely on its default constructor that is inherited from its base class, System.Object. The default constructor is called without any parameters and in fact does nothing except to create an instance of the class. In particular, the fields it contains initialised to zero. In this case, that is sufficient, as all the fields will be filled in explicitly later.

    :Class LoanResult
    :Access public
        :Field Public  Int32[] Periods
        :Field Public Double[] InterestRates
        :Field Public Double[] Payments
    :EndClass

The :Class statement starts the definition of a new class and specifies its name. The :EndClass statement terminates it definition.

The three :Field declaration statements specify the names and data types of three public fields. The Public attributes are necessary to make the fields visible to methods within the LoanService class as a whole, as well as to external clients.

The Periods field is defined to be an array of integers; the InterestRates field an array of Double. Both these arrays are 1-dimensional, i.e. vectors. These will contain the numbers of years, and the different interest rates, to which the repayments matrix applies.

Notice however that Payments is also defined to be 1-dimensional when in fact it is, more naturally, a 2-dimesional matrix. The reason for this is that, currently, Web Services do not support multi-dimensional arrays. This is a .NET restriction and not a Dyalog restriction.

CalcPayments[13] gets a new instance of the LoanResult class by doing ⎕New LoanResult. It then assigns values to each of the three fields in lines [14], [15] and [18].

Testing LoanService from a Browser

Like the methods exported by the APLEXample Web Services described above, the CalcPayments method exported by LoanService is callable from a browser and the page that is displayed when you point a browser at it is shown below.

To test the CalcPayments method, you can enter numbers into the form fields in this page, as shown in the screen shot above, and then press the Invoke button. The result of the method is then displayed in a separate window as illustrated below.

Notice that the result is described using XML, which is in fact the very language used to invoke a Web Service and return its result.

You can see that the result is of type LoanResult, and it contains 3 fields named Payments, InterestRates and Periods. This information was derived by our definition of the LoanResult class in the APLScript file.

As you can see, the InterestRates field shows that it contains a vector of floating-point values (double) from the minimum rate to the maximum rate that we specified on the input form. This time, the increment is 0.5.

Similarly, the Payments field contains the calculated repayment values.

Finally the Periods field, contains a vector of integers from the minimum period to the maximum period that we specified on the input form, in increments of 1.


Sample Web Service: GolfService

GolfService is an example Web Service that resides in the directory samples\asp.net\Golf and is associated with the IIS Virtual Directory dyalog.net/Golf. This example makes extensive use of internal classes to define data structures that are appropriate for a client application, such as C# or VB.

The directory contains a global.asax script, which is used to initialise the application.

The Golf Web Service example manages the reservation of tee-times at golf courses. All the data is held in a component file called GolfData.dcf. This file may be initialised using the function Golf.INITFILE in the workspace samples\asp.net\webservices\webservices.dws. You may need to alter the file path first.

Each golf course managed by the application has a unique code (integer) and a name (string). This is handled by defining a class (structure) called GolfCourse with two fields, Code and Name.

GolfService provides 3 methods:

GetCourses()

Returns a list of Golf Courses (CourseCode and CourseName). The result of this method is an array of GolfCourse objects.

GetStartingSheet(CourseCode,Date)

Returns the starting sheet for a specified golf course on a given day. A starting sheet is a list of starting times with a list of the golfers booked to start their round at that time. The result of this method is a StartingSheet object.

MakeBooking(CourseCode,TeeTime,GimmeNearest, Name1,Name2,Name3,Name4))

Requests a tee reservation at the course specified by CourseCode. TeeTime is a DateTime object that specifies the requested date and time. GimmeNearest is Boolean. If 1, requests the nearest tee-time to that specified; if 0, requests only the specified tee-time. Name1-4 are strings specifying up to 4 players. Note that all parameters are required. The result of this method is a Booking object.

GolfService: Global.asax

<script language="Dyalog" runat=server>

∇ Application_Start;GOLFID
  :Access Public
  GOLFID←'c:\Dyalog\samples\asp.net\golf\GolfData' ⎕FTIE 0 This file needs to be located where it can be modified.1
  Application[⊂'GOLFID']←GOLFID
∇

∇ Application_End;GOLFID
  :Access Public
  :Trap 6
      GOLFID←Application[⊂'GOLFID']
      ⎕FUNTIE GOLFID
  :EndTrap
∇
</script>

The Application_Start function is called when the GolfService Web Service is invoked for the first time. It ties the GolfData component file then stores the tie number in a new Item called GOLFID in the Application object. This item is then subsequently available to methods in the GolfService for the duration of the application.

The Application_End function is invoked when the GolfService Web Service terminates. It unties the GolfData component file.

This example may be considered slightly weak in that the location of the data file is hard-coded in the application's Global.asax file. An alternative is to store this information in the <appsettings> section of the appropriate web.config file or in the global machine.config file. This is preferable if the resource (in this case a file name) is to be accessed from more than one script. For further information on ASP.NET config files, see the documentation for the .NET Framework SDK.

Note that the GolfData file may be initialised using the function Golf.INITFILE in the samples\asp.net\webservices\webservices.dws workspace. The function will prompt you for the path of the file, initialize it and update the Global.asax file accordingly.

GolfService: GolfCourse class

The GolfCourse class is effectively a structure with two fields named Code and Name. Code is an integer code that provides a shorthand way to refer to a specific golf course; Name is a String containing its full name.

:Class GolfCourse
    :Access Public
    :Field Public Int32 Code
    :Field Public String Name

    ∇ ctor args
     :Implements Constructor
     :Access public
     :Signature fn Int32, String
      Code Name←args
    ∇
    ∇ ctor_def
     :Implements Constructor
     :Access public
      ctor ¯1 ''
    ∇
:EndClass

The GolfCourse class provides two constructors. The first, named ctor_def, takes no arguments and therefore overrides the default constructor that is inherited from System.Object. ctor_def calls ctor to initialise the instance with a Code of ¯1 and an empty Name.

The constructor named ctor accepts two parameters named CourseCode (an integer) and CourseName (a string), and simply assigns these values into the corresponding fields.

Therefore, valid ways to create an instance of a GolfCourse are:

      GC←⎕NEW GolfCourse
      GC.(Code Name)←1 'St Andrews'

Or, more simply

      GC←⎕NEW GolfCourse (1 'St Andrews')

Note that the names of the constructor functions are not visible outside the class. Constructors are identified by their signatures (basically, the :Implements Constructor statement) and not by their names.

GolfService: Slot class

The Slot class is effectively a structure with two fields named Time and Players. Time is a DateTime object that represents a time that can be reserved on the first tee. Players is an array of (up to 4) strings that contains the names of the golfers who have reserved to start their round of golf at that time.

:Class Slot
    :Access Public
    :Field Public DateTime Time
    :Field Public String[] Players

    ∇ ctor1 arg
     :Implements Constructor
     :Access public
     :Signature fn DateTime
      Time←arg
      Players← 0⍴⊂''
    ∇
    ∇ ctor2 args
     :Implements Constructor
     :Access public
     :Signature fn DateTime, String[]
      Time Players←args
    ∇
    ∇ ctor_def
     :Implements Constructor
     :Access public
    ∇
:EndClass

This class provides two constructor functions named ctor1 and ctor2. However, for internal reasons, if a class defines any constructor functions, it is currently necessary to provide a dummy default constructor (the form of the constructor that takes no parameters); hence ctor_def.

The constructor ctor1 accepts a single DateTime parameter, which it assigns to the Time, field, and initialises the Players field to an empty array.

The constructor ctor2 accepts two arguments, a specified tee time, and an array of strings that contains golfers' names. It assigns these parameters to Time and Players respectively.

GolfService: Booking class

The Booking class represents the result of the MakeBooking method. It contains 4 fields named OK, Course, TeeTime and Message.

OK is Boolean and indicates whether or not the attempt to make a reservation was successful. If OK is false (0), the Message field (a string) indicates the reason for failure.

If OK is true (1) the Course field contains an instance of a GolfCourse object, and the TeeTime field contains an instance of a Slot object. Together, these objects identify the reserved golf course and starting slot. The latter specifies both the starting time, and the names of all the golfers who have been allocated that starting time and who will therefore play together.

:Class Booking
    :Access Public
    :Field Public Boolean OK
    :Field Public GolfCourse Course
    :Field Public Slot TeeTime
    :Field Public String Message

    ∇ ctor args
     :Implements Constructor
     :Access public
     :Signature fn Boolean, GolfCourse, Slot, String
      OK Course TeeTime Message←args
    ∇
    ∇ ctor_def
     :Access public
     :Implements Constructor
    ∇
:EndClass

This class provides a single constructor method, which must be called with values for all four fields.

GolfService: StartingSheet class

The StartingSheet class represents the result of the GetStartingSheet method. It contains 5 fields named OK, Course, Date, Slots and Message. OK is Boolean and indicates whether or not a starting sheet is available for the specified course and date.

If OK is false (0), the Message field (a string) indicates the reason for failure.

If OK is true (1) the Course field contains an instance of a GolfCourse object, the Date field contains the date in question, and the Slots field contains an array of Slot objects. Each Slot object specifies a starting time and the names of golfers who are booked to play at that time.

:Class StartingSheet
    :Access Public
    :Field Public Boolean OK
    :Field Public GolfCourse Course
    :Field Public DateTime Date
    :Field Public Slot[] Slots
    :Field Public String Message

    ∇ ctor args
     :Implements Constructor
     :Access public
     :Signature fn Boolean, GolfCourse, DateTime
      OK Course Date←args
    ∇

    ∇ ctor_def
     :Implements Constructor
     :Access public
    ∇
:EndClass

Like the Booking class, the StartingSheet class provides a single constructor method. In this case, the constructor is called with values for just 3 of the fields; the values of the other fields are expected to be assigned later.

GolfService: GetCourses function

     ∇ R←GetCourses;COURSECODES;COURSES;INDEX;GOLFID
[1]   ⍝
[2]   :Access WebMethod
[3]   :Signature GolfCourse[]←fn
[4]
[5]    GOLFID←Application[⊂'GOLFID']
[6]    COURSECODES COURSES INDEX←⎕FREAD GOLFID 1
[7]    R←⎕NEW¨GolfCourse,¨⊂¨↓⍉↑COURSECODES COURSES
     ∇

The GetCourses function retrieves the tie number of the GolfData component file from the Application object and reads its first component.

The function then creates a GolfCourse object for each of the courses recorded on the file, and returns the array of GolfCourse objects as its result.

GolfService: GetStartingSheet function

The GetStartingSheet function retrieves the tie number of the GolfData component file from the Application object and reads its first component. Line [10] creates an instance of a StartingSheet object and uses it to initialise the result R. The value of the OK field is set to zero to indicate failure.

It then validates the requested CourseCode. If invalid, it simply sets the Message field in the result and returns it. Similarly, it checks to see if there is a starting sheet on file for the requested date. If not, it sets the Message field to indicate this, and returns.

Note that line [15] extracts the Year, Month and Day properties from the requested tee time, a DateTime object, and converts them to an IDN. This is used to index the component containing the starting sheet for that day.

     ∇ R←GetStartingSheet ARGS;CODE;COURSE;DATE;GOLFID;
       COURSECODES;COURSES;INDEX;COURSEI;IDN;DATES;COMPS;
       IDATE;TEETIMES;GOLFERS;I;T
[1]   ⍝
[2]   :Access WebMethod
[3]   :Signature StartingSheet←fn Int32 CCode,
                                  DateTime Date
[4]
[5]    CODE DATE←ARGS
[6]    GOLFID←Application[⊂'GOLFID']
[7]    COURSECODES COURSES INDEX←⎕FREAD GOLFID 1
[8]    COURSEI←COURSECODES⍳CODE
[9]    COURSE←⎕NEW GolfCourse (CODE(COURSEI⊃COURSES,⊂''))
[10]   R←⎕NEW StartingSheet (0 COURSE DATE)
[11]   :If COURSEI>⍴COURSECODES
[12]       R.Message←'Invalid course code'
[13]       :Return
[14]   :EndIf
[15]   IDN←2 ⎕NQ'.' 'DateToIDN',DATE.(Year Month Day)
[16]   DATES COMPS←⎕FREAD GOLFID,COURSEI⊃INDEX
[17]   IDATE←DATES⍳IDN
[18]   :If IDATE>⍴DATES
[19]       R.Message←'No Starting Sheet available'
[20]       :Return
[21]   :EndIf
[22]   TEETIMES GOLFERS←⎕FREAD GOLFID,IDATE⊃COMPS
[23]   R.OK←1
[24]   T←⎕NEW¨DateTime,¨⊂¨(⊂DATE.(Year Month Day)),¨
                  3↑¨↓[1]24 60⊤TEETIMES
[25]   R.Slots←⎕NEW¨Slot,¨⊂¨T,∘⊂¨↓GOLFERS
     ∇

Line[23] sets the OK field of the result to 1 (success).

Line[24] converts the stored tee times (in minutes) to DateTime objects.

Line[25] combines the tee times and golfers into a vector of 2-element arrays, and creates a Slot object for each of them. The result is assigned to the Slots field of the result R.

GolfService: MakeBooking function

The MakeBooking function checks that the requested tee-time is available, for the specified number of players and updates the starting sheet accordingly. The result of the function is a Booking object.

MakeBooking first retrieves the tie number of the GolfData component file from the Application object and reads its first component.

Lines[13 14] create instances of GolfCourse and Slot objects, which at this stage are not validated. Line[15] then initialises the result R, a Booking object, which includes these instances. At this stage, R.OK is 0 indicating failure.

Line[16] validates the requested CourseCode, and, if invalid, simply sets R.Message and returns.

Similarly, lines [20 23] check that the requested tee time is within the next 30 days from now. If not, the function assigns the appropriate error message to R.Message and returns. Note that these two statements employ the APL primitive function > (rather that the op_GreaterThan method) to compare the requested tee time (a DateTime object) with a new DateTime object that represents now and now+30 days respectively.

Notice that line[24] uses the AddDays method to create a new DateTime object that represents now + 30 days. An alternative expression, to get now+30 days is:

      TEETIME.Now+⎕NEW TimeSpan (30 0 0 0)

Lines[28-47] are concerned with retrieving the appropriate component from the file, initialising it or re-using an old one, if it is not present. Each component represents the starting sheet for a particular course on a particular day.

Lines[48-63] check whether or not the requested slot is available (for the specified number of golfers). If not it returns an error message as before or, if GimmeNearest is 1 (true), it attempts to allocate the slot closest to the requested time.

If an appropriate slot is found, Lines[72 73] update the Slot object with the assigned time and names of the golfers. Line[74] then inserts the modified Slot object into the result, and sets the OK field to 1 (true) to indicate success.

    ∇ R←MakeBooking ARGS;CODE;COURSE;SLOT;TEETIME;GOLFID;
                    COURSECODES;COURSES;INDEX;COURSEI;IDN;
                    DATES;COMPS;IDATE;TEETIMES;GOLFERS;
                    OLD;COMP;HOURS;MINUTES;NEAREST;TIME;
                    NAMES;FREE;FREETIMES;I;J;DIFF
[1]  ⍝
[2]   :Access WebMethod
[3]   :Signature Booking←Int32 CourseCode,
                         DateTime TeeTime,
                         Boolean GimmeNearest,
                         String Name1,
                         String Name2,
                         String Name3,
                         String Name4
[4]
[5]
[6]  ⍝ If GimmeNearest=0, books (or fails) for specified time
[7]  ⍝ If GimmeNearest=1, books (or fails) for nearest to
                                           specified time
[8]
[9]    CODE TEETIME NEAREST←3↑ARGS
[10]   GOLFID←Application[⊂'GOLFID']
[11]   COURSECODES COURSES INDEX←⎕FREAD GOLFID 1
[12]   COURSEI←COURSECODES⍳CODE
[13]   COURSE←⎕NEW GolfCourse,⊂CODE(COURSEI⊃COURSES,⊂'')
[14]   SLOT←⎕NEW Slot TEETIME
[15]   R←⎕NEW Booking (0 COURSE SLOT '')
[16]   :If COURSEI>⍴COURSECODES
[17]       R.Message←'Invalid course code'
[18]       :Return
[19]   :EndIf
[20]   :If TEETIME.Now>TEETIME
[21]       R.Message←'Requested tee-time is in the past'
[22]       :Return
[23]   :EndIf
[24]   :If  TEETIME>TEETIME.Now.AddDays 30
[25]       R.Message←'Requested tee-time is more than
                      30 days from now'
[26]       :Return
[27]   :EndIf
[28]   IDN←2 ⎕NQ'.' 'DateToIDN',TEETIME.(Year Month Day)
[29]   DATES COMPS←⎕FREAD GOLFID,COURSEI⊃INDEX
[30]   IDATE←DATES⍳IDN
[31]   :If IDATE>⍴DATES
[32]       TEETIMES←(60×7)+10×¯1+⍳1+8×6
                    ⍝ 10 minute intervals, 07:00 to 15:00
[33]       GOLFERS←((⍴TEETIMES),4)⍴⊂''
                    ⍝ up to 4 golfers allowed per tee time
[34]       :If 0=OLD←⊃(DATES<
                  2 ⎕NQ'.' 'DateToIDN',3↑⎕TS)/⍳⍴DATES
[35]           COMP←(TEETIMES GOLFERS)⎕FAPPEND GOLFID
[36]           DATES,←IDN
[37]           COMPS,←COMP
[38]           (DATES COMPS)⎕FREPLACE GOLFID,COURSEI⊃INDEX
[39]
           :Else
[40]           DATES[OLD]←IDN
[41]           (TEETIMES GOLFERS)⎕FREPLACE
                                 GOLFID,COMP←OLD⊃COMPS
[42]           DATES COMPS ⎕FREPLACE GOLFID,COURSEI⊃INDEX
[43]       :EndIf
[44]   :Else
[45]       COMP←IDATE⊃COMPS
[46]       TEETIMES GOLFERS←⎕FREAD GOLFID COMP
[47]   :EndIf
[48]   HOURS MINUTES←TEETIME.(Hour Minute)
[49]   NAMES←(3↓ARGS)~⍬''
[50]   TIME←60⊥HOURS MINUTES
[51]   TIME←10×⌊0.5+TIME÷10 ⍝ Round to nearest
                              10-minute interval
[52]   :If ~NEAREST
[53]       I←TEETIMES⍳TIME
[54]       :If I>⍴TEETIMES
[55]       :OrIf (⍴NAMES)>⊃,/+/0=⍴¨GOLFERS[I;]
[56]           R.Message←'Not available'
[57]           :Return
[58]       :EndIf
[59]   :Else
[60]       :If ~∨/FREE←(⍴NAMES)≤⊃,/+/0=⍴¨GOLFERS
[61]           R.Message←'Not available'
[62]           :Return
[63]       :EndIf
[64]       FREETIMES←(FREE×TEETIMES)+32767×~FREE
[65]       DIFF←|FREETIMES-TIME
[66]       I←DIFF⍳⌊/DIFF
[67]   :EndIf
[68]   J←(⊃,/0=⍴¨GOLFERS[I;])/⍳4
[69]   GOLFERS[I;(⍴NAMES)↑J]←NAMES
[70]   (TEETIMES GOLFERS)⎕FREPLACE GOLFID COMP
[71]   TEETIME←⎕NEW DateTime,⊂TEETIME.(Year Month Day),
                                   3↑24 60⊤I⊃TEETIMES
[72]   SLOT.Time←TEETIME
[73]   SLOT.Players←(⊃,/0<⍴¨GOLFERS[I;])/GOLFERS[I;]
[74]   R.(OK TeeTime)←1 SLOT
  ∇

Testing GolfService from a Browser

If you point your browser at the URL:

 http://localhost/dyalog.net.15.0.unicode.32/Golf/Golf.asmx

GolfService will be compiled and ASP.NET will fabricate a page about it for the browser to display as shown below.

The three methods exposed by GolfService are listed.

Invoking the GetCourses method generates the following output.

Notice that the data type of the result is ArrayOfGolfCourse, and the data type of each element of the result is GolfCourse. Furthermore, the public fields defined for the GolfCourse object are clearly named.

All this information is derived from the declarations in the Golf.asmx script.

As supplied, the GolfData component file contains only 3 golf courses as shown below.

ASP.NET generates a Form containing fields that allow the user to invoke the MakeBookings method as shown below.

Notice the way a DateTime value is specified. Note too that the GimmeNearest parameter is Boolean, so you must enter "True"" or "False". If you enter 0 or 1, it will cause an error and the application will refuse to try to call MakeBookings because you have specified the wrong type for a parameter.

When you try this yourself, remember to enter a date that is within the next 30 days, and a time between 07:00 and 15:00. Alternatively, you may wish to experiment with invalid data to check the error handling.

The result of invoking MakeBooking with this data is shown below.

Notice how all the information about the Booking object structure, including the structure of the sub-objects, is provided.

The following picture shows data suitable for invoking the GetStartingSheet method.

If you try this for yourself, choose a course and date on which you have made at least one successful booking.

Finally, the result of the GetStartingSheet function is illustrated below.

The output clearly shows that the result, a StartingSheet object, contains an array of Slot objects, each of which contains a Time field and a Players field.

Using GolfService from C#

The csharp sub-directory in samples\asp.net\golf contains sample files for accessing the GolfService Web Service from C#. The C# source code in Golf.cs is shown below.

using System;

class MainClass  {

    static void Main(String[] args)
        {
        GolfService golf = new GolfService();
        int nArgs = args.Length;
        Booking booking;

        booking=golf.MakeBooking(
/* Course Code 	  */	1,
/* Desired Tee Time */	DateTime.Parse(args[0]),
/* nearest is OK    */	true,
/* player 1		  */	(nArgs > 1) ? args[1] : "",
/* player 2		  */	(nArgs > 2) ? args[2] : "",
/* player 3		  */	(nArgs > 3) ? args[3] : "",
/* player 4		  */	(nArgs > 4) ? args[4] : ""
            );

        Console.WriteLine(booking.OK);
        Console.WriteLine(booking.TeeTime.Time.ToString());
        foreach (String player in booking.TeeTime.Players)
            Console.WriteLine(player);
        }
}

The following example shows how you may run the C# program golf.exe from a Command Prompt window. Please remember to specify a reasonable date and time rather than the one used in this example.

csharp>golf 2006-08-07T08:00:00 T.Woods A.Palmer P.Donnelly
True
25/08/2008 08:00:00
T.Woods
A.Palmer
P.Donnelly

csharp>


Sample Web Service: EG2

In all the previous examples, we have relied upon ASP.NET to compile the APLScript into a .NET class prior to running it. This sample illustrates how you can make a .NET class yourself.

For this example, the Web Service script, which is supplied in the file samples\asp.net\webservices\eg2.asmx (mapped via an IIS Virtual Directory to the URL http://localhost/dyalog.net/webservices/eg2.asmx)is reduced to a single statement that merely invokes the pre-defined class called APLServices.Example.

The entire file, viewed in Notepad, is shown below.

Given this instruction, ASP.NET will locate the APLServices.Example Web Service by searching the bin sub-directory for assemblies. Therefore, to make this work, we have only to create a .NET assembly in samples\asp.net\aplservices\bin. The assembly should contain a .NET Namespace named APLServices, which in turn defines a class named Example.

The procedure for creating .NET classes and assemblies in Dyalog APL was discussed in Writing .NET Classes in Dyalog APL on page 1. Making a WebService class is done in exactly the same way.

Note that the sub-directory samples\asp.net\aplservices\bin already contains copies of the dependant Dyalog DLLs that are required to execute the code.

Start Dyalog as Administrator. This is essential both to allow you to create an assembly.

Starting with a CLEAR WS, create a namespace called APLServices. This will act as the container corresponding to a .NET Namespace in the assembly.

      )NS APLServices
#.APLServices

Within APLServices, create a class called Example that inherits from System.Web.Services.WebService. This is the Web Service class.

      )CS APLServices
#.APLServices
      )ED ○Example

:Class Example: WebService
:Using System
:Using System.Web.Services,System.Web.Services.dll
    ∇ R←Add arg
      :Access webmethod
      :Signature Int32←Add Int32 arg1, Int32 arg2
      R←+/arg
    ∇
:EndClass

Within APLServices.Example, we have a function called Add that will represent the single method to be exported by this Web Service.

Fix the class, then click File/Save As ... in the Session menubar and save the workspace in samples\asp.net\aplwebservices\bin.

C:\Program Files\Dyalog\Dyalog APL 15.0 Unicode\Samples\asp.net\webservices\bin\eg2.dws saved Mon Sep 26 15:31:56 2016

Select the Export… item from the Session File menu, and save the assembly as eg2.dll in the same directory, i.e. samples\asp.net\webservices\bin.

When you click Save, the Status Window displays the following information to confirm that the assembly has been created correctly.

Testing EG2 from a Browser

If you point your browser at the URL:

 http://localhost/dyalog.net.15.0.unicode.32/webservices/eg2.asmx

ASP.NET will fabricate a page about it for the browser to display as shown below.

The Add method exposed by APLServices.Example is shown, together with a Form from which you can invoke it.

If you enter the numbers 123 and 456 in the fields provided, then press Invoke, the method will be called and the result displayed as shown below.


Introduction

In order to call a Web Service, you need a "proxy class" on the client, which exposes the same methods and properties as the web service. The proxy creates the illusion that the web service is present on the client. Client applications create instances of the proxy class, which in turn communicate with the Web Service via IIS, using TCP/IP and HTTP/XML protocols.

Microsoft provides a utility called WSDL.EXE that queries the metadata (Web Service Definition Language) of a Web Service and generate C# source code for a matching proxy class.


MakeProxy function

The MakeProxy function

The MakeProxy function is provided in the supplied workspace samples\asp.net\webservices\webservices.dws.

MakeProxy is monadic and its argument specifies the URL of the Web Service to which you want to connect. For example, the following expressions uses MakeProxy to connect to the LoanService sample Web Service provided with Dyalog .NET:

   MakeProxy'http://localhost/dyalog.net/Loan/Loan.asmx'

MakeProxy runs the Microsoft utility WSDL.EXE passing the name of your URL to it as an argument. The utility then creates a C# source code file in your current directory that contains the code necessary to create a proxy class. The name of the C# file is the name of the Web Service (as declared in its header line) followed by the extension .cs.

MakeProxy then calls the C# compiler to compile this file, creating an assembly with the same name, but with a .dll extension, in your current directory. This assembly contains a .NET class of the same name.

MakeProxy attempts to determine the correct path for WSDL.EXE and CSC.EXE, but future versions of Microsoft.NET or Visual Studio require changes, in which case you will have to modify this function to locate these tools.


Using LoanService from Dyalog APL

For example, the above call to MakeProxy will create a C# source code file called LoanService.cs, and an assembly called LoanService.dll in your current directory. The name of the proxy class in LoanService.dll is LoanService.

You use this proxy class in exactly the same way that you use any .NET class. For example:

      ⎕USING ←,⊂',.\LoanService.dll'
      LN←⎕NEW LoanService
      LN.CalcPayments 100000 20 10 15 2
LoanResult

Notice that, as expected, the result of CalcPayments is an object of type LoanResult. For convenience, we will assign this to LR and then reference its fields:

      LR←LN.CalcPayments 100000 20 10 15 2
      LR.Periods
10 11 12 13 14 15 16 17 18 19 20
      LR.InterestRates
2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 9.5 10 10.5 ...
      LR.(((⍴InterestRates),⍴Periods)⍴Payments)
920.1345384 844.5907851 781.6836919 728.4970675 682.947 ...

The Payments field is, of course, a vector because it was defined that way. However, as can be seen above, it is easy to give it the "right" shape.

When you execute the CalcPayments method in the proxy class, the class transforms and packages up your arguments into an appropriate SOAP/XML stream and sends them, using TCP/IP, to the URL that represents the Web Service wherever that URL is on the internet or your Intranet. It then decodes the SOAP/XML that comes back, and returns the response as the result of the method.

Note that, depending upon the speed of your connection, and the logical distance away of the Web Service itself, calling a Web Service method can take a significant amount of time; regardless of how much time it actually takes to execute on its server.


Using GolfService from Dyalog APL

The workspace samples\asp.net\webservices\webservices contains functions that present a GUI interface to the GolfService web service.

The GOLF function accesses GolfService through a proxy class. GOLF is called with an argument of 0 or 1. Use 1 to force GOLF to create or rebuild the proxy class, which it does by calling MakeProxy. You must use an argument of 1 the first time you call GOLF, or if you ever change the GolfService APL code.

Note that you cannot make the proxy for GolfService unless the Web Server class has been compiled on the server. At present, the only way to trigger the compilation of golf.asmx into a Web Service is to visit the page once using Internet Explorer as described in the previous chapter.

The first few lines of the function are listed below. If the argument is 1, line[2] makes the proxy class GolfService.DLL in the current directory; if not it is assumed to be there already. Line[6] defines ⎕USING to use it, and Line[7] creates a new instance which is assigned to GS. Line[8] calls the GetCourses method, which returns a vector of GolfCourse objects. Notice how namespace reference array expansion is used to extract the course codes and names from the Code and Name fields respectively.

     ∇ GOLF FORCE;F;DLL;COURSES;COURSECODES;N;GS;⎕USING
[1]    :If FORCE≢0
[2]        DLL←MakeProxy
             'http://localhost/dyalog.net/golf/golf.asmx'
[3]    :Else
[4]        DLL←'.\GolfService.dll'
[5]    :EndIf
[6]    ⎕USING←'System'(',',DLL)
[7]    GS←⎕NEW GolfService
[8]    COURSECODES COURSES←↓⍉↑GS.GetCourses.(Code Name)

The following screen shot illustrates the user interface provided by GOLF. In this example, the user has typed the names of two golfers (one rather more famous than the other - at least in APL circles) and then presses the Book it! button.

This action fires the BOOK callback function which is shown below.

     ∇ BOOK;CCODE;YMD;HOUR;MINUTES;FLAG;NAMES;BOOKING;M
[1]    CCODE←⊃F.COURSE.SelItems/COURSECODES
[2]    YMD←3↑F.DATE.(IDNToDate⊃DateTime)
[3]    HOUR MINUTES←2↑1↓F.TIME.DateTime
[4]    FLAG←1=F.Nearest.State
[5]    NAMES←F.(Name1 Name2 Name3 Name4).Text
[6]    BOOKING←GS.MakeBooking CCODE
        (⎕NEW DateTime (YMD,HOUR MINUTES 0)),FLAG,NAMES
[7]    'M'⎕WC'MsgBox'
[8]    :If BOOKING.OK
[9]        M.Text←'Tee reserved for
             ',¯2↓⊃,/BOOKING.TeeTime.Players,¨⊂', '
[10]       M.Text,←' at ',BOOKING.Course.Name
[11]       M.Text,←' on ',BOOKING.TeeTime.Time.
            (ToLongDateString,' at ',ToShortTimeString)
[12]   :Else
[13]       M.Text←BOOKING.(Course.Name,'',
                   TeeTime.Time.(ToLongDateString,
            ' at ',ToShortTimeString),' ',Message)
[14]   :EndIf
[15]   ⎕DQ'M'
     ∇

Line[6] calls the MakeBooking method of the GS object, passing it the data entered by the user. The result, a Booking object, is assigned to BOOKING. Line[8] checks its OK field to tell whether or not the reservation was successful. If so, lines[9-11] display the message box illustrated below.

Notice how the various fields are extracted and notice how the ToLongDateString and ToShortTime String methods are employed.

Pressing the Starting Sheet button runs the SS callback listed below.

    ∇ SS;CCODE;YMD;M;SHEET;OK;COURSE;TEETIME;S;DATA;N
        ;TIMES
[1]    CCODE←⊃F.COURSE.SelItems/COURSECODES
[2]    YMD←3↑F.DATE.(IDNToDate⊃DateTime)
[3]    SHEET←GS.GetStartingSheet CCODE(⎕NEW DateTime YMD)
[4]    :If SHEET.OK
[5]        DATA←↑(SHEET.Slots).Players
[6]        TIMES←(SHEET.Slots).Time
[7]        'S'⎕WC'Form'('Starting Sheet for ',
              SHEET.Course.Name,' ',
              SHEET.Date.ToLongDateString)
              ('Coord' 'Pixel')('Size' 400 480)
[8]        'S.G'⎕WC'Grid'DATA(0 0)(S.Size)
[9]        S.G.RowTitles←TIMES.ToShortTimeString
[10]       S.G.ColTitles←'Player 1' 'Player 2'
                         'Player 3' 'Player 4'
[11]       S.G.TitleWidth←60
[12]       ⎕DQ'S'
[13]   :Else
[14]       'M'⎕WC'MsgBox'('Starting Sheet for ',
              SHEET.Course.Name,' ',
              SHEET.Date.ToLongDateString)
                         ('Style' 'Error')
[15]       M.Text←SHEET.Message
[16]       ⎕DQ'M'
[17]   :EndIf
     ∇

Line[3] calls the GetStartingSheet method of the GS object. The result, a StartingSheet object, is assigned to SHEET. Line[4] checks its OK field to see if the call succeeded. If so, lines[5-12] display the result in a Grid, which is illustrated below.


Exploring Web Services

You can use the Workspace Explorer to browse the proxy class associated with a Web Service, in exactly the same way that you can browse any other .NET Assembly. The following screen shots show the Metadata for LoanService, loaded from the LoanService.dll proxy.

Remember, LoanService was written in APLScript, but it appears and behaves just like any other .NET class.

The first picture displays the structure of the LoanResult class.

The second picture shows the methods exposed by LoanService. In addition to CalcPayments, which was written in APLScript, there are a large number of other methods, which have been inherited from the base class.


Asynchronous Use

Web Services provide both synchronous (client calls the function and waits for a result) and asynchronous operation.

Each method is exposed as a function with the same name (the synchronous version) together with a pair of functions with that name prefixed with Begin and End respectively.

The Beginxxx functions take two additional parameters; a delegate class that represents a callback function and a state parameter.

To initiate the call, you execute the Beginxxx method using the standard parameters followed by two objects. The first is an object of type System.AsyncCallback that represents an asynchronous callback, i.e. a callback to be invoked when the asynchronous call is complete. The second is an object which is used to supply extra information. We will see how callbacks are used later in this section. If you are not using a callback, these items should be null object references. You can specify a reference to a null object using the expression (⎕NS''). For example, using the LoanService sample as above:

      A←LN.BeginCalcPayments 10000 16 10 12
                             9(⎕NS'')(⎕NS'')

The result is an object of type WebClientAsynchResult.

      A
System.IAsyncResult ⎕CLASS System.Web.Services.Protocols.WebClientAsyncResult

Then, some time later, you call the Endxxx method with this object as a parameter. For example:

      LN.EndCalcPayments A
LoanResult

You can execute several asynchronous calls in parallel:

      A1←LN.BeginCalcPayments 20000 20 10 15
                              7(⎕NS'')(⎕NS'')
      A2←LN.BeginCalcPayments 30000 10  8 12
                              3(⎕NS'')(⎕NS'')

      LN.EndCalcPayments A1
LoanResult
      LN.EndCalcPayments A2
LoanResult

Using a callback

The simple approach described above is not always practical. If it can take a significant amount of time for the web service to respond, you may prefer to have the system notify you, via a callback function, when the result from the method is available.

The example function TestAsyncLoan in the workspace samples\asp.net\webservices\webservices.dws illustrates how you can do this. It is somewhat artificial, but hopefully explains the mechanism that is involved.

TestAsyncLoan itself is just a convenience function that calls AsyncLoan with suitable arguments. TestAsyncLoan takes an argument of 1 or 0 that determines whether or not a Proxy class for LoanService is to be built.

     ∇ TestAsyncLoan MAKEPROXY
[1]    (⍕MAKEPROXY),' AsyncLoan 10000 10 8 5 3'
[2]    MAKEPROXY AsyncLoan 10000 10 8 5 3
     ∇

The AsyncLoan function and its callback function GetLoanResult are more interesting.

     ∇ {MAKEPROXY}AsyncLoan ARGS;DLL;SINK;LN;AS;AR
[1]    :If 2≠⎕NC'MAKEPROXY' ⋄ MAKEPROXY←0 ⋄ :EndIf
[2]    :If MAKEPROXY
[3]       DLL←MakeProxy'http://localhost/dyalog.net/loan/
                         loan.asmx'
[4]    :Else
[5]       DLL←'.\LoanService.dll'
[6]    :EndIf
[7]    ⎕USING←'System'(',',DLL)
[8]    LN←⎕NEW LoanService
[9]    AS←⎕NEW System.AsyncCallback,⊂⎕OR'GetLoanResult'
[10]   AR←LN.BeginCalcPayments ARGS,AS,LN
[11]   'AsyncLoan waits for async call to complete'
[12]   :While 0=AR.IsCompleted
[13]       ⍞←'.'
[14]   :EndWhile
     ∇
     ∇ GetLoanResult arg;OBJ;LR;RSLT
[1]    'GetLoanResult callback fires ...'
[2]    OBJ←arg.AsyncState
[3]    LR←OBJ.EndCalcPayments arg
[4]    RSLT←LR.(((⍴Periods),(⍴InterestRates))⍴Payments)
[5]    RSLT←((⊂''),LR.Periods),(LR.InterestRates),[1]RSLT
[6]    'Result is'
[7]    ⎕←RSLT
     ∇

The effect of running TestAsyncLoan is as follows:

      TestAsyncLoan 0
0 AsyncLoan 10000 10 8 4 3

...AsyncLoan waits for async call to complete...
...GetLoanResult callback fires ...

...Result is
      3           3.5         4
 8  117.2957193 105.7694035  96.5607447
 9  119.5805173 108.0741442  98.88586746
121.892753  110.409689  101.2451382

AsyncLoan[8] creates a new instance of the LoanService class called LN. The next line creates an object of type System.AsyncCallback named AS. This object, which is termed a delegate, identifies the callback function that is to be invoked when the asynchronous call to CalcPayments is complete. In this case, the name of the callback function is GetLoanResult. Note that ⎕OR is necessary because the AsyncCallback constructor must be called with a parameter of type System.Object. The line AsyncLoan[10] calls BeginCalcPayments with the parameters for CalcPayments, followed by references to AS (which identifies the callback) and LN, which identifies the object in question. The latter will turn up in the argument supplied to the GetLoanResult callback. Lines[12-14] loop, displaying dots, until the asynchronous call is complete. GetLoanResult will be invoked during or immediately after this loop, and will be executed in a different APL thread.

When the GetLoanResult callback is invoked, its argument arg is an object of type System.Web.Services.Protocols.WebClientAsyncResult. It is in fact a reference to the same object AR that was the result returned by BeginCalcPayments.

This object has an AsyncState property that references the LoanService object LN that we passed as the final parameter to BeginCalcPayments. GetLoanResult[2] retrieves this object and assigns it to OBJ. GetLoanResult[3] calls the EndCalcPayments method, passing it arg as the AsyncResult parameter as before. The resulting LoanResult object is then formatted and displayed.


Introduction

Under Microsoft IIS, a static web page is defined by a simple text file with the extension .htm or .html that contains simple HTML. When a browser requests such a page, IIS simply reads it and sends its content back to the client. The contents of a static web page are constant and, until somebody changes it, the page appears the same to all users at all times.

A dynamic web page is represented by a simple text file with the extension .aspx. Such a file may contain a mixture of (static) HTML, ASP.NET objects and a server-side script. ASP.NET objects are built-in .NET classes that generate HTML when the page is processed. Scripts contain functions and subroutines that are invoked by events (such as the Page_Load event) or by user interaction.

Typically, a script will generate HTML dynamically, when the page is loaded. For example, a script could perform a database operation and return an HTML table containing a list of products and prices. A script may also contain code to process user interaction, for example to process the contents of a Form that is filled in and then submitted by the user. These scripts are referred to as server-side scripts because they are executed on the server. The browser sees only the results produced by the scripts and not the scripts themselves. Code in a server-side script always involves the generation of a new page by the server for display in the browser.

The first time ASP.NET processes a .NET web page, it compiles the entire page into a .NET Assembly. Subsequently, it calls the code in the assembly directly. The language used to compile the page is defined in the <script> section, which is typically defined at the top of the page. If the <script> section is omitted, or if it fails to explicitly specify the language attribute, the page is compiled using the default scripting language. This is configurable, but is typically VB or C#.

This Chapter is made up almost entirely of examples, the source code of which is supplied in the samples\asp.net directory and the sub-directories it contains. This directory is mapped as an IIS Virtual Directory named dyalog.net, so you may execute the examples by specifying the URL http://localhost/dyalog.net/ followed by the name of the sub-directory and page. You can get an overview of the samples by starting on the page http://localhost/dyalog.net/index.htm and follow links from there.

To use APLScript effectively in Web Pages, you need to have a thorough understanding of how ASP.NET works.

In the first example, an outline description ASP.NET technology is provided. For further information, see the Microsoft .NET Framework documentation and Beginning ASP.NET using VB.NET, Wrox Press Ltd, ISBN 1861005040.


Your first APL Web Page

The first web page example is tutorial/intro1.aspx, which is listed below. This page displays a button whose text is reversed each time you press it.

Note that the example is intended to be run in the framework of the tutorial and contains two lines of code (shown in italic) that refer to this framework and should be ignored.

<%@Register TagPrefix="tutorial" Namespace="Tutorial" Assembly="tutorial" %>
<script language="Dyalog" runat="server">

∇Reverse args
:Access public
:Signature Reverse Object,EventArgs
(⊃args).Text←⌽(⊃args).Text
∇

</script>

<html>
<body>
<Form runat=server>
      <asp:Button id="Pressme"
      Text="Press Me"
      runat="server"
      OnClick="Reverse"
      />
</form>
<tutorial:index runat="server"/>
</body>
</html>

In this example, the page language is defined in the <script> section to be "Dyalog". This in turn is mapped to the APLScript compiler via information in the application's web.config file or the global IIS configuration file, machine.config.

The page layout is described in the section between the <html> and </html> tags. This page contains a Form in which there is a Button labelled (initially) "Press Me"

The Form and Button page elements may appear to be simple HTML, but in fact there is more to them than meets the eye and they are actually both types of ASP.NET intrinsic controls.

Firstly, the runat="server" attribute indicates that an HTML element should be parsed and treated as an HTML server control. Instead of being handled as pure text that is to be transmitted to the browser "as is", an HTML server control is effectively compiled into statements that then generate HTML when executed. Furthermore, an HTML server control can be accessed programmatically by code in the Script, whereas a pure HTML element cannot. On its own, runat="server" identifies the HTML element as a so-called basic intrinsic control.

When you add runat="server" to a Form, ASP.NET automatically adds other attributes that cause the values of its controls to be POSTed back to the same page. In addition, ASP.NET adds a HIDDEN control to the form and stores state information in it. This means that when the page is reloaded into the browser the state and contents of some or all of its controls can be maintained, without the need for you to write additional code.

The asp: prefix for the Button, identifies the control as a special ASP.NET intrinsic control. These are fully-fledged .NET Classes in the .NET Namespace System.Web.UI.WebControls that expose properties corresponding to the standard attributes that are available for the equivalent HTML element. You manipulate the control as an object, while it, at runtime, emits HTML that is inserted into the page.

At this point, it is instructive to study what happens when the page is first loaded and the appearance of the page is illustrated below.

The HTML that is transmitted to the browser is:

<html>
<body>
    <form name="ctrl1" method="post" action="intro1.aspx" id="ctrl1">
<input type="hidden" name="__VIEWSTATE"
value="YTB6NTQ3ODg0MjcyX19feA==5725bd57" />

        <input type="submit" name="Pressme" value="Press Me"
id="Pressme" />
    </form>
</body>
</html>

Firstly, notice that, as expected, the contents of the <script> section are not present. Secondly, because the Form and Button are intrinsic controls, ASP.NET has added certain attributes to the HTML that were not specified in the source code.

The Button now has the added attribute input type="submit", which means that pressing the Button causes the contents of the Form to be transmitted back to the sever.

The Form now has method="post" and action="intro1.aspx" attributes, which means that, when the Form is submitted, the data is POSTed back to intro1.aspx, the page that generated the HTML in the first place.

So when the user presses the button, the browser sends back a POST statement, with the contents of the Form, including the value of the HIDDEN field, requesting the browser to load intro1.aspx.

In the server, ASP.NET reloads the page and processes it again. In fact, because of the stateless nature of HTTP, the server does not know that it is reprocessing the same page, except that it is being executed by a POST command with the hidden data embedded in the Form that it put there the first time around. This is the mechanism by which ASP.NET remembers the state of a page from one invocation to another.

This time, because a POST back is loading the page, and because the Pressme button caused the POST, ASP.NET executes the function associated with its onClick attribute, namely the APLScript function Reverse.

When it is called, the argument supplied to Reverse contains two items. The first of these is an object that represents the control that generated the onClick event; the second is an object that represents the event itself. In fact, Reverse and its argument are very similar to a standard Dyalog APL callback function.

∇Reverse args
:Access public
:Signature Reverse Object,EventArgs
(⊃args).Text←⌽(⊃args).Text
∇

The code in the Reverse function is simple. The expression (⊃args) is a namespace reference (ref) to the Button, and (⊃args).Text refers to its Text property whose value is reversed. Note that Reverse could just as easily refer to the Button by name, and use Pressme.Text instead.

After pressing the button, the page is redisplayed as shown below:

This time, the HTML generated by intro1.aspx is:

<html>
<body>
    <form name="ctrl1" method="post" action="intro1.aspx" id="ctrl1">
<input type="hidden" name="__VIEWSTATE"
value="YTB6NTQ3ODg0MjcyX2Ewel9oejV6MXhfYTB6X2h6NXoxeF9hMHph
MHpoelRlXHh0X2VNIHNzZXJQeF9feF9feHhfeHhfeF9feA==45acf576"
/>

        <input type="submit" name="Pressme" value="eM sserP"
id="Pressme" />
    </form>
</body>
</html>

Returning to the Reverse function, note that the declaration statements at the top of the function are essential to make it callable in this context.

∇Reverse args
:Access public
:Signature Reverse Object,EventArgs
(⊃args).Text←⌽(⊃args).Text
∇

Firstly the Reverse function must be declared as a public member of the script. This is achieved with the statement.

:Access Public

Secondly, the .NET runtime will only call the function if it possesses the correct signature, which is derived from its parameters and their types.

The required signature for a method connected to an event, such as the OnClick event of a Button, is that it takes two parameters; the first of which is of type System.Object and the second is of type System.EventArgs. The Reverse function declares its parameters with the statements:

:Signature Reverse Object,EventArgs

Note that the parameter declarations do not include the System prefix. This is because when the script is compiled the names are resolved using the current value of ⎕USING. When the APLScript is compiled, the default value for ⎕USING is automatically defined to contain System along with most of the other namespaces that will be used when writing web pages

(Strictly speaking, the first argument is expected to be of type System.Web.UI.WebControls.Button, but as this type inherits ultimately from System.Object the function signature is satisfied.)

Note that if the Reverse function is defined with a signature that does not match that expected signature for the OnClick callback, the function will not be run.

Furthermore, if the function associated with the OnClick statement is not defined as a public method in the APLScript the page will appear to compile but the Reverse function will not get executed.

Note that unlike Web Services, there is no requirement for a :Class or :EndClass statement in the script. This is because a file with an .aspx extension implicitly generates a class that inherits from System.Web.UI.Page.


The Page_Load Event

Intro3.aspx illustrates how you can dynamically initialise the contents of a Web Page using the Page_Load event. This example also introduces another type of Web Control, the DropDownList object.

<%@Register TagPrefix="tutorial" Namespace="Tutorial" Assembly="tutorial" %>
<script language="Dyalog" runat="server">

∇Page_Load
:Access Public
list.Items.Add ⊂'Apples'
list.Items.Add ⊂'Oranges'
list.Items.Add ⊂'Bananas'
∇

∇Select (obj ev)
:Access Public
:Signature Select Object obj, EventArgs ev
out.Text←'You selected ',list.SelectedItem.Text
∇
</script>

<html>
<head>
<title>Initialising the contents of the Page using the Page_Load method</title>
<link rel="stylesheet" type="text/css" href="apl.css">
</head>

<body>
<h1>intro3: The Page_Load method</h1>
<form runat="server">
<asp:DropDownList id="list" runat="server"/>
<p>
<asp:Label id="out" runat="server" />
</p>
<asp:Button id="btn"
    Text="Submit"
    runat="server"
    OnClick="Select"/>
</form>
<tutorial:index runat="server"/>
</body>
</html>

When an ASP.NET web page is loaded, it generates a Page_Load event. You can use this event to perform initialisation simply by defining a public function called Page_Load in your APLScript. This function will automatically be called every time the page is loaded. The Page_Load function should be niladic.

Note that, if the page employs the technique illustrated in Intro1.aspx, whereby the page is continually POSTed back to itself by user interaction, your Page_Load function will be run every time the page is loaded and you may not wish to repeat the initialisation every time. Fortunately, you can distinguish between the initial load, and a subsequent load caused by the post back, using the IsPostBack property. This property is inherited from the System.Web.UI.Page class, which is the base class for any .aspx page.

The Page_Load function in this example checks the value of IsPostBack. If 0 (the page is being loaded for the first time) it initialises the contents of the list object, adding 3 items "Apples", "Oranges" and "Bananas". The explanation for the statement:

      list.Items.Add ⊂'...'

is that the DropDownList WebControl has an Items property that is a collection of ListItem objects. The collection implements an Add function that takes a String Argument that can be used to add an item to the list.

Notice that the name of the object list is defined by the id="list" attribute of the DropDownList control that is defined in the page layout section of the page.

In this example, the page is processed by a POST back caused by pressing the Submit button. As it stands, changing the selection in the list object does not cause the text in the out object to be changed; you have to press the Submit button first.

However, you can make this happen automatically by adding the following attributes to the list object (see intro4.aspx):

AutoPostback="true"

OnSelectedIndexChanged="Select"/>

AutoPostback causes the object to generate HTML that will provoke a post back whenever the selection is changed. When it does so, the OnSelectedIndexChanged event will be generated in the server-side script which in turn will call Select, which in turn will cause the text in the out object to change.

Note that this technique, which can be used with most of the ASP.NET controls including CheckBox, RadioButton and TextBox controls, relies on a round trip to the server every time the value of the control changes. It will not perform well except on a fast connection to a lightly loaded server.


Code Behind

It is often desirable to separate the code content of a page completely from the HTML and other text, layout or graphical information by placing it in a separate file. In ASP.NET parlance, this technique is known as code behind.

The intro5.aspx example illustrates this technique.

<%@Page Language="Dyalog"
    Inherits="FruitSelection"
    src="fruit.apl" %>
<%@Register TagPrefix="tutorial" Namespace="Tutorial" Assembly="tutorial" %>
<html>
<head>
<title>Code behind: separating your code from the page layout</title>
<link rel="stylesheet" type="text/css" href="apl.css">
</head>
<body>
<h1>intro5: Code Behind</h1>
<p>This example illustrates how you can separate your code from the page layout.</p>
<form  runat="server" >
<asp:DropDownList id="list"
    runat="server"
    autopostback="true"
    OnSelectedIndexChanged="Select"/>
<p>
<asp:Label id="out" runat="server" /></p>
</form>
</body>
<tutorial:index runat="server"/>
</html>

The statement

%@Page Language="Dyalog" Inherits="FruitSelection" src="fruit.apl" %>

says that this page, when compiled, should inherit from a class called FruitSelection. Furthermore, the FruitSelection class is written in the "Dyalog" language, and its source code resides in a file called fruit.apl. FruitSelection is effectively the base class for the .aspx page.

In this case, fruit.apl is simply another text file containing the APLScript code and is shown below.

:Class FruitSelection: System.Web.UI.Page
:Using System

∇Page_Load
:Access Public
:if 0=IsPostBack
    list.Items.Add ⊂'Pears'
    list.Items.Add ⊂'Nectarines'
    list.Items.Add ⊂'Strawberries'
:endif
∇

∇Select args
:Access public
:Signature Select Object,EventArgs
out.Text←'You selected ',list.SelectedItem.Text
∇
:EndClass

The first thing to notice is that the file requires :Class and :EndClass statements. These are required to tell the APLScript compiler the name of the class being defined, and the name of its base class. When the source code is in a .aspx file, this information is provided automatically by the APLScript compiler.

The name of the class, in this case FruitSelection, must be the same name as is referenced in the .aspx web page file itself (intro5.aspx). The base class must be System.Web.UI.Page

The body of the script is just the same as the script section from the previous example. Only the names of the fruit have been changed so that it is clear which example is being executed.


Workspace Behind

The previous section discussed how APL logic can be separated from page layout, by placing it in a separate APLScript file which is referred to from the .aspx web page. It is also possible to have the code reside in a separate workspace. This allows you to develop web pages using a traditional workspace approach, and it is probably the quickest way to give an HTML front-end to an existing Dyalog APL application.

In the previous example, you saw that the fruit.apl file defined a new class called FruitSelection that inherits from System.Web.UI.Page. This class contains a Page_Load function that (by virtue of its name) overrides the Page_Load method of the underlying base class and will be called every time the web page is loaded or posted back. The Page_Load function takes whatever action is required; for example, initialisation. The class also contained a callback function to perform some action when the user pressed a button.

A similar technique is employed when the code behind the web page is implemented in a separate workspace. The workspace should contain a class that inherits from System.Web.UI.Page. This class may contain a Page_Load function that will be invoked every time the corresponding web page is loaded, and as many callback functions as are required to provide the application logic. The workspace is hooked up to one or more web pages by the Inherits="<classname>" and src="<workspace>" declarations in the Page directive statement that appears at the beginning of the web page script.

The ACTFNS sub-directory in samples\asp.net contains some examples of Dyalog APL systems that have been converted to run as Web applications using this technique.

Dyalog is grateful to David Hughes who provided the original workspaces and advised on their conversion.

The two workspaces are named ACTFNS.DWS and PROJ.DWS. The original code used the Dyalog APL GUI to display an input Form, collect and validate the user's input, and calculate and display the results. The original logic supported field level validation and results were immediately recalculated whenever any field was changed. With some exceptions, this has been changed so that the user must press a button to tell the system to recalculate the results. This approach is more appropriate in an Internet application, especially when connection speed is low. Apart from this change, the applications run more-or-less as originally designed.

The diagram above illustrates the structure of the web application and the various files involved. The starting page, actfns.htm, simply provides a menu of choices which link to various .aspx web pages. These pages in turn are linked to one of the two workspaces via the src="" declaration

The actfns.htm start page offers 3 application choices

The result of choosing Tabulate single life insurance and annuity values

When you choose the first option, the system loads sla_tab.aspx. This defines the screen layout in terms of ASP.NET controls, including the DataGrid control for tabulating the results. The sla_tab.aspx script contains the declarations Inherits="actuarial" src="actfns.dws", so ASP.NET loads the actuarial class from this workspace (via a call to Dyalog APL). When the page is loaded, it generates a Page_Load event, which in turn calls its Page_Load method. This populates the ASP controls with data, and the resulting web page is displayed. The mechanism is described below.

For further details, see the sla_tab.aspx script and ACTFNS.DWS workspace.

Converting an Existing Workspace

The steps involved in converting the workspaces were as follows:

  1. Replace the Dyalog APL GUI with the equivalent HTML Forms, which are defined in one or more separate .aspx web pages. To retain consistency, it is helpful to give the ASP controls the same names as the original GUI controls, which they are replacing.
  2. Attach the names of APL callback functions to the appropriate ASP controls; essentially, any controls that will be involved in a postback operation, such as the Submit button.
  3. Starting with a CLEAR WS, create a Class that represents a .NET class based upon System.Web.UI.Page. For example, in converting the ACTFNS workspace, we started by creating the class:
          )edit ○actuarial

  4. then defining ⎕USING as follows:
    :Using System
:Using System.Web.UI,system.web.dll
:Using System.Web.UI.WebControls
:Using System.Web.UI.HtmlControls
:Using System.Data,system.data.dll

    The name you choose for this class will replace classname in the Inherits="classname" declaration in the .aspx web page(s) that call it.

  5. Create a namespace, change into it, and copy the workspace to be converted; in this case, the starting point was a workspace named DH_ACTFNS:
          )NS actuarial_utils
      )CS actuarial_utils
#.actuarial_utils
      )COPY DH_ACTFNS
DH_ACTFNS saved ...
  6. Modify the code as appropriate, inserting a Page_Load function and whatever callback functions that are required.
  7. Make sure the class 'actuarial' has an :Include actuarial_utils statement

The Page_Load function

The Page_Load function must be declared as :Access Public. Page_Load must be spelled correctly as it is this name that causes the function to supersede the base class Page_Load method of the same name.

For example, the Page_Load function of the actuarial class in ACTFNS.DWS is shown below:

    ∇ Page_Load;INT;AGE;DUR;TERM;TAB_DURS;MPC1;INT1;INT2;
                INTY;RUN_OPTION;OPT
      :Access public
      :Signature Page_Load
     ⍝ Overrides Page_Load method of Page class
     ⍝ Called when Page is loaded or re-loaded after postback
     ⍝ Initialise fields and calculate on initial load only
      :If 0=IsPostBack
          RUN_OPTION←GET_RUN_OPTION
          :Select RUN_OPTION
          :Case 1
              EINT.Text←⍕INT←3.25
              EAGE.Text←⍕AGE←30
              EDUR.Text←⍕DUR←0
              ETRM.Text←⍕TERM←10
              TA.Checked←TAB_DURS←1
              CHANGE_TABLES ⍬
          :Case 2
              CPLAN.Items.Clear
              :For OPT :In ↓⊃OPTSPLAN
              CPLAN.Items.Add{82∊⎕DR 1⍴⍵:⊂⍵ ⋄ ⍵}DETRAIL OPT
              :EndFor
              EMPC1.Text←⍕MPC1←100
              EINT1.Text←⍕INT1←3.25
              EINT2.Text←⍕INT2←3.25
              EINTY.Text←⍕INTY←99
              EAGE.Text←⍕AGE←30
              EDUR.Text←⍕DUR←0
              ETRM.Text←'N/A'
              CHANGE_TABLES ⍬
          :EndSelect
      :EndIf
    ∇

If exported correctly, Page_Load will be called every time the calling web page is loaded. This occurs when the page is loaded for the first time, and whenever the page is submitted back to the web server by the browser (postback). A postback will occur whenever a callback function is involved, and potentially at other times.

The Page_Load function may determine whether it is being invoked by a first time load, or by a postback, from the value of the IsPostBack property. This is a property that it inherits from its base class System.Web.UI.Page.

The Page_Load example shown above uses this property to control the initialisation of the controls in the calling web page. The names EINT, EAGE, EDUR and so forth refer to names of controls in the calling web page. When Page_Load is executed, the actuarial object is associated with the web page itself, and so the names of all its controls are visible as sub-objects within it.

Note that the actuarial class is used by two different web pages, and the function GET_RUN_OPTION function determines which of these are involved. (It does so by detecting the presence or otherwise of a particular control on the page).

Callback functions

The actuarial class in ACTFNS.DWS provides four callback functions named CALC_FSLTAB_RESULTS, CALC_FSL_RESULTS, CHANGE_TABLES and CHANGE_TABLE_FORMAT. The first two of these functions are attached as callbacks to the Calculate button in each of two separate web pages sla_tab.aspx and sla_disp.aspx. For example, the statement that defines the button in sla_tab.aspx is:

<asp:Button id=Button1 runat="server" Text="Calculate" onClick="CALC_FSLTAB_RESULTS"></asp:Button>

The third callback, CHANGE_TABLES, is called by sla_tab.aspx when the user selects a different set of Mortality Tables from the three provided. CHANGE_TABLE_FORMAT is called when the user clicks either of the two radio buttons that select how the output is to be displayed.

Like the Page_Load function, callback functions must be declared as being Public methods. This is done using the :Access statement.

In addition, and this is essential, APL callback functions must be declared to have the correct signature expected of .NET callback functions. This means that they must be monadic, and their argument must be declared to be a 2-element nested array containing two .NET objects; the object that generated the event, and an object that represents the arguments to the event.

Specifically, these parameters must be of type System.Object and System.EventArgs respectively. However, as our ⎕USING contains System, it is not necessary to include the System prefix.

For example, the statements for the function CALC_FSLTAB_RESULTS is shown below:

:Access Public
:Signature CALC_FSLTAB_RESULTS Object obj, EventArgs ev

Validation functions

In a Dyalog APL web page application, there are basically two approaches to validation. You can handle it entirely yourself or you can exploit the various validation controls that come with ASP.NET. The sample application uses the latter approach by way of illustration. For example:

<asp:TextBox id=EINT runat="server"></asp:TextBox>
<asp:RequiredFieldValidator id="RFVINT"
     ControlToValidate="EINT"
     ErrorMessage="Interest Rate must be a number
                   between 0 and 20"
     Text="*"
     runat="server"/></td>

These ASP.NET statements associate a RequiredFieldValidator named RFVINT with the EINT field, the field used to enter Interest Rate. If the user leaves this field blank, the system will automatically generate the specified error message. The page defines a separate ValidationSummary control as follows:

<asp:ValidationSummary id="Summary1"
HeaderText="Please enter a value in the following
      fields"
     Font-Size="smaller"
     ShowSummary="false"
     ShowMessageBox="true"
     EnableClientScript="true"
     runat="server"/>

The ValidationSummary control collects error messages from all the other validation controls on the page, and displays them together. In this case, a pop-up message box is used. One advantage of this approach is that this type of validation can be carried out client-side by local JavaScript that is generated automatically on the server and incorporated in the HTML that is sent to the browser.

Logical field validation for this page is carried out on the server by APL functions that are attached to CustomValidator controls. For example:

<asp:CustomValidator id="CustomValidator_INT"
     OnServerValidate="VALIDATE_INT"
     ControlToValidate="EINT"
     Display="Dynamic"
     ErrorMessage="Interest Rate must be a number between
                   0 and 20"
     runat="server"/>

These ASP.NET statements associate a CustomValidator control named CustomValidator_INT with the Interest Rate field EINT. The statement OnServerValidate="VALIDATE_INT" specifies that VALIDATE_INT is the validation function for the CustomValidator_INT object.

The VALIDATE_INT function and its .NET Properties page are shown below.

     ∇ VALIDATE_INT MSG;source;args
[1]   ⍝ Validates Interest Rate
[2]    :Access Public
[3]    :Signature VALIDATE_INT Object source,
                  ServerValidateEventArgs args
[4]    source args←MSG
[5]    :Trap 0
[6]        INT←Convert.ToDouble args.Value
[7]    :Else
[8]        args.IsValid←0
[9]        :Return
[10]   :EndTrap
[11]   args.IsValid←(0≤INT)^20≥INT
     ∇

To make the VALIDATE_INT function available to the calling web page, it is exported as a method. Its calling signature, namely that it takes two parameters of type System.Object and System.Web.UI.WebControls.ServerValidateEventArgs respectively, identifies it as a validation function. All these factors are essential in making it recognizable and callable.

VALIDATE_INT[4] assigns its (2-element) argument to source and args respectively. Both are namespace references to .NET objects. source is the object that fired the event (CustomValidator_INT). args is an object that represents the event. Its Value property returns the text in the control being validated, in this case the control named EINT1.

VALIDATE_INT[6] converts the text in the EINT control to a number, using the ToDouble method of the System.Convert class. You could of course use ⎕VFI, but the Convert methods automatically cater for National Language numerical formats. This statement is executed within a :Trap control structure because the method will generate a .NET exception if the data in the field is not a valid number.

VALIDATE_INT[8 11] set the IsValid property of the ServerValidateEventArgs object args to 0 or 1 accordingly. This also sets the IsValid property of the validation control represented by source. The system will automatically display the error message associated with any validation control whose IsValid property is 0. Furthermore, the page itself has an IsValid property, which is the logical-and of all the IsValid properties of all the validation controls on the page. This is used later by the calculation function CALC_FSLTAB_VALUES.

In this case, the validation function stores the numeric value of the control in a variable INT, which will subsequently be used by the calculation functions.

When the page is posted back to the server, ASP.NET executes its own built-in validation controls and then calls the functions associated with the CustomValidator controls, in the order they are defined on the page. In addition to the VALIDATE_INT function, there are eight other custom validation functions. Three of these, which validate the Initial Age, Endowment Term and Initial Duration fields, are listed below. Note that all of the VALIDATE_xxx functions have the same .NET signature as VALIDATE_INT.

     ∇ VALIDATE_AGE MSG;source;args
[1]    ⍝ Validates Age
[2]    :Access Public
[3]    :Signature VALIDATE_AGE Object source,
                  ServerValidateEventArgs args
[4]    source args←MSG
[5]    :Trap 0
[6]        AGE←Convert.ToInt32 args.Value
[7]    :Else
[8]        args.IsValid←0
[9]        :Return
[10]   :EndTrap
[11]   args.IsValid←(10≤AGE)^80≥AGE
     ∇

VALIDATE_AGE is similar to VALIDATE_INT, except that, because it expects an integer value, it uses the ToInt32 method instead of the ToDouble method.

VALIDATE_TERM, which validates the Endowment Term field, is slightly more interesting because there are two levels of checking involved. The first check that the user has entered an integer number, is performed by lines [10-15] in the same way as in the previous examples, using the ToInt32 method of the System.Convert class within a :Trap control structure. However, validation of the Endowment Term field depends upon the value of another field, namely Initial Age.

Not only must the user enter an integer, but also its value must be between 10 and (90-AGE) where AGE is the value in the Initial Age field. However, if the user has entered an incorrect value in the Initial Age field, this, the second level of validation cannot be performed.

     ∇ VALIDATE_TERM MSG;source;args
[1]    ⍝ Validates Endowment Term
[2]    :Access Public
[3]    :Signature VALIDATE_TERM Object source,
                  ServerValidateEventArgs args
[4]    source args←MSG
[5]    :If ^/(RFVAGE CustomValidator_AGE).IsValid
[6]          source.ErrorMessage←'Endowment Term must
             be an integer between 10 and ',(⍕90-AGE),
             ' (90-Age)'
[7]    :Else
[8]        source.ErrorMessage←'Endowment Term must
           be an integer between 10 and (90-Age)'
[9]     :EndIf
[10]    :Trap 0
[11]       TERM←Convert.ToInt32 args.Value
[12]   :Else
[13]       args.IsValid←0
[14]       :Return
[15]   :EndTrap
[16]   :If ^/(RFVAGE CustomValidator_AGE).IsValid
[17]       args.IsValid←(TERM≥10)^TERM≤90-AGE
[18]   :EndIf
     ∇

At this stage it is worth reviewing the sequence of events that occurs when a user action in the browser causes a postback to the server.

  1. The page, including all the contents of its fields, is sent back to the ASP.NET server using an http POST command.
  2. The postback causes the creation of a new instance of the page; which is represented by a new clone of the actuarial namespace.
  3. The creation of a new page instance raises the Page_Load event which in turn invokes the Page_Load method associated with the Page class, or an override method is one is specified. In this case, it calls our Page_Load function in the newly cloned instance of the actuarial namespace. The Page_Load function typically deals with initialisation, such as opening a component file or establishing a connection to a data source. In this case, it does nothing on a postback.
  4. Because the Calculate button was pressed (see Forcing Validation), each of the CustomValidator controls on the page raises an OnServerValidate event, which in turn calls the associated function in the current instance of the page. These events occur in the order the controls are defined within the page. Note that built-in validation controls, including any RequiredFieldValidator controls, are invoked first, potentially in the browser prior to the postback.
  5. Because the Calculate button was pressed (see Forcing Validation), each of the CustomValidator controls on the page raises an OnServerValidate event, which in turn calls the associated function in the current instance of the page. These events occur in the order the controls are defined within the page. Note that built-in validation controls, including any RequiredFieldValidator controls, are invoked first, potentially in the browser prior to the postback.
  6. The control that caused the postback raises an appropriate event, which in turn fires the associated callback function.
  7. After all the control events have been raised and processed the Page_UnLoad event is raised and the associated function (if any) is invoked. This function is a good place to implement termination code, such as closing a component file or data source.
  8. The instance of the page is destroyed. Any global variables in the namespace that were defined by the Page_Load function, the validation functions and the callback function are lost because the clone of the actuarial namespace disappears.

This means that within the life of the cloned instance of the actuarial namespace, the system runs our Page_Load function followed by VALIDATE_INT, followed by VALIDATE_AGE, VALIDATE_TERM, VALIDATE_DUR etc. and finally by CALC_FSLTAB_RESULTS. These functions take their input from the values passed in their arguments (as in the case of the VALIDATE_xxx functions) or from the properties of any of the controls on the Page. They perform output by modifying these properties, or by invoking standard methods on the Page.

Notice that, if successful, the VALIDATE_INT function set up a global variable (strictly speaking, only global within the current instance of the actuarial namespace) called INT that contains the value in the Interest Rate field. Similarly, VALIDATE_AGE defines a variable called AGE. These variables are subsequently available for use by the calculation function.

This technique, of having each validation function define a variable for its associated field, saves repeating the conversion work in the calculation routine CALC_FSLTAB_RESULTS that will be called when the validation is complete. It also saves repeating the conversion work in a validation routine that needs to know the value of a previously validated field.

Returning to the explanation of VALIDATE_TERM, line [16] checks to see that both the RequiredFieldValidator and CustomValidator controls for the Initial Age field register that the value in the field is valid, before attempting to perform the second stage of the validation which depends upon AGE. Note that AGE must exist (and be a reasonable value) if CustomValidator_AGE.IsValid is true. Notice too that it is insufficient just to check the CustomValidator control, because its validation function will not be invoked (and the control will register that the field is valid) if the field is empty.

Line [5] uses similar logic to set up an appropriate error message, which is assigned to the ErrorMessage property of the corresponding CustomValidator control, represented by source.

VALIDATE_DUR, which validates the Initial Duration field, uses similar logic to check that the value in the Endowment Term field is correct and that TERM, on which it depends, is therefore defined. In addition, in line [8] it refers to the Checked property of the RadioButton controls named TA and TB respectively.

    ∇ VALIDATE_DUR MSG;source;args;DT
[1]    ⍝ Validates Initial Duration
[2]    :Access Public
[3]    :Signature VALIDATE_DUR Object source,
                  ServerValidateEventArgs args
[4]    source args←MSG
[5]    :If 2=GET_RUN_OPTION
[6]       DT←1
[7]   :Else
[8]      DT←+/10 1×(TA TB).Checked
[9]   :EndIf
[10]  :If ^/(RFVTRM CustomValidator_TERM).IsValid

[11]     source.ErrorMessage←'Initial Duration must be an
         integer between 0 and ',(⍕TERM-DT),
         ' (TERM-',(⍕DT),')'
[12]  :Else
[13]     source.ErrorMessage←'Initial Duration must be an
            integer between 0 and (Term-',(⍕DT),')'
[14]  :EndIf
[15]  :Trap 0
[16]     DUR←Convert.ToInt32 args.Value
[17]  :Else
[18]     args.IsValid←0
[19]     :Return
[20]  :EndTrap
[21]  :If ^/(RFVTRM CustomValidator_TERM).IsValid
[22]     args.IsValid←(0≤DUR)^DUR≤TERM-DT
[23]  :EndIf
     ∇

Forcing Validation

Validation controls are automatically invoked when the user activates a Button control, but not when other postbacks occur. For example, when the user selects a different Mortality Table (represented by a RadioButtonList control), the page calls the CHANGE_TABLES function.

<asp:RadioButtonList id=MT runat="server"
     RepeatDirection="Vertical" RepeatRows="3"  tabIndex=1
     onSelectedIndexChanged="CHANGE_TABLES"
     AutoPostBack="true">
<asp:ListItem Value="UK Assured Lives">
     Selected="True">UK Assured Lives</asp:ListItem>
<asp:ListItem Value="UK Immediate Annuitant">
     UK Immediate Annuitant</asp:ListItem>
<asp:ListItem Value="UK Pension Annuitant">
     UK Pension Annuitant</asp:ListItem>
</asp:RadioButtonList>

A RadioButtonList control does not cause validation to occur, so this must be done explicitly. This is easily achieved by calling the Validate method of the Page itself as shown in CHANGE_TABLES[11] below.

     ∇ CHANGE_TABLES ARGS;TableNames;TableName;OPTSMORT;
                MORT_OPTION;RUN_OPTION
[1]   :Access public
[2]   :Signature CHANGE_TABLES  Object obj, EventArgs ev
[3]    RUN_OPTION←GET_RUN_OPTION
[4]    MORT_OPTION←1+MT.SelectedIndex
[5]    OPTSMORT←MORT_OPTION⊃OPTSMORT_ASS OPTSMORT_ANNI
                            OPTSMORT_ANNP
[6]    TableNames←⊃OPTSMORT       ⍝ Assured lives/term
                                     assurance tables
[7]    TableNames←↓(2=⎕NC 0 1↓3⊃OPTSMORT)⌿TableNames
[8]    TableNames←TableNames~¨' '
[9]    CMTAB.Items.Clear
[10]   :For TableName :In TableNames
[11]       CMTAB.Items.Add TableName
[12]   :EndFor
[13]   Page.Validate ⍝ Force page validation
[14]   :Select RUN_OPTION
[15]   :Case 1
[16]       CALC_FSLTAB_RESULTS ⍬
[17]   :Case 2
[18]       CALC_FSL_RESULTS ⍬
[19]   :EndSelect
     ∇

Calculating and Displaying Results

The function CALC_FSLTAB_RESULTS, which for brevity is only partially shown below, is used by the sla_tab.aspx page to calculate and display results.

    ∇ CALC_FSLTAB_RESULTS ARGS;X;ULT;MORTOPT;QTAB;TABLE;
         TAB_DURS;RUN_OPTION;MORT_OPTION;UNIX;DOS;
         CURRENTDATE;CURRENTTIME;OPTSMORT;TABLES;MSG;data
[1]    :If IsValid ⍝ Is page valid ?
...
[6]        MORT_OPTION←1+MT.SelectedIndex
[7]        OPTSMORT←MORT_OPTION⊃OPTSMORT_ASS
                                OPTSMORT_ANNI
                                OPTSMORT_ANNP
[8]
[9]        TABLES←↓3⊃OPTSMORT
[10]       MORTOPT←(⍴TABLES)⍴0
[11]       MORTOPT[1+CMTAB.SelectedIndex]←1
[12]       TABLE←⊃MORTOPT/TABLES
...
[15]       TAB_DURS←TA.Checked
...
[41]       FSLT←((⍴X)⍴(3 0)(3 0)(3 0)(11 4)(11 6)(12 4)
                (11 6)(8 0))⍕¨X
[42]       FSLT←FSLT~¨' '
[43]       :With data←⎕NEW DataTable
[44]           cols←Columns.Add¨⊂¨##.FSL_HEADER
[45]           {
[46]               row←NewRow ⍬
[47]               row.ItemArray←⍵
[48]               Rows.Add row
[49]           }¨↓##.FSLT
[50]       :EndWith
[51]       fsl.DataSource←⎕NEW DataView data
[52]       fsl.DataBind
[53]       fsl.Visible←1
[54]   :Else
[55]       fsl.Visible←0
[56]   :EndIf
     ∇

The results of the calculation are displayed in a DataGrid object named fsl. This is defined within the sla_tab.aspx page as follows:

<asp:DataGrid id="fsl" runat="server" Width="700"
     AllowPaging="false" BorderColor="black" CellPadding="3"
     CellSpacing="0" Font-Size="9pt" PageSize="10">
     <ItemStyle HorizontalAlign="right" Width="100">
     </ItemStyle>
     <HeaderStyle HorizontalAlign="center"
     Font-Size="12pt" Font-Bold="true" BackColor="#17748A"
     ForeColor="#FFFFFF"></HeaderStyle>
     </asp:DataGrid>

CALC_FSLTAB_RESULTS[1] checks to see if the user input is valid. If not, [55] hides the DataGrid object fsl so that no results are displayed in the page. The display of error messages is handled separately, and automatically, by the ValidationSummary control on the page.

CALC_FSLTAB[11 15] obtain the values of the CMTAB (DropDownList) and TA (RadioButton) controls on the page.

CALC_FSLTAB[43-53] store the calculated data table FSLT in the DataGrid fsl.


Introduction

The previous chapter showed how you can build ASP.NET Web Pages by combining APL code with the Web Controls provided in the .NET Namespace System.Web.UI.WebControls. These controls are in fact just ordinary .NET classes. In particular, they are extensible components that can be used to develop more complex controls that encapsulate additional functionality.

This chapter describes how you can go about building custom server-side controls, for deployment in ASP.NET Web Pages.

A custom control is simply a .NET class that inherits from the Control class in the .NET Namespace System.Web.UI, or inherits from a higher class that is itself based upon the Control class. Like any other .NET class, a custom control is implemented in an assembly, physically as a DLL file. This chapter explores three different ways to implement a custom control.

The Control class provides a Render method whose job is to generate the HTML that defines appearance of the control. The first example, the SimpleCtl control, overrides the Render method to display a simple string "Hello World" in the browser.

The TemperatureConverterCtl1 control is an example of a compositional control, i.e. one that is composed of other standard controls packaged with special functionality. The TemperatureConverterCtl2 control, uses the basic approach of the SimpleCtl control, but provides the same functionality as TemperatureConverterCtl1. The TemperatureConverterCtl3 control illustrates how to generate events for the hosting page to catch and process.

These examples, which are based upon a series of articles called Advanced ASP.NET Server-Side Controls by George Shepherd that appeared in the msdn magazine (October 2000, January 2001 and March 2001 issues), are implemented as Dyalog classes in a namespace called DyalogSamples in the workspace samples\asp.net\temp\bin\temp.dws. The corresponding .NET Assembly samples\asp.net\temp\bin\temp.dll was generated from this workspace.

      )LOAD "C:\Program Files (x86)\Dyalog\Dyalog APL 15.0 Unicode\Samples\asp.net\temp\bin\temp.dws"
C:\Program Files (x86)\Dyalog\Dyalog APL 15.0 Unicode\Samples\asp.net\temp\bin\temp.dws saved Tue Nov 22 15:04:11 2016
      )obs
DyalogSamples
      )cs DyalogSamples
#.DyalogSamples
      )Classes
SimpleCtl       TemperatureConverterCtl1        TemperatureConverterCtl2        TemperatureConverterCtl3


The SimpleCtl Control

The SimpleCtl Class is illustrated below:

:Class SimpleCtl: Control
:Access public
:Using System
:Using System.Collections.Specialized,System.dll
:Using System.Web,System.Web.dll
:Using System.Web.UI
:Using System.Web.UI.WebControls
:Using System.Web.UI.HtmlControls

    ∇ Render output;HTML
      :Access public override
      :Signature Render  HtmlTextWriter output
      HTML←'<h3>Hello World</h3>'
      output.WriteLine⊂HTML
    ∇

:EndClass ⍝ SimpleCtl

The Render function supercedes (see :Access Statement) the Render method that SimpleCtl has inherited from its base class, System.Web.UI.Control.

The Render method defined by the System.Web.UI.Control base class is void and takes a parameter of type HtmlTextWriter. When the SimpleCtl control is referenced in a Web Page, ASP.NET creates an instance of it and calls its Render method because it is a Control and is expected to have one. Moreover, ASP.NET supplies an object of type HtmlTextWriter as its parameter. You do not need to worry where this object came from, or what it actually represents. You need only know that an HtmlTextWriter provides a method called WriteLine that may be used to output a text string to the browser. The mechanics of how this actually happens are handled by the HtmlTextWriter object itself.

In APL terms, the argument to our Render function, output, will be a namespace reference, and the function can simply call its WriteLine method with a character vector argument. This argument can contain any valid HTML string and defines the appearance of the SimpleCtl control.

Using the :Signature statement, the Render function is defined to have the same syntax as the method it overrides, i.e. it does not return a result void and takes a single parameter of type HtmlTextWriter. Note that to successfully replace the base class method, the Render function must have exactly this :Signature.

Using SimpleCtl

Our SimpleCtl control may now be included in any .NET Web Page from which temp.dll is accessible. The file samples\asp.net\temp\Simple.aspx is simply an example. The fact that this control is written in Dyalog APL is immaterial.

<%@ Register TagPrefix="Dyalog"
             Namespace="DyalogSamples" Assembly="temp" %>

<html>
<body>
<Dyalog:SimpleCtl runat=server/>
</body>
</html>

The first line of the script specifies that any controls referenced later in the script that are prefixed by Dyalog:, refer to custom controls in the .NET Namespace called DyalogSamples which is located in the Assembly temp.dll in the bin subdirectory.


The TemperatureConverterCtl1 Control

The TemperatureConverterCtl1 control is an example of a compositional control, i.e. a server-side custom control that is composed of other standard controls.

In this example, The TemperatureConverterCtl1 control gathers together two textboxes and two push buttons into a single component as illustrated below. Type a number into the Centigrade box, click the Centigrade To Fahrenheit button, and the control converts accordingly. If you click the Fahrenheit To Centigrade button, the reverse conversion is performed.

The TemperatureConverterCtl1 control contains other standard controls as child controls. A control that acts as a container must implement an interface called INamingContainer.

This interface does not in fact require any methods; it merely acts as a marker. So the :Class statement specifies that it provides this interface:

:Class TemperatureConverterCtl1: Control,
                  System.Web.UI.INamingContainer

Child Controls

Whenever ASP.NET initialises a Control, it calls its CreateChildControls method. The default CreateChildControls method does nothing). So we simply define a function called CreateChildControls with the appropriate public interface (no arguments and no result) as shown below.

     ∇ CreateChildControls
[1]    :Access Public override
[2]    :Signature CreateChildControls
[3]
[4]    Controls.Add ⎕NEW LiteralControl,⊂⊂'<h3>Fahrenheit: '
[5]       m_FahrenheitTextBox←⎕NEW TextBox
[6]       m_FahrenheitTextBox.Text←,'0'
[7]       Controls.Add m_FahrenheitTextBox
[8]    Controls.Add ⎕NEW LiteralControl,⊂⊂'</h3>'
[9]
[10]   Controls.Add ⎕NEW LiteralControl,⊂⊂'<h3>Centigrade: '
[11]      m_CentigradeTextBox←⎕NEW TextBox
[12]      m_CentigradeTextBox.Text←,'0'
[13]      Controls.Add m_CentigradeTextBox
[14]   Controls.Add ⎕NEW LiteralControl,⊂⊂'</h3>'
[15]
[16]   F2CButton←⎕NEW Button
[17]   F2CButton.Text←'Fahrenheit To Centigrade'
[18]   F2CButton.onClick←⎕OR'F2CConvertBtn_Click'
[19]   Controls.Add F2CButton
[20]
[21]   C2FButton←⎕NEW Button
[22]   C2FButton.Text←'Centigrade To Fahrenheit'
[23]   C2FButton.onClick←⎕OR'C2FConvertBtn_Click'
[24]   Controls.Add C2FButton
     ∇

Line[4] creates an instance of a LiteralControl (a label) containing the text "Fahrenheit" with an HTML tag "<h3>". Controls is a property of the Control class (from which TemperatureConverterCtl1 inherits) that returns a ControlCollection object This has an Add method whose job is to add the specified control to the list of child controls managed by the object.

Lines[5-6] create a TextBox child control containing the text "0", and Line[7] adds it to the child control list.

Line[8] adds a second LiteralControl to terminate the "<H3>" tag.

Lines [10-14] do the same for Centigrade.

Lines[16-17] create a Button control labelled "Fahrenheit To Centigrade". Line[18] associates the callback function F2CConvertBtn_Click with the button's onClick event. Note that it is necessary to assign the ⎕OR of the function rather than its name. Line[19] adds the button to the list of child controls.

Lines[21-24] create a Centigrade button in the same way.

This function is run every time the page is loaded; however in a postback situation, other code steps in to modify the values in the textboxes, as we shall see.

Fahrenheit and Centigrade Values

The TemperatureConverterCtl1 maintains two public properties named CentigradeValue and FahrenheitValue, which may be accessed by a client application. These properties are not exposed directly as variables, but are obtained and set via property get (or accessor) and property set (or mutator) functions. (This is recommended practice for C#, so the example shows how it is done in APL). In this case, the values are simply stored in or obtained directly from the corresponding textboxes set up by CreateChildControls.

      :Property CentigradeValue
        ∇ C←get
          :Access Public
          :Signature Double←get_CentigradeValue
          C←⍎m_CentigradeTextBox.Text
        ∇

        ∇ set C
          :Access Public
          :Signature set_CentigradeValue Double Value
          m_CentigradeTextBox.Text←⍕C.NewValue
        ∇
    :EndProperty ⍝ CentigradeValue

Notice that the Get function uses ⍎ to convert the text in the textbox to a numeric value. Clearly something more robust would be called for in a real application

Similar functions to handle the Fahrenheit property are provided but are not shown here.

Responding to Button presses

We have seen how APL callback functions have been attached to the onClick events in the two buttons. The C2FconvertBtn_Click callback function simply obtains the CentigradeValue property, converts it to Fahrenheit using C2F, and then sets the FahrenheitValue property.

     ∇ C2FConvertBtn_Click args
      :Access Public
      :Signature C2FConvertBtn_Click Object,EventArgs
      FahrenheitValue←C2F CentigradeValue
     ∇

     ∇ f←C2F c
[1]    f←32+c×1.8
     ∇

     ∇ F2CConvertBtn_Click args
      :Access Public
      :Signature F2CConvertBtn_Click Object ,EventArgs
      CentigradeValue←F2C FahrenheitValue
     ∇

     ∇ c←F2C f
[1]    c←(f-32)÷1.8
     ∇

The F2CconvertBtn_Click callback function converts from Fahrenheit to Centigrade. Note that the functions C2F and F2C areinternal functions that are private to the control, and it is therefore not necessary to define public interfaces for them.

Using the Control on the Page

The text of the script file samples\temp\temp1.aspx is shown below. There is really no difference between this example and the simple.aspx described earlier.

<%@ Register TagPrefix="Dyalog" Namespace="DyalogSamples"
                                Assembly="TEMP"%>
<html>
<body bgcolor="yellow">
<br><br>
<center>
<h3><font face="Verdana" color="black">Temperature Control</font></h3>

<form runat=server>
<Dyalog:TemperatureConverterCtl1 id=TempCvtCtl1 runat=server/>
</form>
</center>
</body>
</html>

The HTML generated by the control at run-time is shown below. Notice that in place of the server-side control declaration in temp1.aspx, there are two edit controls with numerical values in them, and two push buttons to submit data entered on the form to the server.

<html>
<body bgcolor="yellow">
<br><br>
<center>
<h3><font face="Verdana" color="black">Temperature Control</font></h3>

<form name="ctrl1" method="post" action="temp1.aspx" id="ctrl1">
<input type="hidden" name="__VIEWSTATE" value="YTB6MTc3MzAxNzYxNF9fX3g=03f01d88" />

<h3>Fahrenheit: <input name="TempCvtCtl1:ctrl1" type="text" value="32" /></h3><h3>Centigrade: <input name="TempCvtCtl1:ctrl4" type="text" value="0" /></h3><input type="submit" name="TempCvtCtl1:ctrl6" value="Fahrenheit To Centigrade" /><input type="submit" name="TempCvtCtl1:ctrl7" value="Centigrade To Fahrenheit" />
</form>

</center>
</body>
</html>


The TemperatureConverterCtl2 Control

The previous example showed how to compose an ASP.NET custom control from other standard controls. This example shows how you can instead generate standard form elements on the browser by rendering the HTML for them directly.

In the composite temperature control TemperatureConverterCtl1, discussed previously, all the data transfers between the browser and the server, relating to the standard child controls that it contains, are handled automatically by the controls themselves. Rendered controls require a bit more programming because it is up to the control developer to do the data transfer. The data transfer is managed through two interfaces, namely IPostBackDataHandler and IPostBackEventHandler. We will see how these interfaces are used later.

The :Class statement for TemperatureConverterCtl2 specifies that it provides these interfaces.

:Class TemperatureConverterCtl2: Control,
                  System.Web.UI.IPostBackDataHandler,
                  System.Web.UI.IPostBackEventHandler

Fahrenheit and Centigrade Values

Like the previous TemperatureConverterCtl1 control, the TemperatureConverterCtl2 maintains two public properties named CentigradeValue and FahrenheitValue using property get and property set functions.

This time, the control manages the current temperature values in two internal variables named _CentigradeValue and _FahrenheitValue, which we must initialise.

      _CentigradeValue←0
      _FahrenheitValue←0

The CentigradeValue's get function simply returns the current value of _CentigradeValue. Its .NET Properties are defined as shown so that it is exported as a property get function for the CentigradeValue property, and returns a Double.

       ∇ C←get
        :Access Public
        :Signature Double←get
        C←_CentigradeValue
       ∇

The CentigradeValue's set function simply resets the value of _CentigradeValue to that of its argument. Its .NET Properties are defined as shown so that it is exported as a property set function for the CentigradeValue property, and takes a Double.

       ∇ set C
        :Access Public
        :Signature set Double Value
        _CentigradeValue←C.NewValue
       ∇

The property get and property set functions for the FahrenheitValue property are similarly defined. The .signatures for these functions are similar to those for the CentigradeValue functions and are not shown.

Rendering the Control

Like the SimpleCtl example described earlier in this Chapter, the TemperatureConverterCtl2 control has a Render function that generates the HTML to represent its appearance, and in this case its behaviour too.

     ∇ Render output;C;F;BF;CF
[1]    :Access Public override
[2]    :Signature Render HtmlTextWriter output
[3]
[4]    F←'<h3>Fahrenheit <input name='
[5]    F,←UniqueID
[6]    F,←' id=FahrenheitValue type=text value='
[7]    F,←⍕_FahrenheitValue
[8]    F,←'></h3>'
[9]    output.Write⊂F
[10]
[11]   C←'<h3>Centigrade <input name='
[12]   C,←UniqueID
[13]   C,←' id=CentigradeValueKey type=text value='
[14]   C,←⍕_CentigradeValue
[15]   C,←'></h3>'
[16]   output.Write⊂C
[17]
[18]   BF←'<input type=button value=FahrenheitToCentigrade '
[19]   BF,←' onClick="jscript:'
[20]   BF,←Page.GetPostBackEventReference ⎕THIS'FahrenheitToCentigrade'
[21]   BF,←'">'
[22]   output.Write⊂BF
[23]
[24]   CF←'<input type=button value=CentigradeToFahrenheit '
[25]   CF,←' onClick="jscript:'
[26]   CF,←Page.GetPostBackEventReference ⎕THIS'CentigradeToFahrenheit'
[27]   CF,←'">'
[28]   output.Write⊂CF
[29]
[30]   output.WriteLine∘⊂¨'' '<br>' '<br>'
     ∇

As we saw in the SimpleCtl example, the Render method will be called by ASP.NET with a parameter that represents an HtmlTextWriter object. This is represented by the APL local name output.

Lines[4-9] and lines [11-16] generate HTML that defines two text boxes in which the user may enter the Fahrenheit and centigrade values respectively. Lines[9&16] use the Write method of the HtmlTextWriter object to output the HTML.

Lines[5&12] obtain the fully qualified identifier for this particular instance of the TemperatureConverterCtl2 control from its UniqueID property. This is a property, which it inherits from Control and is therefore also a property of the current (APL) namespace.

Lines[18-22] and Lines[24-28] generate and output the HTML to represent the two buttons that convert from Fahrenheit to Centigrade and from Centigrade to Fahrenheit respectively.

Lines[19-20] and [25-26]generate HTML that wires the buttons up to JavaScript handlers to be executed by the browser. The JavaScript simply causes the browser to execute a postback, i.e. send the page contents back to the server. GetPostBackEventReference is a (shared) method provided by the System.Web.UI.Page class that generates a reference to a client-side script function. In this case it is called with two parameters, an object that represents the current instance of the TemperatureConverterCtl2 control, and a string that will be passed to the server to indicate the cause of the postback (i.e. which button was pressed). The first parameter is a reference to the current object, which is returned by the system function ⎕THIS.

The client-side script is itself generated, and inserted into the HTML stream automatically.

To help to understand this process fully, it is instructive to examine the HTML that is generated by these functions. We will do this a bit later in the Chapter.

Loading the Posted Data

Once the server-side control has rendered the HTML for the browser, the user is free to type numbers into the text boxes and to press the buttons.

When the user presses a button, the browser runs the client-side JavaScript code that in turn generates a postback to the server.

The :Class statement for TemperatureConverterCtl2 specifies that it supports the IPostBackDataHandler interface. This interface must be implemented by controls that want to receive postback data (i.e., the contents of Form fields that the user may have entered or changed) IpostBackDataHandler has two methods LoadPostData and RaisePostDataChangedEvent. LoadPostData is automatically invoked when a postback occurs, and the postback data is supplied as a parameter.

So when the postback occurs, the server reloads the original page and, because this is a postback situation and our control has advertised the fact that it implements IPostBackDataHandler, ASP.NET invokes its LoadPostBack method. This method is called with two parameters. The first is a key and the second is a collection of name/value pairs. This contains the names of all the Form fields on the page (and there may be others not directly associated with our custom control) and the values they had when the user pressed the button. The key provides the means to extract the relevant part of this collection. The LoadPostData function is shown below.

     ∇ R←LoadPostData args;postDataKey;values;controlValues;new
[1]    :Signature Boolean←IPostBackDataHandler.LoadPostData String postDataKey,NameValueCollection values
[2]    postDataKey values←args
[3]    controlValues←values[⊂postDataKey]
[4]    new←ParseControlValues controlValues
[5]    R←∨/new=_FahrenheitValue _CentigradeValue
[6]    _FahrenheitValue _CentigradeValue←new
     ∇

Line[2] obtains the two parameters from the argument and Line[3] uses the key to extract the appropriate data from the collection. ControlValues is a comma-delimited string containing name/value pairs. The function ParseControlValues simply extracts the values from this string, i.e. the contents of the Fahrenheit and Centigrade text boxes.

Postback Events

The result of LoadPostData is Boolean and indicates whether or not any of the values in a control have changed. If the result is True (1), ASP.NET will next call the RaisePostDataChanged method. This method is called with no parameters and merely signals that something has changed. The control knows what has changed by comparing the old with the new, as in LoadPostData[5].

Finally, the page framework calls the RaisePostBackEvent method, passing it a string that identifies the page element that caused the post back.

The objective of these calls is to provide the control with the information it requires to synchronise its internal state with its appearance in the browser.

In this case, we are not interested in which of the two text box values the user has altered; what matters is which of the two buttons FarenheitToCentigrade or CentigradeToFarenheit was pressed. Therefore, in this case, the control uses RaisePostBackEvent rather than RaisePostDataChanged (or indeed, LoadPostData itself, which is another option). The reason is that RaisePostBackEvent receives the name of the button as its argument.

So in our case, the RaisePostDataChanged function does nothing. Nevertheless, it is essential that the function is provided and essential that it supports the correct public interface, namely that it takes no arguments are returns no result (Void).

     ∇ RaisePostDataChangedEvent
[1]  :Access public
[2]  :Signature RaisePostDataChangedEvent
[3]  ⍝ Do nothing
     ∇

The RaisePostBackEvent function simply switches on its argument, which is the name of the button that the user pressed, and recalculates _CentigradeValue or _FahrenheitValue accordingly.

     ∇ RaisePostBackEvent eventArgument
[1]    :Access public
[2]    :Signature RaisePostBackEvent  String eventArg
[3]    :Select eventArgument
[4]    :Case 'FahrenheitToCentigrade'
[5]        _CentigradeValue←F2C _FahrenheitValue
[6]    :Case 'CentigradeToFahrenheit'
[7]        _FahrenheitValue←C2F _CentigradeValue
[8]    :EndSelect
     ∇

Finally, the page framework calls the OnPreRender and Render functions again, which generate new HTML for the browser.

Using the Control on a Page

So long as it has access to this DLL, our custom control may be accessed from any ASP.NET Web Page, and a simple example is shown below.

<%@ Register TagPrefix="Dyalog" Namespace="DyalogSamples"
                                Assembly="TEMP" %>

<html>
<body bgcolor="yellow">
<center>
<h3><font face="Verdana" color="black">
Temperature Control</font></h3>
<h4><font face="Verdana" color="black">
Server-Side Noncompositional control</font></h4>

<form runat=server>
<Dyalog:TemperatureConverterCtl2 id=TempCvtCtl2
runat=server/>
</form>

</center>
</body>
</html>

The HTML that is generated by the control is illustrated below. Notice the presence of a JavaScript function named __doPostBack. This is generated by the RegisterPostBackScript method called from the OnPreRender function. The code that wires the buttons to this function was generated by the GetPostBackEventReference method called from the Render function.

<html>
<body bgcolor="yellow">
<center>
<h3><font face="Verdana" color="black">Temperature Control</font></h3>
<h4><font face="Verdana" color="black">Server-Side Noncompositional control</font></h4>

<form name="ctrl1" method="post" action="temp2.aspx" id="ctrl1">
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" value="YTB6MTc3MzAxNzYxM19fX3g=9cfcfa5c" />

<script language="javascript">
<!--
    function __doPostBack(eventTarget, eventArgument) {
        var theform = document.ctrl1
        theform.__EVENTTARGET.value = eventTarget
        theform.__EVENTARGUMENT.value = eventArgument
        theform.submit()
    }
// -->
</script>

<h3>Fahrenheit <input name=TempCvtCtl2 id=FahrenheitValue type=text value=0></h3><h3>Centigrade <input name=TempCvtCtl2 id=CentigradeValueKey type=text value=0></h3><input type=button value=FahrenheitToCentigrade  onClick="jscript:__doPostBack('TempCvtCtl2','FahrenheitToCentigrade')"><input type=button value=CentigradeToFahrenheit  onClick="jscript:__doPostBack('TempCvtCtl2','CentigradeToFahrenheit')">
<br>
<br>

</form>

</center>
</body>
</html>


The TemperatureConverterCtl3 Control

In the previous examples, events generated by control have been internal events, i.e. events that have been detected and processed internally by the control itself.

A separate requirement is to be able to design a custom control that generates external events, i.e. events that can be detected and handled by the page that is hosting the control. This example illustrates how to do this.

The TemperatureConverterCtl3 namespace is a copy of TemperatureConverterCtl2 with a couple of changes.

The first change is that it describes an event that the control is going to generate. This is done using ⎕NQ inside TemperatureConverterCtl3 like this:

   2 ⎕NQ '' 'SetEventInfo' 'Export'
               (('Double' 'Fahrenheit')
                ('Double' 'Centigrade'))

In this case, the name of the event is Export and it will report two parameters named Fahrenheit and Centigrade which are both of data type Double.

This version of the control presents a slightly different appearance to the previous one. The control itself is wrapped up in an HTML Table, with the conversion buttons arranged in a column. These buttons generate internal events that are caught and handled by the control itself. The third row of the table contains an additional button labelled Export which will generate the Export event when pressed. The Render function is shown below.

     ∇ Render output;TableRow;HTML;SET
[1]    :Access public override
[2]    :Signature Render  HtmlTextWriter output
[3]    TableRow←{
[4]        HTML←'<tr><td>',⍺,'</td><td><input name=',UniqueID
[5]        HTML,←' id=',⍺,'Value type=text '
[6]        HTML,←'value=',(⍕⍵),'></td>'
[7]        HTML,←'<td><input type=button value=Convert'
[8]        HTML,←' onClick="jscript:'
[9]        HTML,←(Page.GetPostBackEventReference ⎕THIS ⍺),'"></td></tr>'
[10]       HTML
[11]   }
[12]
[13]   HTML←''
[14]   HTML←'<table>'
[15]   HTML,←'Fahrenheit'TableRow _FahrenheitValue
[16]   HTML,←'Centigrade'TableRow _CentigradeValue
[17]
[18]   SET←'<tr><td><input type=button value=Export '
[19]   SET,←' onClick="jscript:'
[20]   SET,←Page.GetPostBackEventReference ⎕THIS'Export'
[21]   SET,←'"></td></tr>'
[22]   HTML,←SET,'</table>'
[23]   output.Write⊂HTML
     ∇

Notice that Render[18] causes the Export button to generate a Postback event which will call RaisePostBackEvent with the argument 'Export'. Up to now, this is just an internal event just like the events generated by the conversion buttons.

The RaisePostBackEvent propagates this event to the host page.

     ∇ RaisePostBackEvent eventArgument
[1]    :Signature IPostBackEventHandler.RaisePostBackEvent String eventArg
[2]    :Select eventArgument
[3]    :Case 'Fahrenheit'
[4]        _CentigradeValue←F2C _FahrenheitValue
[5]    :Case 'Centigrade'
[6]        _FahrenheitValue←C2F _CentigradeValue
[7]    :Case 'Export'
[8]        4 ⎕NQ'' 'Export'_FahrenheitValue _CentigradeValue
[9]    :EndSelect
     ∇

This is simply done by the third :Case statement, so that when the function is invoked with the argument 'Export', it fires an Export event. This is done by line [8] using 4 ⎕NQ. The elements of the right argument are:

[1] | '' | Specifies that the event is generated by this instance of the control
[2] | 'Export' | The name of the event to be generated
[3] | _FahrenheitValue | The value of the first parameter, Fahrenheit
[4] | _CentigradeValue | The value of the second parameter, Centigrade

It is then up to the page that is hosting the control to respond to the event in whatever way it deems appropriate.

Hosting the Control on a Page

The following example illustrates an ASP.NET web page that hosts the TemperatureConverterCtl3 custom control and responds to its Export event. The page uses a <script> written in APL, but it could just as easily be written in VB.NET.

<%@ Register TagPrefix="Dyalog" Namespace="DyalogSamples"
                                Assembly="TEMP"%>

<script language="Dyalog" runat="server">
     ∇ ExportCB args;sender;e
[1]    sender e←args
[2]    (Flab Clab).Text←⍕¨e.(Fahrenheit Centigrade)
     ∇
</script>

<html>
<body>
<center>
<h3><font face="Verdana">Temperature Control
    </font></h3>
<h4><font face="Verdana">Generating Events
    </font></h4>

<form runat=server>
<Dyalog:TemperatureConverterCtl3 id="TempcvtCtl3"
        onExport="ExportCB"
runat=server/>
</form>

<p>Exported values are:</p>
<table>
<tr><td>Fahrenheit:</td>
    <td><asp:Label id="Flab" Text="" runat="server">
        </asp:Label></td>
</tr>
<tr><td>Centigrade:</td>
    <td><asp:Label id="Clab" Text="" runat="server">
        </asp:Label></td>
</tr>
</table>
</center>
</body>
</html>

In this example, the host page associates a callback function ExportCB with the Export event The ExportCB callback function is defined within the <script></script> section of the page. It simply sets the Text property of two Label controls to display the parameters reported by the event.

The picture below illustrates what happens when you run the page. Notice that the user can independently convert values between the two temperature scales and export these values from the control, to the host page, by pressing the Export button.


Introduction

APLScript is a Dyalog APL scripting language. It was originally designed specifically to program ASP.NET Web Pages and Web Services, but it has been extended to be of more general use outside the Microsoft .NET environment.

APLScript is not workspace oriented (although you can call workspaces from it) but is simply a character file containing function bodies and expressions.

APLScript files may be viewed and edited using any character-based editor which supports Unicode text files, such as Notepad. APLScript files may also be edited using Microsoft Word, although they must be saved as text files without any Word formatting.

APLScript files employ Unicode encoding so you need a Unicode font with APL symbols, such as APL385 Unicode, to view them. In order to type Dyalog APL symbols into an APLScript file, you also need the Dyalog APL Input Method Editor (IME), or other APL compatible keyboard.

If you choose to use the Dyalog APL IME it can be configured from the Dyalog Configuration dialog. You may change the associated .DIN file and various other options. See Unicode Input Tab (Unicode Edition Only).

There are basically three types of APLScript files that may be identified by three different file extensions. APLScript files with the extension .aspx and .asmx specify .NET classes that represent ASP.NET Web Pages and Web Services respectively. APLScript files with the extension .apl may specify .NET classes or may simply represent an APL application in a script format as opposed to a workspace format. Such applications do not necessarily require the Microsoft .NET Framework.


The APLScript Compiler

APLScript files are compiled into executable code by the APLScript compiler whose name is given in the table below.

 | Unicode Edition | Classic Edition
32-Bit | dyalogc_unicode.exe | dyalogc.exe
64-Bit | dyalogc64_unicode.exe | dyalogc64.exe

This program is called automatically by ASP.NET when a client application requests a Web Page (.aspx) or Web Service (.asmx) and in these circumstances always generates the corresponding .NET class. However, the Script Compiler may also be used to:

  • Compile an APLScript into a workspace (.dws) that you may subsequently run using dyalog.exe or dyalogrt.exe in the traditional manner.
  • Compile an APLScript into a .NET class (.dll) which may subsequently be used by any other .NET compatible host language such as C# or Visual Basic.
  • Compile an APLScript into a native Windows executable program (.exe), which may be run as a stand-alone executable. This program may be distributed, along with the Dyalog APL runtime DLL, as a packaged application, and does not require any of the additional support files and registry entries that are typically needed by the Dyalog APL run-time dyalogrt.exe. Note too that the Dyalog APL dynamic link library does not use MAXWS but instead allocates workspace dynamically as required. See the Dyalog for Microsoft Windows Installation and Configuration Guide: Run-Time Applications and Components for further details.
  • Compile a Dyalog APL Workspace (.dws) into a native Windows executable program, with the same characteristics and advantages described above.

The Script is designed to be run from a command prompt. If in the 32-bit Classic Edition you type dyalogc /? (to query its usage) the following output is displayed:

Dyalog APLScript compiler 32 bit. Classic Mode. Version 13.1.12350.0
Copyright Dyalog Ltd 2012

dyalogc.exe command line options:

/?                Usage
/r:file           Add reference to assembly
/o[ut]:file       Output file name
/x:file           Read source files from Visual Studio.NET project file
/res:file         Add resource to output file
/icon:file        File containing main program icon
/q                Operate quietly
/v                Verbose
/s                Treat warnings as errors
/nonet            Creates a binary that does not use Microsoft .NET
/runtime          Build a non-debuggable binary
/lx:expression    Specify entry point (Latent Expression)
/t:library        Build .NET library (.dll)
/t:nativeexe      Build native executable (.exe). Default
/t:workspace      Build dyalog workspace (.dws)
/nomessages       Process does not use windows messages. Use when creating
                  a process to run under IIS
/console          Creates a console application
/c                Creates a console application
/unicode          Creates an application that runs in a Unicode intepreter
/wx:[0|1|3]       Sets ⎕WX for default code


Creating an APLScript File

Conceptually, the simplest way to create an APLScript file is with Notepad, although you may use many other tools including Microsoft Visual Studio as described in the next Chapter.

  1. Start Notepad
  2. Choose Format/Font from the Menu Bar and select an appropriate Unicode font that contains APL symbols, such as APL 385 Unicode or Arial Unicode MS.
  3. Select an APL keyboard by clicking on your keyboard selector in the System Tray. Note that this keyboard setting (and button) is associated only with the current instance of Notepad. If you start another instance of Notepad, or another editor, you will have to select the APL keyboard for it separately and there will be two floating toolbars on your display.
  4. Now type in your APL code. If you use a Ctrl keyboard, you will discover that Ctrl+ keystrokes generate APL symbols For example, Ctrl+n generates ⊤.
  5. Choose File/Save. When the Save As dialog appears, ensure that Encoding is set to Unicode and Save as type: is set to All Files. Enter the name of the file, adding the extension .asmx or .aspx, and then click Save. Note that you have to save the .asmx file somewhere in an IIS Virtual Directory structure.


Transferring code from the Dyalog APL Session

Copying code from the Dyalog Session

You may find it easier to write APL code using the Dyalog APL function or class editor that is provided by the Dyalog APL Session. Or you may already have code in a workspace that you want to copy into an APLScript file.

If so, you can transfer code from the Session into your APLScript editor (e.g. Notepad) using the clipboard. Notice that because APLScript requires Unicode encoding (for APL symbols), you must ensure that character data is written to the clipboard in Unicode.

In the Unicode interpreter this is always done. In the Classic interpreter this is controlled by a parameter called UnicodeToClipboard that specifies whether or not data is transferred to and from the Windows clipboard as Unicode. This parameter may be changed using the Trace/Edit page of the Configure dialog box.

If set (the default), APL text pasted to the clipboard from the Session is written as Unicode and APL requests Unicode data back from the clipboard when it is required. This makes it easy to transfer APL code between the Session and an APLScript editor, which is using the Arial Unicode MS font.

In the Classic interpreter when pasting code into the Dyalog editor, there are two menu items under the Edit menu, which allow you to explicitly select whether the Unicode mapping should be used, or the old mapping which corresponds to the Dyalog Std TT or Dyalog Alt TT fonts. You should use "Paste non-Unicode" when transferring text from the on line help, or text copied from earlier versions of Dyalog APL without the Unicode option.

Unless you explicitly want to have line numbers in your APLScript, the simplest way to paste APL code from the Session into an APLScript text editor is as follows:

  1. open the function in the function editor
  2. select all the lines of code, or just the lines you want to copy
  3. select Edit/Copy or press Ctrl+Ins
  4. switch to your APLScript editor and select Edit/Paste or press Shift+Ins.
  5. insert Del (∇) symbols at the beginning and end of the function.

If you want to preserve line numbers (this is allowed, but not recommended in APLScript files), you may use the following technique:

  1. in the Session window, type a del (∇) symbol followed by the name of the function, followed by another del (∇) and then press Enter. This causes the function to be displayed, with line numbers, in the Session window.
  2. select the function lines, including the surrounding Dels (∇) and choose Edit/Copy or press Ctrl+Insert.
  3. switch to your APLScript editor and select Edit/Paste or press Shift+Ins.


General principles of APLScript

The layout of an APLScript file differs according to whether the script defines a Web Page, a Web Service, a .NET class, or an APL application that may have nothing to do with the .NET Framework. However, within the APLScript, the code layout rules are basically the same.

An APLScript file contains a sequence of function bodies and executable statements that assign values to variables. In addition, the file typically contains statements that are directives to the APLScript compiler. If the script is a Web Page or Web Service, it may also contain directives to ASP.NET. The former all start with a colon symbol (:) in the manner of control structures. For example, the :Namespace statement tells the APLScript compiler to create, and change into, a new namespace. The :EndNamespace statement terminates the definition of the contents of a namespace and changes back from whence it came.

Assignment statements are used to set up system variables, such as ⎕ML, ⎕IO, ⎕USING and arbitrary APL variables. For example:

      ⎕ML←2
      ⎕IO←0
      ⎕USING∪←⊂'System.Data'

      A←88
      B←'Hello World'

      ⎕CY'MYWS'

These statements are extracted from the APLScript and executed by the compiler in the order that they appear. It is important to recognise that they are executed at compile time, and not at run-time, and may therefore only be used for initialisation.

Notice that it is acceptable to execute ⎕CY to bring in functions and variables from a workspace that are to be incorporated into the code. This is especially useful to import a set of utilities. Note also that it is possible to export these functions as methods of .NET classes if the functions contain the appropriate colon statements.

The APLScript compiler will in fact execute any valid APL expression that you include. However, the results may not be useful and may indeed simply terminate the compiler. For example, it is not sensible to execute statements such as ⎕LOAD, or ⎕OFF.

Function bodies are defined between opening and closing del (∇) symbols. These are fixed by the APLScript compiler using ⎕FX. Line numbers and white space formatting are ignored.


Creating Programs with APLScript

Creating Programs (.exe) with APLScript

The following examples, which illustrate how you can create an executable program (.exe) direct from an APLScript file, may be found in the directory samples\aplscript.

A simple GUI example

The following APLScript illustrates the simplest possible GUI application that displays a message box containing the string "Hello World".

:Namespace N
⎕LX←'N.RUN'
∇RUN;M
'M'⎕WC'MsgBox' 'A GUI exe' 'Hello World'
⎕DQ'M'
∇
:EndNamespace

This example, which is saved in the file eg1.apl, is compiled to a Windows executable (.exe) using dyalogc.exe and run from the same command window as shown below. Notice that it is essential to surround the code with :Namespace / :EndNamespace statements and to define a ⎕LX either in the APLScript itself, or as a parameter to the dyalogc command.

You can associate the .exe with a desktop icon, and it will run stand-alone, without a Command Prompt window. Furthermore, any default APL output that would normally be displayed in the session window will simply be ignored.

A simple console example

The following APLScript illustrates the simplest possible application that displays the text "Hello World".

This example, which is saved in the file eg2.apl, is compiled to a Windows executable (.exe) and run from a command window as shown below. Notice that the /console flag is used to tell the APLScript compiler to create a console application that runs from a command prompt. In this case, default APL output that would normally be displayed in the session window turns up in the command window from which the program was run.

:Namespace N
⎕LX←'N.RUN'
∇RUN
'Hello World'
∇
:EndNamespace

Once more, it is essential to surround the code with :Namespace/:EndNamespace statements and to define a ⎕LX either in the APLScript itself, or as a parameter to the dyalogc command.

Defining Namespaces

Namespaces are specified in an APLScript using the :Namespace and :EndNamespace statements. Although you may use ⎕NS and ⎕CS within functions inside an APLScript, you should not use these system functions outside function bodies. Note that such use is not prevented, but that the results will be unpredictable.

:Namespace Name

introduces a new namespace called Name relative to the current space.

:EndNamespace

terminates the definition of the current namespace. Subsequent statements and function bodies are processed in the context of the original space.

It is imperative that at least ONE namespace be specified.

All functions specified between the :Namespace and :EndNamespace statements are fixed in that namespace. Similarly, all assignments define variables inside that namespace.

The following example illustrates how APL namespace usage is handled in APLScript. The program, contained in the file eg3.apl, is as follows:

:Namespace N
⎕LX←'N.RUN'

∇RUN
⎕PATH←'↑'
NS.START
END
∇
∇R←CURSPACE
R←⊃⎕NSI
∇
∇END
'Ending in ',CURSPACE
∇

:NameSpace NS
∇START
'Starting in ',CURSPACE
∇
:EndNameSpace
:EndNameSpace

This somewhat contrived example illustrates how a namespace is defined inside another namespace using :NameSpace and :EndNamespace statements. The namespace NS contains a single function called START, which is called from the main function RUN.

Notice that ⎕PATH is defined dynamically in function RUN. If it were defined outside a function in a static statement in the script (say, after the statement that sets ⎕LX), it would not be honoured when the application was run.

This program is shown, compiled and run as a console application, below.


Creating .NET Classes with APLScript

It is possible to define and use new .NET classes within an APLScript.

A class is defined by :Class and :EndClass statements. The methods provided by the class are defined as function bodies enclosed within these statements. Please see the Language Reference for a complete discussion of writing classes in Dyalog APL. This chapter will only provide a brief introduction to the subject, aimed specifically at APLScript.

You may also define sub-classes or nested classes using nested :Class and :EndClass statements.

:Class Name: Type

Declares a new class called Name, which is based upon the Base Class Type, which may be any valid .NET Class.

:EndClass

Terminates a class definition block

A class specified in this way will automatically support the methods, properties and events that it inherits from its Base Class, together with any new public methods that you care to specify.

However, the new class only inherits a default constructor (which is called with no parameters) and does not inherit all of the other private constructors from its Base Class. You can define a method to be a constructor using the :Implements Constructor declarative comment. Constructor overloading is supported and you may define any number of different constructor functions in this way, but they must have unique parameter sets for the system to distinguish between them.

You can create and use instances of a class by using the ⎕NEW system function in statements elsewhere in the APLScript.

Exporting Functions as Methods

Within a :Class definition block, you may define private functions and public functions. A public function is one that is exposed as a method and may be called by a client that creates an instance of your class. Public functions must have a section of declaration statements. Other functions are purely internal to the class and are not directly accessible by a client application.

The declaration statements for public functions perform the same task for an APLScript that is performed using the .NET Properties dialog box, or by executing SetMethodInfo in the Dyalog APL Session, prior to creating a .NET assembly. The following declaration statements may be used.

:Access Public

Specifies that the function is callable. This statement applies only to a .NET class or to a Web Page and is not applicable to a Web Service.

:Access WebMethod

Specifies that the function is callable as a Web Method. This statement applies only to a Web Service (.asmx). From version 11.0, the statement is equivalent to:

:Access Public
:Attribute System.Web.Services.WebMethodAttribute

:Implements Constructor

Specifies that the function is a constructor for a new .NET class. This function must appear between :Class and :EndClass statements and this applies only to a Web Page (.aspx). See Defining Classes in APLScript for further details. A constructor is called when you execute the New method in the class.

:Signature result←fn type1 Name1, type2 Name2,..

Declares the result of the method to have a given data type, if any. It also declares parameters to the method to have given data types and names. Namex is optional and may be any well-formed name that identifies the parameter. This name will appear in the metadata and is made available to a client application as information. It is therefore sensible to choose meaningful names. The names you allocate to parameters have no other meaning and are not associated with the names of local variables that you may choose to receive them. However, it is not a bad idea to use the same local names as the public names of your parameters.

A .NET Class example

The following APLScript illustrates how you may create a .NET Class using APLScript. The example class is the same as Example 1 in Chapter 5. The APLScript code, saved in the file samples\aplclasses\aplclasses6.apl, is as follows:

:Namespace APLClasses

:Class Primitives: Object
⎕USING←,⊂'System'
:Access public

∇ R←IndexGen N
:Access Public
:Signature Int32[]←IndexGen Int32 number
R←⍳N
∇
:EndClass

:EndNamespace

This APLScript code defines a namespace called APLClasses. This simply acts as a container and is there to establish a .NET namespace of the same name within the resulting .NET assembly. Within APLClasses is defined a .NET class called Primitives whose base class is System.Object. This class has a single public method named IndexGen, which takes a parameter called number whose data type is Int32, and returns an array of Int32 as its result.

The following command shows how aplclasses6.apl is compiled to a .NET Assembly using the /t:library flag.

APLClasses>dyalogc /t:library aplclasses6.apl
Dyalog APLScript compiler 32bit Classic Mode Version 13.0.8690.0
Copyright Dyalog Limited 2011
APLClasses>

The next picture shows a view of the resulting aplclasses6.dll using ILDASM.

This .NET Class can be called from APL just like any other. For example:

      )CLEAR
clear ws

       ⎕USING←'APLClasses,Samples\APLClasses\
                                  aplclasses6.dll'
      APL←⎕NEW Primitives
      APL.IndexGen 10
1 2 3 4 5 6 7 8 9 10

Defining Properties

Properties are defined by :Property and :EndProperty statements. A property pertains to the class in which it is defined.

:Property Name
     ∇ C←get
[1]   :Access public
[2]   :Signature Double←get
[3]    C←...
     ∇

Declares a new property called Name whose data type is System.Double. The latter may be any valid .NET type which can be located through ⎕USING.

:EndProperty

Terminates a property definition block

Within a :Property block, you must define the accessors of the property. The accessors specify the code that is associated with referencing and assigning the value of the property. No other function definitions or statements are allowed inside a :Property block.

The accessor used to reference the value of the property is represented by a function named get that is defined within the :Property block. The accessor used to assign a value to the property is represented by a function named set that is defined within the :Property block.

The get function is used to retrieve the value of the property and must be a niladic result returning function. The data type of its result determines the Type of the property. The set function is used to change the value of the property and must be a monadic function with no result. The argument to the function will have a data type Type specified by the :Signature statement. A property that contains a get function but no set function is effectively a read-only property.

The following APLScript, saved in the file samples\aplclasses\aplclasses7.apl, shows how a property called IndexOrigin can be added to the previous example. Within the :Property block there are two functions defined called get and set which are used to reference and assign a new value respectively. These functions have the fixed names and syntax specified for property get and property set functions as described above.

:Namespace APLClasses

:Class Primitives: Object
⎕USING←,⊂'System'
:Access public

∇ R←IndexGen N
:Access Public
:Signature Int32[]←IndexGen Int32 number
R←⍳N
∇

:Property IndexOrigin
∇io←get
      :Signature Int32←get Int32 number
io←⎕IO
∇

∇set io
      :Signature set Int32 number
:If io∊0 1
    ⎕IO←io
:EndIf
∇
:EndProperty

:EndClass

:EndNamespace

The ILDASM view of the new aplclasses7.dll, with the addition of an IndexOrigin property, is illustrated below.

For other examples of the use of property definitions, see The Component File Solution in Chapter 11.

This .NET Class can be called from APL just like any other. For example:

      )CLEAR
clear ws

      ⎕USING←'APLClasses,Samples\APLClasses\
                                 APLClasses7.DLL'
      APL←⎕NEW Primitives
      APL.IndexGen 10
1 2 3 4 5 6 7 8 9 10
      APL.IndexOrigin
1
      APL.IndexOrigin←0
      APL.IndexGen 10
0 1 2 3 4 5 6 7 8 9

Indexers

An indexer is a property of a class that enables an instance of that class (an object) to be indexed in the same way as an array, if the host language supports this feature. Languages that support object indexing include C# and Visual Basic. Dyalog APL does also allow indexing to be used on objects. This means that you can define an APL class that exports an indexer and you can use the indexer from C#, Visual Basic or Dyalog APL.

Indexers are defined in the same way as properties, between :Property Default and :EndProperty statements. There may be only one indexer defined for a class.

Note: the :Property Default statement in Dyalog APL is closely modelled on the indexer feature in C# and employs similar syntax. If you use ILDASM to browse a .NET class containing an indexer, you will see the indexer as the default property of that class, which is how it is actually implemented.


Creating ASP.NET Classes with APLScript

As mentioned previously, the original purpose of APLScript was to provide the ability to write ASP.NET Web Pages and Web Services in Dyalog APL. Both these applications are based upon script files.

Web Page Layout

An ASP.NET Web Page typically consists of a mixture of HTML and code written in a scripting language. The script code is separated from the HTML by being embedded within <script> and </script> tags and normally appears in the <head> </head> section of the page. Only one block of script is allowed in a page. The script block normally consists of a collection of functions, which are invoked by some event on the page, or on an element of the page.

APLScript code starts with a statement:

<script language="Dyalog" runat=server>

and finishes with:

</script>

Typically, the APLScript code consists of callback functions that are attached to server-side events on the page.

For further information, see The web.config file.

Web Service Layout

The first line in a Web Service script must be a declaration statement such as:

<%@ WebService Language="Dyalog" Class="ServiceName" %>

where ServiceName is an arbitrary name that identifies your Web Service.

The next statement must be a :Class statement that declares the name of the Web Service and its Base Class from which it inherits. The base class will normally be System.Web.Services.WebService. For example:

:Class ServiceName: System.Web.Services.WebService

The last line in the script must be:

:EndClass

Although it may appear awkward to have to specify the name of your Web Service twice, this is necessary because the two statements are being processed quite separately by different software components. The first statement is processed by ASP.NET. When it sees Language="Dyalog", it then calls the Dyalog APLScript compiler, passing it the remainder of the script file. The :Class statement tells the APLScript compiler the name of the Web Service and its base class. :Class and :EndClass statements are private directives to the APLScript compiler and are not relevant to ASP.NET.

How APLScript is processed by ASP.NET

Like any other Web Page or Web Service, an APLScript file is processed by ASP.NET.

The first time ASP.NET processes a script file, it first performs a compilation process whose output is a .NET assembly. ASP.NET then calls the code in this assembly to generate the HTML (for a Web Page) or to run a method (for a Web Service).

ASP.NET associates the compiled assembly with the script file, and only recompiles it if/when it has changed.

ASP.NET does not itself compile a script; it delegates this task to a specialised compiler that is associated with the language declared in the script. This association is made either in the application's web.config file or in the global machine.config file. Dyalog Installs a default web.config file which includes these settings in the samples\asp.net folder.

The APLScript compiler is itself written in Dyalog APL.

Although the compilation process takes some time, it is typically only performed once, so the performance of an APLScript Web Service or Web Page is not compromised. Once it has been compiled, ASP.NET redirects all subsequent requests for an APLScript to its compiled assembly.

Please note that the use of the word compile in this process does not imply that your APL code is actually compiled into Microsoft Intermediate Language (MSIL). Although the process does in fact generate some MSIL, your APL code will still be interpreted by the Dyalog APL DLL engine at run-time. The word compile is used only to be consistent with the messages displayed by ASP.NET when it first processes the script.


Introduction

The Dyalog DLL is the Dyalog APL engine that hosts the execution of all .NET classes that have been written in Dyalog APL, including APL Web Pages and APL Web Services. The Dyalog DLL provides the interface between client applications (such as ASP.NET) and your APL code. It receives calls from client applications, and executes the appropriate APL code. It also works the other way, providing the interface between your APL code and any .NET classes that you may call.

The Development DLL (the full developer version of the Dyalog DLL) contains the APL Session, Editor, Tracer and so forth, and may be used to develop and debug an APL .NET class while it is executing. Note that to gain access to the various workspace tools, such as the Workspace Explorer and the Search/Replace Dialog, the corresponding DyaRes DLL must be present alongside (in the same directory as) the Development DLL.

The Run-Time DLL (the re-distributable run-time version of the Dyalog DLL) contains no debugging facilities.

For the names of these files corresponding to the version of Dyalog that you are using, see Files.


Isolation Mode

For each application which uses a class written in Dyalog APL, at least one copy of the development or run-time version of the Dyalog DLL will be started in order to host and execute the appropriate APL code. Each of these engines will have an APL workspace associated with it, and this workspace will contain classes and instances of these classes. The number of engines (and associated workspaces) which are started will depend on the Isolation Mode which was selected when the APL assemblies used by the application were generated. Isolation modes are:

  • Each host process has a single workspace
  • Each appdomain has its own workspace
  • Each assembly has its own workspace

Note that, in this context, Microsoft Internet Information Services (IIS) is a single application, even though it may be hosting a large number of different web pages. Each ASP.NET application will be running in a separate AppDomain, a mechanism used by .NET to provide isolation within an application. Other .NET applications may also be divided into different AppDomains.

In other words, if you use the first option, ALL classes and instances used by any IIS web page will be hosted in the same workspace and share a single copy of the interpreter. The second option will start a new Dyalog engine for each ASP.NET application; the final option an engine for each assembly containing APL classes.


Workspace Size

By default, there is no limit placed upon the size of the workspace used by the Dyalog DLL and it will grow (and shrink) according to user demand.

The maximum workspace size may be specified by the maxws parameter that is used to control the workspace size in the development and run-time versions of the Dyalog program. The difference is that the maxws parameter must be specified for the host application, the application in which the Dyalog DLL is embedded.

This is achieved by defining a Registry key named:

HKLM\Software\Dyalog\Embedded\<appname>

or on 64-bit Windows:

HKLM\Software\Wow6432Node\Dyalog\Embedded\<appname>

where <appname> is the name of the application, containing a String Value named maxws set to the desired size.

The name of the ASP.NET application is aspnet_wp.exe or w3wp.exe ((IIS 6 and above).

An additional way is to set the maxws parameter on the command line of the Assembly at export time. That might be be useful if you know that you are only using one Dyalog assembly or the IsolationMode is "Each Assembly". For more information, see Isolation Mode.


Structure of the Active Workspace

Each engine which is started has a workspace associated with it that contains all the APL objects it is currently hosting.

Unless the highest isolation mode, Each assembly has its own workspace has been selected, the workspace will contain one or more namespaces associated with .NET AppDomains. When .NET calls Dyalog APL to process an APL class, it specifies the AppDomain in which it is to be executed. To maintain AppDomain isolation and scope, Dyalog APL associates each different AppDomain with a namespace whose name is that of the AppDomain, prefixed by AppDomain_.

Within each AppDomain_ namespace, there will be one or more namespaces associated with the different Assemblies from which the APL classes have been loaded. These namespaces are named by the Assembly name prefixed by Assembly_. If the APL class is a Web Page or a Web Service, the corresponding Assembly is created dynamically when the page is first loaded. In this case, the name of the Assembly itself is manufactured by .NET. Below the Assembly_ namespace is a namespace that corresponds to the .NET Namespace that represents the container of your class. If the APL class is a Web Page or Web Service, this namespace is called ASP. Finally, the namespace tree ends with a namespace that represents the APL class. This will have the same name as the class. In the case of a Web Page or Web Service, this is the name of the .aspx or .asmx file.

Note that in the manufactured namespace names, characters that would be invalid symbols in a namespace name are replaced by underscores.

The following picture shows the namespace tree that exists in the Dyalog DLL workspace when the first example (see Example 1) in the chapter Writing .Net Classes is executed under Visual Studio. However, to cause the suspension, an error has been introduced in the method IndexGen.

In this case, there is a single AppDomain involved whose name, DyApp_vshost_exe is specified by .NET. APL has made a corresponding namespace called AppDomain_DyApp_vshost_exe. Next, there is a namespace associated with the Assembly aplclasses, named Assembly_aplclasses. Beneath this is a namespace called APLClasses associated with the .NET Namespace of the same name. Finally, there is the APL Class called Primitives .

Notice that the state indicator displays the entire .NET calling structure, and not just the APL stack. In this case, the state indicator shows that IndexGen was called from MainClass.Main, which combines the class and method names specified in aplfns.cs. Note that .NET calls are slightly indented.

Notice too that IndexGen has been started on APL thread 1 which, in this case, is associated with system thread 8752. If the client application were to call IndexGen on multiple system threads, this would be reflected by multiple APL threads in the workspace. This topic is discussed in further detail below.

The possibility for the client to execute code in several instances of an object at the same time requires that each executing instance is separated from all the others. Each instance will be created as an unnamed object in the workspace, within the relevant appdomain and assembly namespaces.

The picture below shows the workspace structure when the assembly was generated with isolation mode set to Each assembly has its own workspace. In this case, the AppDomain and Assembly structure is not created above the classes in the workspace, so the workspace structure is somewhat simpler:


Threading

The .NET Framework is inherently a multi-threaded environment. For example, ASP.NET runs its own thread pool from which it allocates system threads to its clients. Calls from ASP.NET into APL Web Pages and Web Services will typically be made from different system threads. This means that APL will receive calls from .NET while it is processing a previous call. The situation is further complicated when you write an APL Web Page that calls an APL Web Service, both of which may be hosted by a single Dyalog DLL inside ASP.NET. In these circumstances, ASP.NET may well allocate different system threads to the .NET calls, which are made into the two separate APL objects. Although in the first example (multiple clients) APL could theoretically impose its own queuing mechanism for incoming calls, it cannot do so in the second case without causing a deadlock situation.

It is important to remember that whether running as DYALOG.EXE, or as the Dyalog DLL, the Dyalog APL interpreter executes in a single system thread. However, APL does provide the ability to run several APL threads at the same time. If you are unfamiliar with APL threads, see Language Reference, Chapter 1 for an introduction to this topic.

To resolve this situation, Dyalog APL automatically allocates APL threads to .NET system threads and maintains a thread synchronisation table so that calls on the same system thread are routed to the same APL thread, and vice versa. This is important because a GUI object (cf. System.Winforms) is owned by the system thread that created it and can only be accessed by that thread.

The way that system threads are allocated to APL threads differs between the case where APL is running as the primary executable (DYALOG.EXE) or as a DLL hosted by another program. The latter is actually the simpler of the two and will be considered first.

DYALOG DLL Threading

In this case, all calls into the Dyalog DLL are initiated by Microsoft .NET.

When a .NET system thread first needs to run an APL function, APL starts a new APL thread for it, and executes the function in that APL thread. For example, if the first call is a request to create a new instance of an APL .NET object, its constructor function will be run in APL thread 1. An entry is made in the internal thread table that associates the originating system thread with APL thread 1. When the constructor function terminates, the APL thread is retained so that it is available for a subsequent call on its associated system thread. In this respect, the automatically created APL thread differs from an APL thread that was created using the spawn operator & (See Language Reference).

When a subsequent call comes in, APL locates the originating system thread in its internal thread table, and runs the appropriate APL function in the corresponding APL thread. Once again, when the function terminates, the APL thread is retained for future use. If a call comes in on a new system thread, a new APL thread is created.

Notice that under normal circumstances, APL thread 0 is never used in the Dyalog DLL. It is only ever used if, during debugging, the APL programmer explicitly changes to thread 0 by executing )TID 0 and then runs an expression.

Periodically, APL checks the existence of all of the system threads in the internal thread table, and removes those entries that are no longer running. This prevents the situation arising that all APL threads are in use.

DYALOG.EXE Threading

In these cases, all calls to Microsoft .NET are initiated by Dyalog APL. However, these calls may well result in calls being made back from .NET into APL.

When you make a .NET call from APL thread 0, the .NET call is run on the same system thread that is running APL itself.

When you make a .NET call from any other APL thread, the .NET call is run on a different system thread. Once again, the correspondence between the APL thread number and the associated system thread is maintained (for the duration of the APL thread) so that there are no thread/GUI ownership problems. Furthermore, APL callbacks invoked by .NET calls back into APL will automatically be routed to the appropriate APL thread. Notice that, unlike a call to a DLL via ⎕NA, there is no way to control whether or not the system uses a different system thread for a .NET call. It will always do so if called from an APL thread other than APL thread 0.

Thread Switching

Dyalog APL will potentially thread switch, i.e. switch execution from one APL thread to another, at the start of any line of APL code. In addition, Dyalog APL will potentially thread switch when a .NET method is called or when a .NET property is referenced or assigned a value. If the .NET call accesses a relatively slow device, such as a disk or the internet, this feature can improve overall throughput by allowing other APL code while a .NET call is waiting. On a multi-processor computer, APL may truly execute in parallel with the .NET code.

Note that when running DYALOG.EXE, .NET calls made from APL thread 0 will prevent any switching between APL threads. This is because the .NET code is being executed in the same system thread as APL itself. If you want to use APL multi-threading in conjunction with .NET calls, it is therefore advisable to perform all of the .NET calls from threads other than APL thread 0.


Debugging an APL.NET Class

All DYALOG.NET objects are executed by the Dyalog DLL. The full development version of the Dyalog DLL contains all of the development and debug facilities of the APL Session, including the Editors and Tracer. The run-time version contains no debugging facilities at all. The choice of which version of the Dyalog DLL is used is made when the assembly is exported from APL using the File|Export menu, or compiled using dyalogc.exe.

If an APL .NET object that is bound to the full development version generates an untrapped APL error (such as a VALUE ERROR) and the client application is configured so that it is allowed to interact with the desktop, the APL code will suspend and the APL Session window will be displayed. Otherwise, it will throw an exception.

If an APL .NET object that is bound to the run-time version of the Dyalog DLL generates an untrapped APL error it will throw an exception.

Specifying the DLL

There are a number of different ways that you choose to which of the two versions of the Dyalog DLL your DYALOG.NET class will be bound. Note that the appropriate DLL must be available when the class is subsequently invoked. If the DLL to which the APL .NET class is bound is not present, it will throw an exception.

If you build a .NET class from a workspace using the File/Export menu item, you use the Runtime application checkbox. If Runtime application is unchecked, the .NET Class will be bound to the full development version. If Runtime application is checked, the .NET Class will be bound to the run-time version.

If you build a .NET class using the APLScript compiler, it will by default be bound to the full development version. If you specify the /runtime flag, it will be bound to the run-time version.

If your APL .NET class is a Web Page or a Web Service, you specify to which of the two DLLs it will be bound using the Debug attribute. This is specified in the opening declaration statement in the .aspx, .asax or .asmx file. If the statement specifies "Debug=true", the Web Page or Web Service will be bound to the full development version. If it specifies "Debug=false", the Web Page or Web Service will be bound to the run-time version.

If you omit the Debug= attribute in your Web page, the value will be determined from the various .NET config files on your computer.

Forcing a suspension

If an APL error occurs in an APL .NET object, a suspension will occur and the Session will be available for debugging. But what if you want to force this to happen so that you can Trace your code and see what is happening?

If your APL class is built directly from a workspace, you can force a suspension by setting stops in your code before using Export to build the DLL. If your class is a Web Page or Web Service where the code is contained in a workspace using the workspace behind technique (See Chapter 8), you can set stops in this workspace before you )SAVE it.

If your APL class is defined entirely in a Web Page, Web Service, or an APLScript file, the only way to set a break point is to insert a line that sets a stop explicitly using ⎕STOP. It is essential that this line appears after the definition of the function in the script. For example, to set a stop in the Intro\intro1.aspx example discussed in Chapter 8, the script section could be as follows:

<script language="dyalog" runat="server">

∇Rotate args
:Access Public
:Signature Reverse Object,EventArgs

(⊃args).Text←⌽Pressme.Text
∇

3 ⎕STOP 'Rotate'

</script>

As an alternative, you can always insert a deliberate error into your code!

Finally, you can usually force a suspension by generating a Weak Interrupt. This is done from the pop-up menu on the APL icon in the System Tray that is associated with the full development version of the Dyalog DLL. Note that selecting Weak Interrupt from this menu will not have an immediate effect, but it sets a flag that will cause Dyalog APL to suspend when it next executes a line of APL code. You will need to activate your object in some way, e.g. by calling a method, for this to occur. Note that this technique may not work if the Dyalog DLL is busy because a thread switch automatically resets the Weak Interrupt flag. In these circumstances, try again.

The run-time version of the Dyalog DLL does not display an icon in the System Tray.

Using the Session, Editor and Tracer

When an DYALOG.NET object suspends execution, all other active APL .NET objects bound to the full development version of the Dyalog DLL that are currently being executed by the same client application will also suspend. Furthermore, all the classes currently being hosted by the Dyalog DLL are visible to the APL developer whether active (an instance is currently being executed) or not. Note that if a client application, such as ASP.NET, is also hosting APL .NET objects bound to the runtime version of the Dyalog DLL, these objects will be hosted in a separate workspace attached to the run-time version of the Dyalog DLL and will not be visible to the developer.

Debugging a running DYALOG.NET object is substantially the same process as debugging a stand-alone multi-threaded APL application. However, there are some important things to remember.

Firstly, the namespace structure above your APL class should be treated as being inviolate. There is nothing to prevent you from deleting namespaces, renaming namespaces, or creating new ones in the workspace. However, you do so at your peril!

Similarly, you should not alter, delete or rename any functions that have been automatically generated on your behalf by the APLScript compiler. These functions are also inviolate.

If execution in the Dyalog DLL is suspended, you may not execute )CLEAR or )RESET. You may execute )OFF or ⎕OFF, but if you do so, the client application will terminate. If you attempt to close the APL Session window, you will be warned that this will terminate the client application and you may cancel the operation or continue (and exit).

If you fix a problem in a suspended function and then press Resume or Continue (Tracer) or execute a branch, and the execution of the currently invoked method succeeds, you will be left with an empty state indicator (assuming that no other threads are actively involved). The Dyalog DLL is at this stage idle, waiting for the next client request and the state indicator will be empty.

If, at this point, you close the APL Session window, a dialog box will give you the option of terminating the (client) application, or simply hiding the APL Session Window. If you execute )OFF or ⎕OFF the client application will terminate.

Note that in the discussion above, a reference to terminating the client application means that APL executes Application.Exit(). This may cause the application to terminate cleanly (as with ASP.NET) or it may cause it to crash.


ASP.NET Configuration File

The web.config file

ASP.NET configuration parameters are defined in a file named web.config located in or above the root directory of an ASP.NET application. Parameters defined in these files supplement or override ASP.NET parameters which are defined system-wide.

The web.config file provided with Dyalog is located in the Dyalog sub-directory samples\asp.net and applies to all the examples residing in child directories of this directory. If you create a Dyalog ASP.NET application elsewhere on your system, you will need to copy this web.config into the application root directory. The parameters defined in the Dyalog web.config file are described below. Further details are provided in comments in the file.

DyalogBinDirectory

This specifies the full path to the Dyalog binaries (DLLs and script compiler).

dyalog (compiler)

This section defines an ASP.NET language named dyalog so that the expression Language = "dyalog" in a script file associates that script with the Dyalog APLScript compiler dyalogc.exe. Subsidiary parameters and keys for the dyalog compiler are:

debug | "true" (default) or "false" to bind the script to the Development DLL or the Run-time DLL
DyalogCompilerEncoding | "classic" or "unicode"..
DyalogCompilerOptions | This is used to define options for the script compiler. For example, to set []WX to 1 use "/wx:1".
DyalogCompilerEmitPragmas | Must be "true" if you are using workspace behind.

DyalogIsolationMode

This parameter specifies the isolation method. See Isolation Mode for further details.

DyalogCacheDirectory may be used to define the directory used to save the cached files.


Version 16.0 Key Features

Key Features

Dyalog APL Version 16.0 provides the following new features, enhancements and changes:

Performance Improvements

As part of the ongoing Performance Quality Assurance project, Version 16.0 includes a considerable amount of research and development work designed to substantially improve speed of execution.

Language Enhancements

New Language Features

  • New monadic ⍸ function. See Where.
  • New dyadic ⍸ function. See Interval Index.
  • New monadic ⊆ function. See Nest.
  • New dyadic ⊆ function. See Partition. This function is independent of ⎕ML, but is identical to dyadic ⊂ when 3≤⎕ML.
  • New system function ⎕CSV. See Comma Separated Values.
  • New system function ⎕JSON. See JSON Convert. This provides improved and extended functionality to the existing I-beam functions 7159⌶ and 7160⌶ which are deprecated. The JSON Name Mangling rules have changed. See JSON Name Mangling and JSON Translate Name.
  • New @ operator. See At.
  • New ⌺ operator. See Stencil.

Enhancements

  • Improvement to ⎕DR. You may now specify 0 as the first element of the left argument, to mean convert "as is". See Data Representation (Dyadic).
  • ⎕SIGNAL now returns a result, and calling ⎕SIGNAL 0 now causes error-related system constants to be reset. See Changes to ⎕SIGNAL.
  • Error guards (dfns) have been changed to use dynamic scope rules. See Dfn Error-Guards.
  • There is a new option for ⎕R and ⎕S. See UCP Option for ⎕R and ⎕S.
  • The default value for ⎕RL has been changed to (⍬ 1).
  • Certain System Commands now take parameters. See System Command Parameters.
  • ⎕PROFILE 'start' has a new 'coverage' option that avoids the cost (of memory) in counting the number of times lines of code are executed.
  • Version 16.0 introduces trigger functions that apply to assigments to all global variables in the same namespace. See Global Triggers.

IDE Enhancements

  • Text searches in the Session and Editor are now performed using PCRE. See PCRE for Text Searches.
  • The Editor toolbar has two new option buttons. See Editor Toolbar.
  • The edit boxes used in Session GUI components now have a clear button [image] button. Clicking this button clears the contents of the edit field.
  • New Options/Configure dialog. See Configuration Dialog: Saved Responses Tab.

GUI Enhancements

  • There is a new HasClearButton property that applies to objects that have edit boxes. See HasClearButton.
  • The DevCaps property has a new, 4th, element which reports the DPI scaling factor. See Notes.

Distributing Run-Time Components

Under Windows, many of the Dyalog APL run-time components (.EXE and .DLL) are linked dynamically with the Microsoft Universal C Runtime library (the UCRT) which is supplied and installed as part of the normal Dyalog development installation.

At execution time it is important that the Dyalog runtime components bind with a version of the UCRT that is compatible with (i.e. the same as or newer than) the one with which they were built.

Windows 10

If the end-user of the Dyalog application is known to be running Windows 10, the Dyalog application will pick up the system-wide UCRT which is part of Windows 10. There is therefore no need to include the UCRT with a Dyalog run-time application.

Other Versions of Windows

The UCRT is not supplied with versions of Windows prior to Windows 10. On these platforms, it is therefore necessary to install the UCRT as part of the installation of the Dyalog run-time application. There are two ways to achieve this which are referred to herein as the VCRedist installation and App-local installation. Dyalog recommends the former.

VCRedist Installation (Recommended)

The VCRedist package, which includes the UCRT, is supplied with the Dyalog development package.

Simply copy the vc_redistx86.exe (32-bit version) or vc_redistx64.exe (64-bit version) program from the Dyalog development package into your own installation package and execute it as part of the installation of your Dyalog run-time application. This installs the UCRT into a shared Windows location; in effect the UCRT becomes part of the Windows system. The installation therefore requires Administrator privileges.

App-local Installation

An alternative is to install the UCRT components into the same directory as your Dyalog run-time application. There are two ways to obtain these files.

Either:

Install the Dyalog development package (ideally onto a separate system just for this purpose) without administrator rights. This will perform an App-local installation of Dyalog itself. Then copy the UCRT files into your installation package. These files are:

  • those beginning with api-ms*
  • ucrtbase.dll
  • vcruntime140.dll

Or:

Download and install the Windows 10 SDK from:
https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk, and follow the instructions in the link below.https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt

Finally, modify your installer to add these files to the same folder as your Dyalog run-time application.


Version 16.0 System Requirements

System Requirements

Microsoft Windows

Dyalog APL Version 16.0 is supported on versions of Windows from Microsoft Windows 7 up to and including Microsoft Windows 10 and Microsoft Windows Server 2016.

Microsoft .NET Interface

Dyalog APL Version 17.0 .NET Interface requires Version 4.0 or greater of the Microsoft .NET Framework. It does not operate with earlier versions of .NET.

For full Data Binding support (including support for the INotifyCollectionChanged interfaceThis interface is used by Dyalog to notify a data consumer when the contents of a variable, that is data bound as a list of items, changes. 1), and Syncfusion, Version 17.0 requires .NET Version 4.5.

The examples provided in the sub-directory Samples/asp.net require that IIS is installed. If IIS and ASP.NET are not present, the asp.net sub-directory will not be installed during the Dyalog installation.

AIX

For AIX, Version 17.0 requires AIX 7.2 or higher, and a POWER7 chip or higher.

Raspberry Pi

On the Raspberry Pi, Dyalog 32-bit Unicode supports Raspbian Jessie or later.

Non-Pi Linux

For non-Pi Linux, Version 17.0 only exists as 64-bit interpreters - there are no 32-bit versions. It is built on Debian 7, and QAed on RedHat 6; it runs on all recent distributions, including Ubuntu 14.04 and openSUSE Leap 42.3. Contact Dyalog for information about other distributions.

macOS/Mac OS X

Version 17.0 requires Mac OS X Yosemite or El Capitan or macOS Sierra or later. The target Mac must have been introduced in 2010 or later.


Version 16.0 Interoperability and Compatibility

Inter-operability

Introduction

Workspaces and component files are stored on disk in a binary format (illegible to text editors). This format differs between machine architectures and among versions of Dyalog. For example, a file component written by a PC may well have an internal format that is different from one written by a UNIX machine. Similarly, a workspace saved from Dyalog Version 16.0 will differ internally from one saved by a previous version of Dyalog APL.

It is convenient for versions of Dyalog APL running on different platforms to be able to interoperate by sharing workspaces and component files. From Version 11.0, component files and workspaces can generally be shared between Dyalog interpreters running on different platforms. However, this is not always possible, for example:

  • Component files created by Version 10.1 can often not be shared across platforms, even when used by later versions.
  • Small-span (32-bit) component files become read-only when opened on a different architecture from that on which they were created.

Note however that the system function ⎕FCOPY can be used to make a logically identical copy of an old file, but the copy will be fully inter-operable.

The following sections describe other limitations in inter-operability:

Code and ⎕ORs

Code that is saved in workspaces, or embedded within ⎕ORs stored in component files, can only be read by the Dyalog version which saved them and later versions of the interpreter. In the case of workspaces, a load (or copy) into an older version would fail with the message:

this WS requires a later version of the interpreter.

Every time a ⎕OR object is read by a version later than that which created it, time may be spent in converting the internal representation into the latest form. Dyalog recommends that ⎕ORs should not be used as a mechanism for sharing code or objects between different versions of APL.

"Ordinary" Arrays

With the exception of the Unicode restrictions described in the following paragraphs, Dyalog APL provides inter-operability for arrays that only contain (nested) character and numeric data. Such arrays can be stored in component files - or transmitted using TCPSocket objects and Conga connections, and shared between all versions and across all platforms.

As mentioned in the introduction, full cross-platform interoperability of component files is only available for large-span component files.

Null Items (⎕NULL)

⎕NULLs created in Version 16.0 can be brought into Versions 14.0, 14.1 and 15.0 provided that the interpreters have been patched to revision 29846 or higher. Attempts to bring ⎕NULL into earlier versions of Dyalog APL or lower revisions of the aforementioned versions will fail with a DOMAIN ERROR: Array is from a later version of APL.

Object Representations (⎕OR)

An attempt to ⎕FREAD a component containing a ⎕OR that was created by a later version of Dyalog APL will generate DOMAIN ERROR: Array is from a later version of APL. This also applies to APL objects passed via Conga or TCPSockets, or objects that have been serialised using 220⌶ .

32 vs. 64-bit Component Files

It is no longer possible to create small-span (32-bit) files; however it is still currently possible to read and write small span files. Setting the second item of the right argument of ⎕FCREATE to anything other than 64 will generate a DOMAIN ERROR.

Note that small-span (32-bit-addressing) component files cannot contain Unicode data. Unicode editions of Dyalog APL can only write character data which would be readable by a Classic edition (consisting of elements of ⎕AV).

External Variables

External variables are implemented as small-span (32-bit-addressing) component files, and are subject to the same restrictions as these files. External variables are unlikely to be developed further; Dyalog recommends that applications which use them should switch to using mapped files or traditional component files. Please contact Dyalog if you need further advice on this topic.

32 vs. 64-bit Interpreters

From Dyalog APL Version 11.0 onwards, there are two separate versions of programs for 32-bit and 64-bit machine architectures (the 32-bit versions will also run on 64-bit machines running 64-bit operating systems). There is complete inter-operability between 32- and 64-bit interpreters, except that 32-bit interpreters are unable to work with arrays or workspaces greater than 2GB in size.

Note however that under Windows a 32-bit version of Dyalog APL may only access 32-bit DLLs, and a 64-bit version of Dyalog APL may only access 64-bit DLLs. This is a Windows restriction.

Unicode vs. Classic Editions

Two editions are available. Unicode editions work with the entire Unicode character set. Classic editions (a term which includes versions prior to 12.0) are limited to the 256 characters defined in the atomic vector, ⎕AV).

Component files have a Unicode property. When this is enabled, all characters will be written as Unicode data to the file. The Unicode property is always off for small-span (32-bit addressing) files, as these cannot contain Unicode data. For large-span (64-bit addressing) component files, the Unicode property is set on by Unicode Editions and off by Classic Editions, by default. The Unicode property can subsequently be toggled on and off using ⎕FPROPS.

When a Unicode edition writes to a component file that cannot contain Unicode data, character data is mapped using ⎕AVU; it can therefore be read without problems by Classic editions.

A TRANSLATION ERROR will occur if a Unicode edition writes to a non-Unicode component file (that is either a 32-bit file, or a 64-bit file when the Unicode property is currently off) if the data being written contains characters that are not in ⎕AVU.

Likewise, a Classic edition will issue a TRANSLATION ERROR if it attempts to read a component containing Unicode data that is not in ⎕AVU from a component file.

A TRANSLATION ERROR will also be issued when a Classic edition )LOADs or )COPYs a workspace containing Unicode data that cannot be mapped to ⎕AV using the ⎕AVU in the recipient workspace.

TCPSocket objects have an APL property that corresponds to the Unicode property of a file, if this is set to Classic (the default) the data in the socket will be restricted to ⎕AV, if Unicode it will contain Unicode character data. As a result, TRANSLATION ERRORs can occur on transmission or reception in the same way as when updating or reading a file component.

The symbols ⊆, ⍸, ⍤, ⍠, ⌸ and ⌺ used for the Nest (Interval Index) and Where (Partition) functions, the Rank, Variant, Key and Stencil operators respectively are available only in the Unicode edition. In the Classic edition, these symbols are replaced by ⎕U2286, ⎕U2378, ⎕U2364, ⎕U2360, ⎕U2338 and ⎕U233A respectively. In both Unicode and Classic editions Variant may be represented by ⎕OPT.

Very large array components

An attempt to read a component greater than 2GB in 32-bit interpreters will result in a WS FULL.

TCPSockets and Conga

TCPSockets and Conga can be used to communicate between differing versions of Dyalog APL and are subject to similar limitations to those described above for component files.

Auxiliary Processors

A Dyalog APL process is restricted to starting an AP of exactly the same architecture from the same operating system. In other words, the AP must share the same word-width and byte-ordering as its interpreter process.

Session Files

Session (.dse) files can only be used on the platform on which they were created and saved.


Announcements

Withdrawal of Support for Version 14.0

The supported Versions of Dyalog APL are now Version 16.0, 15.0 and 14.1. Version 14.0 and earlier are no longer supported.

Planned Operating System Requirements for the next version

Dyalog Ltd expects that the next version of Dyalog will require the following minimum platform requirements:

Operating System | Version
Microsoft Windows | Windows 7 or Server 2008
AIX | 7.1 on POWER 7
Linux | RedHat/Centos 6 or equivalent
OS X | OS X Yosemite 10.10.x
Raspberry Pi | Raspbian Jessie or above

Further information will appear on the Forums as and when available.

Planned Hardware Requirements for next version

The same as Dyalog 16.0.

Withdrawal of ability to disable Native Look and Feel

In versions 15.0 and 16.0 Native Look and Feel (NLF)is enabled by default but it is possible to disable it. Dyalog expects that the ability to disable NLF will be removed from the next major release of Dyalog APL. Not only do non-NLF applications look more and more dissimilar to "standard" applications, but it is becoming increasingly impractical to support non-NLF code in the interpreter.

Deprecation of small-span component files

Dyalog intends that version 16.0 will be the last that will be able to write to small-span component files.

Since Version 10.1, Dyalog APL has supported large-span (64-bit) component files, and since Version 12.0 ⎕FCREATE has created these by default. From Version 14.0 onwards it has not possible to create small-span component files, although you may still continue to read and write components on existing small-span component files.

Dyalog recommends that you convert any existing small-span component files to large-span files using ⎕FCOPY. ⎕FCOPY will create a large-span copy even if the file being copied is small-span. You may use the user command ]File.tolarge to locate existing small-span files and convert them to the large-span architecture.

Deprecation of JSON I-Beam Functions

7159⌶ and 7160⌶ are replaced by ⎕JSON and 7161⌶ has been found to be not required. These three I-beam functions are deprecated (and no longer documented) and will be removed in the next major release. 7162⌶ continues to be supported.

math.dws

The utility math.dws and its associated files fftw.dll and lapack.dll have been removed and are not part of 16.0.

More recent versions of these files for both 32 and 64 bit Windows are now available from github.com/dyalog/math, although math.dws has been replaced with math.dyalog. You can download a zip file for Windows, and it would be possible to download the source and compile the shared libraries for any platform as long as there is a Fortran compiler as well as a C compiler installed on the system.

Withdrawal of the default_rl parameter

16.0 no longer checks for the value of default_rl; it no longer appears in the Configure Box, nor appears in the registry. If set as an environment variable, Dyalog ignores its value.

Withdrawal of 16807⌶

As announced in the Dyalog Version 15.0 Release Notes, 16807⌶ has been withdrawn from 16.0.

A simple replacement for "16807⌶1" is "⎕RL←⍬ 1" (or "⎕RL←0 1" if you need to be able to generate repeatable sequences of "random" numbers).

Note that, since 14.0, random number generator 1 is the default in a CLEAR WS so you may not need to perform these steps unless the workspace was created in a version earlier than 14.0.

Conga and Windows

Conga 3 requires Windows Vista or higher, or Windows Server 2008 or higher. Note that this is now also true of Conga 2.6 and higher.

RIDE DLLs/shared libraries

In previous versions of Dyalog separate DLLs/shared libraries were supplied for Conga and for RIDE. In Version 16.0 the two sets of shared libraries/DLLs have been merged; the Conga libraries are required for RIDE to function.


Bug Fixes

A number of bug fixes implemented in Version 16.0 may change the way that existing code operates and are therefore documented in this section.

Namespace serialisation (14144)

Version 16.0 is stricter than 15.0 about serialising namespaces. "Serialising" happens every time you write a namespace to a component file or send it over a socket. (There is also an explicit "Serialise/Deserialise Array" I-beam, 220⌶.)

In 16.0, when you serialise a namespace A it can only refer to other namespaces that are children of itself. If it contains a ref to some other namespace (e.g. a parent or sibling of A) then you will get an error:

      A←⎕NS''    ⍝ Create two sibling namespaces
                 ⍝ (both are children of #)
      B←⎕NS''
      A.x←B      ⍝ Create a ref from A to B
      {}1(220⌶)A ⍝ Try to serialise A
DOMAIN ERROR: Namespace is not self contained

15.0 allowed you to serialise non-self-contained namespaces like A, but was inconsistent about where it would recreate the namespaces when you deserialised them (e.g. when reading the namespace back from a component file); typically B would be recreated as a child of A, thus breaking the original namespace hierarchy.

Control Structure Parameters (13633)

Prior to 16.0, parameters supplied to control structure expressions that do not expect a parameter were ignored. From 16.0 onwards any control structure that should not have a parameter must not have a parameter. For example, the expression:

   :Continue 88

now generates a SYNTAX ERROR; whereas previously the unwanted parameter 88 was ignored.

Dfn Localisation Issue (7945)

There was a dfn bug whereby in executing an expression such as f←{(⍴)var←⍵}, where a simple assignment is immediately preceded by a function in parentheses, the system failed to localise var, so it would be established as a global variable.

The fix for this issue causes some dfns, that previously appeared to work, to fail. For example:

     foo←+ ⍝ foo is defined as any function
     f←{(left argument expression)foo var←⍵}

15.0 behaviour:

The expression f 0 would assign ⍵ to var and then apply foo dyadically. However, the system failed to localise var, but instead established it as a spurious global variable. And this isn't how dfns are supposed to work anyway; an expression like foo var←⍵ is supposed to assign to both foo and var, regardless of how/whether they were previously defined.

16.0 behaviour:

The expression generates a SYNTAX ERROR or LENGTH ERROR. The fix is to rewrite the expression in one of these two ways, according to taste:

f←{(left argument expression)foo ⊢ var←⍵} ⍝ add ⊢
f←{(left argument expression)foo (var←⍵)} ⍝ add parens

Invalid Control Structure Syntax

Invalid control structure, such as in the following example, now generates a SYNTAX ERROR as it should. In previous versions it was wrongly accepted.

     ∇ foo;a;b
[1]    a←b←1
[2]    :If a :AndIf b
[3]        'a and b are true'
[4]    :EndIf
[5]    ∇
     ∇

Scope of System Variables

The scope of system variables ⎕DCT and ⎕FR has been changed from workspace scope to namespace scope.


Error Guards (dfns)

Dfn Error-Guards

Prior to Version 16.0, in common with regular names, error-guards used "lexical scope" rules. This meant that when an error occurred, the interpreter would look outwards through enclosing nesting levels to find an appropriate error-guard. In particular, a function could not set an error-guard for a called function unless the called function was nested within the calling function.

With Version 16.0, error-guards have been changed to use "dynamic scope" rules. This means that when an error occurs, the interpreter looks back along the calling stack to find an appropriate error-guard: a calling function can set an error-guard for a called function, irrespective of their relative nesting levels.

    main←{            ⍝ from V16:
        0::'error'    ⍝ this error-guard will catch ...
        sub ⍵
    }

    sub←{÷0}          ⍝ ... this error

Here is an example of a piece of code that will behave differently in Version 16.0:

    {
        11::'old behaviour'
        {
            ÷0
        }{
            11::'new behaviour'
            ⍺⍺ ⍵
        }⍵
    }

Note:

Following the setting of an error-guard, subsequent function calls will disable tail call optimisation:

    {
        22::'Oops!'     ⍝ this error-guard means that ...
        tie←⍵ ⎕ftie 0
        subfn tie       ⍝ ... tail call not optimised
    }

One way to maintain the tail call optimisation in the presence of an error-guard is to isolate it within an inner function:

    {
        tie←{
            22::0        ⍝ error-guard local to inner fn
            ⍵ ⎕ftie 0
        }⍵
        tie=0:'Oops!'
        subfn tie        ⍝ ... so this is a tail call
    }


IDE Enhancements

PCRE for Text Searches

Text searches in the Workspace Search Tool and Find/Replace dialogs are now performed using PCRE. If the Use Regular Expressions box is checked, the full range of regular expressions provided by PCRE are available for use.

See PCRE Regular Expression Syntax Summary. This is the same mechanism as used by ⎕R and ⎕S.

Editor Toolbar

The Editor and Tracer toolbar contains two new option buttons which affect how searches are performed in the Edit window.

Button | Description
Match whole word | Specifies whether or not the search matches a whole word
Use Regular Expressions | Specifies whether or not the search uses PCRE regular expressions

Clear Button

Where appropriate, an [image] (clear) button has been added to edit boxes in the Session dialog boxes. Clicking the [image] button clears the data in the field.


Saved Responses Tab

Configuration Dialog: Saved Responses Tab

There is now a Saved Responses tab on the Configuration Dialog. This was actually added in Version 15.0 but after the completion of the documentation.

The Saved Responses tab of the Configuration dialog is used to remove preferences that the user has previously established.

In the example illustrated above, the user has at some point chosen to save a text file with a .h extension as text in the workspace and, by checking the option Save this response for all files with a ".h" extension, saved this as a preference for all such text files. Similarly, the user has checked the option Do not show this message again when responding to the warning dialog Saving as text will ....

If the user wishes to reverse these decisions, even temporarily, it is necessary to select the corresponding option /preference name(s) and click Delete. The names are intended to be self-explanatory and are not listed here.


Other Changes

)LIB

Under Windows, the names of directories listed by )LIB were displayed in upper-case. This has been changed and )LIB now reports the names of directories as they are displayed by the Operating System.

MAXWS

With the exception of the Raspberry Pi, the default value of MAXWS has increased from 64Mb to 256Mb.

CONTINUE workspace

The handling of the continue workspace has been changed as follows:

  • By default the automatic saving of a CONTINUE workspace (such as when a run-time violation occurs) is disabled. There is a new I-Beam function to control the autosave of a CONTINUE workspace; i.e. other than when directed to do so by the )CONTINUE system command. See Continue Autosave.
    Note that Dyalog will not introduce a configuration parameter to mimic the setting of 2704⌶; this is considered a security issue and therefore is one that must be under APL program control.
  • Dyalog no longer loads a CONTINUE workspace automatically on start-up. The only way a CONTINUE workspace may be loaded is by using )LOAD or ⎕LOAD or by specifying continue.dws on the command line

Command Line option

The -F flag has been removed as a command-line option for starting Dyalog. It has been ignored since Version 14.0.

Changes to ⎕SIGNAL

⎕SIGNAL now returns a shy result which is the same as the right argument.

⎕SIGNAL 0 is a special case of ⎕SIGNAL, and results in ⎕DM, ⎕EN, ⎕DMX and ⎕EXCEPTION being reset.

⎕SIGNAL 0 is the only form of ⎕SIGNAL that can be used to reset the aforementioned system variables; including a left argument or using a name/value pair right argument of ⎕SIGNAL will result in a DOMAIN ERROR.

Shy Result for ⎕PROFILE

⎕PROFILE'start', 'stop', 'clear' and 'calibrate' now return shy results.

UCP Option for ⎕R and ⎕S

There is a new UCP variant option for ⎕R and ⎕S which is either 0 or 1.

This affects the way PCRE that processes \B, \b, \D, \d, \S, \s, \W, \w, and some of the POSIX character classes.

If UCP is 0 (the default), only ASCII characters are recognized. If UCP is 1, Unicode properties are used instead to classify characters.

Examples

By default, the character ø (which is not an ASCII character) is considered to be a "non-word" character, so:

      ('\w'⎕S'\0')'Bjørn'  ⍝ identify "word" characters
 B  j  r  n
      ('\W'⎕S'\0')'Bjørn'  ⍝ non-word" characters
 ø

When UCP is set to 1, Unicode characters are matched as "word" characters (\w) too.

      ('\w'⎕S'\0' ⍠'UCP' 1)'Bjørn'
 B  j  ø  r  n

System Error Dialog Box

The System Error Dialog box has changed and the option Generate complete image core has been replaced by Create a process dump file. See System Error Dialog Box.

Copy, Cut and Paste Options

The configuration option Use Ctrl-X,C,V for clipboard option has been moved from the interpreter to the IME. See Input Method Editor Properties.

Changes to German locale files

Session files and Classic input translate tables for the German locale have been renamed so that they are now referred to as "DE" rather than "GR". The BuildSe workspace has been updated to reflect these changes.

Changes to French keyboard layout in the IME

The French keyboard supplied with the IME has been changed so that it now has the same APL character overlay as other languages (for example, ⍺ appears on the "q" key rather than the "a" key). The previous version appears in the aplkeys subdirectory of the IME installation directory as fr-FR_legacy.din.

F1 Help

Under Windows, F1 help is now case-insensitive, so if you place the cursor on a string such as size and press function key F1, you will obtain the help topic for the Size property.

Similarly, if you have a default Session (with Use online help for non-Dyalog topics checked, and the URL set to http://social.msdn.microsoft.com/Search/en-US?query=%s) typing com and pressing F1 will launch the appropriate msdn page with "com" as the search string.

Native File Functions and APLX

The native file functions ⎕NREAD and ⎕NREPLACE have been enhanced for compatibility with APLX. Specifically, the current file position may be specified by the value ¯1. This enhancement was added to Version 15.0.


Language Enhancements

Language Changes

The following table summarises the main changes to language features in Version 16.0.

Function | Description | Change
⍸ (monadic) | Where | New function
⍸ (dyadic) | Interval Index | New function
⊆ (monadic) | Nest | New function
⊆ (dyadic) | Partition | Equivalent to dyadic ⊂ but independent of ⎕ML
@ | At | New operator
⌺ | Stencil | New operator
⎕CSV | Comma Separated Values | New system function
⎕JSON | JSON Import and Export | New system function. Replaces 7159⌶ and 7160⌶
⎕R and ⎕S |  | New UCP option
dfns & dops | Error Guards | Error guards have been changed to use dynamic scope rule
⎕RL | New default | The default value for ⎕RL has been changed to ⍬ 1
⎕SIGNAL |  | ⎕SIGNAL 0 causes error-related system constant to be reset; ⎕SIGNAL now returns a shy result
Trigger * |  | See Global Triggers.


Global Triggers

Version 16.0 provides an enhancement for Triggers that allows a single function to trigger on any assignment to a global variable in the same namespace.

This is implemented by the function declaration statement:

    :Implements Trigger *

Example:

     ∇ foo args
[1]    :Implements Trigger *
[2]    args.Name,' is: ',⍎args.Name
     ∇
      a←⍳10
a is:  1 2 3 4 5 6 7 8 9 10
      a[3]←⊂'pete'
a is:  1 2  pete  4 5 6 7 8 9 10
      a b←10 'pete'
a is:  10
b is: pete

Notes:

  • like other Triggers, only the most recently fixed global trigger function will apply and be called on assignment to a global variable.
  • global triggers do not apply to local names nor to semi-globals (names which are localised further up the stack).
  • in the case of a global trigger, the argument to the trigger function (an instance of the internal class TriggerArguments) contains the single member Name. This may be extended in the future.
  • an assignment to a global variable will fire both its specific trigger (if defined) and the global trigger. However, the order of execution is undefined.

Further Example

A potential use for a global trigger is to detect the unintended creation of global variables due to localisation omissions. Note however that the timing of the activation of the Trigger is unpredictable. In this example, the trigger for the assignment to b activates after funtion hoo has exited. When Threads are involved, timing becomes even less predictable.

     ∇ CatchGlobals arg
[1]    ⍝ Displays a warning when a global is assigned
[2]    :Implements Trigger *
[3]    '*** assigment to global variable: ',
        arg.Name,' from ',1↓⎕SI
     ∇
     ∇ foo
[1]    goo
     ∇
     ∇ goo
[1]    hoo
     ∇
     ∇ hoo
[1]    a←10
[2]    b←a
     ∇
      foo
*** assigment to global variable: a from  hoo  goo  foo
*** assigment to global variable: b from  goo  foo


System Command Parameters

Certain system commands now accept parameters as shown in the table and examples below.

System Command | Description
)SAVE -force ws | force causes the specified file to be overwritten when the name specified by ws differs from ⎕WSID.
)SI n -tid=tn | n restricts the display to the first or last n lines of the full output. -tid=tn specifies that the state indicator is to be displayed only for thread number tn.
)RESET n | Clears the top n suspensions on the stack.

State Indicator

      foo
DOMAIN ERROR: Divide by zero
loo[1] 1÷0
      ∧
      )SI
#.loo[1]*
#.hoo[1]
#.goo[1]
#.foo[1]
      )SI 2
#.loo[1]*
#.hoo[1]
      )SI ¯2
#.goo[1]
#.foo[1]

       ⎕←foo&¨10 10 10 10
┌→─────────┐
│9 10 11 12│
└~─────────┘
       )si
·   #.foo[1]
&9
·   #.foo[1]
&10
·   #.foo[1]
&11
·   #.foo[1]
&12
      )si -tid=11
#.foo[1]

Reset State Indicator

      )reset
      foo
DOMAIN ERROR: Divide by zero
loo[1] 1÷0
      ∧
      foo
DOMAIN ERROR: Divide by zero
loo[1] 1÷0
      ∧

      )si
#.loo[1]*
#.hoo[1]
#.goo[1]
#.foo[1]
#.loo[1]*
#.hoo[1]
#.goo[1]
#.foo[1]
      )reset 3

      )si
#.foo[1]*
#.loo[1]*
#.hoo[1]
#.goo[1]
#.foo[1]


Changes to I-Beams

I-beam Changes

I-beam functionality changed from Version 16.0.

A | Description | Change
2704 | See Continue Autosave. | New function
16807 | Random Number Generator. See Withdrawal of 16807⌶. | Removed
7159 | Replaced by ⎕JSON. See JSON Convert. | Deprecated
7160 | Replaced by ⎕JSON. See JSON Convert. | Deprecated
7161 | JSON TrueFalse | Deprecated
7162 | See JSON Translate Name. | Modified


GUI Enhancements

The following table summarises the main changes to GUI features in Version 16.0.

Name | Change
DevCaps | Now returns 4 elements rather than 3
HasClearButton | New property


UNIX Specific Release Notes

Summary

This section summarises the changes specific to Dyalog APL Version 16.0 on non-Windows platforms. This list currently consists of:

  • AIX
  • Linux (including the Raspberry Pi)
  • macOS/ Mac OS X

Hardware Requirements

AIX

For AIX, Version 17.0 requires AIX 7.2 or higher, and a POWER7 chip or higher.

Raspberry Pi

On the Raspberry Pi, Dyalog 32-bit Unicode supports Raspbian Jessie or later.

Non-Pi Linux

For non-Pi Linux, Version 17.0 only exists as 64-bit interpreters - there are no 32-bit versions. It is built on Debian 7, and QAed on RedHat 6; it runs on all recent distributions, including Ubuntu 14.04 and openSUSE Leap 42.3. Contact Dyalog for information about other distributions.

macOS/Mac OS X

Version 17.0 requires Mac OS X Yosemite or El Capitan or macOS Sierra or later. The target Mac must have been introduced in 2010 or later.

RIDE and Dyalog APL 16.0

Dyalog Version 16.0 supports RIDE 3 and RIDE 4 only; RIDE 2 is not supported. Dyalog recommends that RIDE 4 is used in preference to RIDE 3. RIDE 4 can be used with Version 15.0 too.

RIDE 4 is supported on Raspberry Pi models 2 and 3 only; models Zero and 1 are not supported (the underlying libraries which RIDE is build on are not available for the Pi Zero and 1). The Dyalog RIDE Reference Guide details how to configure the APL session to support the underscored alphabet; contact support@dyalog.com if you wish to be able to generate key-chords which result in the underscored alphabet being entered into APL.

Note that on Linux and Pi, if RIDE 4 is installed after Dyalog 16.0 an extra icon will be added to the window manager's start menu which will start Dyalog with a RIDE front end.

Linux Window Managers and APL characters

If your Linux window manager does not include support for APL characters (Gnome is an example), then the first time that you run Dyalog having started the window manager afresh, you must run

$ dyalog -kbd

Subsequent invocations of dyalog should not require this flag.

Location of configuration and log files

In Dyalog 16.0 the location of various configuration and log files has been changed so that they are all put in one directory. See the UNIX Installation and Configuration Guide for more information.

SQAPL on macOS

Dyalog 16.0 for macOS includes support for SQAPL. However, it is necessary to install iODBC and suitable drivers for your database before SQAPL can work. The SQL Interface Guide describes the steps that are typically necessary to get SQAPL connected to a MySQL database.

4000⌶ and 4002⌶

4000⌶ (Fork process) and 4002⌶ (Reap processes) have been withdrawn on all platforms except AIX. This is due to limitations imposed by the HTMLRenderer, and due to problems in the interaction of forking processes and using RIDE.


Version 15.0 Key Features

Key Features

Dyalog APL Version 15.0 provides the following new features, enhancements and changes:

Installation

I t is now possible to install Dyalog without Administrator privileges, although there are a number of consequential limitations. See Non Admin Installation.

Performance Improvements

Version 15.0 includes a considerable amount of research and development work designed to substantially improve speed of execution. See Performance Improvements .

Language Enhancements

New Language Features

  • The Random Link system variable ⎕RL has been extended to specify the random number generator. See Random Link . This enhancement supersedes the use of and replaces the use of (16807⌶) which is deprecated and will be removed in the next release.
  • Catenate reduction has been extended to operate on empty arrays instead of generating a DOMAIN ERROR. See Reduce.
  • New system functions are provided to plug some gaps in the native file sub-system. Like the existing native file functions, the new ones are portable across all the operating systems supported by Dyalog, and obviate the need for non-portable solutions (such as the use of the .NET classes for handling directories). See File Name Parts, Make Directory, Native File Delete, Native File Exists, Native File Information, Read Text File and Write Text File.
  • The native file functions ⎕NREAD and ⎕NREPLACE have been enhanced for compatibility with APLX. The current file position may now be specified by the value ¯1.

New I-Beam Features

  • A new I-beam function transforms character arrays into lower or upper case and is provided to optimise performance for these operations. See Case Convert.
  • A new I-beam function is provided to disassociate data binding from a data-bound variable. See Remove Data Binding.
  • Two new I-beams have been added to control when APL threads allocated to incoming .NET calls are re-used or discarded. See Discard Thread on Exit and Discard Parked Threads.
  • A new I-beam function is provided to control the error handling behaviour of :Trap and ⎕TRAP. See Trap Control.
  • A new I-beam function creates a hashed array on which dyadic ⍳ and other set functions can be expected to perform faster. See Hash Array.
  • The Dyalog compiler remains experimental but the I-beam to control it is now documented. See Compiler Control.
  • A previously undocumented I-beam is provided to obtain the APL code for methods in classes. See Canonical Representation.
  • A new I-beam is provided to identify the precise type of a delegate required by a .NET method or property. See Create .NET Delegate.
  • A new I-beam function is provided to assist with inverting matrices. See Singular Value Decomposition.
  • Two new I-beams are provided to obtain information concerning files loaded for editing or scripts fixed from file. See List Loaded Files and Examples:.
  • A new I-beam is provided to control connections to the RIDE. See Manage RIDE Connections.

IDE Enhancements

  • Native Look and Feeel is now enabled by default for the Dyalog Session and for GUI applications. See Native Look and Feel.
  • The Editor has been extended to allow you to edit Dyalog script files and arbitrary text files. See Editing Scripts and Text Files.
  • The Editor has a new Syntax menu. See Editor: Syntax Menu. The Edit menu has two additional options. See Editor: Edit Menu.
  • The Editor now has an option to identify lines of a function which failed to compile. See Editor: Compiler Errors.
  • The Options menu in the Session provides a new option to Disable suspended :Trap blocks or localised ⎕TRAPs. See Disable traps in session.

GUI Enhancements

  • There is a new GetFocusObj method that identifies the GUI object which currently has the input focus. GetFocusObj returns a ref to the object, whereas GetFocus returns its name. See GetFocusObj.
  • Native Look and Feel is now enabled by default; whereas previously it was disabled.
  • It is now possible to allocate values for the Dispatch ID (DISPID) of exported methods, properties and events of OLEServer and ActiveXControl objects. See DISPID (Dispatch ID).

Rationalisation of filename extensions

The process of rationalising filename extensions, which was begun in Version 14.1 with the introduction of the WSEXT parameter for workspaces, has been extended to component files. See Component Files without File Extensions. This is intended to simplify file naming conventions for cross-platform development.

.NET Interface Enhancements

  • The I-beam functions Create Data Binding Source (2015⌶) and Update Data Table (2010⌶) have been enhanced to handle DateTime data more efficiently. In cases where the functions expect DateTime data, it is no longer necessary to create instances of DateTime objects in the workspace. Instead, the data may be represented by 7-element integer vectors (⎕TS format) or character strings that can be parsed by the DateTime.Parse(String) method. Using either form is typically faster than creating DateTime objects in the workspace, especially for large arrays. This applies only to Create Data Binding Source and Update Date Table. See Example 6a (Casting to DateTime)
  • When a .NET method/property/field etc. returns a null result, it is now represented by ⎕NULL. In previous versions of Dyalog a null result from a .NET method generates a VALUE ERROR. Be aware that this may result in your code returning a SYNTAX ERROR rather than a VALUE ERROR (as in 14.1 and earlier) in code such as (⎕NEW Window).Owner.Left
  • The web.config file now includes a key DyalogBinDirectory to specify the location of the Dyalog .NET interface, the Dyalog DLLs and the Dyalog script compiler. The web.config file installed in samples\asp.net sets this to the directory that is identified by the dyalog parameter. This new key allows different Dyalog ASP.NET applications to use different versions of Dyalog.

Including Script Files in Scripts

  • There is a new :Require directive that if present must precede any code (either a workspace script or a script file). A :Require statement instructs Dyalog to load and fix a script file prior to processing the current script. See Including Script Files in Scripts.

Unicode Encodings for ⎕S and ⎕R

The introduction of ⎕NGET and ⎕NPUT has caused some changes to ⎕S and ⎕R so that they match. In particular, the InEnc, OutEnc and Enc options take the same encoding values as ⎕NGET and ⎕NPUT use:

  • UTF8 and other UTF encodings are now spelled UTF-8 etc (old spellings are retained for backward compatibility)
  • UTF-32 is a new addition
  • UTF-16 and UTF-32 may optionally be qualified with BE or LE and assume host endianness when omitted; previously the endianness had to be specified
  • All UTF variants can be qualified with -BOM or -NOBOM when neither is specified
  • UTF-8 assumes -NOBOM and UTF-16/UTF-32 assume -BOM. Before only -BOM was an option and not specifying was equivalent to -NOBOM. Note that this means that the old UTF16LE and UTF16BE have changed their behaviour: before there would have been no BOM, now there is.
  • Windows-1252 "replaces" ANSI (ANSI is a synonym, but Windows-1252 is the preferred name).

File Explorer Integration

Using Unicode Edition, it is now possible to browse workspaces and script (.dyalog) files from the Windows File Explorer. Dyalog presents the contents of workspaces and scripts in the File Explorer preview pane. In addition script files can be opened from File Explorer using the standard Dyalog Editor, changed and re-saved; all without starting Dyalog itself. See File Explorer Integration .

The facility to browse Dyalog script files in a preview pane extends to Microsoft Outlook ,which will use Dyalog to preview such files when received as attachments in emails.

This feature is not supported in Classic Edition.


Non Admin Installation

If you run the setup.exe program without Administrator rights, you are offered the choice to continue or to restart the setup-exe program with Administrator privileges.

If you install Dyalog without Administrator privileges, the following limitations apply:

  • The APL 385 font is not installed. Dyalog will use the correct font, but no other application will have access to it.
  • The IME is not installed. Instead the keyboard is defined as a series of Registry entries. This means that the Dyalog keyboard layout can be used only with Dyalog and not with other software.
  • No attempt is made to install the VS2015 redistributables globally; they are therefore not available outside the interpreter unless they have been installed beforehand.
  • A non-administrator installation is available only to the user who performed the installation; on a shared machine all users would have to perform a non-administrator installation.

Dyalog APL is installed under your AppData directory, for example

c:\users\andys\AppData\Local\Programs\Dyalog\Dyalog APL 15.0 Unicode. Note that the VS2015 redistributables will also be placed in this directory. The registry entries for your version of Dyalog will appear under HKEY_CURRENT_USER\Software\Dyalog.


Version 15.0 System Requirements

System Requirements

Microsoft Windows

Dyalog APL Version 15.0 supports versions of Windows from Microsoft Windows Vista up to and including Microsoft Windows 10 and Microsoft Windows Server 2015. Dyalog APL Version 15.0 will not run on earlier versions.

Microsoft .NET Interface

Dyalog APL Version 17.0 .NET Interface requires Version 4.0 or greater of the Microsoft .NET Framework. It does not operate with earlier versions of .NET.

For full Data Binding support (including support for the INotifyCollectionChanged interfaceThis interface is used by Dyalog to notify a data consumer when the contents of a variable, that is data bound as a list of items, changes. 1), and Syncfusion, Version 17.0 requires .NET Version 4.5.

The examples provided in the sub-directory Samples/asp.net require that IIS is installed. If IIS and ASP.NET are not present, the asp.net sub-directory will not be installed during the Dyalog installation.

AIX

For AIX, Version 17.0 requires AIX 6.1 or higher, and a POWER6 chip or higher.

Raspberry Pi

On the Raspberry Pi, Dyalog (32-bit Unicode) supports Raspbian Wheezy and Jessie.

Non-Pi Linux

For non-Pi Linux, Version 17.0 only exists as 64-bit interpreters - there are no 32-bit versions. It is built on RedHat 6, and runs on all recent distributions, including Ubuntu 14.01 and openSUSE 13.2. Contact Dyalog for information about other platforms.

macOS/Mac OS X

Version 15.0 requires Mac OS X Yosemite or El Capitain or macOS Sierra. The target Mac must have been introduced in 2010 or later.


Version 15.0 Interoperability and Compatibility

Inter-operability

Introduction

Workspaces and component files are stored on disk in a binary format (illegible to text editors). This format differs between machine architectures and among versions of Dyalog. For example, a file component written by a PC may well have an internal format that is different from one written by a UNIX machine. Similarly, a workspace saved from Dyalog Version 15.0 will differ internally from one saved by a previous version of Dyalog APL.

It is convenient for versions of Dyalog APL running on different platforms to be able to interoperate by sharing workspaces and component files. From Version 11.0, component files and workspaces can generally be shared between Dyalog interpreters running on different platforms. However, this is not always possible, for example:

  • Component files created by Version 10.1 can often not be shared across platforms, even when used by later versions.
  • Small-span (32-bit) component files become read-only when opened on a different architecture from that on which they were created.

Note however that the system function ⎕FCOPY can be used to make a logically identical copy of an old file, but the copy will be fully inter-operable.

The following sections describe other limitations in inter-operability:

Code and ⎕ORs

Code that is saved in workspaces, or embedded within ⎕ORs stored in component files, can only be read by the Dyalog version which saved them and later versions of the interpreter. In the case of workspaces, a load (or copy) into an older version would fail with the message:

this WS requires a later version of the interpreter.

Every time a ⎕OR object is read by a version later than that which created it, time may be spent in converting the internal representation into the latest form. Dyalog recommends that ⎕ORs should not be used as a mechanism for sharing code or objects between different versions of APL

"Ordinary" Arrays

With the exception of the Unicode restrictions described in the following paragraphs, Dyalog APL provides inter-operability for arrays that only contain (nested) character and numeric data. Such arrays can be stored in component files - or transmitted using TCPSocket objects and Conga connections, and shared between all versions and across all platforms.

As mentioned in the introduction, full cross-platform interoperability of component files is only available for large-span component files.

Null Items (⎕NULL)

⎕NULLs created in Version 15.0 can be brought into Versions 13.2, 14.0 and 14.1 provided that the interpreters have been patched to revision 27114 or higher. Attempts to bring ⎕NULL into earlier versions will fail with a DOMAIN ERROR.

Object Representations (⎕OR)

From Version 13.2 onwards, an attempt to ⎕FREAD a component containing a ⎕OR that was created by a later version of Dyalog APL will generate DOMAIN ERROR: Array is from a later version of APL. This also applies to APL objects passed via Conga or TCPSockets, or objects that have been serialised using 220⌶ .

32 vs. 64-bit Component Files

Large-span (64-bit-addressing) component files are inaccessible to versions of the interpreter that pre-dated their introduction (versions earlier than 10.1).

From version 14.0 onwards it is no longer possible to create small-span (32-bit) files; however it is still possible to read and write small span files. Setting the second item of the right argument of ⎕FCREATE to anything other than 64 will generate a DOMAIN ERROR.

Note that small-span (32-bit-addressing) component files cannot contain Unicode data. Unicode editions of Dyalog APL can only write character data which would be readable by a Classic edition (consisting of elements of ⎕AV).

External Variables

External variables are implemented as small-span (32-bit-addressing) component files, and are subject to the same restrictions as these files. External variables are unlikely to be developed further; Dyalog recommends that applications which use them should switch to using mapped files or traditional component files. Please contact Dyalog if you need further advice on this topic.

32 vs. 64-bit Interpreters

From Dyalog APL Version 11.0 onwards, there are two separate versions of programs for 32-bit and 64-bit machine architectures (the 32-bit versions will also run on 64-bit machines running 64-bit operating systems). There is complete inter-operability between 32- and 64-bit interpreters, except that 32-bit interpreters are unable to work with arrays or workspaces greater than 2GB in size.

Note however that under Windows a 32-bit version of Dyalog APL may only access 32-bit DLLs, and a 64-bit version of Dyalog APL may only access 64-bit DLLs. This is a Windows restriction.

Unicode vs. Classic Editions

From Version 12.0 onwards, a Unicode edition is available, which is able to work with the entire Unicode character set. Classic editions (a term which includes versions prior to 12.0) are limited to the 256 characters defined in the atomic vector, ⎕AV).

Component files have a Unicode property. When this is enabled, all characters will be written as Unicode data to the file. The Unicode property is always off for small-span (32-bit addressing) files, as these cannot contain Unicode data. For large-span (64-bit addressing) component files, the Unicode property is set on by Unicode Editions and off by Classic Editions, by default. The Unicode property can subsequently be toggled on and off using ⎕FPROPS.

When a Unicode edition writes to a component file that cannot contain Unicode data, character data is mapped using ⎕AVU; it can therefore be read without problems by Classic editions.

A TRANSLATION ERROR will occur if a Unicode edition writes to a non-Unicode component file (that is either a 32-bit file, or a 64-bit file when the Unicode property is currently off) if the data being written contains characters that are not in ⎕AVU.

Likewise, a Classic edition (Version 12.0 or later) will issue a TRANSLATION ERROR if it attempts to read a component containing Unicode data that is not in ⎕AVU from a component file. Version 11.0 cannot read components containing Unicode data and issues a NONCE ERROR.

A TRANSLATION ERROR will also be issued when a Classic edition )LOADs or )COPYs a workspace containing Unicode data that cannot be mapped to ⎕AV using the ⎕AVU in the recipient workspace.

TCPSocket objects have an APL property that corresponds to the Unicode property of a file, if this is set to Classic (the default) the data in the socket will be restricted to ⎕AV, if Unicode it will contain Unicode character data. As a result, TRANSLATION ERRORs can occur on transmission or reception in the same way as when updating or reading a file component.

The symbols ⍤, ⍠ and ⌸ used for the Rank, Variant and Key operators respectively are available only in the Unicode edition. In the Classic edition, these symbols are replaced by ⎕U2364, ⎕U2360 and ⎕U2338 respectively. In both Unicode and Classic editions Variant may be represented by ⎕OPT.

AVU changes

The implementation of the function Right in Version 13.0 led to the discovery that ⎕AVU incorrectly defined ⎕AV[59+⎕IO] as ¤ (⎕UCS 164) rather than ⊢ (Right Tack, ⎕UCS 8866). This error has been corrected in the default ⎕AVU and in workspace AVU.dws. If you are operating in a mixed Unicode/Classic environment, this error will have caused earlier Classic editions to map ⎕AV[59+⎕IO] to the wrong Unicode character (¤). This may cause TRANSLATION ERRORs when a Version 13.0 Classic system attempts to read the data, as it will not be able to represent ¤ in the Atomic Vector.

DECFs and Complex numbers

Version 13.0 introduced two new data types; DECFs and Complex numbers. Attempts to read components of these types in earlier interpreters will result in a DOMAIN ERROR.

Very large array components

The maximum size (in bytes) of a component written by Version 12.1 and prior is 2GB. This is the size of the component as held on disk which may be different than the size reported by ⎕SIZE. In Version 13.0 the maximum size of a component written by a 64-bit interpreter is 4GB. From Version 13.2 onwards, the limit on the size of arrays or components is so large that for most practical purposes, there is effectively no limit.

An attempt to read a component greater than 2GB in 32-bit interpreters will result in a WS FULL. An attempt to read such a component in 64-bit Versions 12.0 and 12.1 patched after 1st April 2011 will result in a NONCE ERROR; earlier patches generate a FILE COMPONENT DAMAGED error.

File Journaling

Version 12.0 introduced File Journaling (level 1), and 12.1 added journaling levels 2 and 3 and checksumming. Versions earlier than 12.0 cannot tie files that have any form of journaling or checksumming enabled. Version 12.0 cannot tie files with journaling levels greater than 1, or checksumming enabled. Attempting to tie such files will result in a FILE NAME ERROR. Files can be shared with earlier versions by using ⎕FPROPS to amend the journaling and checksumming levels.

File Component Compression

Version 14.0 introduced File Component Compression; earlier versions will be able to perform all file operation on such files with the exception of being able to ⎕FREAD or ⎕FCOPY any compressed component. In particular, it is possible for any earlier version to ⎕FREPLACE a compressed component with a non-compressed one.

Dyalog 14.0.27143 and 14.1.27143 and later can read compressed components written using 15.0. Attempts to read such components in lower levels of 14.0 and 14.1 will generate DOMAIN ERROR: Array is from a later version of APL

Attempting to read a compressed component using versions of Dyalog APL earlier than 14.0 will generate an error:

  • All 13.2 and 13.1.14842 and later:
    DOMAIN ERROR: Array is from a later version of APL
  • 13.1 before revision 14842:
    FILE COMPONENT DAMAGED: Incoming array is invalid
  • 13.0 and 12.1 after revision 11154:
    DOMAIN ERROR
  • 13.0 and 12.1 before revision 11154:
    FILE COMPONENT DAMAGED

TCPSockets and Conga

TCPSockets and Conga can be used to communicate between differing versions of Dyalog APL and are subject to similar limitations to those described above for component files.

Auxiliary Processors

A Dyalog APL process is restricted to starting an AP of exactly the same architecture from the same operating system. In other words, the AP must share the same word-width and byte-ordering as its interpreter process.

Session Files

Session (.dse) files can only be used on the platform on which they were created and saved.


Announcements

Withdrawal of Support for Version 13.2

The supported Versions of Dyalog APL are now Version 15.0, 14.1, and Version 14.0. Version 13.2 and earlier are no longer supported.

Withdrawal of Support for Old Workspaces

Dyalog APL workspaces saved by Version 10.1 (released 2004) and earlier may not be loaded using Version 15.0. Only workspaces saved by Version 11.0 and later may be loaded. Contact Dyalog support if this affects you.

Withdrawal of Support for Windows XP

Version 15.0 is not supported under Windows XP.

Withdrawal of Support for .NET earlier than Version 4.

Version 15.0 requires .NET 4. As no other versions of .NET are supported, the .NET Framework tab has been removed from the Options/Configure dialog.

dfns workspace now frozen in Classic Editions

Dyalog does not intend to enhance the dfns workspace in Classic Editions any more; only bug fixes will be made. The workspace will continue to be developed for Unicode Editions; the latest version of the dfns workspace is as ever available from http://dfns.dyalog.com.

Planned Operating System Requirements for the next version

Dyalog Ltd expects that the next version of Dyalog will require the following minimum platform requirements:

Operating System | Version
Microsoft Windows | Vista or Server 2008
AIX | 7.1 on POWER 7
Linux | RedHat/Centos 6 or equivalent
OS X | OS X Yosemite 10.10.x

Further information will appear on the Forums as and when available.

Planned Hardware Requirements for next version

The same as Dyalog 15.0.

C32 and C64 Calling Conventions

⎕NA used to support syntax such as dllname.C32, which specified that 32-bit calling conventions were to be used.

This has not been necessary for several versions; in Version 15.0 the interpreter checks that if this syntax is present and that it is one of .C32 or .C64, but otherwise ignores it.

Dyalog intends to remove all traces of this syntax from supplied APL code (either in workspaces or in scripts) and it is recommended that users do the same. Dyalog may in future generate an error when this syntax is found, rather than simply ignoring it.

Copies of the files namespace and code that manipulates the registry are most likely to contain this syntax.

Default Value for Random Link ⎕RL

The default value for ⎕RL will be changed to ⍬ in the next major release.

Withdrawal of Random Number Generator I-Beam 16807⌶

The Random Number Generator I-Beam 16807⌶ is deprecated and will be removed in the next release.

SharpPlot workspace (Classic Edition)

The sharpplot.dws workspace is no longer supported in Classic Edition and has been removed from the Classic Edition build.

Array Editor

Version 1.1.0.91 of the Array Editor is included in the Unicode version 15.0 for Windows installation images.

Syncfusion libraries

Version 14.1.0.41 of the Syncfusion libraries are included in the version 15.0 for Windows installation images.

dyalogdata4.5.dll

dyalogdata4.5.dll is no longer needed. The bridge dll has been compiled with .NET 4.0 which includes the required functionality.

The use of GR to mean German

For reasons that are over 20 years old, the BuildSE workspace and the input and output translate tables in Classic installations use the abbreviation "GR" to represent "German". In the next version Dyalog intends to replace all such occurrences with "DE".

WSEXT parameter

The default value for WSEXT on non-Windows platforms has been changed so that it favours extensions. On AIX and Linux the default WSEXT is now .dws:.DWS:; on OS X it is .dws:.

Trailing directory delimiters

In version 15.0 all environment variables or registry entries which contains a directory or directories have been made consistant in that there are no trailing directory delimeter. This affects the dyalog registry entry.

Namespaces and External Variables

From version 15.0 onwards it is no longer possible to assign namespaces and other ⎕NL 9 objects, nor the ⎕OR of such objects to external variables. Earlier versions could make such assignments, but were apt to lead to APL terminating abnormally, or the external variable on disk not being correctly updated.


Performance Improvements

As part of the ongoing Performance Quality Assurance project , Version 15.0 includes a number of performance improvements as summarised in the following table.

Expression | Factor | Comments
↑x | 5-12 | for elements with the same rank and same shape with possible exception of leading axis
↓x | 1-1.75 | AKA ⊂⍤1⊢x
⊂⍤r⊢x | 1-1.75 | AKA ⊂[(-r)↑⍳⍴⍴x]x
↓[a]x | 1.5-5 |
⍕b | 1-40 |
⍕int8 | 1-10 |
x⍕b | 1-300 | for x having 1 or 2 elements
x⍕int8 | 1-180 | for x having 2 elements, the first of which is non-zero
b∘.f x | 1-8 |
b⊥b | 3-∞ | equivalent to +/∧\⌽b, the number of trailing 1s in b
b(≢¨⊂)x | TBA | partition pseudo operator
b(f/¨⊂)x | TBA | partition pseudo operator, for f one of + × ⌈ ⌊ ∧ ∨ ≠ =
>/b ≥/b ⍱/b ⍲/b </b ≤/b | 1800-87e3 |
∧/b ∨/b | 1-∞ |
+/b | 1-8 |
,/y | 1-∞ | for arguments with arrays with rank > 1
2 f/ x | 1.2-4 | for vector x and f one of + - × ⌈ ⌊ = ≠ < ≤ ≥ = ∨ ∧ ⍲ ⍱
n,/[a]x | 1-50 | for simple array x
n+/[a]x n≠/[a]b n=/[a]b | TBA |
n⌈/[a]x n⌊/[a]x | TBA |
x∘.,y | 2-4 |
∧.∧ ∨.∨ | 5-∞ | for Boolean vector arguments
x⍳⍤1 0⊢y | 13 |
x⌷⍤r⊢y | 1-370 | where the effective left rank is 0
b[;;i] b[i] | 1-4 | Boolean column indexing and Boolean vector indexing
x[i;;] | 2-18 | row (major cell) indexing AKA (⊂i)⌷xAKA i⌷⍤0 15⊢x
+z, -z y+z y-z ○z | 1-6 | complex arguments; greatest speed-ups are only on Linux
x≡y x≢y | 1-8.7 | 64-bit floats or complex arguments
x≡y x≢y | 1-1.4 | non float simple arguments
x⊥y | 1-26 | special case for scalar or vector x
x⊤y | 1-3.3 | special case for integer vector x and integer y
f\[a]x | 2-20 | f is + × (deferred from 14.0)
-\[a]x ÷\[a]x | 1-∞ |
⍺⍕⍵ ⍺ ⎕FMT ⍵ | varies | E F and I formats, non-DECF data
⍋p | 10-50 | for permutations
⍒p | 10-50 | for permutations
⍋⍵ ⍒⍵ | 1-1.7 | result in smallest datatype
⍋⍵ ⍒⍵ | 2-20 | for small-range arguments
÷⍵ | 1-1.1 | for non .NET systems only
≡⍵ | 2-∞ |
{⍺,f⌿⍵}⌸ {⍺(f⌿⍵)}⌸ | TBA | for f one of + ⌈ ⌊ = ≠ ∨ ∧
x*b | 1-90 | scalar x and Boolean b
f⍤r | 1-1.5 | general case of rank operator on small arguments
f⌸ | 1-1.8 | general case of key operator on small arguments and/or in monadic case
f.g | 1-1.6 | general case of inner product
f¨ |  | f is any monadic or dyadic scalar function
≢¨⍵ | 25 |
f/¨⍵ | 1-16 | f one of + ⌈ ⌊ ∧ ∨ = ≠
⍺+.×⍵ | 1-11 | Boolean vector ⍺ and Boolean array ⍵; also +.∧
⍺+.f ⍵ | 4 | Boolean array ⍺ and Boolean vec ⍵, for f one of × ∧ > < ≠ ∨ ⍱ = ≥ ≤ ⍲
⌈/⍵ ⌊/⍵ | 1-29 | for non-vector ⍵
+/x | 6-35 | for integer x
0∊b 1∊b | 1-400 |
⌽[a]x | 1-3.7 |
⍋b {⍵[⍋⍵;]}b | 1-7 | also ⍒ instead of ⍋; for boolean b with a multiple of 8 columns
⍋b {⍵[⍋⍵;]}b | 1-5 | also ⍒ instead of ⍋; for boolean b with 1-element major cells
⍋b {⍵[⍋⍵;]}b | 5-27 | also ⍒ instead of ⍋; for boolean b with NOT a multiple of 8 columns
?m⍴n | 1.1-1.4 | result is smallest datatype based on n >
x∧.=1 | 1-100 | also 1∧.=x, x∨.≠1, 1∨.≠x; also 0 instead of 1
⍉bm | 1.2 | POWER8 only, transposing a matrix with multiple of 8 rows and columns
y∊x | 3-17 | where x and/or y have 1- or 2-byte items
y~x | 3-12 | where x and/or y have 1- or 2-byte items
y∩x | 3-12 | where x and/or y have 1- or 2-byte items
x∪y | 3-13 | where x and/or y have 1- or 2-byte items
∪x | 3-16 | where x has 1- or 2-byte items

New Idiom

The following new idiom is recognised:

Expression | Description
XA↓⍨←NS | This idiom applies only when NS is negative, when it removes the last -NS items from XA along its leading axis. For example, if NS is ¯3 then the idiom removes the last -¯3 (i.e. 3) items.


Bug Fixes

A number of bug fixes implemented in Version 15.0 may change the way that existing code operates and are therefore documented in this section.

011659: Modified, selective assignment returns wrongly enclosed result

In 14.1 and earlier the interpreter incorrectly enclosed the result of a modified, selective assignment. This has been fixed in 15.0.

15.0 behaviour:

      var←⊂'Dyalog'
      'APL'≡(⊃var),←'APL'
1
      var
 DyalogAPL

14.1 and earlier behaviour:

      var←⊂'Dyalog'
      'APL'≡(⊃var),←'APL'
0
      var
 DyalogAPL

Change to Component File Names

There were exceptions to the following rules which have been corrected:

  • The file name returned by ⎕FNAMES should be precisely the same as that which was specified when the file was tied.
  • The left argument to ⎕FERASE should be identical to the name used to tie the file.

Examples of errors that have been fixed in Version 15.0

      t←'a.DCF' ⎕TIE 0 ⋄ ⎕FNAMES
a     ⍝  WAS INCORRECT, SHOULD BE a.DCF
      t←'a' ⎕FTIE 0 ⋄ 'a.DCF' ⎕FERASE t
⍝ INCORRECTLY DELETED THE FILE

      t←'a.DCF' ⎕FTIE 0 ⋄ 'a' ⎕FERASE t
⍝ INCORRECTLY DELETED THE FILE

Length of left argument of ⎕WC limited to 2*15

The maximum length of the left argument of ⎕WC is now limited to 2*15 in order to eliminate a number of system crashes.

Change to User-Defined Event Message

Previously, if you created a GUI object using ⎕NEW to which you attached a user-defined event, the first element of the event message (that identifies the object) reported for that event was a generic character vector. It is now a ref.

      f←⎕NEW ⊂'Form'
      f.on999←'foo'

     ∇ foo m
[1]    m
     ∇

      ⎕NQ f 999
 #.[Form]  999

Correction to ⎕FIX

⎕FIX now handles the inheritance of system variables by sub-namespaces correctly.

Example:

      script←':Namespace ML2' '⎕ML←2'
      script,←':Namespace NOML' ':EndNamespace'
      script,←⊂ ':EndNamespace'
      ↑script
:Namespace ML2
⎕ML←2
:Namespace NOML
:EndNamespace
:EndNamespace
      ⎕ML←1
      ⎕FIX script
      ML2.NOML.⎕ML
2

In Version 14.1, ML2.NOML.⎕ML is 1.

dfns no longer accept 3 or more colons in statements

In version 14.1 and earlier expressions such as

      {1::::3}

were treated as valid. In version 15.0 such expressions will generate a SYNTAX ERROR.

Change to behaviour of selective modified assignment

In version 14.1 and earlier the result of some selective modified assignments was incorrectly nested. This has been fixed in 15.0. For example in 14.1:

      text←⊂'Dyalog '
      'APL'≡(⊃text),←'APL'
0

In version 15.0 the result is correctly not enclosed:

      text←⊂'Dyalog '
      'APL'≡(⊃text),←'APL'
1

Comparisons involving the prototype of Null Item

In version 14.1 and earlier expressions such as

      (0⍴⎕NULL)≡0⍴⎕NULL

or

      ⎕null≡⊃0⍴⎕null

incorrectly generated NONCE ERRORs. In version 15.0 onwards the above expressions both return 1.

Note that comparisons involving the prototype of # or ⎕SE will still generate a NONCE ERROR.

Classic Edition: 'UTF-8'⎕UCS errors

In version 14.1 and earlier in Classic interpreters an attempt to convert an invalid UTF-8 sequence into a Unicode code point resulted in a TRANSLATION ERROR. In 15.0 onwards a TRANSLATION ERROR is only generated if the resulting (valid) Unicode code point is not in ⎕AVU. Attempts to convert invalid UTF-8 sequences generate DOMAIN ERRORs; the same behaviour as in Unicode interpreters.

Debug modifier for user commands

Having run ]udebug on to enable debugging user commands, the user command must be called with "-" as the last modifier. That is, the "-" must be preceded by at least one space. If there is no space the "-" is assumed to be part of the preceding modifier or flag. In previous versions of SALT the "-" was treated as an instruction to debug the user command whether or not it is preceded by a space.

⎕SI and ⎕XSI can return the wrong name when an inner dfn is called via an operator

In earlier versions of Dyalog ⎕SI and ⎕XSI could return the wrong name when an inner dfn is called via an operator; ⎕LC would however report the correct line numbers. This has been fixed in Version 15.0.

Example

     ∇r←hoo;foo;goo;dop
      dop←{
          r←1
          +⍺⍺ ⍵
      }
      foo←{
      ⍝ comment
      ⍝ comment1
      ⍝ comment2
      ⍝ comment3
      ⍝ comment4
          goo←{
              +{
                    ⎕XSI,¨⎕LC
              }⍵
          }
          +goo dop ⍵
      }
      r←foo 1
     ∇
      hoo ⍝ Version 15.0
  #.foo 8  #.foo 7  #.dop 2  #.foo 11  #.hoo8 18
      hoo ⍝ Version 14.1 and prior. Wrong.
  #.goo 8  #.goo 7  #.dop 2  #.foo 11  #.hoo 18


Native Look and Feel and the Dyalog Session

During development, both the Dyalog Session and the Dyalog APL GUI will display native style buttons, combo boxes, and other GUI components if Native Look and Feel is enabled. The option is provided in the General tab of the Configuration dialog and in Version 15.0 onwards is enabled by default.

Furthermore, from Version 14.1 onwards, the appearance of the Session tool buttons on the Session, Editor, Tracer and other windows is different according to whether or not Native Look and Feel is enabled.

Native Look and Feel Enabled

Native Look and Feel Disabled


Component Files without File Extensions

When locating a component file where no file name extension has been explicitly provided, the new CFEXT parameter is used to identify the corresponding file.

This parameter specifies component file filename extensions.

CFEXT is a string that specifies a colon-separated list of one or more extensions, including any period (".") which separates the extension from its basename.

If undefined, CFEXT defaults to .dcf: on Windows and OS X, and .dcf:.DCF: on all other platforms.

Creating a Component File

If the new file name specified for ⎕FCREATE, ⎕FCOPY or ⎕FRENAME contains no extension, the first extension in CFEXT will be added.

Tieing a Component File

If the component file name specified for ⎕FTIE, ⎕FSTIE or ⎕FCHK does not end with a file extension, the corresponding file is located by appending the specified file name with each extension in CFEXT in turn until the file is found.

Consequential Change to ⎕FLIB

As a result of the implementation of CFEXT, ⎕FLIB now reports all file extensions. Previously, ⎕FLIB removed "standard" file extensions .dcf and .DCF.


IDE Enhancements

Disable traps in session

There is a new menu item on the Options menu labelled Disable traps in session. This is designed to prevent undesirable behaviour when an expression executed in the session inadvertently triggers a suspended trap expression.

This option has no effect on the behaviour of error-guards in dfns.

If there is a suspension on the stack and the suspended code is within a :Trap block or contains a localised ⎕TRAP, this option disables the trap.

Example

     ∇ r←Recip x
[1]    :Trap 11
[2]        r←÷x
[3]    :Else
[4]        r←1
[5]    :EndTrap
     ∇

      Recip 3
0.3333333333
      Recip 0
1
      2 ⎕STOP 'Recip'
      Recip 0

Recip[2]
      )SI
#.Recip[2]*

Now there is a suspended :Trap on the stack set to fire when a DOMAIN ERROR (error number 11) is generated.

This can lead to undesirable behaviour if an expression executed directly in the Session, or within a function executed from the Session, causes a DOMAIN ERROR.

In Versions prior to Version 15.0, or if the new option to Disable traps in the session is OFF, any expression that generates a DOMAIN ERROR will invoke the suspended :TRAP. In this case, that will cause the suspended function to execute the :Else clause and return the value 0.

      'a'+2
1

However, if the option to Disable traps in the session is ON, the system will ignore the :Trap and the DOMAIN ERROR will be handled as if it were not there:

      'a'+0
DOMAIN ERROR
      'a'+2
     ∧

Note that this behaviour can also be controlled by calling 600⌶. See Trap Control.

Editor: Syntax Menu

There is a new Syntax Menu for the Editor.

The Syntax menu illustrated above provides options to specify how the data displayed in the Editor window is to be syntax coloured. For workspace objects, the default is APL for functions and operators, and Nothing for variables.

Item | Syntax Colour as
Nothing | Variable
APL | Function
JSON | JSON array
XML | XML array

Editor: Edit Menu

There are two new options on the Edit menu of the Editor.

Item | Description
Reformat Scripts Automatically | If checked, the Editor will automatically reformat a Dyalog script when it loads it.
Highlight All Matches | If checked, all strings in the object being edited that match the search string are highlighted. The highted items change dynamically as the seacrh string is entered or changed.

Editor: Compiler Errors

The View Menu of the Editor now has an option Compiler Errors which, if enabled, identifies which lines of a function failed to compile.

Aligning Comments

Comments which are preceded only by white space (i.e. in lines which contain no executable code) are ignored (remain unaltered) when comments are aligned, unless only such lines are selected.

Hitting <F1> immediately to the right of ⎕ or :

In earlier versions on Windows, hitting <F1> on or immediately to the right of a ⎕ or : result in the help system being opened for ⎕ or : respectively. In version 15.0 the help system will be opened for the system object or control structure respectively.

Altering the hint on SysTray icons

"SysTray" has been added to the list of Window Names for which the caption can be set. This defines the hint that appears when hovering over Dyalog icons in the System Tray, and can be used to identify more easily which icon is associated with which Dyalog process. Dyalog suggests including "{PID}" to the caption of both the SysTray and the Session. See Window Captions.


DateTime Enhancement

To illustrate the extension for DateTime objects, the following example has been added to the section on Data Binding in the chapter on Windows Presentation Foundation in the .NET Interface Guide: .

Example 6a (Casting to DateTime)

This example is similar to Example 6 but illustrates how numeric data in ⎕TS format can be converted to DateTime type.

The XAML

The XAML shown below describes a Window containing a StackPanel, inside which is a ListBox.

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DateTimes using ⎕TS data"
    SizeToContent="WidthAndHeight" >
    <StackPanel>
         <TextBlock Text="Some High Tides at Portsmouth, England"
          FontSize="18" Margin="5"/>
         <ListBox Name="TideTimes" Height="200"
          Margin="5" />
    </StackPanel>
</Window>

The APL Code

The function Tides is shown below.

     ∇ Tides;⎕USING;win;dt;Highs
[1]    ⎕USING←'System'
[2]    win←LoadXAML XAML_Tides
[3]    win.times←win.FindName⊂'TideTimes'
[4]    Highs←(⊂2016 2 18),¨(7 9)(8 44)(19 47)(21 47)
[5]    Highs,←(⊂2016 2 19),¨(8 17)(10 12)(20 51)(22 51)
[6]    dt←7↑¨Highs
[7]    win.times.ItemsSource←DateTime(2015⌶)'dt'
[8]    sink←win.ShowDialog
     ∇

Tides[3] uses FindName to obtain a ref to the ListBox (defined in the XAML) named TideTimes:

[3]    win.times←win.FindName⊂'TideTimes'

Tides[4-5] creates a vector of integer vectors each of which species the time and date of a high tide at Portsmouth. Tides[6] extends each to 7-elements, which is required to represent a DateTime object.

Then, Tides[7] creates a binding source object from this array and assigns it to the ItemsSource property of the ListBox. Note that the left argument DateTime specifies that the data be cast to that type.

[7]    win.times.ItemsSource←DateTime(2015⌶)'dt'

Testing the Data Binding

      )LOAD wpfintro
      DataBinding.NetObjects.Tides


Other Changes

Changes to ⎕R and ⎕S

The PCRE engine used to support ⎕R and ⎕S has been upgraded from version 8.12 to 8.37 and includes a number of bug fixes in the engine. The full list of changes to the engine is at: http://pcre.org/original/changelog.txt.

The options InEnc and OutEnc have been changed to provide compatibility with ⎕NGET and ⎕NPUT.

⎕R and ⎕S now support the specification of characters in transformation strings using the syntax \x{nnnn}, i.e.

\x{nnnn} represents a Unicode code point; nnnn is a hexadecimal sequence of characters yielding a value between 0x1 and 0x0FFFFFFF.

Change to )SI

As a consequence of performance improvements, certain primitive operators including Commute, Axis and some cases of Outer Product are no longer reported by )SI and ⎕STACK.

Version 15.0 Version 14.1 and Prior
      2 foo⍨ 3
SYNTAX ERROR
foo[2] ∘
      ∧
      )SI
#.foo[2]*
      ⎕STACK
      *
 ∇foo
      *

      2 foo⍨ 3
SYNTAX ERROR
foo[2] ∘
      ∧
      )SI
#.foo[2]*
⍨
      ⎕STACK
      *
 ∇foo
      ⍨
      *


Language Enhancements

Language Changes

The following table summarises the main changes to language features in Version 15.0.

Function | Descritpion | Change
R←f/[K]Y | Reduce | Enhanced
⎕RL | Random Link | Enhanced
⎕MKDIR | Make Directory | NEW
⎕NDELETE | Native File Delete | NEW
⎕NEXISTS | Native File Exists | NEW
⎕NGET | Read Text File | NEW
⎕NINFO | Native File Information | NEW
⎕NPARTS | File Name Parts | NEW
⎕NPUT | Write Text File | NEW


Changes to I-Beams

I-Beam Changes

In the following tables, A is an integer that specifies the type of operation to be performed.

The column labelled O/S indicates if a function applies only on Windows (W) or only on non-Windows (X) platforms.

I-beam functionality added to Version 15.0.

A | Derived Function | O/S
180 | Canonical Representation |
400 | Compiler Control |
600 | Trap Control |
819 | Case Convert |
1500 | Hash Array |
2014 | Remove Data Binding | W
2016 | Create .NET Delegate | W
2041 | Override COM Defrault Value | W
2501 | Discard thread on exit | W
2502 | Discard parked threads | W
3502 | Manage RIDE Connections |
5176 | List Loaded Files |
5177 | List Loaded File Objects |
8415 | Singular Value Decomposition |

Error Messages

When attempting to use I-Beam with an unsupported operation value, Version 15.0 now reports three different error messages:

  • Invalid I-Beam function selection
  • I-Beam function xxx has been withdrawn
  • I-Beam function xxx is not supported by this interpreter

This allows the user to distinguish between operation values that have never been used, those that have been used in earlier versions but are no longer included in the current version, and those that are valid in other editions or on other platforms other than the current interpreter.


GUI Enhancements

The following table summarises the main changes to GUI features in Version 15.0.

Name | Change
DISPID |
Native look and feel | Default changed to enabled
GetFocusObj | New method
SetEventInfo | Enhanced to set DISPID
SetFnInfo | Enhanced to set DISPID
SetPropertyInfo | Enhanced to set DISPID


DISPID

DISPID (Dispatch ID)

COM objects created by Dyalog (OLEServer and ActiveXControl objects) export their members (methods, properties and events) using the standard IDispatch interface.

Using this interface, a client application may discover the names and parameters of the members supported by an object at run-time, and then access them by name. Alternatively, a client application may compile references to the object's members in advance using their Dispatch IDs or DISPIDs.

Prior to Version 14.1, Dyalog assigned all DISPIDs automaticallyAn automatically assigned DISPID is its index into the list of the names of the object's members in alphabetic order, and may therefore change when this list is altered in any way. 1, making it impractical for them to be compiled into client applications.

From Version 14.1 onwards, the SetFnInfo, SetPropertyInfo and SetEventInfo methods allow the Dyalog programmer to assign DISPIDs so that they may be used directly by client applications. The specified DISPID must be a non-zero integer. The special value ¯1 causes Dyalog to assign the DISPID automatically as before.

Note

Each of the DISPIDs exported by a COM object must be unique. Furthermore, the behaviour of a COM object with non-unique DISPIDs is undefined. Non-unique DISPIDs may prevent the COM object from being registered (with or without generating an error) or may cause a run-time failure. If Dyalog assigns all the DISPIDs of an object, they will be unique. If you choose to allocate your own DISPIDs to any of the members of a Dyalog COM object, the responsibility to ensure that they are all unique is yours. In this case, Dyalog does not guarantee nor check for uniqueness.


UNIX Specific Release Notes

Summary

This section summarises the changes specific to Dyalog APL Version 15.0 on UNIX-based platforms. This list currently consists of:

  • AIX
  • Linux (including the Raspberry Pi)
  • OS X

Hardware Requirements

AIX

For AIX, Version 17.0 requires AIX 6.1 or higher, and a POWER6 chip or higher.

Raspberry Pi

On the Raspberry Pi, Dyalog (32-bit Unicode) supports Raspbian Wheezy and Jessie.

Non-Pi Linux

For non-Pi Linux, Version 17.0 only exists as 64-bit interpreters - there are no 32-bit versions. It is built on RedHat 6, and runs on all recent distributions, including Ubuntu 14.01 and openSUSE 13.2. Contact Dyalog for information about other platforms.

macOS/Mac OS X

Version 15.0 requires Mac OS X Yosemite or El Capitain or macOS Sierra. The target Mac must have been introduced in 2010 or later.

Obtaining the exit code from ⎕SH

In Version 15.0, ⎕DMX.Message contains the exit code from all calls to ⎕SH which result in an error:

      z←⎕SH'exit 17'
DOMAIN ERROR
      ⎕DMX.Message
Command interpreter returned failure code 17

In previous versions of Dyalog APL it was necessary to use an expression such as

      ⎕SH'mycmd; echo $? ; exit 0'

to obtain the exit code.

Dyalog intends to return the exit code in a more usable form in a future version.

Suppressing error traps in the session

600⌶ allows the user to control what happens when an error is generated in the session when there are functions suspended which have traps assigned.

Under Windows this can be toggled using a MenuItem in the session; on non-Windows platforms you must use 600⌶ to achieve the same result. Note that if SALT is active, setting 600⌶0 (disable all traps everywhere) will result in the SALT-related editor backend code suspending, which is undesirable. See the Dyalog Language Reference or the I-Beam section of the online help for more information.

RIDE 3.0 and Dyalog APL 15.0

Note that Dyalog Version15.0 supports RIDE 3 only; RIDE 2 is not supported.

The Dyalog RIDE Reference Guide details how to configure the APL session to support the underscored alphabet; contact support@dyalog.com if you wish to be able to generate key-chords which result in the underscored alphabet being entered into APL.

Linux Window Managers and APL characters

If your Linux window manager does not include support for APL characters (Gnome is an example), then the first time that you run Dyalog having started the window manager afresh, you must run

$ dyalog -kbd

Subsequent invocations of dyalog should not require this flag.

Change to event handling

The handling of events from "GUI" objects (TCPSockets and Timers) has been altered in version 15.0 on non-Windows platforms to eliminate the possibility of Dyalog hanging. In previous versions all GUI events were added to a pipe, and processed only when ⎕DQ was called. This could lead to a situation where the pipe filled, at which point Dyalog would hang. In version 15.0 the code has been changed so that at the end of each line of APL code, any valid events are moved to an internal APL message queue. This brings the non-Windows versions more in line with the Windows version of Dyalog.


Version 14.1 Key Features

Key Features

Dyalog APL Version 14.1 provides the following new features, enhancements and changes:

Performance Improvements

Version 14.1 includes a considerable amount of research and development work designed to substantially improve speed of execution. See Performance Improvements .

Language Enhancements

New Language Features

  • New :Disposable ... :EndDisposable control structure for the automatic disposal of unwanted .NET objects and resources. See Disposable Statement.

New I-Beam Features

  • A new I-Beam is provided to execute expressions under program control, which handles shy results differently than the primitive function monadic Execute. See Execute Expression.
  • A new I-Beam is provided to overwrite unused memory in the workspace in order to erase potentially secure data. See Overwrite Free Pockets.
  • A new I-Beam is provided to determine whether or not the current function was called monadically. See Called Monadically.
  • A new I-Beam is provided to report the names of dynamic link libraries loaded by ⎕NA. See Loaded Libraries.
  • A new I-Beam is provided to make a thread uninterruptible. See Mark Thread as Uninterruptible.
  • A new I-Beam is provided to spawn a .NET thread from APL thread 0. See This function determines the way that .NET calls are executed in APL thread 0. .
  • A new I-Beam function provides a faster way to reference early elements of ⎕LC. See Line Count.
  • Four new I-Beams are provided to import and export text in JavaScript Object Notation (JSON) Data Interchange FormatIETF RFC 7159 1. See I-Beam Changes.

Extensions

  • There are 2 new options for Edit Object (⎕ED). See Variants of Edit Object.
  • The arbitrary input and output system functions have been simplified and re-engineered, primarily for use in non-Windows environments. See Arbitrary Input and Arbitrary Output .

Component File System Improvements

  • File properties S and U have been added to the properties that may be set when the file is created using a function derived from ⎕FCREATE and the Variant operator ⍠. See File Create and Variant.

IDE Enhancements

  • The editor can now be used to view the values of ⍺, ⍺⍺, ⍵ and ⍵⍵. See Tracing dfn Arguments.
  • Align Comments has been extended to scripted objects. See Aligning Comments in Scripts Aligning Comments in Scripts.

GUI Enhancements

  • Version 14.1 provides a new coordinate system that automatically scales GUI windows and controls created by ⎕WC according to the scale factor set by the user's Desktop Windows Manager. See High DPI Support.
  • Version 14.1 provides support for Windows Gestures. A workspace gesturedemo.dws is provided to illustrate how to use this new feature (touch-screen required). See Gestures.
  • The Masked property has been extended to provide greater portability for ImageLists. See Masked.
  • WPF Data Binding now supports matrices. See WPF Data Binding Using Matrices.


WPF Data Binding Using Matrices

WPF Data Binding has been extended to allow you to bind APL matrices. The example shown later in this section, Example 8, is an addition to the existing documentation on WPF Data Binding. See .NET Interface Guide: Windows Presentation Foundation.

Binding a Matrix

Binding a matrix is like binding a vector of namespaces. Each row of Y represents one of a collection of instances of an object, which exports a particular set of properties for binding purposes. Each column of Y represents one of these properties.

Every row in the datasource will be of the same type (which might not be the case with an array of namespaces), and so the collection is a collection of specific things. The specific thing is a .NET type that is created dynamically and has a unique name.

Unlike variables in namespaces, the columns of an APL matrix do not have names which can be exported as properties, so this information must be provided in the left argument to (2015⌶) which also specifies their data types. If the left argument is omitted, the default names are Column1, Column2, ... and so forth and the default data type is System.Object.

So if the right argument of (2015⌶) Y is the name of a matrix, the left argument X is a matrix with as many rows as there are columns in Y. X[;1] contains the names by which each of the columns of Y will be exported as a property, and X[;2] their data types.

Values in the matrix may be scalar numbers, character scalars or vectors, or nested vectors, but each column in the matrix must be uniform.

The result R is a specific type that is created dynamically and assigned a unique name of the form Dyalog.Data.DyalogCollectionNotifyHandler`1[Dyalog.Data.DataBoundRow_nnnnnnnn]. This is suitable for binding to a WPF property that requires an IEnumerable implementation, such as the ItemsSource property of the DataGrid.

Example

mat is a matrix of numbers and is bound with default property/column names Column1, Column2, ... Column10 and the default data type of System.Object.

      mat←?20 10⍴100
      bindSource←2015⌶'mat'

Example

winelist is a matrix whose first column contains a list of wines, and whose second column their prices. The left argument is a matrix. Its first column specifies the property names by which the columns will be exported ('Name' and 'Price') and its second column, their data types (System.Object)

 winelist←Wines,[1.5]0.01×10000+?(⍴Wines)⍴10000
 info←(⍪'Name' 'Price'),⊂Object

 bindSource←info(2015⌶)'winelist'

Example

emp is a 3-column matrix which contains names, numbers and addresses. Each address is made up of two character vectors containing street and town

      emp
┌───────────────────┬──────────────────┬────────────────────┐
│John Smith         │Mary White        │T.W. Penk           │
├───────────────────┼──────────────────┼────────────────────┤
│1                  │2                 │3                   │
├───────────────────┼──────────────────┼────────────────────┤
│┌─────────┬───────┐│┌──────────┬─────┐│┌──────────┬───────┐│
││2 East Rd│Headley│││42 High St│Alton│││23 West St│Farnham││
│└─────────┴───────┘│└──────────┴─────┘│└──────────┴───────┘│
└───────────────────┴──────────────────┴────────────────────┘
      schema
┌───────┬────────────────────────┐
│Name   │(System.Object)         │
├───────┼────────────────────────┤
│Number │(System.Object)         │
├───────┼────────────────────────┤
│Address│┌──────┬───────────────┐│
│       ││Street│(System.Object)││
│       │├──────┼───────────────┤│
│       ││Town  │(System.Object)││
│       │└──────┴───────────────┘│
└───────┴────────────────────────┘

      bindSource←schema(2015⌶)'emp'


Version 14.1 System Requirements

System Requirements

Microsoft Windows

Dyalog APL Version 14.1 supports versions of Windows from Microsoft Windows XP up to and including Microsoft Windows 8.1 and Microsoft Windows Server 2012. Dyalog APL Version 14.1 will not run on earlier versions.

Microsoft .NET Interface

Dyalog APL Version 14.1 .NET Interface requires Version 2.x or greater of the Microsoft .NET Framework. It does not operate with .NET Version 1.0.

For Windows Presentation Foundation (WPF) and basic Data Binding, Version 14.1 requires .NET Version 4.0.

For full Data Binding support (including support for the INotifyCollectionChanged interfaceThis interface is used by Dyalog to notify a data consumer when the contents of a variable, that is data bound as a list of items, changes. 1), and Syncfusion, Version 14.1 requires .NET Version 4.5.

AIX and Linux

For AIX, Version 14.1 requires AIX 6.1 or higher, and a POWER5 chip or higher.

Version 14.1 is built on RedHat 5, and runs on all recent distributions, including Ubuntu 12.04 and openSUSE 12.3. Contact Dyalog for information about other platforms.

OS X

For OS X Version 14.1 requires OS X Yosemite (10.10.x) or higher.


Version 14.1 Interoperability and Compatibility

Inter-operability

Introduction

Workspaces and component files are stored on disk in a binary format (illegible to text editors). This format differs between machine architectures and among versions of Dyalog. For example, a file component written by a PC may well have an internal format that is different from one written by a UNIX machine. Similarly, a workspace saved from Dyalog Version 14.1 will differ internally from one saved by a previous version of Dyalog APL.

It is convenient for versions of Dyalog APL running on different platforms to be able to interoperate by sharing workspaces and component files. From Version 11.0, component files and workspaces can generally be shared between Dyalog interpreters running on different platforms. However, this is not always possible, for example:

  • Component files created by Version 10.1 can often not be shared across platforms, even when used by later versions.
  • Small-span (32-bit) component files become read-only when opened on a different architecture from that on which they were created.

Note however that the system function ⎕FCOPY can be used to make a logically identical copy of an old file, but the copy will be fully inter-operable.

The following sections describe other limitations in inter-operability:

Code

Code that is saved in workspaces, or embedded within ⎕ORs stored in component files, can generally only be read by the Dyalog version which saved them and later versions of the interpreter. In the case of workspaces, an load (or copy) into an older version would fail with the message:

this WS requires a later version of the interpreter.

Every time a ⎕OR object is read by a version later than that which created it, time may be spent in converting the internal representation into the latest form. Dyalog recommends that ⎕OR should not be used as a mechanism for sharing code or objects between different versions of APL

"Ordinary" Arrays

With the exception of the Unicode restrictions described in the following paragraphs, Dyalog APL provides inter-operability for arrays that only contain (nested) character and numeric data. Such arrays can be stored in component files - or transmitted using TCPSocket objects and Conga connections, and shared between all versions and across all platforms.

As mentioned in the introduction, full cross-platform interoperability of component files is only available for large-span component files.

Null Items (⎕NULL)

In Version 13.0 and earlier, an attempt to ⎕FREAD a component containing a ⎕NULL that was created by a Version 13.1 or later Dyalog APL will generate DOMAIN ERROR. ⎕NULLs can be shared between Version 14.1 and Versions 13.1, 13.2 and 14.0 provided that the interpreters have been patched to revision 23705 or higher.

Object Representations (⎕OR)

From Version 13.2 onwards, an attempt to ⎕FREAD a component containing a ⎕OR that was created by a later version of Dyalog APL will generate DOMAIN ERROR: Array is from a later version of APL.

32 vs. 64-bit Component Files

Large-span (64-bit-addressing) component files are inaccessible to versions of the interpreter that pre-dated their introduction (versions earlier than 10.1).

From version 14.0 onwards it is no longer possible to create small-span (32-bit) files; Version 14.0 and 14.1 are still able to read and write to small span files. Setting the second item of the right argument of ⎕FCREATE to anything other than 64 will generate a DOMAIN ERROR.

Note that small-span (32-bit-addressing) component files cannot contain Unicode data. Unicode editions of Dyalog APL can only write character data which would be readable by a Classic edition (consisting of elements of ⎕AV).

External Variables

External variables are implemented as small-span (32-bit-addressing) component files, and are subject to the same restrictions as these files. External variables are unlikely to be developed further; Dyalog recommends that applications which use them should switch to using mapped files or traditional component files. Please contact Dyalog if you need further advice on this topic.

32 vs. 64-bit Interpreters

From Dyalog APL Version 11.0 onwards, there are two separate versions of programs for 32-bit and 64-bit machine architectures (the 32-bit versions will also run on 64-bit machines running 64-bit operating systems). There is complete inter-operability between 32- and 64-bit interpreters, except that 32-bit interpreters are unable to work with arrays or workspaces greater than 2GB in size.

Note however that under Windows a 32-bit version of Dyalog APL may only access 32-bit DLLs, and a 64-bit version of Dyalog APL may only access 64-bit DLLs. This is a Windows restriction.

Unicode vs. Classic Editions

From Version 12.0 onwards, a Unicode edition is available, which is able to work with the entire Unicode character set. Classic editions (a term which includes versions prior to 12.0) are limited to the 256 characters defined in the atomic vector, ⎕AV).

Component files have a Unicode property. When this is enabled, all characters will be written as Unicode data to the file. The Unicode property is always off for small-span (32-bit addressing) files, as these cannot contain Unicode data. For large-span (64-bit addressing) component files, the Unicode property is set on by Unicode Editions and off by Classic Editions, by default. The Unicode property can subsequently be toggled on and off using ⎕FPROPS.

When a Unicode edition writes to a component file that cannot contain Unicode data, character data is mapped using ⎕AVU; it can therefore be read without problems by Classic editions.

A TRANSLATION ERROR will occur if a Unicode edition writes to a non-Unicode component file (that is either a 32-bit file, or a 64-bit file when the Unicode property is currently off) if the data being written contains characters that are not in ⎕AVU.

Likewise, a Classic edition (Version 12.0 or later) will issue a TRANSLATION ERROR if it attempts to read a component containing Unicode data that is not in ⎕AVU from a component file. Version 11.0 cannot read components containing Unicode data and issues a NONCE ERROR.

A TRANSLATION ERROR will also be issued when a Classic edition )LOADs or )COPYs a workspace containing Unicode data that cannot be mapped to ⎕AV using the ⎕AVU in the recipient workspace.

TCPSocket objects have an APL property that corresponds to the Unicode property of a file, if this is set to Classic (the default) the data in the socket will be restricted to ⎕AV, if Unicode it will contain Unicode character data. As a result, TRANSLATION ERRORs can occur on transmission or reception in the same way as when updating or reading a file component.

The symbols ⍤, ⍠ and ⌸ used for the Rank, Variant and Key operators respectively are available only in the Unicode edition. In the Classic edition, these symbols are replaced by ⎕U2364, ⎕U2360 and ⎕U2338 respectively. In both Unicode and Classic editions Variant may be represented by ⎕OPT.

AVU changes

The implementation of the function Right in Version 13.0 led to the discovery that ⎕AVU incorrectly defined ⎕AV[59+⎕IO] as ¤ (⎕UCS 164) rather than ⊢ (Right Tack, ⎕UCS 8866). This error has been corrected in the default ⎕AVU and in workspace AVU.dws. If you are operating in a mixed Unicode/Classic environment, this error will have caused earlier Classic editions to map ⎕AV[59+⎕IO] to the wrong Unicode character (¤). This may cause TRANSLATION ERRORs when a Version 13.0 Classic system attempts to read the data, as it will not be able to represent ¤ in the Atomic Vector.

DECFs and Complex numbers

Version 13.0 introduced two new data types; DECFs and Complex numbers. Attempts to read components of these types in earlier interpreters will result in a DOMAIN ERROR.

Very large array components

The maximum size (in bytes) of a component written by Version 12.1 and prior is 2GB. This is the size of the component as held on disk which may be different than the size reported by ⎕SIZE. In Version 13.0 the maximum size of a component written by a 64-bit interpreter is 4GB. From Version 13.2 onwards, the limit on the size of arrays or components is so large that for most practical purposes, there is effectively no limit.

An attempt to read a component greater than 2GB in 32-bit interpreters will result in a WS FULL. An attempt to read such a component in 64-bit Versions 12.0 and 12.1 patched after 1st April 2011 will result in a NONCE ERROR; earlier patches generate a FILE COMPONENT DAMAGED error.

File Journaling

Version 12.0 introduced File Journaling (level 1), and 12.1 added journaling levels 2 and 3 and checksumming. Versions earlier than 12.0 cannot tie files that have any form of journaling or checksumming enabled. Version 12.0 cannot tie files with journaling levels greater than 1, or checksumming enabled. Attempting to tie such files will result in a FILE NAME ERROR. Files can be shared with earlier versions by using ⎕FPROPS to amend the journaling and checksumming levels.

File Component Compression

Version 14.0 introduced File Component Compression; earlier versions will be able to perform all file operation on such files with the exception of being able to ⎕FREAD any compressed component. In particular, it is possible for any earlier version to ⎕FREPLACE a compressed component with a non-compressed one.

Attempting to read a compressed component using earlier versions of Dyalog APL will generate an error:

  • All 13.2 and 13.1.14842 and later:
    DOMAIN ERROR: Array is from a later version of APL
  • 13.1 before revision 14842:
    FILE COMPONENT DAMAGED: Incoming array is invalid
  • 13.0 and 12.1 after revision 11154:
    DOMAIN ERROR
  • 13.0 and 12.1 before revision 11154:
    FILE COMPONENT DAMAGED

TCPSockets

TCPSockets used to communicate between differing versions of Dyalog APL are subject to similar limitations to those described above for component files. In particular TCPSockets with 'Style' 'APL' will only be able to pass arrays that are supported by both versions.

Auxiliary Processors

A Dyalog APL process is restricted to starting an AP of exactly the same architecture. In other words, the AP must share the same word-width and byte-ordering as its interpreter process.

Session Files

Session (.dse) files can only be used on the platform on which they were created and saved.


Announcements

Withdrawal of Support for Version 13.1

The supported Versions of Dyalog APL are now Version 14.1, Version 14.0 and Version 13.2. Version 13.1 and earlier are no longer supported.

.NET Support

Support for Microsoft .NET Version 2 will be dropped in the next release of Dyalog.

Planned Operating System Requirements for the next version

Dyalog expects that the next version of Dyalog will require the following minimum platform requirements:

Operating System | Version
Microsoft Windows | Vista or Server 2008
AIX | 6.1 on POWER 6
Linux | RedHat/Centos 6 or equivalent
OS X | OS X Yosemite 10.10.x

Further information will appear on the Forums as and when available.

Planned Hardware Requirements for next version

The next version of Dyalog running on Intel or AMD processors will require at lesat SSE2 or equivalent. This affects 32 bit interpreters only.

New Method

In Version 14.0 and earlier, Dyalog APL artificially added a method named New to all .NET objects which did not have such a member. This allowed the APL programmer to create an instance of an object (such as in this example a DateTime object) by executing the statements:

      ⎕USING←'System'
      dt←DateTime.New 1949 4 30

This feature has been removed in Version 14.1. This mechanism was made redundant by the introduction of ⎕NEW, and the following syntax should be adopted:

      dt←⎕NEW DateTime (1949 4 30)

Uppercase Property

The UpperCase property of the Root object has been removed. This was previously used to force property, method and event names to be reported in upper-case.

Thread Synchronisation Method (1113⌶)

1113⌶ has been removed. All operating systems supported by Dyalog APL have semaphores, so this feature is no longer needed.

XPLookAndFeelDocker parameter

This parameter and the related check-box on the General tab of the Configuration dialog box have been removed.


Performance Improvements

The following primitives (or sub-cases thereof) are faster inVersion 14.1.

∧.= ∨.≠ +.= +.≠ ∘.≡ ∘.≢
⎕dr
⊂ ⊂[⎕io]
⍴
⍋ {⍵[⍋⍵]}
⍒ {⍵[⍒⍵]}
=\
+/ ⊢/ ⊣/ ⌈/ ⌊/
⍉
, b[i]←x
⍳ ∊ ∪ 8⌶ (≢∪)
≡⍤r ⌷⍤0 15
{⍺⍵}⌸ {⍺(≢∪⍵)}⌸ {⊂⍵}⌸ {⍺(≢⍵)}⌸ {⍺,≢⍵}⌸ {⍺}⌸ ⊣⌸

Highlights:

The interpreter now exploits some special instructions available on modern CPUs (SSE2, SSE4, BMI2). Primitives that benefit from such exploitation include +/, ⌈/, ⌊/, ⍋, {⍵[⍋⍵]}, ⍳, ∊, ∪, ⍉.

Some primitives execute faster by exploiting the following insight: x⍳x are like ID numbers; questions of identity on x can often be answered more efficiently on x⍳x than on x itself. For example, x∧.=y ←→ (x⍳x)∘.=x⍳⍉y and x∘.≡y ←→ (x⍳x)∘.=x⍳y; the longer expressions used to be faster and in Version 14.1 the short and longer expressions are equally fast.

x⍳y has special code for relational tables, matrices in which the items of a column have the same type and same rank. (If the type is floating point, the special code is invoked only if 0=⎕CT.)

The following table lists the cases for which performance improvements have been achieved in Version 14.1.

Expression | Factor | Comments
x∧.=y | 1.5- | (x⍳x)∘.=x⍳⍉y for matrix x
⎕dr | 1-3.8 | AKA squeeze
(≢∪)x | 2.8-∞ | when x is floating point, optimized code is used only when 0=⎕ct
b⊂[⎕io]x | 1.3-42 | underlies the general case of ⌸, among other things
x{⊂⍵}⌸y | 1.2 |
s⍴x | 2 | for non-pointer x which is 1, 2, 4, or 8 bytes
=\b | 1.1 | now as fast as ≠\b
⍋b and ⍒b | 1-1.7 | for Boolean vector b
⍋x and ⍒x | 1-1.6 | for x with 1-byte items
x∧.=v | 7 | for non-tolerant = and vector v with 1,2,4, or 8 bytes
x≡⍤r⊢y | 7 | for non-tolerant ≡ and one of x or y is a single cell with 1,2,4, or 8 bytes
⊢/ and ⊣/ | 3-28 | the largest factors are for Boolean arguments
⌈/ and ⌊/ | 2-20 | on POWER6 onwards AIX systems, vectors
⌈/ and ⌊/ | 1-30 | on Windows and Linux systems, vectors
+/ | 2-4 | on POWER6 and POWER7 AIX systems, 1-byte and 2-byte integer vectors
+/ | 2-5 | on Windows and Linux systems, integer vectors
x∘.≡y and x∘.≢y | 6-64 | non-simple arrays x and y not requiring tolerant comparison
⍉y | 10 | on Intel CPUs with BMI2, Boolean matrices with both dimensions a multiple of 8
999,b and b[1]←999 and similar | 2 | any expression which blows up an array from Boolean to 16-bit integer
99,b and b[1]←99 and similar | 1.7 | on Intel CPUs with BMI2, any expression which blows up an array from Boolean to 8-bit integer
x⍳y | 3-6 | on 4-byte major cells
y∊x | 4-18 | on 4-byte major cells
∪x | 4-12 | on 4-byte major cells
x⍳y | 2-4 | on k-byte major cells
x⍳y | 2.5-6 | on relational matrices
x(8⌶)y | 1-1.5 | exploit special cases for the inverted table index-of
i⌷⍤0 15⊢x | 2-250 | selecting major cells
⍋x and {⍵[⍋⍵]}x | 1-1.5 | grade/sort on small-range 4-byte integers
{⍺}⌸ and ⊣⌸ | 5-60 | special code; equivalent to extended ∪x

New Idioms

The following new idioms are recognised:

Expression | Description
≢⍴ | Rank. Note that ≢⍴ returns a scalar, whereas ⍴⍴ returns a 1-element vector.


Bug Fixes

A number of bug fixes implemented in Version 14.1 may change the way that existing code operates and are therefore documented in this section.

Change to the File Library System Function

There was an inconsistency in the result of the expression ⎕FLIB '.'. Under UNIX it returned relative path names but under Windows it returned full path names. From 14.1 it returns relative path names under all operating systems.

      'dummy1' ⎕FCREATE 1
      'dummy2' ⎕FCREATE 2
      'dummy3' ⎕FCREATE 3
      ⎕FUNTIE ⎕FNUMS

      ⎕FLIB '.'
.\dummy1
.\dummy2
.\dummy3

If the right argument specifies a full pathname, the results include the pathname as before:

      ⎕FLIB 'c:\users\pete\desktop'
c:\users\pete\desktop\dummy1
c:\users\pete\desktop\dummy2
c:\users\pete\desktop\dummy3

Change to Scripted Objects

In previous versions of Dyalog APL it was possible to specify multiple definitions of the same one-lined named dfn in a script, whereas multiple definitions of the same multi-lined dfn or tradfn would generate an error. In version 14.1 the behaviour for one-lined dfns has been brought into sync with other attempts to redefine functions and now too generates an error.

In previous versions, the expression:

   ⎕fix ':class c' 'foo←{' '1}' 'foo←{' '2}' ':EndClass'

would cause an error, whereas:

   ⎕FIX':class c' 'foo←{1}' 'foo←{2}' ':EndClass'

would work.

In Version 14.1, both expressions correctly generate an error.


File Create and Variant

The following properties have been added to those that may be set using the Variant Operator:

  • 'U' - Unicode; 0 or 1
  • 'S' - File Size (span); 64

The principal option remains as follows; in all cases U and S are not changed.

  • 0 - sets ('J' 0) ('C' 0)
  • 1 - sets ('J' 1) ('C' 1)
  • 2 - sets ('J' 2) ('C' 1)
  • 3 - sets ('J' 3) ('C' 1)

For example,

      'newfile' (⎕FCREATE ⍠3) 0
1
      'SEUJCZ' ⎕FPROPS 1
64 0 1 3 1 0

Alternatively:

      JFCREATE←⎕FCREATE ⍠ 3

will name a variant of ⎕FCREATE which will create component file with level 3 journaling, and checksum enabled. Then:

      'newfile'JFCREATE 0
1


File Copy and Variant

⎕FCOPY allows you to specify properties for the new file via the variant operator ⍠ used with the following options:

  • 'J' - journaling level; a numeric value.
  • 'C' - checksum level; 0 or 1.
  • 'Z' - compression; 0 or 1.
  • 'U' - Unicode; 0 or 1
  • 'S' - File Size (span); 64

The Principal Option is as follows:

  • 0 - sets ('J' 0) ('C' 0)
  • 1 - sets ('J' 1) ('C' 1)
  • 2 - sets ('J' 2) ('C' 1)
  • 3 - sets ('J' 3) ('C' 1)

Examples

      newfid←'newfile' (⎕FCOPY ⍠3) 1

      'SEUJCZ' ⎕FPROPS newfid
64 0 1 3 1 0

Alternatively:

      JFCOPY←⎕FCOPY ⍠ 3

will name a variant of ⎕FCREATE which will create component file with level 3 journaling, and checksum enabled. Then:

      newfid←'newfile' JFCOPY 1

Note: Setting ('U' 0) (no Unicode support) is discouraged as it may cause the copy to fail with a TRANSLATION ERROR. Similarly using a Classic interpreter to ⎕FCOPY files may result in TRANSLATION ERRORs.


IDE Enhancements

Aligning Comments in Scripts

The alignment of comments has been extended to scripted objects. If the user is editing a script, selects one or more lines in the script, and chooses Align Comments from the Session pop-up menu, the comments in the selected lines are aligned.

If no lines are selected, and the user chooses Align Comments:

  • If the cursor is in a line of a function or operator, all of the comments within that function are aligned. If the function is a dfn, all of the comments within the same capsuleA capsule is defined as the outermost dfn in a set of nested dfns. 1 are aligned.
  • If the cursor is in a line that is not in a function, all of the comments between the end of the preceding function (or the start of the script) and the beginning of the next function (or the end of the script) are aligned.

Tracing dfn Arguments

It is now possible to view the value of ⍺, ⍺⍺, ⍵ and ⍵⍵ when tracing a dfn, using the mouse or using )ED or ⎕ED. If you open an edit window on them it will be read-only.

Tracing Blank Lines and Comments

It is now possible to separately specify whether or not the Tracer should skip blank lines and comments.

See Trace/Edit Tab and SkipBlankLines.


Workspaces without File Extensions

When locating a workspace where no file name extension has been explicitly provided, the new WSEXT parameter is used to identify the corresponding file.

This parameter specifies workspace filename extensions. It complements the WSPATH parameter in that together they determine the file search order to satisfy )LOAD or )COPY; it also specifies the filename extension to add on )SAVE or )CONTINUE if none is explicitly provided.

WSEXT is a string that specifies a colon-separated list of one or more extensions, including any period (".") which separates the extension from its basename.

If undefined, WSEXT defaults to .dws: on Windows and OS X, and :.dws:.DWS on all other platforms.

Loading a Workspace

If the workspace name specified for )LOAD, )XLOAD, )COPY, )PCOPY, ⎕LOAD and ⎕CY, and the workspace name given on the Dyalog command line, does not end with a file extension, the corresponding file is located as follows:

The name is appended with each extension in WSEXT in turn.

  • If the resulting name is a full or relative pathname, the system tries to open the named file in the appropriate directory.
  • If the resulting name contains no directory information, the system looks in each of the directories specified by WSPATH.

This operation is repeated (the outer loop is the extensions specified by WSEXT, the inner loop is the list of directories specified by WSPATH) until a file matching the name is found or until the list of extensions is exhausted.

Saving a Workspace

If the workspace name specified for )SAVE or )CONTINUEis elided, the file will be saved with the name contained in ⎕WSID. If an extension was specified in the name assigned to ⎕WSID or )WSID, that extension will be used. If not, the corresponding file name is constructed by adding the first extension in WSEXT.

If the workspace name specified for )SAVE, )CONTINUE or ⎕SAVE does not end with a file extension, the corresponding file name is constructed by adding the first extension in WSEXT.

Dropping a Workspace

If the workspace name specified for )DROP does not end with a file extension, the system identifies all the files in the specified directory whose names match the workspace name for all extensions in WSEXT

If this identifies a single file match, that file is deleted. If it identifies more than one file match, the list of matching files is displayed but no file is erased.

Example:

      )lib .
pete.dws        pete1.dws

      )CMD copy pete.dws pete
1 file(s) copied.

      )lib .
pete.   pete.dws        pete1.dws

      )drop pete
Multiple possibilities:
  pete.dws
  pete.

Consequential Changes

As a result of the implementation of WSEXT, certain changes have been made to the output generated by )WSID and )LIB. No changes have been made to the behaviour of ⎕WSID, because this might have affected existing code.

Trailing Dot for Workspace Names Without File Extensions

Under Windows only, all system commands that report workspace names add a dot to any workspace name whose file name does not have an extension (see previous example).

Workspace Identification

)WSID now always reports the file extension whether it was assigned explicitly, or implicitly by the application of WSEXT.


DMX Removal of HelpUrl

Removal of HelpURL from DMX

HelpURL has been removed from the display form of ⎕DMX, although it remains as a property.

Version 14.0

      1÷0
DOMAIN ERROR: Divide by zero
      1÷0
     ∧
      ⎕DMX
 EM       DOMAIN ERROR
 Message  Divide by zero
 HelpURL  http://help.dyalog.com/dmx/14.0/General/1

Version 14.1

      1÷0
DOMAIN ERROR: Divide by zero
      1÷0
     ∧
      ⎕DMX
 EM       DOMAIN ERROR
 Message  Divide by zero


Changes to I-Beams

I-Beam Changes

In the following tables, A is an integer that specifies the type of operation to be performed.

I-Beam functionality added to Version 14.1.

A | Derived Function
85 | Execute Expression
127 | Overwrite Free Pockets
900 | Called Monadically
950 | Loaded Libraries
2017 | Identify .NET Type
2035 | Set Dyalog Pixel Type
2101 | Close .NET AppDomain
2503 | Mark Thread as Uninterruptible
2520 | Spawn .NET Thread
3500 | Send Text to RIDE-embedded Browser
3501 | Connected to the RIDE
3502 | Enable RIDE in Run-time Interpreter
7159 | JSON Import
7160 | JSON Export
7161 | JSON TrueFalse
7162 | JSON Translate Name
50100 | Line Count


Manage RIDE

Manage RIDE 3502⌶⍬

By default, the RIDE is not enabled on run-time executables.

For security reasons, enabling the RIDE is a two-step process rather than using (for example) a single environment variable. To enable the RIDE, two steps must be taken:

  1. Set the RIDE_INIT configuration parameter on the machine on which the run-time interpreter is running to an appropriate value.
  2. Execute 3502⌶⍬ in your application code

The run‑time interpreter can then attempt to connect to a RIDE client.

Note:

Enabling the RIDE to access applications that use the run-time interpreter means that the APL code of those applications can be accessed. The I-Beam mechanism described above means that the APL code itself must grant the right for a RIDE client to connect to the run‑time interpreter. Although Dyalog Ltd might change the details of this mechanism, the APL code will always need to grant connection rights. In particular, no mechanism that is only dependent on configuration parameters will be implemented.


JSON Import

JSON Import R←X(7159⌶)Y

This I-beam function has been removed in Version 17.0. See JSON Convert.

Imports text in JavaScript Object Notation (JSON) Data Interchange FormatIETF RFC 7159 1.

Y is a character vector or matrix in JSON format. There is an implied newline character between each row of a matrix.

The optional left argument X specifies the conversion format and is a scalar or a vector singleton 0, 1 or 2 as follows. If not specified, the default value is 0.

Import as Object (X is 0)

  • JSON objects are created as APL namespaces.
  • JSON null is converted to ⎕NULL.
  • JSON true is converted to the enclosed character vector ⊂'true'
  • JSON false is converted to the enclosed character vector ⊂'false'. The values for true and false can be obtained using 7161⌶.
  • If the JSON source contains object names which are not valid APL names they are converted to APL objects with mangled names. See JSON Name Mangling. 7162⌶ can be used to obtain the original name.

Example

      ⍴JSON
18 19
      JSON
{
  "a": {
    "b": [
      "string 1",
      "string 2"
    ],
    "c": true,
    "d": {
      "e": false,
      "f⍺": [
        "string 3",
        123,
        1000.2,
        null
      ]
    }
  }
}

      j←0 (7159⌶) JSON ⍝ Import JSON as namespace
      j.⎕NL 9
a
      j.a.⎕NL 2
b
c
        j.a.b
┌────────┬────────┐
│string 1│string 2│
└────────┴────────┘
      j.a.c
┌────┐
│true│
└────┘
      j.a.⎕NL 9
d
      j.a.d.⎕NL 2 ⍝ Note that f⍺ is an invalid APL name
e
⍙_102_9082

      j.a.d.e
┌─────┐
│false│
└─────┘
      j.a.d.⍙_102_9082
┌────────┬───┬──────┬──────┐
│string 3│123│1000.2│[Null]│
└────────┴───┴──────┴──────┘

Import as a 4-col matrix (X is 1)

The columns contain the following:

[;1] | depth
[;2] | name (for JSON object members)
[;3] | value
[;4] | JSON type (integer: see below)
  • The representation of null, true and false are the same as for conversion format 0.
  • Object names are reported as specified in the JSON text; they are not mangled as they are for conversion format 0.

JSON types are as follows:

Type | Description
1 | Object
2 | Array
3 | Numeric
4 | String
5 | Null
6 | Boolean (true / false)

Table 53: JSON data types

Example (JSON is as before)

      1 (7159⌶) JSON
┌─┬──┬────────┬─┐
│0│  │        │1│
├─┼──┼────────┼─┤
│1│a │        │1│
├─┼──┼────────┼─┤
│2│b │        │2│
├─┼──┼────────┼─┤
│3│  │string 1│4│
├─┼──┼────────┼─┤
│3│  │string 2│4│
├─┼──┼────────┼─┤
│2│c │┌────┐  │6│
│ │  ││true│  │ │
│ │  │└────┘  │ │
├─┼──┼────────┼─┤
│2│d │        │1│
├─┼──┼────────┼─┤
│3│e │┌─────┐ │6│
│ │  ││false│ │ │
│ │  │└─────┘ │ │
├─┼──┼────────┼─┤
│3│f⍺│        │2│
├─┼──┼────────┼─┤
│4│  │string 3│4│
├─┼──┼────────┼─┤
│4│  │123     │3│
├─┼──┼────────┼─┤
│4│  │1000.2  │3│
├─┼──┼────────┼─┤
│4│  │[Null]  │5│
└─┴──┴────────┴─┘

Import as a 3-col matrix (X is 2)

The columns contain the following:

[;1] | name (for JSON object members)
[;2] | value
[;3] | JSON type (integer: see above)

Example:

       2 (7159⌶) JSON
┌┬────────────────────────────────┬─┐
││┌─┬──────────────────────────┬─┐│1│
│││a│┌─┬────────────────────┬─┐│1││ │
│││ ││b│┌┬────────┬─┐       │2││ ││ │
│││ ││ │││string 1│4│       │ ││ ││ │
│││ ││ │├┼────────┼─┤       │ ││ ││ │
│││ ││ │││string 2│4│       │ ││ ││ │
│││ ││ │└┴────────┴─┘       │ ││ ││ │
│││ │├─┼────────────────────┼─┤│ ││ │
│││ ││c│┌────┐              │6││ ││ │
│││ ││ ││true│              │ ││ ││ │
│││ ││ │└────┘              │ ││ ││ │
│││ │├─┼────────────────────┼─┤│ ││ │
│││ ││d│┌──┬─────────────┬─┐│1││ ││ │
│││ ││ ││e │┌─────┐      │6││ ││ ││ │
│││ ││ ││  ││false│      │ ││ ││ ││ │
│││ ││ ││  │└─────┘      │ ││ ││ ││ │
│││ ││ │├──┼─────────────┼─┤│ ││ ││ │
│││ ││ ││f⍺│┌┬────────┬─┐│2││ ││ ││ │
│││ ││ ││  │││string 3│4││ ││ ││ ││ │
│││ ││ ││  │├┼────────┼─┤│ ││ ││ ││ │
│││ ││ ││  │││123     │3││ ││ ││ ││ │
│││ ││ ││  │├┼────────┼─┤│ ││ ││ ││ │
│││ ││ ││  │││1000.2  │3││ ││ ││ ││ │
│││ ││ ││  │├┼────────┼─┤│ ││ ││ ││ │
│││ ││ ││  │││[Null]  │5││ ││ ││ ││ │
│││ ││ ││  │└┴────────┴─┘│ ││ ││ ││ │
│││ ││ │└──┴─────────────┴─┘│ ││ ││ │
│││ │└─┴────────────────────┴─┘│ ││ │
││└─┴──────────────────────────┴─┘│ │
└┴────────────────────────────────┴─┘

Duplicate Names

The JSON standard says that members of a JSON object should have unique names and that different implementations behave differently when there are duplicates. Dyalog handles duplicate names as follows:

  • No error is generated
  • For format 0, the last member encountered is used and all previous members with the same name are discarded
  • For other formats all duplicate members are recorded in the result matrix


JSON and APL

The JavaScript Object Notation

IETF RFC 7159 - The JavaScript Object Notation (JSON) Data Interchange Format - is a widely supported, text based data interchange format for the portable representation of structured data; any application which conforms to the standard may exchange data with any other. Note, however, that the standard describes a limited set of data types and JSON does not provide a general APL import/export mechanism. In particular:

Not all APL arrays are representable in JSON.

For example, arrays with more than one dimension cannot be represented in JSON. Of course, this does mean that applications using JSON are unlikely to use such objects; you probably will need rearrange your data into the format that is expected by the receiving application. In the case of a 2-dimensional matrix, a split will give you a vector of tuples that a JSON application is likely to expect:

      (7160⌶) 3 4⍴⍳12
DOMAIN ERROR: Array unsupported by JSON
      (7160⌶) 3 4⍴⍳12
     ∧
      (7160⌶) ↓3 4⍴⍳12
[[1,2,3,4],[5,6,7,8],[9,10,11,12]]

Not all names are valid APL names.

The names of JSON object members which would not be valid for APL are modified. See JSON Name Mangling.

Not all JSON types have exact APL equivalents

The JSON standard includes Boolean values true and false which are distinct from numeric values 1 and 0, and have no direct APL equivalent.

To represent JSON true and false types this implementation adopts the convention of using APL arrays ⊂'true' and ⊂'false' respectively. These arrays cannot otherwise be represented in JSON and allow true and false to be uniquely identified. See also: JSON TrueFalse.


JSON Export

JSON Export R←X(7160⌶)Y

This I-beam function has been removed in Version 17.0. See JSON Convert.

Exports text in JavaScript Object Notation (JSON) Data Interchange FormatIETF RFC 7159 1.

Y is the data to be exported as JSON, in one of the formats imported by 7159⌶.

If X is specified it must be a scalar or a vector containing at most 3 elements as follows:

  1. Conversion format - an integer between 0 and 2 inclusive; defaults to 0 if omitted
  2. Generate compact JSON if 0; generate formatted JSON if non-zero; defaults to 0 if omitted
  3. Tolerate data which cannot be exported as JSON if zero (only valid if conversion format is 0); error if data cannot be exported if non-zero; defaults to 1 if omitted.

The result R is a character vector.

If invalid JSON data is tolerated it is represented in R as an asterisk. This allows invalid data to be located within the array.

The name of any namespace member that begins with ⍙ and otherwise conforms to the conversion format used for JSON object names will be included.

Example

      j
#.[JSON object]

     ⍴JS←0(7160⌶)j
94
      JS
{"a":{"b":["string 1","string 2"],"c":true,"d":{"e":false,"f⍺":["string 3",123,1000.2,null]}}}

      0 1(7160⌶)j
{
  "a": {
    "b": [
      "string 1",
      "string 2"
    ],
    "c": true,
    "d": {
      "e": false,
      "f⍺": [
        "string 3",
        123,
        1000.2,
        null
      ]
    }
  }
}

Note:

If an error is detected in the matrix input in conversion formats 1 and 2 the error description identifies the relevant row number. This is ⎕IO sensitive. Conversion format 2 allows nesting of matrices within matrices and the row may be identified by multiple comma separated numbers: the first number is the row number of the outermost matrix, the second is the row number of the next level matrix, and so on. If the matrices are nested very deeply this will be truncated to the innermost matrix row number and depth.

See also: The JavaScript Object Notation.


JSON TrueFalse

JSON TrueFalse R←7161⌶Y

This I-beam function has been removed in Version 17.0. See JSON Convert.

This function returns the value of the APL array to which the JSON values of true and false are converted by JSON Import (7159⌶). It is also the value from which the JSON values of true and false are converted by JSON Export (7160⌶).

Y is a scalar or 1-element vector with the value 0 or 1.

If Y is 1, R is the APL equivalent of JSON true. If Y is 0, R is the APL equivalent of JSON false.

This function is provided to permit the programmer to avoid hard-coding the current values used to represent JSON true and false, as these may change in the future. It is also slightly faster to use this function for comparison than to hard-code the values.

See also: The JavaScript Object Notation.

Examples

      7161⌶1
 true

      7161⌶0
 false


JSON Translate Name

JSON Translate Name R←X(7162⌶)Y

Converts between JSON names and APL names.

When 0(7159⌶) imports an entity from JSON text whose name would be an invalid APL name, the function converts the invalid name into a valid APL name using a name mangling algorithm. For details, see JSON Name Mangling. When 0(7160⌶) exports an APL namespace as JSON text, the process is reversed.

This function performs the same name mangling allowing the programmer to identify JSON entities as APL names, and vice-versa.

Y is a character vector or scalar.

X is a scalar numeric value which must be 1 or 0.

When X is 0, R is the name in Y converted, if necessary, so that it is a valid APL name. It performs the same translation of JSON object names to APL names that is performed when importing JSON.

When X is 1, R is the name in Y which, if mangled, is converted back to the original form.. It performs the same translation of APL names to JSON object names that is performed when exporting JSON.

Note: It is highly likely that the JSON-related I-beams will be superseded by a JSON system function in a future release of Dyalog APL. It is strongly recommended that you place all code that references the JSON I-beams in cover functions.

Examples:

      0(7162⌶)'2a'
⍙_50_97
      1(7162⌶)'⍙_50_97'
2a
      0(7162⌶)'foo'
foo
      1(7162⌶)'foo'
foo
      1(7162⌶)'⍙_97_'
⍙_97_

Note that the algorithm can be applied, even when mangling is not required. So:

      1(7162⌶)'⍙_97'
a

For further details, see JSON Name Mangling.


JSON Name Mangling

When Dyalog converts from JSON to APL data, and a member of a JSON object has a name which is not a valid APL name, it is renamed.

Example:

In this example, the JSON describes an object containing two numeric items, one named a (which is a valid APL name) and the other named 2a (which is not):

{"a": 1, "2a": 2}

When this JSON is imported as an APL namespace using 0(7159⌶), Dyalog converts the name 2a to a valid APL name. The name mangling algorithm creates a name beginning with ⍙, followed by the ⎕UCS of each of the characters in the JSON name preceded by an underscore (_).

      (0(7159⌶)'{"a": 1, "2a": 2}').⎕NL 2
a
⍙_50_97

When Dyalog exports JSON it performs the reverse name mangling, so:

      0 1(7160⌶)0(7159⌶)'{"a": 1, "2a": 2}'
{
  "a": 1,
  "2a": 2
}

Should you need to create and decode these names directly,7162⌶ provides the same name mangling and un-mangling operations.

      0(7162⌶)'2a'
⍙_50_97
      1(7162⌶)'⍙_50_97'
2a


Native Look and Feel

Windows Native Look and Feel is an optional feature of Windows. It is enabled by default in Dyalog Version 15.0. In previous Versions, it was disabled by default. It may be that the ability to disable Native Look and Feel cannot be supported in future versions.

When Native Look and Feel is enabled, user-interface controls such as Buttons take on a different appearance and certain controls (such as the ListView) provide enhanced features.

Dyalog Session

During development, both the Dyalog Session and the Dyalog APL GUI displays native style buttons, combo boxes, and other GUI components if Native Look and Feel is enabled. The option is provided in the General tab of the Configuration dialog.

Applications

There are two ways to disable Native Look and Feel in end-user applications.

If you use the File/Export… menu item on the Session MenuBar to create a bound executable, an OLE Server (in-process or out-of-process), an ActiveX Control or a .NET Assembly, clear the option box labelled Enable Native Look and Feel in the create bound file dialog box. See UI Guide: .

If not, set the XPLookandFeel parameter to 0, when you run the program. For example:

dyalogrt.exe XPLookAndFeel=0 myws.dws

Note that to have effect, Native Look and Feel must also be enabled at the Windows level.


UNIX Specific Release Notes

Summary

This section summarises the change specific to Dyalog APL Version 14.1 on UNIX-based platforms. This list currently consists of:

  • AIX
  • Linux (including the Raspberry Pi)
  • OS X

Trace on Error

From Dyalog 14.1 onwards UNIX-based versions of Dyalog now open the tracer windows when an error occurs in the application. This brings UNIX-based versions in line with the Windows version.

This is controlled via the environment variable TRACE_ON_ERROR, which is set in the startup script. The previous behaviour can be configured by setting this environment variable to 0 or unsetting the environment variable.

The LoadData workspace

The loaddata workspace is included with Unicode editions of Dyalog APL Version 14.1. Note that the LoadXL and SaveXL functions will not run on UNIX-based versions of Dyalog since they require OLEControls. Note also that the SQL functions (and indeed to SQAPL workspace (where included)) require ODBC drivers to be installed before they will function correctly.

RIDE_SPAWNED environment variable

On certain platforms the Dyalog RIDE spawns a Dyalog interpreter. In such cases )SH on its own, and calls to ⎕SR will apparently hang the interpreter because it is waiting for input to the old-style session. If RIDE_SPAWNED is set to 1, in these two instances an error is generated instead.


Introduction

Licences for third-party components

The software product you have received may include one or more third-party software components. Licence notices for these components are provided in Licences for third-party components.docx in the help subdirectory of the Dyalog installation directory.

Note that if your Dyalog licence permits the distribution of applications built upon Dyalog APL, or the redistribution of Dyalog APL itself, these licence notices must also be redistributed. For your convenience they are supplied as a Word document for use in your own documentation. If you have any concerns about redistributing these third party software products, please contact Dyalog to discuss your options.


ActiveXControl Children

ActiveXContainer | Animation | Bitmap
BrowseBox | Button | ButtonEdit
Calendar | Circle | Clipboard
ColorButton | Combo | ComboEx
CoolBar | Cursor | DateTimePicker
Edit | Ellipse | FileBox
Font | Form | Grid
Group | Icon | Image
ImageList | Label | List
ListView | Locator | Marker
MDIClient | Menu | MenuBar
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertySheet
Rect | RichEdit | Scroll
Spinner | Splitter | Static
StatusBar | SubForm | TabBar
TabControl | TCPSocket | Text
Timer | TipField | ToolBar
ToolControl | TrackBar | TreeView
UpDown |  |


Animation Children

Bitmap | Circle | Cursor
Ellipse | Font | Marker
Poly | Rect | Text
Timer |  |


Bitmap Children

Circle | Ellipse | Font
Image | Marker | Metafile
Poly | Rect | Text
Timer |  |


BrowseBox Children

Timer


Button Children

Bitmap | Circle | Cursor
Ellipse | Font | Marker
Poly | Rect | Text
Timer |  |


ButtonEdit Children

Circle | Ellipse | Font
ImageList | Marker | Poly
Rect | Text | Timer


Calendar Children

Cursor | Font | Menu
MsgBox | TCPSocket | Timer


Circle Children

Timer


Clipboard Children

Timer


Combo Children

Circle | Cursor | Ellipse
Font | Marker | Poly
Rect | Text | Timer


ComboEx Children

Circle | Cursor | Ellipse
Font | Marker | Poly
Rect | Text | Timer


CoolBand Children

Bitmap | BrowseBox | Button
Clipboard | Combo | ComboEx
Cursor | Edit | FileBox
Font | Grid | Group
Icon | ImageList | Label
List | ListView | Menu
Metafile | MsgBox | OCXClass
OLEClient | Printer | ProgressBar
RichEdit | Scroll | Spinner
Static | StatusBar | SubForm
TabControl | TCPSocket | Timer
TipField | ToolBar | ToolControl
TrackBar | TreeView | UpDown


CoolBar Children

CoolBand | ImageList | Menu
Timer |  |


Cursor Children

Timer


DateTimePicker Children

Cursor | Font | Menu
MsgBox | TCPSocket | Timer


Edit Children

Circle | Cursor | Ellipse
Font | Marker | Poly
Rect | Text | Timer


Ellipse Children

Timer


FileBox Children

Timer


Font Children

Timer


Form Children

ActiveXControl | Animation | Bitmap
BrowseBox | Button | ButtonEdit
Calendar | Circle | Clipboard
ColorButton | Combo | ComboEx
CoolBar | Cursor | DateTimePicker
Edit | Ellipse | FileBox
Font | Form | Grid
Group | Icon | Image
ImageList | Label | List
ListView | Locator | Marker
MDIClient | Menu | MenuBar
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertySheet
Rect | RichEdit | Scroll
SM | Spinner | Splitter
Static | StatusBar | SubForm
SysTrayItem | TabBar | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolControl
TrackBar | TreeView | UpDown


Grid Children

Bitmap | BrowseBox | Button
Circle | ColorButton | Combo
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Icon | Image | Label
Marker | Menu | MsgBox
OCXClass | Poly | Rect
Spinner | Text | Timer
TrackBar |  |


Group Children

Animation | Bitmap | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
Cursor | DateTimePicker | Edit
Ellipse | Font | Grid
Group | Image | ImageList
Label | List | ListView
Locator | Marker | Metafile
Poly | ProgressBar | Rect
RichEdit | Scroll | SM
Spinner | Splitter | Static
SubForm | Text | Timer
TipField | TrackBar | TreeView
UpDown |  |


Icon Children

Timer


Image Children

Timer


ImageList Children

Bitmap | Cursor | Icon
Timer |  |


Label Children

Circle | Cursor | Ellipse
Font | Marker | Poly
Rect | Text | Timer


List Children

Circle | Cursor | Ellipse
Font | Marker | Poly
Rect | Text | Timer


ListView Children

Bitmap | Circle | Cursor
Ellipse | Font | Icon
ImageList | Marker | Poly
Rect | Text | Timer


Locator Children

Timer


Marker Children

Timer


MDIClient Children

Circle | Ellipse | Font
Marker | Poly | Rect
SubForm | Text | Timer


Menu Children

Bitmap | Menu | MenuItem
Separator | Timer |


MenuBar Children

Bitmap | Menu | MenuItem
Separator | Timer |


MenuItem Children

Bitmap Timer


Metafile Children

Circle | Ellipse | Font
Image | Marker | Poly
Rect | Text | Timer


MsgBox Children

Timer


NetClient Children

Timer


NetControl Children

NetClient OLEClient Timer


NetType Children

Bitmap | NetClient | TCPSocket
Timer |  |


OLEClient Children

Form TCPSocket Timer


OLEServer Children

Bitmap | BrowseBox | Clipboard
Cursor | FileBox | Font
Form | Icon | ImageList
Menu | Metafile | MsgBox
OCXClass | OLEClient | OLEServer
Printer | PropertySheet | TCPSocket
Timer | TipField |


Poly Children

Timer


Printer Children

Bitmap | Circle | Ellipse
Font | Icon | Image
Marker | Metafile | Poly
Rect | Text | Timer


ProgressBar Children

Bitmap | Circle | Cursor
Ellipse | Font | Icon
Marker | Poly | Rect
Text | Timer |


PropertyPage Children

Animation | Bitmap | BrowseBox
Button | ButtonEdit | Calendar
Circle | Clipboard | ColorButton
Combo | ComboEx | Cursor
DateTimePicker | Edit | Ellipse
FileBox | Font | Grid
Group | Icon | Image
ImageList | Label | List
ListView | Locator | Marker
Metafile | MsgBox | OCXClass
Poly | Printer | ProgressBar
Rect | RichEdit | Scroll
SM | Spinner | Splitter
Static | SubForm | TCPSocket
Text | Timer | TipField
TrackBar | TreeView | UpDown


PropertySheet Children

Bitmap | BrowseBox | Circle
Clipboard | Cursor | Ellipse
FileBox | Font | Icon
Locator | Marker | Metafile
MsgBox | Poly | Printer
PropertyPage | Rect | Text
Timer | TipField |


Rect Children

Timer


RichEdit Children

Bitmap | Circle | Cursor
Ellipse | Font | Icon
Marker | Poly | Rect
Text | Timer |


Root Children

Bitmap | BrowseBox | Clipboard
Cursor | FileBox | Font
Form | Icon | ImageList
Locator | Menu | Metafile
MsgBox | NetClient | NetType
OCXClass | OLEClient | OLEServer
Printer | PropertySheet | SysTrayItem
TCPSocket | Timer | TipField


Scroll Children

Circle | Cursor | Ellipse
Font | Marker | Poly
Rect | Text | Timer


Separator Children

Timer


SM Children

Cursor Timer


Spinner Children

Circle | Ellipse | Font
Marker | Poly | Rect
Text | Timer |


Splitter Children

Timer


Static Children

Circle | Cursor | Ellipse
Font | Image | Locator
Marker | Metafile | Poly
Rect | Text | Timer


StatusBar Children

Bitmap | BrowseBox | Circle
Cursor | Ellipse | FileBox
Font | Icon | Image
Marker | Poly | ProgressBar
Rect | StatusField | Text
Timer |  |


StatusField Children

Menu Timer


SubForm Children

Animation | Bitmap | BrowseBox
Button | ButtonEdit | Calendar
Circle | ColorButton | Combo
ComboEx | Cursor | DateTimePicker
Edit | Ellipse | FileBox
Font | Form | Grid
Group | Icon | Image
ImageList | Label | List
ListView | Locator | Marker
MDIClient | Menu | MenuBar
Metafile | MsgBox | OCXClass
Poly | ProgressBar | PropertySheet
Rect | RichEdit | Scroll
SM | Spinner | Splitter
Static | StatusBar | SubForm
TabBar | TabControl | TCPSocket
Text | Timer | TipField
ToolBar | ToolControl | TrackBar
TreeView | UpDown |


SysTrayItem Children

Icon Menu Timer


TabBar Children

Circle | Ellipse | Font
Marker | Poly | Rect
TabBtn | Text | Timer


TabBtn Children

Timer


TabButton Children

Timer


TabControl Children

ImageList | SubForm | TabButton
Timer |  |


TCPSocket Children

Bitmap | BrowseBox | Clipboard
Cursor | FileBox | Font
Form | Icon | ImageList
Locator | Menu | Metafile
MsgBox | OCXClass | OLEClient
Printer | PropertySheet | TCPSocket
Timer | TipField |


Text Children

Timer


TipField Children

Circle | Ellipse | Font
Marker | Poly | Rect
Text | Timer |


ToolBar Children

Bitmap | BrowseBox | Button
Calendar | Circle | Combo
ComboEx | Cursor | DateTimePicker
Edit | Ellipse | FileBox
Font | Group | Icon
Image | ImageList | Label
List | ListView | Locator
Marker | Menu | Metafile
MsgBox | OCXClass | Poly
ProgressBar | Rect | RichEdit
Scroll | SM | Spinner
Static | SubForm | Text
Timer | TrackBar | TreeView
UpDown |  |


ToolButton Children

Bitmap Timer


ToolControl Children

Bitmap | BrowseBox | Button
Combo | ComboEx | Cursor
Edit | FileBox | Font
Group | Icon | Image
ImageList | Label | List
ListView | Locator | Menu
MenuBar | Metafile | MsgBox
OCXClass | ProgressBar | RichEdit
Scroll | SM | Spinner
Static | SubForm | Timer
ToolButton | TrackBar | TreeView
UpDown |  |


TrackBar Children

Bitmap | Circle | Cursor
Ellipse | Font | Icon
Marker | Poly | Rect
Text | Timer |


TreeView Children

Bitmap | Circle | Cursor
Ellipse | Font | Icon
ImageList | Marker | Poly
Rect | Text | Timer


UpDown Children

Bitmap | Circle | Cursor
Ellipse | Font | Icon
Marker | Poly | Rect
Text | Timer |


ActiveXContainer Events

Close Create AmbientChanged


ActiveXControl Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | AmbientChanged
Select | PreCreate |


Animation Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
KeyPress | GotFocus | LostFocus
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | GestureZoom | GesturePan
GestureRotate | GestureTwoFingerTap | GesturePressAndTap
AnimStarted | AnimStopped |


Bitmap Events

Close Create Select


BrowseBox Events

Close | Create | FileBoxOK
FileBoxCancel |  |


Button Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
KeyPress | GotFocus | LostFocus
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | GestureZoom | GesturePan
GestureRotate | GestureTwoFingerTap | GesturePressAndTap
FontOK | FontCancel | Select
DropDown |  |


ButtonEdit Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | Select
BadValue | KeyError | Change
DropDown |  |


Calendar Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | SelDateChange
GetDayStates | CalendarDown | CalendarUp
CalendarDblClick | CalendarMove | Select


Circle Events

Close | Create | DragDrop
MouseDown | MouseUp | MouseMove
MouseDblClick | Help | Select


Clipboard Events

Close | Create | ClipChange
Select |  |


ColorButton Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
KeyPress | GotFocus | LostFocus
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | GestureZoom | GesturePan
GestureRotate | GestureTwoFingerTap | GesturePressAndTap
ColorChange | DropDown |


Combo Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | DropDown
Select | Change |


ComboEx Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | DropDown
Select |  |


CoolBand Events

Close | Create | DockStart
DockMove | DockRequest | DockAccept
DockEnd | DockCancel |


CoolBar Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
DockStart | DockMove | DockRequest
DockAccept | DockEnd | DockCancel


Cursor Events

Close Create Select


DateTimePicker Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | DateTimeChange
DropDown | CloseUp | Select


Edit Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | Select
BadValue | Change | KeyError


Ellipse Events

Close | Create | DragDrop
MouseDown | MouseUp | MouseMove
MouseDblClick | Help | Select


FileBox Events

Close | Create | FileBoxOK
FileBoxCancel | Select |


Font Events

Close | Create | FontOK
FontCancel | Select |


Form Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
KeyPress | GotFocus | LostFocus
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | GestureZoom | GesturePan
GestureRotate | GestureTwoFingerTap | GesturePressAndTap
StateChange | DockStart | DockMove
DockRequest | DockAccept | DockEnd
DockCancel | Select | FrameContextMenu
DyalogCustomMessage1 | FontOK | FontCancel
VScroll | HScroll | VThumbDrag
HThumbDrag |  |


Grid Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseEnter
MouseLeave | GridKeyPress | CellChange
CellMove | AddRow | AddCol
CellError | CellOver | CellDown
CellUp | CellDblClick | CellChanged
GridSelect | Expanding | Retracting
SetRowSize | SetColSize | GridCut
GridCopy | GridPaste | GridDelete
GridPasteError | GridDropSel | GridCopyError
IndexChanged | ShowComment | HideComment
ClickComment | Select |


Group Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | Select


Icon Events

Close Create Select


Image Events

Close | Create | DragDrop
MouseDown | MouseUp | MouseMove
MouseDblClick | Help | Select


ImageList Events

Close Create


Label Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
Select |  |


List Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | Select


ListView Events

Close | Create | FontOK
FontCancel | BeginEditLabel | EndEditLabel
DragDrop | Configure | ContextMenu
DropFiles | DropObjects | Expose
Help | KeyPress | GotFocus
LostFocus | MouseDown | MouseUp
MouseMove | MouseDblClick | MouseEnter
MouseLeave | MouseWheel | GestureZoom
GesturePan | GestureRotate | GestureTwoFingerTap
GesturePressAndTap | ColumnClick | SetItemPosition
ItemDown | ItemUp | ItemDblClick
GetTipText | SetColSize | Select


Locator Events

Close | Create | Locator
Select |  |


Marker Events

Close | Create | DragDrop
MouseDown | MouseUp | MouseMove
MouseDblClick | Help | Select


MDIClient Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
KeyPress | GotFocus | LostFocus
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | GestureZoom | GesturePan
GestureRotate | GestureTwoFingerTap | GesturePressAndTap
Select |  |


Menu Events

Close | Create | DropDown
Select |  |


MenuBar Events

Close Create


MenuItem Events

Close Create Select


Metafile Events

Close Create Select


NetType Events


OCXClass Events


OLEClient Events


OLEServer Events

Close Create


Poly Events

Close | Create | DragDrop
MouseDown | MouseUp | MouseMove
MouseDblClick | Help | Select


Printer Events

Close Create Select


ProgressBar Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
KeyPress | GotFocus | LostFocus
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | GestureZoom | GesturePan
GestureRotate | GestureTwoFingerTap | GesturePressAndTap
Select |  |


PropertyPage Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
KeyPress | GotFocus | LostFocus
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | GestureZoom | GesturePan
GestureRotate | GestureTwoFingerTap | GesturePressAndTap
FontOK | FontCancel | PageApply
PageCancel | PageHelp | PageBack
PageNext | PageFinish | PageChanged
PageActivate | PageDeactivate |


PropertySheet Events

Close | Create | FontOK
FontCancel |  |


Rect Events

Close | Create | DragDrop
MouseDown | MouseUp | MouseMove
MouseDblClick | Help | Select


RichEdit Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | Protected
Change | Select |


Root Events

FontOK | FontCancel | DDE
Idle | ExitWindows | ExitApp
WinIniChange | SysColorChange | DisplayChange
ActivateApp | ServiceNotification |


Scroll Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
KeyPress | GotFocus | LostFocus
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | GestureZoom | GesturePan
GestureRotate | GestureTwoFingerTap | GesturePressAndTap
Select | ThumbDrag | Scroll


Separator Events

Close Create


SM Events

Close | Create | MouseDown
MouseUp | MouseDblClick | MouseEnter
MouseLeave | Configure | Help
DragDrop |  |


Spinner Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | Spin
SetSpinnerText | Select | BadValue
KeyError | Change |


Splitter Events

Close | Create | StartSplit
Splitting | EndSplit |


Static Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | FontOK | FontCancel
Select |  |


StatusBar Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
Select |  |


StatusField Events

Close | Create | DropObjects
Select | MouseDown | MouseUp
MouseMove | MouseDblClick |


SubForm Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | StateChange
MDIActivate | MDIDeactivate | DockStart
DockMove | DockRequest | DockAccept
DockEnd | DockCancel | Select
FrameContextMenu | VScroll | HScroll
VThumbDrag | HThumbDrag |


SysTrayItem Events

Close | Create | MouseDown
MouseUp | MouseMove | MouseDblClick
BalloonShow | BalloonHide | BalloonTimeout
BalloonUserClick |  |


TabBar Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | Select |


TabBtn Events

Close | Create | FontOK
FontCancel | DropObjects | Select
MouseDown | MouseUp | MouseMove
MouseDblClick |  |


TabButton Events

Close Create Select


TabControl Events

Close Create


TCPSocket Events

Close | Create | TCPError
TCPAccept | TCPConnect | TCPRecv
TCPClose | TCPGotAddr | TCPGotPort
TCPReady |  |


Text Events

Close | Create | FontOK
FontCancel | DragDrop | MouseDown
MouseUp | MouseMove | MouseDblClick
Help | Select |


Timer Events

Close Create Timer


TipField Events

Close | Create | FontOK
FontCancel |  |


ToolBar Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | Select |


ToolButton Events

Close | Create | Help
MouseDown | MouseUp | MouseMove
MouseDblClick | Select |


ToolControl Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
MouseDown | MouseUp | MouseMove
MouseDblClick | MouseEnter | MouseLeave
MouseWheel | DockStart | DockMove
DockRequest | DockAccept | DockEnd
DockCancel |  |


TrackBar Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
KeyPress | GotFocus | LostFocus
MouseDown | MouseUp | MouseMove
Select | ThumbDrag | Scroll


TreeView Events

Close | Create | FontOK
FontCancel | DragDrop | Configure
ContextMenu | DropFiles | DropObjects
Expose | Help | KeyPress
GotFocus | LostFocus | MouseDown
MouseUp | MouseMove | MouseDblClick
MouseEnter | MouseLeave | MouseWheel
GestureZoom | GesturePan | GestureRotate
GestureTwoFingerTap | GesturePressAndTap | BeginEditLabel
EndEditLabel | Expanding | Retracting
ItemDown | ItemUp | ItemDblClick
GetTipText | Select |


UpDown Events

Close | Create | DragDrop
Configure | ContextMenu | DropFiles
DropObjects | Expose | Help
MouseDown | MouseUp | MouseMove
MouseEnter | MouseLeave | Select
Spin |  |


Splitter: Example 1
'F'⎕WC'Form' 'Vertical Splitter'('Size' 25 25)
'F.E1'⎕WC'Edit'(10 6⍴'Edit 1')('Style' 'Multi')
'F.E2'⎕WC'Edit'(10 6⍴'Edit 2')('Style' 'Multi')
'F.S'⎕WC'Splitter' 'F.E1' 'F.E2'


Splitter: Example 2
'F'⎕WC'Form' 'Horizontal Splitter'('Size' 25 25)
'F.E1'⎕WC'Edit'(5 6⍴'Edit 1')('Style' 'Multi')
'F.E2'⎕WC'Edit'(5 6⍴'Edit 2')('Style' 'Multi')
'F.S'⎕WC'Splitter' 'F.E1' 'F.E2'('Style' 'Horz')


Splitter: Example 3
'F'⎕WC'Form' 'Multiple Splitters: hierarchical using SubForms'('Size' 25 50)
'F.E1'⎕WC'Edit'(10 6⍴'Edit 1')('Style' 'Multi')
'F.SF1'⎕WC'SubForm'('EdgeStyle' 'Default')
'F.S1'⎕WC'Splitter' 'F.E1' 'F.SF1'
'F.SF1.E1'⎕WC'Edit'(10 6⍴'Edit 2')('Style' 'Multi')
'F.SF1.E2'⎕WC'Edit'(10 6⍴'Edit 3')('Style' 'Multi')
'F.SF1.S1'⎕WC'Splitter' 'F.SF1.E1' 'F.SF1.E2'

After dragging the first Splitter to the left.


Splitter: Example 4
'F'⎕WC'Form' 'Multiple Splitters: non-hierarchical'('Size' 25 50)
'F.E1'⎕WC'Edit'(10 6⍴'Edit 1')('Style' 'Multi')
'F.E2'⎕WC'Edit'(10 6⍴'Edit 2')('Style' 'Multi')
'F.E3'⎕WC'Edit'(10 6⍴'Edit 3')('Style' 'Multi')
'F.S1'⎕WC'Splitter' 'F.E1'
'F.S2'⎕WC'Splitter' 'F.E2' 'F.E3'

After dragging the first Splitter to the left.


Splitter: Example 5
'F'⎕WC'Form' 'Combining Horizontal and Vertical Splitters'
'F.E1'⎕WC'Edit'(20 6⍴'Edit 1')('Style' 'Multi')
'F.E2'⎕WC'Edit'(10 6⍴'Edit 2')('Style' 'Multi')
'F.E3'⎕WC'Edit'(10 6⍴'Edit 3')('Style' 'Multi')
'F.E4'⎕WC'Edit'(5 6⍴'Edit 4')('Style' 'Multi')
'F.E5'⎕WC'Edit'(5 6⍴'Edit 5')('Style' 'Multi')

'F.S1'⎕WC'Splitter' 'F.E1'('Style' 'Vert')
'F.S2'⎕WC'Splitter' 'F.E2'('Style' 'Horz')
'F.S3'⎕WC'Splitter' 'F.E3'('Style' 'Vert')
'F.S4'⎕WC'Splitter' 'F.E4' 'F.E5'('Style' 'Horz')


TabControl: Example 1
'F'⎕WC'Form' 'TabControl: Default'('Size' 25 50)
'F.TC'⎕WC'TabControl'

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'One'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Two'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Three'('ImageIndex' 3)

'F.TC.S1'⎕WC'SubForm'('TabObj' 'F.TC.T1')
'F.TC.S2'⎕WC'SubForm'('TabObj' 'F.TC.T2')
'F.TC.S3'⎕WC'SubForm'('TabObj' 'F.TC.T3')


TabControl: Example 2
'F'⎕WC'Form' 'TabControl: Buttons Style'('Size' 25 50)
'F.TC'⎕WC'TabControl'('Style' 'Buttons')

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'One'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Two'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Three'('ImageIndex' 3)


TabControl: Example 3
'F'⎕WC'Form' 'TabControl: FlatButtons Style'('Size' 25 50)
'F.TC'⎕WC'TabControl'('Style' 'FlatButtons')

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'One'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Two'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Three'('ImageIndex' 3)


TabControl: Example 3a
'F1'⎕WC'Form' 'TabControl: FlatButtons with FlatSeparators'('Size' 25 50)
'F1.TC'⎕WC'TabControl'('Style' 'FlatButtons')('FlatSeparators' 1)

'F1.TC.IL'⎕WC'ImageList'
'F1.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F1.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F1.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F1.TC'⎕WS'ImageListObj' 'F1.TC.IL'

'F1.TC.T1'⎕WC'TabButton' 'One'('ImageIndex' 1)
'F1.TC.T2'⎕WC'TabButton' 'Two'('ImageIndex' 2)
'F1.TC.T3'⎕WC'TabButton' 'Three'('ImageIndex' 3)


TabControl: Example 4
'F'⎕WC'Form' 'TabControl: Align Bottom'('Size' 25 50)
'F.TC'⎕WC'TabControl'('Align' 'Bottom')

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'One'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Two'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Three'('ImageIndex' 3)

'F.TC.S1'⎕WC'SubForm'('TabObj' 'F.TC.T1')
'F.TC.S2'⎕WC'SubForm'('TabObj' 'F.TC.T2')
'F.TC.S3'⎕WC'SubForm'('TabObj' 'F.TC.T3')


TabControl: Example 5
'F'⎕WC'Form' 'TabControl: Align Left'('Size' 40 30)
'F.TC'⎕WC'TabControl'('Align' 'Left')

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'One'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Two'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Three'('ImageIndex' 3)

'F.TC.S1'⎕WC'SubForm'('TabObj' 'F.TC.T1')
'F.TC.S2'⎕WC'SubForm'('TabObj' 'F.TC.T2')
'F.TC.S3'⎕WC'SubForm'('TabObj' 'F.TC.T3')


TabControl: Example 7
'F'⎕WC'Form' 'TabControl: Default Scrolling'('Size' 25 40)
'F.TC'⎕WC'TabControl'

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'First Tab'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Second Tab'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Third Tab'('ImageIndex' 3)
'F.TC.T4'⎕WC'TabButton' 'Fourth Tab'('ImageIndex' 1)

'F.TC.S1'⎕WC'SubForm'('TabObj' 'F.TC.T1')
'F.TC.S2'⎕WC'SubForm'('TabObj' 'F.TC.T2')
'F.TC.S3'⎕WC'SubForm'('TabObj' 'F.TC.T3')
'F.TC.S4'⎕WC'SubForm'('TabObj' 'F.TC.T4')


TabControl: Example 8
'F'⎕WC'Form' 'TabControl: MultiLine Tabs'('Size' 25 40)
'F.TC'⎕WC'TabControl'('MultiLine' 1)

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'First Tab'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Second Tab'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Third Tab'('ImageIndex' 3)
'F.TC.T4'⎕WC'TabButton' 'Fourth Tab'('ImageIndex' 1)


TabControl: Example 9
'F'⎕WC'Form' 'TabControl: MultiLine Buttons'('Size' 25 40)
'F.TC'⎕WC'TabControl'('Style' 'Buttons')( 'MultiLine' 1))

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'First Tab'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Second Tab'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Third Tab'('ImageIndex' 3)
'F.TC.T4'⎕WC'TabButton' 'Fourth Tab'('ImageIndex' 1)


TabControl: Example 10
'F'⎕WC'Form' 'TabControl: ScrollOpposite'('Size' 25 40)
'F.TC'⎕WC'TabControl'('ScrollOpposite' 1)

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'First Tab'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Second Tab'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Third Tab'('ImageIndex' 3)
'F.TC.T4'⎕WC'TabButton' 'Fourth Tab'('ImageIndex' 1)


TabControl: Example 11
'F'⎕WC'Form' 'TabControl: MultiLine Tabs, Justify None'('Size' 25 40)
'F.TC'⎕WC'TabControl'('MultiLine' 1)('Justify ' 'None')

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'First Tab'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Second Tab'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Third Tab'('ImageIndex' 3)
'F.TC.T4'⎕WC'TabButton' 'Fourth Tab'('ImageIndex' 1)


TabControl: Example 12
'F'⎕WC'Form' 'TabControl: MultiLine Buttons, Justify None'('Size' 25 40)
'F.TC'⎕WC'TabControl'('Style ' 'Buttons') ('MultiLine' 1)('Justify ' 'None')

'F.TC.IL'⎕WC'ImageList'
'F.TC.IL.'⎕WC'Icon'('' 'APLIcon')
'F.TC.IL.'⎕WC'Icon'('' 'FUNIcon')
'F.TC.IL.'⎕WC'Icon'('' 'EDITIcon')

'F.TC'⎕WS'ImageListObj' 'F.TC.IL'

'F.TC.T1'⎕WC'TabButton' 'First Tab'('ImageIndex' 1)
'F.TC.T2'⎕WC'TabButton' 'Second Tab'('ImageIndex' 2)
'F.TC.T3'⎕WC'TabButton' 'Third Tab'('ImageIndex' 3)
'F.TC.T4'⎕WC'TabButton' 'Fourth Tab'('ImageIndex' 1)


TabControl: Example 13

The TabJustify Property.


ActiveXContainer Methods

Detach OLEQueryInterface


ActiveXControl Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj | SetFnInfo | SetVarInfo
SetEventInfo |  |


Animation Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
AnimOpen | AnimClose | AnimPlay
AnimStop |  |


Bitmap Methods

Detach | FileRead | FileWrite
MakePNG | MakeGIF | GetTextSize


BrowseBox Methods

Detach Wait


Button Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ChooseFont |  |


ButtonEdit Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj |  |


Calendar Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj | GetVisibleRange | GetMinSize
IDNToDate | DateToIDN |


Circle Methods

Detach


Clipboard Methods

Detach Wait


ColorButton Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


Combo Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ChooseFont |  |


ComboEx Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj |  |


CoolBand Methods

Detach


CoolBar Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


Cursor Methods

Detach FileRead FileWrite


DateTimePicker Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj | IDNToDate | DateToIDN


Edit Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ChooseFont |  |


Ellipse Methods

Detach


FileBox Methods

Detach Wait


Font Methods

Detach ChooseFont


Form Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ChooseFont | Wait |


Grid Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj | DelRow | DelCol
SetCellType | RowChange | ColChange
Undo | SetCellSet | RowSetVisibleDepth
ColSorted | DuplicateRow | DuplicateColumn
CellFromPoint | GetCellRect | LockRows
LockColumns | AddComment | DelComment
GetComment |  |


Group Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ChooseFont |  |


Icon Methods

Detach FileRead FileWrite


Image Methods

Detach


ImageList Methods

Detach


Label Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ChooseFont |  |


List Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ChooseFont |  |


ListView Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj | GetItemState | SetItemState
GetItemPosition |  |


Locator Methods

Detach Wait


Marker Methods

Detach


MDIClient Methods

Detach | MDICascade | MDITile
MDIArrange | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


Menu Methods

Detach Wait


MenuBar Methods

Detach


MenuItem Methods

Detach


Metafile Methods

Detach FileRead FileWrite


MsgBox Methods

Detach Wait


NetType Methods


OCXClass Methods

Detach | GetPropertyInfo | GetEventInfo
GetMethodInfo | GetTypeInfo | SetPropertyInfo
SetMethodInfo | ShowHelp | ShowProperties
Browse | OLEAddEventSink | OLEDeleteEventSink
OLEListEventSinks |  |


OLEClient Methods

Browse | Detach | GetEventInfo
GetMethodInfo | GetPropertyInfo | GetTypeInfo
OLEAddEventSink | OLEDeleteEventSink | OLEListEventSinks
OLEQueryInterface | SetMethodInfo | SetPropertyInfo
ShowHelp |  |


OLEServer Methods

Detach | OLERegister | OLEUnregister
SetFnInfo | SetVarInfo | SetEventInfo


Poly Methods

Detach


Printer Methods

Detach | Print | Setup
NewPage | Abort | RTFPrintSetup
GetTextSize |  |


ProgressBar Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ProgressStep |  |


PropertyPage Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj |  |


PropertySheet Methods

Detach | ChooseFont | SetWizard
SetFinishText | CancelToClose | GetFocus
GetFocusObj | Wait |


Rect Methods

Detach


RichEdit Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj | RTFPrintSetup | RTFPrint
FileRead | FileWrite |


Root Methods

ChooseFont | Flush | NameFromHandle
GreetBitmap | GetCommandLine | GetCommandLineArgs
GetEnvironment | ListTypeLibs | DeleteTypeLib
SetServiceState | GetServiceState | GetTextSize
GetFocus | ShowSIP | GetFocusObj
IDNToDate | DateToIDN | TCPGetHostID
GetBuildID | Wait |


Scroll Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


Separator Methods

Detach


SM Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


Spinner Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj |  |


Splitter Methods

Detach


Static Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ChooseFont |  |


StatusBar Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj
ChooseFont |  |


StatusField Methods

Detach


SubForm Methods

Detach | ChooseFont | GetTextSize
Animate | GetFocus | ShowSIP
GetFocusObj |  |


SysTrayItem Methods

Detach ShowBalloonTip Wait


TabBar Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


TabBtn Methods

Detach ChooseFont


TabButton Methods

Detach


TabControl Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


TCPSocket Methods

Detach | TCPSend | TCPGetHostID
TCPSendPicture | Wait |


Text Methods

Detach ChooseFont


Timer Methods

Detach Wait


TipField Methods

Detach ChooseFont


ToolBar Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


ToolButton Methods

Detach


ToolControl Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


TrackBar Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


TreeView Methods

Detach | ChooseFont | GetItemState
SetItemState | AddItems | DeleteItems
AddChildren | DeleteChildren | GetParentItem
GetItemHandle | SetItemImage | ShowItem
GetTextSize | Animate | GetFocus
ShowSIP | GetFocusObj |


UpDown Methods

Detach | GetTextSize | Animate
GetFocus | ShowSIP | GetFocusObj


Animate Method

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | SM | Spinner
Static | StatusBar | SubForm
TabBar | TabControl | ToolBar
ToolControl | TrackBar | TreeView
UpDown |  |


ChooseFont Method

ActiveXControl | Button | ButtonEdit
Calendar | Combo | ComboEx
DateTimePicker | Edit | Font
Form | Grid | Group
Label | List | ListView
PropertyPage | PropertySheet | RichEdit
Root | Spinner | Static
StatusBar | SubForm | TabBtn
Text | TipField | TreeView


Close Event

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OLEServer
Poly | Printer | ProgressBar
PropertyPage | PropertySheet | Rect
RichEdit | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | TabButton | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


Configure Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | SM | Spinner
Static | StatusBar | SubForm
TabBar | ToolBar | ToolControl
TrackBar | TreeView | UpDown


ContextMenu Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | Spinner | Static
StatusBar | SubForm | TabBar
ToolBar | ToolControl | TrackBar
TreeView | UpDown |


Create Event

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OLEServer
Poly | Printer | ProgressBar
PropertyPage | PropertySheet | Rect
RichEdit | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | TabButton | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


Detach Method

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertyPage
PropertySheet | Rect | RichEdit
Scroll | Separator | SM
Spinner | Splitter | Static
StatusBar | StatusField | SubForm
SysTrayItem | TabBar | TabBtn
TabButton | TabControl | TCPSocket
Text | Timer | TipField
ToolBar | ToolButton | ToolControl
TrackBar | TreeView | UpDown


DragDrop Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
CoolBar | DateTimePicker | Edit
Ellipse | Form | Grid
Group | Image | Label
List | ListView | Marker
MDIClient | Poly | ProgressBar
PropertyPage | Rect | RichEdit
Scroll | SM | Spinner
Static | StatusBar | SubForm
TabBar | Text | ToolBar
ToolControl | TrackBar | TreeView
UpDown |  |


DropDown Event

Button | ButtonEdit | ColorButton
Combo | ComboEx | DateTimePicker
Menu |  |


DropFiles Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | Spinner | Static
StatusBar | SubForm | TabBar
ToolBar | ToolControl | TrackBar
TreeView | UpDown |


DropObjects Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | Spinner | Static
StatusBar | StatusField | SubForm
TabBar | TabBtn | ToolBar
ToolControl | TrackBar | TreeView
UpDown |  |


Expose Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | Spinner | Static
StatusBar | SubForm | TabBar
ToolBar | ToolControl | TrackBar
TreeView | UpDown |


FontCancel Event

ActiveXControl | Button | ButtonEdit
Calendar | Combo | ComboEx
DateTimePicker | Edit | Font
Form | Grid | Group
Label | List | ListView
PropertyPage | PropertySheet | RichEdit
Root | Spinner | Static
StatusBar | SubForm | TabBtn
Text | TipField | TreeView


FontOK Event

ActiveXControl | Button | ButtonEdit
Calendar | Combo | ComboEx
DateTimePicker | Edit | Font
Form | Grid | Group
Label | List | ListView
PropertyPage | PropertySheet | RichEdit
Root | Spinner | Static
StatusBar | SubForm | TabBtn
Text | TipField | TreeView


GesturePan Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Group
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | Spinner | SubForm
TreeView |  |


GesturePressAndTap Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Group
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | Spinner | SubForm
TreeView |  |


GestureRotate Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Group
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | Spinner | SubForm
TreeView |  |


GestureTwoFingerTap Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Group
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | Spinner | SubForm
TreeView |  |


GestureZoom Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Group
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Scroll | Spinner | SubForm
TreeView |  |


GetFocus Method

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
ProgressBar | PropertyPage | PropertySheet
RichEdit | Root | Scroll
SM | Spinner | Static
StatusBar | SubForm | TabBar
TabControl | ToolBar | ToolControl
TrackBar | TreeView | UpDown


GetFocusObj Method

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
ProgressBar | PropertyPage | PropertySheet
RichEdit | Root | Scroll
SM | Spinner | Static
StatusBar | SubForm | TabBar
TabControl | ToolBar | ToolControl
TrackBar | TreeView | UpDown


GetTextSize Method

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Calendar
ColorButton | Combo | ComboEx
CoolBar | DateTimePicker | Edit
Form | Grid | Group
Label | List | ListView
MDIClient | Printer | ProgressBar
PropertyPage | RichEdit | Root
Scroll | SM | Spinner
Static | StatusBar | SubForm
TabBar | TabControl | ToolBar
ToolControl | TrackBar | TreeView
UpDown |  |


GotFocus Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Grid
Group | List | ListView
MDIClient | ProgressBar | PropertyPage
RichEdit | Scroll | Spinner
SubForm | TrackBar | TreeView


Help Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
CoolBar | DateTimePicker | Edit
Ellipse | Form | Grid
Group | Image | Label
List | ListView | Marker
MDIClient | Poly | ProgressBar
PropertyPage | Rect | RichEdit
Scroll | SM | Spinner
Static | StatusBar | SubForm
TabBar | Text | ToolBar
ToolButton | ToolControl | TrackBar
TreeView | UpDown |


KeyPress Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Grid
Group | List | ListView
MDIClient | ProgressBar | PropertyPage
RichEdit | Scroll | Spinner
SubForm | TrackBar | TreeView


LostFocus Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Grid
Group | List | ListView
MDIClient | ProgressBar | PropertyPage
RichEdit | Scroll | Spinner
SubForm | TrackBar | TreeView


MouseDblClick Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
DateTimePicker | Edit | Ellipse
Form | Group | Image
Label | List | ListView
Marker | MDIClient | Poly
ProgressBar | PropertyPage | Rect
RichEdit | Scroll | SM
Spinner | Static | StatusBar
StatusField | SubForm | SysTrayItem
TabBar | TabBtn | Text
ToolBar | ToolButton | ToolControl
TreeView |  |


MouseDown Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
DateTimePicker | Edit | Ellipse
Form | Group | Image
Label | List | ListView
Marker | MDIClient | Poly
ProgressBar | PropertyPage | Rect
RichEdit | Scroll | SM
Spinner | Static | StatusBar
StatusField | SubForm | SysTrayItem
TabBar | TabBtn | Text
ToolBar | ToolButton | ToolControl
TrackBar | TreeView | UpDown


MouseEnter Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Grid
Group | Label | List
ListView | MDIClient | ProgressBar
PropertyPage | RichEdit | Scroll
SM | Spinner | Static
StatusBar | SubForm | TabBar
ToolBar | ToolControl | TreeView
UpDown |  |


MouseLeave Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Grid
Group | Label | List
ListView | MDIClient | ProgressBar
PropertyPage | RichEdit | Scroll
SM | Spinner | Static
StatusBar | SubForm | TabBar
ToolBar | ToolControl | TreeView
UpDown |  |


MouseMove Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
DateTimePicker | Edit | Ellipse
Form | Group | Image
Label | List | ListView
Marker | MDIClient | Poly
ProgressBar | PropertyPage | Rect
RichEdit | Scroll | Spinner
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | Text | ToolBar
ToolButton | ToolControl | TrackBar
TreeView | UpDown |


MouseUp Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
DateTimePicker | Edit | Ellipse
Form | Group | Image
Label | List | ListView
Marker | MDIClient | Poly
ProgressBar | PropertyPage | Rect
RichEdit | Scroll | SM
Spinner | Static | StatusBar
StatusField | SubForm | SysTrayItem
TabBar | TabBtn | Text
ToolBar | ToolButton | ToolControl
TrackBar | TreeView | UpDown


MouseWheel Event

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Group
Label | List | ListView
MDIClient | ProgressBar | PropertyPage
RichEdit | Scroll | Spinner
Static | StatusBar | SubForm
TabBar | ToolBar | ToolControl
TreeView |  |


Select Event

ActiveXControl | Bitmap | Button
ButtonEdit | Calendar | Circle
Clipboard | Combo | ComboEx
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | Label
List | ListView | Locator
Marker | MDIClient | Menu
MenuItem | Metafile | Poly
Printer | ProgressBar | Rect
RichEdit | Scroll | Spinner
Static | StatusBar | StatusField
SubForm | TabBar | TabBtn
TabButton | Text | ToolBar
ToolButton | TrackBar | TreeView
UpDown |  |


ShowSIP Method

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
ProgressBar | PropertyPage | RichEdit
Root | Scroll | SM
Spinner | Static | StatusBar
SubForm | TabBar | TabControl
ToolBar | ToolControl | TrackBar
TreeView | UpDown |


Wait Method

BrowseBox | Clipboard | FileBox
Form | Locator | Menu
MsgBox | PropertySheet | Root
SysTrayItem | TCPSocket | Timer


Class Identifier (CLSID)

The CLSID is a unique identifier that, when displayed, appears as a string of hexadecimal digits wrapped in braces; for example "{3B7C8860-D78F-101B-B9B5-04021C009402}".


COM data types

The table below shows the correspondence between COM data types and APL arrays.

OLE DataType | APL array
VT_BOOL | numeric scalar
VT_I1 | numeric scalar
VT_I2 | numeric scalar
VT_I4 | numeric scalar
VT_R4 | numeric scalar
VT_R8 | numeric scalar
VT_BSTR | character vector
VT_CY | 2-element numeric vector
VT_DATE | 6 element numeric vector
VT_VARIANT | any array
VT_SAFEARRAY | any array (VT_ARRAY OF VT_VARIANT)
VT_DISPATCH | ⎕OR of a namespace
VT_COLOR | 3-element RGB

APL vectors may be described by pre-fixing the data type string with 'VT_ARRAY OF '. For example 'VT_ARRAY OF BSTR' specifies a vector of character vectors.

If the APL array is the ⎕OR of a namespace, its data type should be specified as 'VT_DISPATCH'.


Globally Unique Identifier (GUID)

A Globally Unique Identifier (GUID) is a 128-bit number that is generated by a special algorithm and is virtually guaranteed a to be unique in the world. That is to say that every GUID generated by this algorithm is different from any other.

Dyalog APL properties that represent GUIDs are read-only character vectors that represent the GUID as a string of hexadecimal digits wrapped in braces.

For example "{3B7C8860-D78F-101B-B9B5-04021C009402}".


International Day Number

The values of dates used by the properties, events and methods of the Calendar object are specified using IDNs (International Day Numbers).

An IDN is an integer that represents a date as the number of days starting at Jan 1st 1900, i.e. Jan 01 1900 is IDN 1.

Note that the value of IDNs calculated by Dyalog APL are one less than IDNs calculated by Microsoft Excel which incorrectly assumes that 1900 was a leap year.


Port Number

A port number identifies the service provided by a particular server. It is an integer number in the range 0-65536,

Port numbers in the range 0-1023 are reserved for "well-known" services (e.g., FTP and HTTP).

Port number 1024 is reserved for IANA.

Port numbers 1025-5000 are typically assigned for user-defined services.


Stream Sockets

A Stream socket is a connection-based transport that is analogous to a telephone service. A Stream socket handles error correction, guarantees delivery, and preserves data sequence. This means that if you send two messages to a recipient, the messages are sure to arrive and in the sequence that you sent them. However, individual messages may be broken up into several packets (or accumulated into one), and there is no predetermined protocol to identify message boundaries. This means that Stream-based applications must implement some kind of message protocol that both ends of a connection understand and adhere to.


Twips

There are 1,440 Twips to one inch.


User Datagram Protocol (UDP)

User Datagram Protocol (UDP) is a connection-less transport mechanism that is somewhat similar to a postal service. It permits a sending application to transmit a message or messages to a recipient. It neither guarantees delivery nor acknowledgment, nor does it preserve the sequence of messages. Messages are also limited to fit into a single packet which is typically no more than 1500 bytes in size. However, a UDP message will be delivered in its entirety.

You may wonder why anybody would use a service that does not guarantee delivery. The answer is that although UDP is technically an unreliable service, it is perfectly possible to implement reliable applications on top of it by building in acknowledgments, time-outs and re-transmissions.


Native Look and Feel

Native Look and Feel is a Dyalog option that affects the appearance of the controls provided by the Dyalog GUI Interface and those used by the Dyalog Session. It is implemented by the XPLookAndFeel parameter.

Most of the Dyalog controls (with the notable exception of the Dyalog Grid) are standard Windows user-interface components provided by the Windows Common Controls library comctl32.dll. Successive versions of Windows have introduced new versions of the Windows Common Control Library which typically provide additional features as well as certain differences in appearance. However, each version of Windows continues to support older versions of the Common Control Library as well as the latest one. The decision as to which is loaded is made at run-time.

A second factor that affects the appearance of user-interface controls is the application of Visual StylesSee msdn.microsoft.com for details. 1 and Themes. These features enable users to tailor the UI to accommodate their individual needs and preferences. From Windows 8 onwards, the default appearance of certain Common Controls is overridden by the Visual Styles in use. However, this applies only if Native Look and Feel is enabled.

If Native Look and Feel is enabled, Windows loads the latest version of comctl32.dll (and potentially other Windows dlls) that is appropriate for the version of Windows in use. If Native Look and Feel is disabled, an earlier version may be loaded. The specific version that is loaded is not determined by Dyalog, but by Windows.

The Dyalog for Microsoft Windows Object Reference Guide identifies which features require Native Look and Feel to be enabled. It documents the typical appearance of controls with Native Look and Feel disabled but does not specify how the appearance of controls is affected by enabling Native Look and Feel, which is in any case affected by the Visual Styles selected by the user.

Dyalog Session

During development, both the Dyalog Session and the Dyalog APL GUI will display native style buttons, combo boxes, and other GUI components if Native Look and Feel is enabled. The option is provided in the General tab of the Configuration dialog.

Applications

By default Native Look and Feel is disabled in end-user applications. There are two ways to enable it.

If you use the File/Export… menu item on the Session MenuBar to create a bound executable, an OLE Server (in-process or out-of-process), an ActiveX Control or a .NET Assembly, check the option box labelled Enable Native Look and Feel in the create bound file dialog box. See Creating Executables and COM Servers.

If not, set the XPLookandFeel parameter to 1, when you run the program. For example:

dyalogrt.exe XPLookAndFeel=1 myws.dws


NetControl Object
Parents Children Properties
Purpose: The NetControl object provides the means to instantiate a .NET control in the Dyalog GUI.

Description

In principle, you may use the NetControl to embed any class that derives from System.Windows.Forms.Control (from system.windows.forms.dll), including derived classes written in Dyalog APL.

To load a particular .NET control, the appropriate .NET Assembly must be specified in ⎕USING; otherwise the expression will cause a LIMIT ERROR. For example, to load one of the standard .NET controls:

⎕USING,←⊂'System.Windows.Forms,system.windows.forms.dll'

The ClassName property specifies the name of the .NET control to be instantiated and to which the new object named by the left argument of ⎕WC is to be connected. ClassName may only be specified by ⎕WC.

Once you have created an instance of a particular NetControl, the properties, events and methods it supports may be obtained using ⎕NL. These are the properties, events and methods defined for the control by its author. The "Dyalog" properties listed above, are not reported by ⎕NL, but take precedence over (i.e. mask) any members of the same name that may be exposed by the class itself.

The following example illustrates the use of the Button class. In this case, the FlatStyle property of the button is set to "Popup". This gives the button a flat appearance until the mouse is hovered over it, when its appearance it changes to 3-dimensional.

       ⎕USING←'System'
       ⎕USING,←⊂'System.Windows.Forms,system.windows.forms.dll'
       ⎕USING,←⊂'System.Drawing,system.drawing.dll'
       an←⎕NEW FontFamily(⊂'Arial')
       myfont←⎕NEW Font(an 24 FontStyle.Bold GraphicsUnit.Point)

       'f'⎕WC'Form'('Coord' 'Pixel')('Size' 120 200)
       f.Caption←'NetControl'
       'f.l'⎕WC'Label' 'Button with FlatStyle=Popup'(2 2)

       'f.b'⎕WC'NetControl' 'Button'('Size' 60 160)

       f.b.⎕NL ¯2
AutoSizeMode DialogResult AutoEllipsis AutoSize BackColor FlatStyle FlatAppearance...

       f.b.⎕NL ¯3
BeginInvoke BringToFront Contains CreateControl CreateGraphics CreateObjRef Dispose DoDragDrop...

       f.b.⎕NL¯8
DoubleClick MouseDoubleClick AutoSizeChanged ImeModeChanged BackColorChanged...

       f.b.Text←'Popup'
       f.b.Font←myfont

       f.b.(FlatStyle←FlatStyle.Popup)

Normal appearance (Flat) | Appearance when mouse over

In most cases, you may use a NetControl in the cells of a Grid object. Unless you specify otherwise, using the InputProperties property of the Grid, the default property of the NetControl will be associated with the corresponding element of Values. The following example illustrates the use of a TextBox control. In this example, the CharacterCasing property of the TextBox is set to Upper, causing all text to be converted to upper-case.

       ⎕USING←'System'
       ⎕USING,←⊂'System.Windows.Forms,system.windows.forms.dll'
       ⎕USING,←⊂'System.Drawing,system.drawing.dll'
       an←⎕NEW FontFamily(⊂'Arial Narrow')
       myfont←⎕NEW Font(an 11 FontStyle.Bold GraphicsUnit.Point)
       'f'⎕WC'Form'('Coord' 'Pixel')('Size' 130 500)
       f.Caption←'Grid using .NET TextBox Control'
       'f.g'⎕WC'Grid'('Posn' 0 0)f.Size
       f.g.(ShowInput TitleWidth)←1 0
       'f.g.tb'⎕WC'NetControl' 'TextBox'
       f.g.tb.Font←myfont
       f.g.tb.(CharacterCasing←CharacterCasing.Upper)
       f.g.Input←'f.g.tb'
       wds←'All' 'TeXt' 'Is' 'Changed' 'to' 'Upper' 'casE'
       wds,←'ακομα' 'kai' 'τα' 'Ελληνικα'
       f.g.Values←5 5⍴wds

Implementation note: The instance of the .NET control is actually placed inside an instance of the .NET class System.Windows.Forms.ContainerControl. This ContainerControl is then embedded in the Dyalog parent, such as a Form. This "extra level" should have no effect on how the control is used or on how it behaves.


ActiveXContainer Parents

ActiveXControl


ActiveXControl Parents

Form


Animation Parents

ActiveXControl | Form | Group
PropertyPage | SubForm |


Bitmap Parents

ActiveXControl | Animation | Button
CoolBand | Form | Grid
Group | ImageList | ListView
Menu | MenuBar | MenuItem
NetType | OLEServer | Printer
ProgressBar | PropertyPage | PropertySheet
RichEdit | Root | StatusBar
SubForm | TCPSocket | ToolBar
ToolButton | ToolControl | TrackBar
TreeView | UpDown |


BrowseBox Parents

ActiveXControl | CoolBand | Form
Grid | OLEServer | PropertyPage
PropertySheet | Root | StatusBar
SubForm | TCPSocket | ToolBar
ToolControl |  |


Button Parents

ActiveXControl | CoolBand | Form
Grid | Group | PropertyPage
SubForm | ToolBar | ToolControl


ButtonEdit Parents

ActiveXControl | Form | Group
PropertyPage | SubForm |


Calendar Parents

ActiveXControl | Form | Group
PropertyPage | SubForm | ToolBar


Circle Parents

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Combo
ComboEx | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
Metafile | Printer | ProgressBar
PropertyPage | PropertySheet | RichEdit
Scroll | Spinner | Static
StatusBar | SubForm | TabBar
TipField | ToolBar | TrackBar
TreeView | UpDown |


Clipboard Parents

ActiveXControl | CoolBand | Form
OLEServer | PropertyPage | PropertySheet
Root | TCPSocket |


ColorButton Parents

ActiveXControl | Form | Grid
Group | PropertyPage | SubForm


Combo Parents

ActiveXControl | CoolBand | Form
Grid | Group | PropertyPage
SubForm | ToolBar | ToolControl


ComboEx Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm
ToolBar | ToolControl |


CoolBand Parents

CoolBar


CoolBar Parents

ActiveXControl Form


Cursor Parents

ActiveXControl | Animation | Button
Calendar | Combo | ComboEx
CoolBand | DateTimePicker | Edit
Form | Grid | Group
ImageList | Label | List
ListView | OLEServer | ProgressBar
PropertyPage | PropertySheet | RichEdit
Root | Scroll | SM
Static | StatusBar | SubForm
TCPSocket | ToolBar | ToolControl
TrackBar | TreeView | UpDown


DateTimePicker Parents

ActiveXControl | Form | Grid
Group | PropertyPage | SubForm
ToolBar |  |


Edit Parents

ActiveXControl | CoolBand | Form
Grid | Group | PropertyPage
SubForm | ToolBar | ToolControl


Ellipse Parents

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Combo
ComboEx | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
Metafile | Printer | ProgressBar
PropertyPage | PropertySheet | RichEdit
Scroll | Spinner | Static
StatusBar | SubForm | TabBar
TipField | ToolBar | TrackBar
TreeView | UpDown |


FileBox Parents

ActiveXControl | CoolBand | Form
Grid | OLEServer | PropertyPage
PropertySheet | Root | StatusBar
SubForm | TCPSocket | ToolBar
ToolControl |  |


Font Parents

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Calendar
Combo | ComboEx | CoolBand
DateTimePicker | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
Metafile | OLEServer | Printer
ProgressBar | PropertyPage | PropertySheet
RichEdit | Root | Scroll
Spinner | Static | StatusBar
SubForm | TabBar | TCPSocket
TipField | ToolBar | ToolControl
TrackBar | TreeView | UpDown


Form Parents

ActiveXControl | Form | OLEClient
OLEServer | Root | SubForm
TCPSocket |  |


Grid Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm


Group Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm
ToolBar | ToolControl |


Icon Parents

ActiveXControl | CoolBand | Form
Grid | ImageList | ListView
OLEServer | Printer | ProgressBar
PropertyPage | PropertySheet | RichEdit
Root | StatusBar | SubForm
SysTrayItem | TCPSocket | ToolBar
ToolControl | TrackBar | TreeView
UpDown |  |


Image Parents

ActiveXControl | Bitmap | Form
Grid | Group | Metafile
Printer | PropertyPage | Static
StatusBar | SubForm | ToolBar
ToolControl |  |


ImageList Parents

ActiveXControl | ButtonEdit | CoolBand
CoolBar | Form | Group
ListView | OLEServer | PropertyPage
Root | SubForm | TabControl
TCPSocket | ToolBar | ToolControl
TreeView |  |


Label Parents

ActiveXControl | CoolBand | Form
Grid | Group | PropertyPage
SubForm | ToolBar | ToolControl


List Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm
ToolBar | ToolControl |


ListView Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm
ToolBar | ToolControl |


Locator Parents

ActiveXControl | Form | Group
PropertyPage | PropertySheet | Root
Static | SubForm | TCPSocket
ToolBar | ToolControl |


Marker Parents

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Combo
ComboEx | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
Metafile | Printer | ProgressBar
PropertyPage | PropertySheet | RichEdit
Scroll | Spinner | Static
StatusBar | SubForm | TabBar
TipField | ToolBar | TrackBar
TreeView | UpDown |


MDIClient Parents

ActiveXControl Form SubForm


Menu Parents

ActiveXControl | Calendar | CoolBand
CoolBar | DateTimePicker | Form
Grid | Menu | MenuBar
OLEServer | Root | StatusField
SubForm | SysTrayItem | TCPSocket
ToolBar | ToolControl |


MenuBar Parents

ActiveXControl | Form | SubForm
ToolControl |  |


MenuItem Parents

Menu MenuBar


Metafile Parents

ActiveXControl | Bitmap | CoolBand
Form | Group | OLEServer
Printer | PropertyPage | PropertySheet
Root | Static | SubForm
TCPSocket | ToolBar | ToolControl


MsgBox Parents

ActiveXControl | Calendar | CoolBand
DateTimePicker | Form | Grid
OLEServer | PropertyPage | PropertySheet
Root | SubForm | TCPSocket
ToolBar | ToolControl |


NetClient Parents

NetType Root


NetControl Parents

Form | Grid | Group
PropertyPage | SubForm |


NetType Parents

Root


OCXClass Parents

ActiveXControl | CoolBand | Form
Grid | OLEServer | PropertyPage
Root | SubForm | TCPSocket
ToolBar | ToolControl |


OLEClient Parents

ActiveXControl | CoolBand | Form
OLEServer | Root | TCPSocket


OLEServer Parents

ActiveXControl | Form | OLEServer
Root |  |


Poly Parents

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Combo
ComboEx | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
Metafile | Printer | ProgressBar
PropertyPage | PropertySheet | RichEdit
Scroll | Spinner | Static
StatusBar | SubForm | TabBar
TipField | ToolBar | TrackBar
TreeView | UpDown |


Printer Parents

ActiveXControl | CoolBand | Form
OLEServer | PropertyPage | PropertySheet
Root | TCPSocket |


ProgressBar Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | StatusBar
SubForm | ToolBar | ToolControl


PropertyPage Parents

PropertySheet


PropertySheet Parents

ActiveXControl | Form | OLEServer
Root | SubForm | TCPSocket


Rect Parents

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Combo
ComboEx | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
Metafile | Printer | ProgressBar
PropertyPage | PropertySheet | RichEdit
Scroll | Spinner | Static
StatusBar | SubForm | TabBar
TipField | ToolBar | TrackBar
TreeView | UpDown |


RichEdit Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm
ToolBar | ToolControl |


Scroll Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm
ToolBar | ToolControl |


Separator Parents

Menu MenuBar


SM Parents

Form | Group | PropertyPage
SubForm | ToolBar | ToolControl


Spinner Parents

ActiveXControl | CoolBand | Form
Grid | Group | PropertyPage
SubForm | ToolBar | ToolControl


Splitter Parents

ActiveXControl | Form | Group
PropertyPage | SubForm |


Static Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm
ToolBar | ToolControl |


StatusBar Parents

ActiveXControl | CoolBand | Form
SubForm |  |


StatusField Parents

StatusBar


SubForm Parents

ActiveXControl | CoolBand | Form
Group | MDIClient | PropertyPage
SubForm | TabControl | ToolBar
ToolControl |  |


SysTrayItem Parents

Form Root


TabBar Parents

ActiveXControl Form SubForm


TabBtn Parents

TabBar


TabButton Parents

TabControl


TabControl Parents

ActiveXControl | CoolBand | Form
SubForm |  |


TCPSocket Parents

ActiveXControl | Calendar | CoolBand
DateTimePicker | Form | NetType
OLEClient | OLEServer | PropertyPage
Root | SubForm | TCPSocket


Text Parents

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Combo
ComboEx | Edit | Form
Grid | Group | Label
List | ListView | MDIClient
Metafile | Printer | ProgressBar
PropertyPage | PropertySheet | RichEdit
Scroll | Spinner | Static
StatusBar | SubForm | TabBar
TipField | ToolBar | TrackBar
TreeView | UpDown |


Timer Parents

ActiveXControl | Animation | Bitmap
BrowseBox | Button | ButtonEdit
Calendar | Circle | Clipboard
Combo | ComboEx | CoolBand
CoolBar | Cursor | DateTimePicker
Edit | Ellipse | FileBox
Font | Form | Grid
Group | Icon | Image
ImageList | Label | List
ListView | Locator | Marker
MDIClient | Menu | MenuBar
MenuItem | Metafile | MsgBox
NetClient | NetType | OLEClient
OLEServer | Poly | Printer
ProgressBar | PropertyPage | PropertySheet
Rect | RichEdit | Root
Scroll | Separator | SM
Spinner | Splitter | Static
StatusBar | StatusField | SubForm
SysTrayItem | TabBar | TabBtn
TabButton | TabControl | TCPSocket
Text | Timer | TipField
ToolBar | ToolButton | ToolControl
TrackBar | TreeView | UpDown


TipField Parents

ActiveXControl | CoolBand | Form
Group | OLEServer | PropertyPage
PropertySheet | Root | SubForm
TCPSocket |  |


ToolBar Parents

ActiveXControl | CoolBand | Form
SubForm |  |


ToolButton Parents

ToolControl


ToolControl Parents

ActiveXControl | CoolBand | Form
SubForm |  |


TrackBar Parents

ActiveXControl | CoolBand | Form
Grid | Group | PropertyPage
SubForm | ToolBar | ToolControl


TreeView Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm
ToolBar | ToolControl |


UpDown Parents

ActiveXControl | CoolBand | Form
Group | PropertyPage | SubForm
ToolBar | ToolControl |


Accelerator Property

ActiveXControl | Bitmap | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | Cursor | DateTimePicker
Edit | Ellipse | Form
Grid | Group | Icon
Image | Label | List
ListView | Locator | Marker
MDIClient | Menu | MenuItem
Metafile | Poly | Printer
ProgressBar | Rect | RichEdit
Scroll | Spinner | Static
StatusBar | StatusField | SubForm
TabBar | TabBtn | TabButton
Text | ToolBar | ToolButton
TrackBar | TreeView | UpDown


AcceptFiles Property

ActiveXControl | Animation | Button
ButtonEdit | Combo | ComboEx
DateTimePicker | Edit | Form
Grid | Group | Image
Label | List | ListView
ProgressBar | PropertyPage | RichEdit
Scroll | SM | Spinner
Static | StatusBar | SubForm
TabBar | ToolBar | TrackBar
TreeView | UpDown |


Active Property

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | Form | Grid
Group | Label | List
ListView | Menu | MenuItem
ProgressBar | PropertyPage | PropertySheet
RichEdit | Scroll | Spinner
Splitter | Static | StatusBar
SubForm | TabBar | TabBtn
Text | Timer | ToolBar
ToolButton | TrackBar | TreeView
UpDown |  |


Align Property

Animation | Button | ButtonEdit
CoolBar | DateTimePicker | ListView
Menu | MenuItem | Scroll
Spinner | Splitter | StatusBar
TabBar | TabBtn | TabControl
ToolBar | ToolControl |


Attach Property

Animation | Button | ButtonEdit
Calendar | ColorButton | Combo
ComboEx | CoolBar | DateTimePicker
Edit | Grid | Group
Label | List | ListView
MDIClient | ProgressBar | RichEdit
Scroll | SM | Spinner
Static | StatusBar | StatusField
SubForm | TabBar | TabBtn
TabControl | ToolBar | ToolControl
TrackBar | TreeView | UpDown


AutoConf Property

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
DateTimePicker | Edit | Ellipse
Form | Grid | Group
Image | Label | List
ListView | Marker | Poly
ProgressBar | Rect | RichEdit
Scroll | SM | Spinner
Static | StatusBar | StatusField
SubForm | TabBar | TabBtn
Text | ToolBar | TrackBar
TreeView | UpDown |


BCol Property

ActiveXContainer | ActiveXControl | Animation
Button | ButtonEdit | Circle
Combo | ComboEx | CoolBand
CoolBar | Edit | Ellipse
Form | Grid | Group
Label | List | ListView
MDIClient | Menu | MenuItem
Poly | ProgressBar | Rect
RichEdit | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | TabBar | TabBtn
Text | TipField | ToolBar
TrackBar | TreeView | UpDown


Border Property

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Combo
ComboEx | DateTimePicker | Edit
Form | Grid | Group
Label | List | ListView
MDIClient | RichEdit | Scroll
SM | Spinner | Static
StatusBar | StatusField | SubForm
TabBtn | ToolBar | TrackBar
TreeView | UpDown |


Caption Property

BrowseBox | Button | ColorButton
CoolBand | FileBox | Form
Group | Label | Menu
MenuItem | MsgBox | PropertyPage
PropertySheet | Root | StatusField
SubForm | TabBtn | TabButton
ToolButton |  |


ChildList Property

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertyPage
PropertySheet | Rect | RichEdit
Root | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | TabButton | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


Coord Property

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Calendar
Circle | ColorButton | Combo
ComboEx | DateTimePicker | Edit
Ellipse | Font | Form
Grid | Group | Image
ImageList | Label | List
ListView | Locator | Marker
MDIClient | Menu | Metafile
Poly | Printer | ProgressBar
PropertyPage | PropertySheet | Rect
RichEdit | Root | Scroll
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | TabBar | Text
ToolBar | TrackBar | TreeView
UpDown |  |


CursorObj Property

ActiveXControl | Button | ButtonEdit
Calendar | Circle | ColorButton
Combo | ComboEx | CoolBar
DateTimePicker | Edit | Ellipse
Form | Grid | Group
Label | List | ListView
Locator | MDIClient | Poly
ProgressBar | Rect | RichEdit
Root | Scroll | SM
Spinner | Splitter | Static
StatusBar | SubForm | TabBar
Text | ToolBar | TrackBar
TreeView | UpDown |


Data Property

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertyPage
PropertySheet | Rect | RichEdit
Root | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | TabButton | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


Dragable Property

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
DateTimePicker | Edit | Ellipse
Grid | Group | Image
Label | List | ListView
Marker | Poly | ProgressBar
Rect | RichEdit | Scroll
SM | Spinner | Static
StatusField | Text | TrackBar
TreeView | UpDown |


EdgeStyle Property

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | DateTimePicker
Edit | FileBox | Form
Grid | Group | Image
Label | List | ListView
MDIClient | Menu | MenuBar
MenuItem | MsgBox | Printer
ProgressBar | PropertyPage | PropertySheet
Rect | RichEdit | Root
Scroll | Separator | SM
Spinner | Static | StatusBar
StatusField | SubForm | TabBtn
ToolBar | TrackBar | TreeView
UpDown |  |


Event Property

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Form
Grid | Group | Icon
Image | ImageList | Label
List | ListView | Locator
Marker | MDIClient | Menu
MenuBar | MenuItem | Metafile
MsgBox | OCXClass | OLEClient
OLEServer | Poly | Printer
ProgressBar | PropertyPage | PropertySheet
Rect | RichEdit | Root
Scroll | Separator | SM
Spinner | Splitter | Static
StatusBar | StatusField | SubForm
SysTrayItem | TabBar | TabBtn
TabButton | TabControl | TCPSocket
Text | Timer | TipField
ToolBar | ToolButton | ToolControl
TrackBar | TreeView | UpDown


EventList Property

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertyPage
PropertySheet | Rect | RichEdit
Root | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | TabButton | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


FCol Property

ActiveXContainer | ActiveXControl | Button
ButtonEdit | Circle | Combo
ComboEx | CoolBand | CoolBar
Edit | Ellipse | Grid
Group | Label | List
ListView | Marker | Menu
MenuItem | Poly | Rect
RichEdit | Separator | Spinner
Static | StatusBar | StatusField
TabBtn | Text | TipField
ToolBar | TreeView | UpDown


File Property

Animation | Bitmap | Cursor
FileBox | Icon | Metafile
RichEdit |  |


FontObj Property

ActiveXContainer | ActiveXControl | Bitmap
Button | ButtonEdit | Calendar
Combo | ComboEx | DateTimePicker
Edit | Form | Grid
Group | Label | List
ListView | Menu | MenuBar
MenuItem | Printer | PropertyPage
PropertySheet | RichEdit | Root
Spinner | Static | StatusBar
StatusField | SubForm | TabBar
TabBtn | TabControl | Text
TipField | ToolBar | ToolControl
TrackBar | TreeView |


Handle Property

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBar
Cursor | DateTimePicker | Edit
Font | Form | Grid
Group | Icon | ImageList
Label | List | ListView
MDIClient | Menu | MenuBar
Metafile | OLEClient | OLEServer
Printer | ProgressBar | PropertySheet
RichEdit | Scroll | SM
Spinner | Static | StatusBar
SubForm | TabBar | TabControl
ToolBar | ToolControl | TrackBar
TreeView | UpDown |


Hint Property

Animation | Button | ButtonEdit
Calendar | ColorButton | Combo
ComboEx | DateTimePicker | Edit
Form | Grid | Group
Label | List | ListView
MDIClient | MenuItem | ProgressBar
PropertyPage | PropertySheet | RichEdit
Scroll | SM | Spinner
Static | StatusBar | SubForm
TabBar | ToolBar | ToolButton
TrackBar | TreeView | UpDown


HintObj Property

Animation | Button | ButtonEdit
Calendar | ColorButton | Combo
ComboEx | DateTimePicker | Edit
Form | Grid | Group
Label | List | ListView
MDIClient | MenuItem | ProgressBar
PropertyPage | PropertySheet | RichEdit
Root | Scroll | SM
Spinner | Static | StatusBar
SubForm | TabBar | ToolBar
ToolButton | TrackBar | TreeView
UpDown |  |


HScroll Property

Combo | ComboEx | Edit
Form | Grid | ListView
RichEdit | Scroll | StatusBar
SubForm | TabBar | ToolBar
TrackBar | UpDown |


IconObj Property

Form | MDIClient | Root
SubForm | SysTrayItem | TabBar
ToolBar |  |


ImageIndex Property

ButtonEdit | ComboEx | CoolBand
ListView | Menu | MenuItem
TabButton | ToolButton | TreeView


ImageListObj Property

ButtonEdit | ComboEx | CoolBar
ListView | Menu | TabControl
ToolControl | TreeView |


Index Property

Combo | ComboEx | CoolBand
FileBox | Grid | List
TreeView |  |


KeepOnClose Property

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertyPage
PropertySheet | Rect | RichEdit
Root | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | TabButton | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


MethodList Property

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertyPage
PropertySheet | Rect | RichEdit
Root | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | TabButton | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


OnTop Property

Circle | Ellipse | Form
Image | Marker | Poly
PropertySheet | Rect | SubForm
TabBar | Text | ToolBar


Picture Property

ActiveXControl | Button | Clipboard
CoolBand | Form | Group
Image | MDIClient | SM
Static | StatusBar | StatusField
SubForm | TabBar | ToolBar


Points Property

Circle | Ellipse | Image
Marker | Poly | Rect
Text |  |


Posn Property

ActiveXControl | Animation | Button
ButtonEdit | Calendar | ColorButton
Combo | ComboEx | CoolBand
CoolBar | DateTimePicker | Edit
Form | Grid | Group
Label | List | ListView
Locator | MDIClient | Menu
MenuItem | ProgressBar | PropertyPage
PropertySheet | RichEdit | Root
Scroll | Separator | SM
Spinner | Splitter | Static
StatusBar | StatusField | SubForm
TabBar | TabBtn | TabButton
TabControl | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


PropList Property

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertyPage
PropertySheet | Rect | RichEdit
Root | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | TabButton | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


Redraw Property

ActiveXControl | Button | ButtonEdit
Calendar | ColorButton | Combo
ComboEx | CoolBar | DateTimePicker
Edit | Form | Grid
Group | Label | List
ListView | MDIClient | ProgressBar
RichEdit | Scroll | SM
Spinner | Static | StatusBar
SubForm | TabBar | ToolBar
ToolControl | TrackBar | TreeView
UpDown |  |


Size Property

ActiveXControl | Animation | Bitmap
Button | ButtonEdit | Calendar
ColorButton | Combo | ComboEx
CoolBand | CoolBar | DateTimePicker
Edit | Ellipse | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Metafile | ProgressBar | PropertyPage
PropertySheet | Rect | RichEdit
Root | Scroll | SM
Spinner | Splitter | Static
StatusBar | StatusField | SubForm
TabBar | TabBtn | TabButton
TabControl | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


Sizeable Property

Animation | Button | ButtonEdit
Calendar | ColorButton | Combo
ComboEx | DateTimePicker | Edit
Form | Grid | Group
Label | List | ListView
Locator | ProgressBar | RichEdit
Scroll | SM | Spinner
Static | StatusBar | StatusField
SubForm | TabBar | ToolBar
TrackBar | TreeView | UpDown


Step Property

Form | Locator | ProgressBar
Scroll | Spinner | SubForm
TrackBar | UpDown |


Style Property

Button | ButtonEdit | Calendar
Combo | ComboEx | DateTimePicker
Edit | FileBox | Icon
List | ListView | Locator
Marker | MenuItem | MsgBox
ProgressBar | PropertySheet | Separator
Splitter | Static | StatusField
TabControl | TCPSocket | ToolButton
ToolControl | TrackBar |


TabIndex Property

ActiveXControl | Button | ButtonEdit
Calendar | ColorButton | Combo
ComboEx | DateTimePicker | Edit
Form | Grid | Group
Label | List | ListView
MDIClient | ProgressBar | RichEdit
Scroll | SM | Spinner
Static | StatusBar | SubForm
TabBar | ToolBar | TrackBar
TreeView | UpDown |


Text Property

ButtonEdit | Clipboard | Combo
ComboEx | Edit | MsgBox
RichEdit | Spinner | StatusField
Text |  |


TextSize Property

ActiveXControl | Bitmap | Edit
Form | Grid | Printer
Root | Static | StatusBar
SubForm | TabBar | ToolBar


Thumb Property

Form | ProgressBar | Scroll
Spinner | SubForm | TrackBar
UpDown |  |


Tip Property

Animation | Button | ButtonEdit
Calendar | ColorButton | Combo
ComboEx | DateTimePicker | Edit
Form | Grid | Group
Label | List | ListView
MDIClient | MenuItem | ProgressBar
PropertyPage | PropertySheet | RichEdit
Scroll | SM | Spinner
Static | StatusBar | SubForm
SysTrayItem | TabBar | TabButton
ToolBar | ToolButton | TrackBar
TreeView | UpDown |


TipObj Property

Animation | Button | ButtonEdit
Calendar | ColorButton | Combo
ComboEx | DateTimePicker | Edit
Form | Grid | Group
Label | List | ListView
MDIClient | MenuItem | ProgressBar
PropertyPage | PropertySheet | RichEdit
Root | Scroll | SM
Spinner | Static | StatusBar
SubForm | TabBar | ToolBar
TrackBar | TreeView | UpDown


Translate Property

ActiveXControl | Animation | Bitmap
BrowseBox | Button | ButtonEdit
Clipboard | ColorButton | Combo
ComboEx | DateTimePicker | Edit
Form | Grid | Group
ImageList | Label | List
ListView | MDIClient | Menu
MenuBar | MenuItem | Metafile
OCXClass | Printer | ProgressBar
PropertyPage | PropertySheet | RichEdit
Root | Scroll | Separator
Spinner | Static | StatusBar
StatusField | SubForm | SysTrayItem
TabBar | TabBtn | Text
TipField | ToolBar | TrackBar
TreeView | UpDown |


Type Property

ActiveXContainer | ActiveXControl | Animation
Bitmap | BrowseBox | Button
ButtonEdit | Calendar | Circle
Clipboard | ColorButton | Combo
ComboEx | CoolBand | CoolBar
Cursor | DateTimePicker | Edit
Ellipse | FileBox | Font
Form | Grid | Group
Icon | Image | ImageList
Label | List | ListView
Locator | Marker | MDIClient
Menu | MenuBar | MenuItem
Metafile | MsgBox | OCXClass
OLEClient | OLEServer | Poly
Printer | ProgressBar | PropertyPage
PropertySheet | Rect | RichEdit
Root | Scroll | Separator
SM | Spinner | Splitter
Static | StatusBar | StatusField
SubForm | SysTrayItem | TabBar
TabBtn | TabButton | TabControl
TCPSocket | Text | Timer
TipField | ToolBar | ToolButton
ToolControl | TrackBar | TreeView
UpDown |  |


Visible Property

ActiveXControl | Animation | Button
ButtonEdit | Calendar | Circle
ColorButton | Combo | ComboEx
CoolBand | DateTimePicker | Edit
Ellipse | Form | Grid
Group | Image | Label
List | ListView | Marker
MenuBar | Poly | ProgressBar
PropertySheet | Rect | RichEdit
Scroll | SM | Spinner
Splitter | Static | StatusBar
StatusField | SubForm | TabBar
TabBtn | TabControl | Text
ToolBar | ToolButton | ToolControl
TrackBar | TreeView | UpDown


VScroll Property

Combo | ComboEx | Edit
Form | Grid | List
ListView | RichEdit | Scroll
StatusBar | SubForm | TabBar
ToolBar | TrackBar | UpDown


XRange Property

ActiveXControl | Bitmap | Form
Grid | Group | MDIClient
Metafile | Printer | Root
Static | StatusBar | SubForm
TabBar | ToolBar |


YRange Property

ActiveXControl | Bitmap | Form
Grid | Group | MDIClient
Metafile | Printer | Root
Static | StatusBar | SubForm
TabBar | ToolBar |


ActiveXContainer Properties

Type | Event | FontObj
FCol | BCol | Data
KeepOnClose | MethodList | ChildList
EventList | PropList |


ActiveXControl Properties

Type | ClassName | Posn
Size | Coord | Border
Active | Visible | Event
Dragable | FontObj | FCol
BCol | Picture | CursorObj
AutoConf | YRange | XRange
Data | TextSize | EdgeStyle
Handle | Translate | Accelerator
AcceptFiles | ClassID | Container
KeepOnClose | HelpFile | ToolboxBitmap
TypeLibID | TypeLibFile | LastError
Redraw | TabIndex | MethodList
ChildList | EventList | PropList


Animation Properties

Type | Posn | Size
File | Coord | Border
Active | Visible | Event
Sizeable | Dragable | BCol
AutoConf | Data | Attach
EdgeStyle | Handle | Hint
HintObj | Tip | TipObj
Translate | AcceptFiles | KeepOnClose
AutoPlay | Transparent | Align
MethodList | ChildList | EventList
PropList |  |


Bitmap Properties

Type | File | Bits
CMap | KeepBits | Size
Coord | Event | FontObj
YRange | XRange | Data
TextSize | Translate | Accelerator
KeepOnClose | CBits | MaskCol
MethodList | ChildList | EventList
PropList |  |


BrowseBox Properties

Type | Caption | BrowseFor
Target | StartIn | HasEdit
Event | Data | Translate
KeepOnClose | MethodList | ChildList
EventList | PropList |


Button Properties

Type | Caption | Posn
Size | Style | Coord
Align | State | Default
Cancel | Border | Justify
Active | Visible | Event
Sizeable | Dragable | FontObj
FCol | BCol | Picture
BtnPix | CursorObj | AutoConf
Data | Attach | EdgeStyle
Handle | Hint | HintObj
Tip | TipObj | ReadOnly
Translate | Accelerator | AcceptFiles
KeepOnClose | Redraw | TabIndex
Elevated | Note | MethodList
ChildList | EventList | PropList


ButtonEdit Properties

Type | Text | Posn
Size | Style | Coord
Align | Border | Justify
Active | Visible | Event
ImageListObj | SelText | Sizeable
Dragable | FontObj | FCol
BCol | CursorObj | AutoConf
Data | Attach | EdgeStyle
Handle | Hint | HintObj
Tip | TipObj | FieldType
MaxLength | Decimals | Password
ValidIfEmpty | ReadOnly | FormatString
Changed | Value | Translate
Accelerator | AcceptFiles | KeepOnClose
Transparent | ImageIndex | Redraw
TabIndex | Cue | ShowCueWhenFocused
HasClearButton | MethodList | ChildList
EventList | PropList |


Calendar Properties

Type | Posn | Size
Style | Coord | Border
Active | Visible | Event
FirstDay | MaxSelCount | SelDate
MinDate | MaxDate | CalendarCols
Today | HasToday | CircleToday
WeekNumbers | MonthDelta | Sizeable
Dragable | FontObj | CursorObj
AutoConf | Data | Attach
EdgeStyle | Handle | Hint
HintObj | Tip | TipObj
Accelerator | KeepOnClose | Redraw
TabIndex | MethodList | ChildList
EventList | PropList |


Circle Properties

Type | Points | Radius
FCol | BCol | Start
End | ArcMode | LStyle
LWidth | FStyle | FillCol
Coord | Visible | Event
Dragable | OnTop | CursorObj
AutoConf | Data | Accelerator
KeepOnClose | DrawMode | RadiusMode
MethodList | ChildList | EventList
PropList |  |


Clipboard Properties

Type | Event | Data
Formats | Text | Bits
CMap | CBits | MetafileObj
Picture | Array | RTFText
Translate | Accelerator | KeepOnClose
MethodList | ChildList | EventList
PropList |  |


ColorButton Properties

Type | Caption | Posn
Size | CurrentColor | DefaultColors
CustomColors | OtherButton | Coord
Active | Visible | Event
Sizeable | Dragable | CursorObj
AutoConf | Data | Attach
EdgeStyle | Handle | Hint
HintObj | Tip | TipObj
Translate | Accelerator | KeepOnClose
ShowDropDown | Redraw | TabIndex
MethodList | ChildList | EventList
PropList |  |


Combo Properties

Type | Items | Text
Posn | Size | Style
Coord | Rows | Border
Active | Visible | Event
VScroll | HScroll | SelItems
SelText | Sizeable | Dragable
FontObj | FCol | BCol
CursorObj | AutoConf | Index
Data | Attach | EdgeStyle
Handle | Hint | HintObj
Tip | TipObj | Translate
Accelerator | AcceptFiles | KeepOnClose
Redraw | TabIndex | HasClearButton
MethodList | ChildList | EventList
PropList |  |


ComboEx Properties

Type | Items | Text
Posn | Size | Style
Coord | Rows | Border
Active | Visible | Event
Indents | ImageListObj | ImageIndex
SelImageIndex | CaseSensitive | EditImage
EditImageIndent | PathWordBreak | VScroll
HScroll | SelItems | SelText
Sizeable | Dragable | FontObj
FCol | BCol | CursorObj
AutoConf | Index | Data
Attach | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | Translate | Accelerator
AcceptFiles | KeepOnClose | Redraw
TabIndex | HasClearButton | MethodList
ChildList | EventList | PropList


CoolBand Properties

Type | Caption | Posn
Size | Visible | Event
ImageIndex | FCol | BCol
Picture | Index | Data
KeepOnClose | ChildEdge | NewLine
GripperMode | Dockable | UndocksToRoot
MethodList | ChildList | EventList
PropList |  |


CoolBar Properties

Type | Posn | Size
Align | Event | ImageListObj
FCol | BCol | CursorObj
Data | Attach | Handle
KeepOnClose | BandBorders | DblClickToggle
FixedOrder | VariableHeight | DockChildren
Redraw | MethodList | ChildList
EventList | PropList |


Cursor Properties

Type | File | Bits
CMap | Mask | HotSpot
KeepBits | Event | Data
Handle | Accelerator | KeepOnClose
MethodList | ChildList | EventList
PropList |  |


DateTimePicker Properties

Type | Posn | Size
Style | Coord | Align
Border | Active | Visible
Event | DateTime | MinDate
MaxDate | CalendarCols | Today
HasToday | CircleToday | WeekNumbers
MonthDelta | HasCheckBox | FieldType
CustomFormat | Sizeable | Dragable
FontObj | CursorObj | AutoConf
Data | Attach | EdgeStyle
Handle | Hint | HintObj
Tip | TipObj | Translate
Accelerator | AcceptFiles | KeepOnClose
Redraw | TabIndex | MethodList
ChildList | EventList | PropList


Edit Properties

Type | Text | Posn
Size | Style | Coord
Border | Justify | Active
Visible | Event | VScroll
HScroll | SelText | Sizeable
Dragable | FontObj | FCol
BCol | CursorObj | AutoConf
Data | Attach | TextSize
EdgeStyle | Handle | Hint
HintObj | Tip | TipObj
FieldType | MaxLength | Decimals
Password | ValidIfEmpty | ReadOnly
FormatString | Changed | Value
Translate | Accelerator | AcceptFiles
WantsReturn | KeepOnClose | Redraw
TabIndex | Cue | ShowCueWhenFocused
HasClearButton | MethodList | ChildList
EventList | PropList |


Ellipse Properties

Type | Points | Size
FCol | BCol | Start
End | ArcMode | LStyle
LWidth | FStyle | FillCol
Coord | Visible | Event
Dragable | OnTop | CursorObj
AutoConf | Data | Accelerator
KeepOnClose | DrawMode | MethodList
ChildList | EventList | PropList


FileBox Properties

Type | Caption | Directory
Filters | File | FileMode
Style | Event | Index
Data | EdgeStyle | KeepOnClose
MethodList | ChildList | EventList
PropList |  |


Font Properties

Type | PName | Size
Fixed | Italic | Underline
Weight | Rotate | CharSet
Coord | Data | Handle
KeepOnClose | MethodList | ChildList
EventList | PropList |


Form Properties

Type | Caption | Posn
Size | Coord | State
Border | Active | Visible
Event | Thumb | Range
Step | VScroll | HScroll
Sizeable | Moveable | SysMenu
MaxButton | MinButton | HelpButton
OKButton | SIPMode | SIPResize
FontObj | BCol | Picture
OnTop | IconObj | CursorObj
AutoConf | YRange | XRange
Data | TextSize | EdgeStyle
Handle | Hint | HintObj
Tip | TipObj | Translate
Accelerator | AcceptFiles | KeepOnClose
Dockable | Docked | DockShowCaption
DockChildren | UndocksToRoot | MaskCol
AlphaBlend | Redraw | TabIndex
PageSize | MethodList | ChildList
EventList | PropList |


Grid Properties

Type | Values | Posn
Size | FCol | BCol
Coord | Border | Active
Visible | Event | VScroll
HScroll | SelItems | Sizeable
Dragable | FontObj | CursorObj
AutoConf | Index | YRange
XRange | Data | Attach
TextSize | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | FormatString | RowTitles
ColTitles | CurCell | TitleWidth
CellHeights | CellWidths | TitleHeight
CellFonts | Input | CellTypes
AutoExpand | CellSelect | ResizeRows
ResizeCols | ResizeRowTitles | ResizeColTitles
ClipCells | InputModeKey | InputMode
GridFCol | GridBCol | ShowInput
CellSet | RowTitleFCol | ColTitleFCol
RowTitleDepth | ColTitleDepth | RowTitleAlign
ColTitleAlign | OverflowChar | AlignChar
GridLineFCol | GridLineWidth | RowLineTypes
ColLineTypes | EnterReadOnlyCells | RowTitleBCol
ColTitleBCol | RowTreeDepth | RowTreeStyle
RowTreeImages | ColSortImages | SelectionColor
SelectionColorAlpha | SelectionBorderWidth | HighlightHeaders
Translate | Accelerator | AcceptFiles
KeepOnClose | Redraw | InputProperties
TabIndex | AlwaysShowSelection | AlwaysShowBorder
RowHiddenDepth | MethodList | ChildList
EventList | PropList |


Group Properties

Type | Caption | Posn
Size | Coord | Border
Active | Visible | Event
Sizeable | Dragable | FontObj
FCol | BCol | Picture
CursorObj | AutoConf | YRange
XRange | Data | Attach
EdgeStyle | Handle | Hint
HintObj | Tip | TipObj
Translate | Accelerator | AcceptFiles
KeepOnClose | Redraw | TabIndex
MethodList | ChildList | EventList
PropList |  |


Icon Properties

Type | File | Bits
CMap | Mask | Style
KeepBits | Size | Event
Data | Handle | Accelerator
KeepOnClose | CBits | MethodList
ChildList | EventList | PropList


Image Properties

Type | Points | Coord
Visible | Event | Dragable
Picture | OnTop | AutoConf
Data | EdgeStyle | Size
Accelerator | AcceptFiles | KeepOnClose
MethodList | ChildList | EventList
PropList |  |


ImageList Properties

Type | Size | Event
Coord | Data | Handle
Translate | ImageCount | Masked
MapCols | KeepOnClose | MethodList
ChildList | EventList | PropList


Label Properties

Type | Caption | Posn
Size | Coord | Border
Justify | Active | Visible
Event | Sizeable | Dragable
FontObj | FCol | BCol
CursorObj | AutoConf | Data
Attach | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | FieldType | Decimals
FormatString | Value | Translate
Accelerator | AcceptFiles | KeepOnClose
Redraw | TabIndex | MethodList
ChildList | EventList | PropList


List Properties

Type | Items | Posn
Size | Style | Coord
Border | Active | Visible
Event | VScroll | SelItems
Sizeable | Dragable | FontObj
FCol | BCol | CursorObj
AutoConf | Index | Data
Attach | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | Translate | Accelerator
AcceptFiles | MultiColumn | ColumnWidth
KeepOnClose | Redraw | SortItems
TabIndex | MethodList | ChildList
EventList | PropList |


ListView Properties

Type | Items | Posn
Size | Style | Coord
Align | Border | Active
Visible | Event | DragItems
View | AutoArrange | Header
Wrap | EditLabels | ImageListObj
ReportInfo | ColTitles | ImageIndex
ReportImageIndex | ReportBCol | HeaderImageList
HeaderImageIndex | VScroll | HScroll
SelItems | Sizeable | Dragable
FontObj | FCol | BCol
CursorObj | AutoConf | Data
Attach | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | ColTitleAlign | ColTitle3D
Translate | Accelerator | AcceptFiles
KeepOnClose | CheckBoxes | FullRowSelect
GridLines | Redraw | TabIndex
AlwaysShowSelection | ItemGroups | ItemGroupMetrics
MethodList | ChildList | EventList
PropList |  |


Locator Properties

Type | Posn | Size
LStyle | Style | Coord
Event | Step | Sizeable
CursorObj | Data | Accelerator
KeepOnClose | MethodList | ChildList
EventList | PropList |


Marker Properties

Type | Points | Style
Size | FCol | Coord
Visible | Event | Dragable
OnTop | AutoConf | Data
Accelerator | KeepOnClose | DrawMode
MethodList | ChildList | EventList
PropList |  |


MDIClient Properties

Type | Posn | Size
Coord | Border | Event
BCol | Picture | IconObj
CursorObj | YRange | XRange
Data | Attach | EdgeStyle
Handle | MDIActive | MDIActiveObject
Hint | HintObj | Tip
TipObj | Translate | Accelerator
KeepOnClose | Redraw | TabIndex
MethodList | ChildList | EventList
PropList |  |


Menu Properties

Type | Caption | Posn
Coord | Align | Active
Event | FontObj | FCol
BCol | BtnPix | Data
EdgeStyle | Handle | Translate
Accelerator | KeepOnClose | ImageListObj
ImageIndex | MethodList | ChildList
EventList | PropList |


MenuBar Properties

Type | Visible | Event
FontObj | Data | EdgeStyle
MDIMenu | Handle | Translate
KeepOnClose | MethodList | ChildList
EventList | PropList |


MenuItem Properties

Type | Caption | Posn
Style | Align | Active
Event | Checked | FontObj
FCol | BCol | BtnPix
Data | EdgeStyle | Hint
HintObj | Tip | TipObj
Translate | Accelerator | KeepOnClose
ImageIndex | MethodList | ChildList
EventList | PropList |


Metafile Properties

Type | File | Size
Coord | RealSize | Event
YRange | XRange | Data
Handle | Translate | Accelerator
KeepOnClose | MethodList | ChildList
EventList | PropList |


MsgBox Properties

Type | Caption | Text
Style | Btns | Default
Event | Data | EdgeStyle
KeepOnClose | MethodList | ChildList
EventList | PropList |


NetControl Properties

Type | Posn | Size
Coord | ClassName | Attach
MethodList | ChildList | EventList
PropList |  |


NetType Properties

BaseClass


OCXClass Properties

Type | ClassName | Event
Data | Translate | ClassID
KeepOnClose | TypeList | HelpFile
ToolboxBitmap | LicenseKey | QueueEvents
MethodList | ChildList | EventList
PropList |  |


OLEClient Properties

Type | ClassName | Event
Data | Handle | ClassID
KeepOnClose | TypeList | HelpFile
LastError | Locale | AutoBrowse
QueueEvents | InstanceMode | LateBind
MethodList | ChildList | EventList
PropList |  |


OLEServer Properties

Type | ClassName | Event
Data | Handle | ExportedFns
ExportedVars | ClassID | KeepOnClose
TypeLibID | TypeLibFile | ServerVersion
LastError | RunMode | ShowSession
LateBind | MethodList | ChildList
EventList | PropList |


Poly Properties

Type | Points | FCol
BCol | LStyle | LWidth
FStyle | FillCol | Coord
Visible | Event | Dragable
OnTop | CursorObj | AutoConf
Data | Accelerator | KeepOnClose
DrawMode | MethodList | ChildList
EventList | PropList |


Printer Properties

Type | PName | DevCaps
Coord | Event | FontObj
FontList | YRange | XRange
Data | TextSize | EdgeStyle
Handle | Orientation | Copies
PrintRange | Collate | PaperSize
PaperSizes | PaperSource | PaperSources
ColorMode | Resolution | Resolutions
Duplex | Translate | Accelerator
KeepOnClose | MethodList | ChildList
EventList | PropList |


ProgressBar Properties

Type | Posn | Size
Style | Coord | Active
Visible | Event | Thumb
Step | Wrap | Limits
Sizeable | Dragable | BCol
CursorObj | AutoConf | Data
Attach | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | Translate | Accelerator
AcceptFiles | KeepOnClose | ProgressStyle
Redraw | TabIndex | Interval
MethodList | ChildList | EventList
PropList |  |


PropertyPage Properties

Type | Caption | Posn
Size | Coord | Active
Event | HasHelp | FontObj
Data | EdgeStyle | Hint
HintObj | Tip | TipObj
Changed | Translate | AcceptFiles
KeepOnClose | MethodList | ChildList
EventList | PropList |


PropertySheet Properties

Type | Caption | Posn
Size | Style | Coord
Active | Visible | Event
HasApply | HasHelp | PageActive
PageActiveObject | HelpButton | FontObj
OnTop | Data | EdgeStyle
Handle | Hint | HintObj
Tip | TipObj | Translate
KeepOnClose | MethodList | ChildList
EventList | PropList |


Rect Properties

Type | Points | Size
Radius | FCol | BCol
LStyle | LWidth | FStyle
FillCol | Coord | Visible
Event | Dragable | OnTop
CursorObj | AutoConf | Data
EdgeStyle | Accelerator | KeepOnClose
DrawMode | MethodList | ChildList
EventList | PropList |


RichEdit Properties

Type | Text | Posn
Size | File | Coord
Border | Active | Visible
Event | VScroll | HScroll
SelText | Sizeable | Dragable
FontObj | FCol | BCol
CursorObj | AutoConf | Data
Attach | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | Changed | RTFText
Translate | Accelerator | CharFormat
WordFormat | ParaFormat | PageWidth
AcceptFiles | WantsReturn | KeepOnClose
Redraw | TabIndex | MethodList
ChildList | EventList | PropList


Root Properties

Type | Caption | Posn
Size | DevCaps | Coord
Event | FontObj | FontList
PrintList | IconObj | CursorObj
YRange | XRange | Data
TextSize | Yield | EdgeStyle
HintObj | TipObj | Translate
APLVersion | EvaluationDays | KeepOnClose
OLEControls | OLEServers | LastError
RadiusMode | MethodList | ChildList
EventList | PropList |


Scroll Properties

Type | Posn | Size
Coord | Align | Border
Active | Visible | Event
Thumb | Range | Step
VScroll | HScroll | Limits
Sizeable | Dragable | BCol
CursorObj | AutoConf | Data
Attach | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | Translate | Accelerator
AcceptFiles | KeepOnClose | Redraw
TabIndex | PageSize | MethodList
ChildList | EventList | PropList


Separator Properties

Type | Posn | Style
Event | FCol | BCol
Data | EdgeStyle | Translate
KeepOnClose | MethodList | ChildList
EventList | PropList |


SM Properties

Type | Posn | Size
Coord | Border | Visible
Event | Sizeable | Dragable
BCol | Picture | CursorObj
AutoConf | Data | Attach
EdgeStyle | Handle | Hint
HintObj | Tip | TipObj
AcceptFiles | KeepOnClose | Redraw
TabIndex | MethodList | ChildList
EventList | PropList |


Spinner Properties

Type | Items | Text
Posn | Size | Coord
Align | Border | Justify
Active | Visible | Event
Thumb | Step | Wrap
Limits | Sizeable | Dragable
FontObj | FCol | BCol
CursorObj | AutoConf | Data
Attach | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | FieldType | MaxLength
Decimals | Password | ValidIfEmpty
ReadOnly | FormatString | Changed
Value | Translate | Accelerator
AcceptFiles | KeepOnClose | Redraw
TabIndex | MethodList | ChildList
EventList | PropList |


Splitter Properties

Type | SplitObj1 | SplitObj2
Posn | Size | Style
Coord | Align | Active
Visible | Event | BCol
CursorObj | Data | KeepOnClose
MethodList | ChildList | EventList
PropList |  |


Static Properties

Type | Posn | Size
Style | Coord | Border
Active | Visible | Event
Sizeable | Dragable | FontObj
FCol | BCol | Picture
CursorObj | AutoConf | YRange
XRange | Data | Attach
TextSize | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | Translate | Accelerator
AcceptFiles | KeepOnClose | Redraw
TabIndex | MethodList | ChildList
EventList | PropList |


StatusBar Properties

Type | Posn | Size
Coord | Align | Border
Active | Visible | Event
VScroll | HScroll | Sizeable
FontObj | FCol | BCol
Picture | CursorObj | AutoConf
YRange | XRange | Data
Attach | TextSize | EdgeStyle
Handle | Hint | HintObj
Tip | TipObj | Translate
Accelerator | AcceptFiles | KeepOnClose
Redraw | TabIndex | MethodList
ChildList | EventList | PropList


StatusField Properties

Type | Caption | Text
Posn | Size | Style
Coord | Border | Visible
Event | Sizeable | Dragable
FontObj | FCol | BCol
Picture | AutoConf | Data
Attach | EdgeStyle | Translate
Accelerator | KeepOnClose | MethodList
ChildList | EventList | PropList


SubForm Properties

Type | Caption | Posn
Size | Coord | State
Border | Active | Visible
Event | Thumb | Range
Step | VScroll | HScroll
Sizeable | Moveable | SysMenu
MaxButton | MinButton | HelpButton
FontObj | BCol | Picture
OnTop | IconObj | CursorObj
AutoConf | YRange | XRange
Data | Attach | TextSize
EdgeStyle | Handle | Hint
HintObj | Tip | TipObj
TabObj | Translate | Accelerator
AcceptFiles | KeepOnClose | Dockable
Docked | DockShowCaption | DockChildren
UndocksToRoot | Redraw | TabIndex
PageSize | MethodList | ChildList
EventList | PropList |


SysTrayItem Properties

Type | Event | IconObj
Data | Tip | Translate
Popup | KeepOnClose | MethodList
ChildList | EventList | PropList


TabBar Properties

Type | Posn | Size
Coord | Align | Active
Visible | Event | VScroll
HScroll | Sizeable | FontObj
BCol | Picture | OnTop
IconObj | CursorObj | AutoConf
YRange | XRange | Data
Attach | TextSize | Handle
Hint | HintObj | Tip
TipObj | TabObj | Translate
Accelerator | AcceptFiles | KeepOnClose
Redraw | TabIndex | MethodList
ChildList | EventList | PropList


TabBtn Properties

Type | Caption | Posn
Size | Align | Border
Active | Visible | Event
FontObj | FCol | BCol
AutoConf | Data | Attach
EdgeStyle | TabObj | Translate
Accelerator | KeepOnClose | MethodList
ChildList | EventList | PropList


TabButton Properties

Type | Caption | Posn
Size | State | Event
ImageIndex | Data | Tip
TabObj | Accelerator | KeepOnClose
MethodList | ChildList | EventList
PropList |  |


TabControl Properties

Type | Posn | Size
Style | Visible | Event
ImageListObj | FontObj | Data
Attach | Handle | TabObj
KeepOnClose | MultiLine | TabSize
Justify | TabJustify | Align
MultiSelect | TabFocus | HotTrack
ScrollOpposite | FlatSeparators | MethodList
ChildList | EventList | PropList


TCPSocket Properties

Type | LocalAddr | LocalPort
RemoteAddr | RemotePort | Style
Event | LocalAddrName | LocalPortName
RemoteAddrName | RemotePortName | Data
SocketType | SocketNumber | CurrentState
TargetState | KeepOnClose | Encoding
MethodList | ChildList | EventList
PropList |  |


Text Properties

Type | Text | Points
FCol | BCol | VAlign
HAlign | Coord | Active
Visible | Event | Dragable
FontObj | OnTop | CursorObj
AutoConf | Data | Translate
Accelerator | KeepOnClose | DrawMode
MethodList | ChildList | EventList
PropList |  |


Timer Properties

Type | Interval | Active
Event | Data | KeepOnClose
MethodList | ChildList | EventList
PropList |  |


TipField Properties

Type | Event | FontObj
FCol | BCol | Data
Translate | KeepOnClose | MethodList
ChildList | EventList | PropList


ToolBar Properties

Type | Posn | Size
Coord | Align | Border
Active | Visible | Event
VScroll | HScroll | Sizeable
FontObj | FCol | BCol
Picture | OnTop | IconObj
CursorObj | AutoConf | YRange
XRange | Data | Attach
TextSize | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | Translate | Accelerator
AcceptFiles | KeepOnClose | Redraw
TabIndex | MethodList | ChildList
EventList | PropList |


ToolButton Properties

Type | Caption | Posn
Size | Style | State
Active | Visible | Event
ImageIndex | Data | Hint
HintObj | Tip | Accelerator
Popup | KeepOnClose | MethodList
ChildList | EventList | PropList


ToolControl Properties

Type | Posn | Size
Style | Align | Visible
Event | ImageListObj | FontObj
Data | Attach | Handle
KeepOnClose | MultiLine | Transparent
Divider | ShowCaptions | ShowDropDown
Dockable | UndocksToRoot | Redraw
ButtonsAcceptFocus | MethodList | ChildList
EventList | PropList |


TrackBar Properties

Type | Posn | Size
Style | Coord | Border
Active | Visible | Event
Thumb | Step | VScroll
HScroll | Limits | SelRange
Sizeable | Dragable | FontObj
BCol | CursorObj | AutoConf
Data | Attach | EdgeStyle
Handle | Hint | HintObj
Tip | TipObj | Translate
Accelerator | TickAlign | TickSpacing
HasTicks | ShowThumb | TrackRect
ThumbRect | AcceptFiles | KeepOnClose
Redraw | TabIndex | MethodList
ChildList | EventList | PropList


TreeView Properties

Type | Items | Posn
Size | Coord | Border
Active | Visible | Event
Depth | HasLines | HasButtons
EditLabels | ImageListObj | ImageIndex
SelImageIndex | SelItems | Sizeable
Dragable | FontObj | FCol
BCol | CursorObj | AutoConf
Index | Data | Attach
EdgeStyle | Handle | Hint
HintObj | Tip | TipObj
Translate | Accelerator | AcceptFiles
KeepOnClose | CheckBoxes | FullRowSelect
SingleClickExpand | Redraw | TabIndex
AlwaysShowSelection | MethodList | ChildList
EventList | PropList |


UpDown Properties

Type | Posn | Size
Coord | Border | Active
Visible | Event | Thumb
Step | VScroll | HScroll
Wrap | Limits | Sizeable
Dragable | FCol | BCol
CursorObj | AutoConf | Data
Attach | EdgeStyle | Handle
Hint | HintObj | Tip
TipObj | Translate | Accelerator
AcceptFiles | KeepOnClose | Redraw
TabIndex | MethodList | ChildList
EventList | PropList |


Object Management Functions
⎕DQ | Dequeue | processes user actions, invoking callbacks
⎕NQ | Enqueue | generates an event under program control
⎕WC | Create Object | creates new object with specified properties
⎕WG | Get Properties | gets values of properties from an object
⎕WN | Object Names | reports names of all children of an object
⎕WS | Set Properties | sets values of properties for an object


PCRE License

PCRE Licence

Part of the functionality of ⎕R and ⎕S is implemented using the PCRE library which is redistributed according to the following license.
PCRE LICENCE
------------

PCRE is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.

Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
specified below. The documentation for PCRE, supplied in the "doc"
directory, is distributed under the same terms as the software itself.

The basic library functions are written in C and are freestanding. Also
included in the distribution is a set of C++ wrapper functions.

THE BASIC LIBRARY FUNCTIONS
---------------------------

Written by:       Philip Hazel
Email local part: ph10
Email domain:     cam.ac.uk

University of Cambridge Computing Service,
Cambridge, England.

Copyright (c) 1997-2009 University of Cambridge
All rights reserved.

THE C++ WRAPPER FUNCTIONS
-------------------------

Contributed by:   Google Inc.

Copyright (c) 2007-2008, Google Inc.
All rights reserved.
which is redistributed according to the following license:


:Disposable Statement

      |
      :Disposable array
      |
      code
      |
      :End[Disposable]
      |


:For Statement

       |
       :For var :In[Each] aexp
       |
       code
       |
       :End[For]
       |


:Hold Statement

      |
      :Hold token(s)
      |
      code
      |
      |-------.
      |       |
      |       :Else
      |       |
      |       code
      |       |
      |<------.
      |
      :End[Hold]
      |


:Repeat Statement

       |
       :Repeat
       |
       code
       |
       .---------------.
       |               |
       :End[Repeat]    :Until bexp
       |               |
       |               .-------.
       |               |       |
       |               |       andor
       |               |       |
       |               |<------'
       |               |
       |<--------------'
       |


:Trap Statement

       |
       :Trap <ecode>
       |
       code
       |
       |<------------------------------------.
       |                                     |
       .-------.-------.                     |
       |       |       |                     |
       |       :Else   :Case[List] <ecode>   |
       |       |       |                     |
       |       |       |                     |
       |       |       |                     |
       |       code    code                  |
       |       |       |                     |
       |<------'       `---------------------'
       |
       :End[Trap]
       |

Where ecode is a scalar or vector of ⎕TRAP event codes.

Note that within the :Trap control structure, :Case is used for a single event code and :CaseList for a vector of event codes.


:While Statement

       |
       :While bexp
       |
       .-------.
       |       |
       |       andor
       |       |
       |<------'
       |
       code
       |
       .---------------.
       |               |
       :End[While]     :Until bexp
       |               |
       |               .-------.
       |               |       |
       |               |       andor
       |               |       |
       |               |<------'
       |               |
       |<--------------'
       |


:With Statement

       |
       :With namespace (ref or name)
       |
       code
       |
       :End[With]
       |


C H A P T E R 2 Defined Functions Operators

Defined Functions & Operators

A defined function is a program that takes 0, 1, or 2 arrays as arguments and may produce an array as a result. A defined operator is a program that takes 1 or 2 functions or arrays (known as operands) and produces a derived function as a result. To simplify the text, the term operation is used within this chapter to mean function or operator.


Clover Class Example

:Class Clover ⍝ Constructor Overload Example
    :Field Public Con
    ∇ Make0
      :Access Public
      :Implements Constructor
      make 0
    ∇
    ∇ Make1(arg)
      :Access Public
      :Implements Constructor
      make arg
    ∇
    ∇ Make2(arg1 arg2)
      :Access Public
      :Implements Constructor
      make arg1 arg2
    ∇
    ∇ Make3(arg1 arg2 arg3)
      :Access Public
      :Implements Constructor
      make arg1 arg2 arg3
    ∇
    ∇ MakeAny args
      :Access Public
      :Implements Constructor
      make args
    ∇
    ∇ make args
      Con←(⍴args)(2⊃⎕SI)args
    ∇
:EndClass ⍝ Clover


BirdBehaviour Interface

:Interface BirdBehaviour
∇ R←Fly ⍝ Returns description of flying capability
∇
∇ R←Lay ⍝ Returns description of egg-laying behaviour
∇
∇ R←Sing ⍝ Returns description of bird-song
∇
:EndInterface ⍝ BirdBehaviour


FishBehaviour Interface

:Interface FishBehaviour
∇ R←Swim ⍝ Returns description of swimming capability
∇
:EndInterface ⍝ FishBehaviour


Penguin Class

:Class Penguin: Animal,BirdBehaviour,FishBehaviour
    ∇ R←NoCanFly
      :Implements Method BirdBehaviour.Fly
      R←'Although I am a bird, I cannot fly'
    ∇
    ∇ R←LayOneEgg
      :Implements Method BirdBehaviour.Lay
      R←'I lay one egg every year'
    ∇
    ∇ R←Croak
      :Implements Method BirdBehaviour.Sing
      R←'Croak, Croak!'
    ∇
    ∇ R←Dive
      :Implements Method FishBehaviour.Swim
      R←'I can dive and swim like a fish'
    ∇
:EndClass ⍝ Penguin


DiaryStuff Example Namespace

:Namespace DiaryStuff
:Using System

    :Class DiaryEntry
        :Field Public When
        :Field Public What
        ∇ Make(ymdhm wot)
          :Access Public
          :Implements Constructor
          When What←(⎕NEW DateTime(6↑5↑ymdhm))wot
          ⎕DF⍕When What
        ∇
        ∇ Make0
          :Access Public
          :Implements Constructor
          When What←⎕NULL''
        ∇
    :EndClass ⍝ DiaryEntry

    :Class Diary
        :Field Private entries←0⍴⎕NEW DiaryEntry
        ∇ R←Add(ymdhm wot)
          :Access Public
          R←⎕NEW DiaryEntry(ymdhm wot)
          entries,←R
        ∇
        ∇ R←DoingOn ymd;X
          :Access Public
          X←,(↑entries.When.(Year Month Day))^.=3 1⍴3↑ymd
          R←X/entries
        ∇
        ∇ R←Remove ymdhm;X
          :Access Public
          :If R←∨/X←entries.When=⎕NEW DateTime(6↑5↑ymdhm)
              entries←(~X)/entries
          :EndIf
        ∇
        :Property Numbered Default Entry
            ∇ R←Shape
              R←⍴entries
            ∇
            ∇ R←Get arg
              R←arg.Indexers⊃entries
            ∇
            ∇ Set arg
              entries[arg.Indexers]←arg.NewValue
            ∇
        :EndProperty
    :EndClass ⍝ Diary

:EndNamespace


Booking Class

    :Class Booking
        :Field Public OK
        :Field Public Course
        :Field Public TeeTime
        :Field Public Message

        ∇ ctor args
          :Implements Constructor
          :Access Public Instance
          OK Course TeeTime Message←args
        ∇
        ∇ format
          :Implements Trigger OK,Message
          ⎕DF⍕Course TeeTime(⊃OK⌽Message'OK')
        ∇
    :EndClass


GetCourses Method

    ∇ R←GetCourses;COURSECODES;COURSES;INDEX
      :Access Public
      COURSECODES COURSES INDEX←⎕FREAD GOLFID 1
      R←{⎕NEW GolfCourse ⍵}¨↓⍉↑COURSECODES COURSES
    ∇


GetStartingheet Method

    ∇ R←GetStartingSheet ARGS;CODE;COURSE;DATE;COURSECODES
                             ;COURSES;INDEX;COURSEI;IDN
                             ;DATES;COMPS;IDATE;TEETIMES
                             ;GOLFERS;I;T
      :Access Public
      CODE DATE←ARGS
      COURSECODES COURSES INDEX←⎕FREAD GOLFID 1
      COURSEI←COURSECODES⍳CODE
      COURSE←⎕NEW GolfCourse(CODE(COURSEI⊃COURSES,⊂''))
      R←⎕NEW StartingSheet(0 COURSE DATE)
      :If COURSEI>⍴COURSECODES
          R.Message←'Invalid course code'
          :Return
      :EndIf
      IDN←2 ⎕NQ'.' 'DateToIDN',DATE.(Year Month Day)
      DATES COMPS←⎕FREAD GOLFID,COURSEI⊃INDEX
      IDATE←DATES⍳IDN
      :If IDATE>⍴DATES
          R.Message←'No Starting Sheet available'
          :Return
      :EndIf
      TEETIMES GOLFERS←⎕FREAD GOLFID,IDATE⊃COMPS
      T←DateTime.New¨(⊂DATE.(Year Month Day)),¨↓[1]
                                   24 60 1⊤TEETIMES
      R.Slots←{⎕NEW Slot ⍵}¨T,∘⊂¨↓GOLFERS
      R.OK←1
    ∇


GolfCourse Class

    :Class GolfCourse
        :Field Public Code←¯1
        :Field Public Name←''

        ∇ ctor args
          :Implements Constructor
          :Access Public Instance
          Code Name←args
          ⎕DF Name,'(',(⍕Code),')'
        ∇

    :EndClass


Slot Class

    :Class Slot
        :Field Public Time
        :Field Public Players

        ∇ ctor1 t
          :Implements Constructor
          :Access Public Instance
          Time←t
          Players←0⍴⊂''
        ∇
        ∇ ctor2 (t pl)
          :Implements Constructor
          :Access Public Instance
          Time Players←t pl
        ∇
        ∇ format
          :Implements Trigger Players
          ⎕DF⍕Time Players
        ∇
    :EndClass


StartingSheet Class

    :Class StartingSheet
        :Field Public OK
        :Field Public Course
        :Field Public Date
        :Field Public Slots←⎕NULL
        :Field Public Message

        ∇ ctor args
          :Implements Constructor
          :Access Public Instance
          OK Course Date←args
        ∇
        ∇ format
          :Implements Trigger OK,Message
          ⎕DF⍕2 1⍴(⍕Course Date)(↑⍕¨Slots)
        ∇
    :EndClass


Dual Example Class

Dual Class Example

:Class Dual: 'SubForm'
    :Include GUITools
    :Field Private _Caption1←''
    :Field Private _Caption2←''
    :Field Private _Value1←0
    :Field Private _Value2←0
    :Field Private _Range←0
    :Field Private _Intercept←0
    :Field Private _Gradient←1
    :Field Private _Height←40

    ∇ Create args;H;W;POS;SH;CH;Y1;Y2;BaseArgs;MyArgs;Defaults
      :Access Public
      MyArgs BaseArgs←SplitNV args
      :Implements Constructor :Base BaseArgs,⊂'EdgeStyle' 'Dialog'
      ExecNV_ MyArgs ⍝ Set Fields named _PropertyName in MyArgs
      Coord←'Pixel'
      H W←Size
      POS←2↑⌊0.5×0⌈(H-_Height)
      CH←⊃GetTextSize'W'
      'Slider'⎕WC'TrackBar'POS('Size'_Height W)
      Slider.(Limits AutoConf)←_Range 0
      Slider.(TickSpacing TickAlign)←10 'Top'
      Slider.onThumbDrag←'ChangeValue'
      Slider.onScroll←'ChangeValue'
      Y1←POS[1]-CH+1
      Y2←POS[1]+_Height+1
      'Caption1_'⎕WC'Text'_Caption1(Y1,0)('AutoConf' 0)
      'Caption2_'⎕WC'Text'_Caption2(Y2,0)('AutoConf' 0)
      'Value1_'⎕WC'Text'(⍕_Value1)(Y1,W)('HAlign' 2)('AutoConf' 0)
      CalcValue2
      'Value2_'⎕WC'Text'(⍕_Value2)(Y2,W)('HAlign' 2)('AutoConf' 0)
      onConfigure←'Configure'
    ∇
    :Property Caption1, Caption2
    :Access Public
        ∇ R←Get arg
          R←(arg.Name,'_')⎕WG'Text'
        ∇
        ∇ Set arg
          (arg.Name,'_')⎕WS'Text'arg.NewValue
        ∇
    :EndProperty

    :Property Value1
    :Access Public
        ∇ R←Get
          R←_Value1
        ∇
        ∇ Set arg
          ⎕NQ'Slider' 'Scroll' 0 arg.NewValue
        ∇
    :EndProperty

    :Property Intercept, Gradient, Range, Height, Value2
    :Access Public
        ∇ R←Get arg
          R←⍎'_',arg.Name
        ∇
    :EndProperty

    ∇ CalcValue2
      _Value2←_Intercept+_Gradient×_Value1
    ∇

    ∇ ChangeValue MSG
      ⍝ Callback for ThumbDrag and Scroll
      _Value1←⊃¯1↑MSG
      CalcValue2
      Value1_.Text←⍕_Value1
      Value2_.Text←⍕_Value2
    ∇

    ∇ Configure MSG;H;W;POS;CH;Y1;Y2
      2 ⎕NQ MSG
      H W←Size
      POS←2↑⌊0.5×(H-_Height)
      CH←⊃GetTextSize'W'
      Slider.(Posn Size)←POS(_Height W)
      Y1←POS[1]-CH+1
      Y2←POS[1]+_Height+1
      Caption1_.Points←1 2⍴Y1,0
      Caption2_.Points←1 2⍴Y2,0
      Value1_.Points←1 2⍴Y1,W
      Value1_.Points←1 2⍴Y2,W
    ∇

    :EndClass ⍝ Dual


Writing Classes based on the Dyalog GUI

Dyalog GUI Classes

You may create user-defined Classes based upon Dyalog GUI objects. The Temperature Converter Class and Dual Class illustrate how this can be done.

To base a Class on a Dyalog GUI object, you specify the name of the object as its Base Class. For example, the Temperature Converter is based upon a Form:

:Class Temp: 'Form'

and the Dual Control is based upon a SubForm:

:Class Dual: 'SubForm'

Being based upon a top-level GUI object, the Temperature Converter may be used as follows:

      T1←⎕NEW Temp(⊂'Posn'(68 50))

Notice that the :Implements Constructor statement of its Constructor Make:

:Implements Constructor :Base (⊂'Caption' TITLE),pv,⊂('Size' (30 40))

passes on the application-specific property list (pv) given as its argument, but (in this case) specifies Caption and Size as well. The order in which the properties are specified in the :Base call ensures that the former will act as a default (and be overridden by an application-specific Caption requested in pv), whereas the specified Size of (30 40) will override whatever value of Size is requested by the host application in pv.

Other Instances can co-exist with the first:

      T2←⎕NEW Temp(('Caption' 'My Application')('Posn'(10 10))

The Dual Control requires a GUI parent but several Instances can co-exist, quite independently, in the same parent.

For example, function RUN creates a Form and 3 Instances of Dual; one to convert Centigrade to Fahrenheit, one to convert Fahrenheit to Centigrade, and the third to convert centimetres to inches.

     ∇ RUN;F;D1PROPS;D2PROPS;D3PROPS
[1]
[2]    F←⎕NEW'Form'(('Caption' 'Dual Instances')('Coord' 'Pixel')('Size'(320 320)))
[3]
[4]    D1PROPS←('Caption1' 'Centigrade')('Caption2' 'Fahrenheit')
[5]    D1PROPS,←('Intercept' 32)('Gradient'(9÷5))('Value1' 0)('Range'(0 100))
[6]    F.D1←F.⎕NEW Dual(('Coord' 'Pixel')('Posn'(10 10))('Size'(100 300)),D1PROPS)
[7]
[8]    D2PROPS←('Caption1' 'Fahrenheit')('Caption2' 'Centigrade')
[9]    D2PROPS,←('Intercept'(-32×5÷9))('Gradient'(5÷9))('Value1' 0)('Range'(0 212))
[10]   F.D2←F.⎕NEW Dual(('Coord' 'Pixel')('Posn'(110 10))('Size'(100 300)),D2PROPS)
[11]
[12]   D3PROPS←('Caption1' 'Centimetres')('Caption2' 'Inches')
[13]   D3PROPS,←('Intercept' 0)('Gradient'(÷2.54))('Value1' 0)('Range'(0 100))
[14]   F.D3←F.⎕NEW Dual(('Coord' 'Pixel')('Posn'(210 10))('Size'(100 300)),D3PROPS)
[15]
[16]   ⎕DQ'F'
     ∇

Dual's Constructor Make first splits its constructor arguments into those that apply to the Dual Class itself and those that apply to the SubForm. Its :Implements Constructor statement then passes these on to the Base Constructor, together with an appropriate setting for EdgeStyle.

      :Implements Constructor :Base BaseArgs,⊂'EdgeStyle' 'Dialog'


Temperature Converter Example Class

Temperature Converter Example

 class="APLCode">:Class Temp: 'Form'
    ∇ Make pv;TITLE
      :Access Public
      TITLE←'Temperature Converter'
      :Implements Constructor :Base (⊂'Caption' TITLE),pv,⊂('Size' (30 40))
      MB←⎕NEW⊂'MenuBar'
      MB.(M←⎕NEW'Menu'(,⊂'Caption' '&Scale'))
      MB.M.(C←⎕NEW'MenuItem'(('Caption' '&Centigrade')('Checked' 1)))
      MB.M.(F←⎕NEW'MenuItem'(,⊂('Caption' '&Fahrenheit')))
      LF←⎕NEW'Label'(('Caption' 'Fahrenheit')('Posn'(10 10)))
      F←⎕NEW'Edit'(('Posn'(10 40))('Size'(⍬ 20))('FieldType' 'Numeric'))
      LC←⎕NEW'Label'(('Caption' 'Centigrade')('Posn'(40 10)))
      C←⎕NEW'Edit'(('Posn'(40 40))('Size'(⍬ 20))('FieldType' 'Numeric'))
      F2C←⎕NEW'Button'(('Caption' 'F->C')('Posn'(10 70))('Default' 1))
      C2F←⎕NEW'Button'(('Caption' 'C->F')('Posn'(40 70)))
      Q←⎕NEW'Button'(('Caption' '&Quit')('Posn'(70 30))('Size'(⍬ 40))('Cancel' 1))
      S←⎕NEW'Scroll'(⊂('Range' 101))
      MB.M.C.onSelect←'SET_C'
      MB.M.F.onSelect←'SET_F'
      F2C.onSelect←'f2c'
      F.onGotFocus←'SET_DEF'
      C2F.onSelect←'c2f'
      C.onGotFocus←'SET_DEF'
      onClose←'QUIT'
      Q.onSelect←'QUIT'
      S.onScroll←'c2f_scroll'
    ∇

    ∇ f2c
      C.Value←(F.Value-32)×5÷9
    ∇
    ∇ c2f
      F.Value←32+C.Value×9÷5
    ∇
    ∇ c2f_scroll MSG
      ⍝ Callback for Centigrade input via scrollbar
      C.Value←101-4⊃MSG
      c2f
    ∇
    ∇ f2c_scroll Msg
      ⍝ Callback for Fahrenheit input via scrollbar
      F.Value←213-4⊃Msg
      f2c
    ∇
    ∇ Quit
      Close
    ∇
    ∇ SET_DEF MSG
      (⊃MSG).Default←1
    ∇
    ∇ SET_C
      ⍝ Sets the scrollbar to work in Centigrade
      S.Range←101
      S.onScroll←'c2f_scroll'
      MB.M.C.Checked←1
      MB.M.F.Checked←0
    ∇
    ∇ SET_F
      ⍝ Sets the scrollbar to work in Fahrenheit
      S.Range←213
      S.onScroll←'f2c_scroll'
      MB.M.F.Checked←1
      MB.M.C.Checked←0
    ∇
:EndClass ⍝ Temp


Replicate First

Replicate First R←X⌿[K]Y

The form R←X⌿Y implies replication along the first axis of Y. See Replicate.


JSON and APL

The JavaScript Object Notation

IETF RFC 7159 - The JavaScript Object Notation (JSON) Data Interchange Format - is a widely supported, text based data interchange format for the portable representation of structured data; any application which conforms to the standard may exchange data with any other. Note, however, that the standard describes a limited set of data types and JSON does not provide a general APL import/export mechanism. In particular:

Not all APL arrays are representable in JSON.

For example, arrays with more than one dimension cannot be represented in JSON. Of course, this does mean that applications using JSON are unlikely to use such objects; you probably will need rearrange your data into the format that is expected by the receiving application. In the case of a 2-dimensional matrix, a split will give you a vector of tuples that a JSON application is likely to expect:

      ⎕JSON 3 4⍴⍳12
DOMAIN ERROR: Array unsupported by JSON
      ⎕JSON 3 4⍴⍳12
     ∧
      ⎕JSON ↓3 4⍴⍳12
[[1,2,3,4],[5,6,7,8],[9,10,11,12]]

Not all JSON types have exact APL equivalents

The JSON standard includes Boolean values true and false which are distinct from numeric values 1 and 0, and have no direct APL equivalent.

To represent JSON true and false types this implementation adopts the convention of using APL arrays ⊂'true' and ⊂'false' respectively. These arrays cannot otherwise be represented in JSON and allow true and false to be uniquely identified.

Not all APL object names are representable in JSON.

Objects with names which cannot be represented in JSON are renamed on both import and export. See JSON Name Mangling.


JSON Name Mangling

When Dyalog converts from JSON to APL data, and a member of a JSON object has a name which is not a valid APL name, it is renamed.

Example:

In this example, the JSON describes an object containing two numeric items, one named a (which is a valid APL name) and the other named 2a (which is not):

{"a": 1, "2a": 2}

When this JSON is imported as an APL namespace using ⎕JSON, Dyalog converts the name 2a to a valid APL name. The name mangling algorithm creates a name beginning with ⍙.

      (⎕JSON'{"a": 1, "2a": 2}').⎕NL 2
a
⍙2a

When Dyalog exports JSON it performs the reverse name mangling, so:

      1 ⎕JSON ⎕JSON'{"a": 1, "2a": 2}'
{"a":1,"2a":2}

Should you need to create and decode these names directly,7162⌶ provides the same name mangling and un-mangling operations.

      0(7162⌶)'2a'
⍙2a
      1(7162⌶)'⍙2a'
2a


Ampersand &

Ampersand is a Monadic operator with an ambivalent operand

Operator Ampersand means

Spawn

      delay←{'Delayed: ',⎕DL ⍵}    ⍝ delay function

      delay 10    ⍝ delay for 10 seconds
Delayed:  10.2228

      ⎕←delay&10  ⍝ delay for 10 seconds in new thread 1
1

      2+3 4       ⍝ execute something in current thread
5 6
                  ⍝ thread 1 completes:
Delayed:  10.03183

Language Elements


At @

At is a Dyadic operator

Operator At means

At

      (0@2 4) 1 2 3 4 5
1 0 3 0 5

      10 (×@2 4) 1 2 3 4 5
1 20 3 40 5

      (÷@2 4) 1 2 3 4 5
1 0.5 3 0.25 5

      '*'@(2∘|) 1 2 3 4 5   ⍝ Boolean selection 1 0 1 0 1
* 2 * 4 *

      ⌽@(2∘|) 1 2 3 4 5     ⍝ Reversal of sub-array 1 3 5
5 2 3 4 1


Circle ○

Monadic Circle means

Pi Times

      ○ 0 1 2
0 3.14159 6.28319

Dyadic Circle means

Circular Function (Trig)

          Note: Angles are in radians
                radians ← ○ degrees ÷ 180

      1 ○ 0 1.5707963 3.1415927
0 1 ¯4.64102E¯8

 ⍺   ⍺ ○ ⍵         ⍺   ⍺ ○ ⍵
                   0   (1-⍵*2)*0.5
¯1   Arcsin ⍵      1   Sine ⍵
¯2   Arccos ⍵      2   Cosine ⍵
¯3   Arctan ⍵      3   Tangent ⍵
¯4   (¯1+⍵*2)*0.5  4   (1+⍵*2)*0.5
¯5   Arcsinh ⍵     5   Sinh ⍵
¯6   Arccosh ⍵     6   Cosh ⍵
¯7   Arctanh ⍵     7   Tanh ⍵
¯8   -8○⍵          8   (-1+⍵*2)*0.5
¯9   ⍵             9   real part of ⍵
¯10  +⍵           10   |⍵
¯11  ⍵×0J1        11   imaginary part of ⍵
¯12  *⍵×0J1       12   phase of ⍵

Language Elements


Circle Bar ⊖

Monadic Circle Bar means

Reverse First

      mat
1  2  3  4
5  6  7  8
9 10 11 12

      ⊖ mat
9 10 11 12
5  6  7  8
1  2  3  4

Dyadic Circle Bar means

Rotate First

      0 1 2 ¯1 ⊖ mat
1  6 11 12
5 10  3  4
9  2  7  8

Language Elements


Circle Stile ⌽

Monadic Circle Stile means

Reverse

      ⌽ 'trams'
smart

      mat
1  2  3  4
5  6  7  8
9 10 11 12

      ⌽ mat
 4  3  2 1
 8  7  6 5
12 11 10 9

      ⌽[1] mat
9 10 11 12
5  6  7  8
1  2  3  4

Dyadic Circle Stile means

Rotate

      3 ⌽ 'HatStand'
StandHat

      ¯2 ⌽ 1 2 3 4 5 6
5 6 1 2 3 4

      ¯1 ⌽ mat
 4 1  2  3
 8 5  6  7
12 9 10 11

      1 ¯1 2 ⌽ mat
 2  3 4  1
 8  5 6  7
11 12 9 10

      0 1 2 ¯1 ⌽[1] mat
1  6 11 12
5 10  3  4
9  2  7  8

Language Elements


Comma ,

Monadic Comma means

Ravel

      cube    ⍝ 3D array
1 2
3 4

5 6
7 8
      , cube
1 2 3 4 5 6 7 8

      ,[2 3] cube    ⍝ Ravel with axes
1 2 3 4
5 6 7 8

Ravel with Axes

      ,[1.5]'ABC'
A
B
C

Dyadic Comma means

Catenate/Laminate (Join)

      1 2 3 , 4 5 6
1 2 3 4 5 6

      cube , 99
1 2 99
3 4 99

5 6 99
7 8 99

      1 2 3 ,[0.5] 4 5 6   ⍝ Laminate
1 2 3
4 5 6

Language Elements


Comma Bar ⍪

Monadic Comma Bar means

Table

      ⍪ 2 3 4
2
3
4
      cube    ⍝ 3D array
1 2
3 4

5 6
7 8
      ⍪ cube
1 2 3 4
5 6 7 8

Dyadic Comma Bar means

Catenate First

      mat
1 2 3
4 5 6

      mat ⍪ 0
1 2 3
4 5 6
0 0 0

      mat ⍪ 7 8 9
1 2 3
4 5 6
7 8 9

Language Elements


Up Tack Symbol

Up Tack ⊥

Monadic Up Tack is not defined

Dyadic Up Tack means

Decode

      2 ⊥ 1 1 0 1   ⍝ binary decode
13

⍝ mixed radix: conversion of hours,
⍝ minutes and seconds to seconds:

      24 60 60 ⊥ 2 46 40
10000

Language Elements


Diaeresis ¨

Diaeresis is a Monadic operator with an ambivalent operand

Operator Diaeresis means

Each

      ⊃¨ 1 2 3 'ABC' (9 8 7)
1 2 3 A 9

      +/¨ (1 2 3 4)(5 6 7)
10 18

      3 ↑¨ 1 2 (3 4) 'V'
┌─────┬─────┬─────┬───┐
│1 0 0│2 0 0│3 4 0│V  │
└─────┴─────┴─────┴───┘

      1 2 3 ,¨ 99
┌────┬────┬────┐
│1 99│2 99│3 99│
└────┴────┴────┘

Language Elements


Tilde Diaeresis ⍨

Tilde Diaeresis is a Monadic operator with a Dyadic operand

Operator Tilde Diaeresis means

Commute

      2 ⍴ 3     ⍝ ⍺ ⍴ ⍵
3 3
      2 ⍴⍨ 3    ⍝ ⍵ ⍴ ⍺
2 2 2
      ⍴⍨ 3      ⍝ ⍵ ⍴ ⍵
3 3 3

Language Elements


Star Diaeresis ⍣

Star Diaeresis is a Dyadic operator with an ambivalent left operand and an integer or dyadic right operand

Operator Star Diaeresis means

Power Operator

      cube    ⍝ 3D array
AB
CD

EF
GH
      (↓⍣1) cube   ⍝ split once
┌──┬──┐
│AB│CD│
├──┼──┤
│EF│GH│
└──┴──┘
      (↓⍣2) cube   ⍝ split twice
┌───────┬───────┐
│┌──┬──┐│┌──┬──┐│
││AB│CD│││EF│GH││
│└──┴──┘│└──┴──┘│
└───────┴───────┘

      f ← (32∘+)∘(×∘1.8)   ⍝ °F from °C

      f ¯273 ¯40 0 100     ⍝ Fahrenheit
¯459.4 ¯40 32 212

      c ← f⍣¯1             ⍝ Inverse: °C from °F

      c ¯459.4 ¯40 32 212  ⍝ Celsius
¯273 ¯40 0 100

      1 +∘÷⍣= 1            ⍝ fixpoint: golden mean
1.61803

Language Elements


Divide Sign ÷

Monadic Divide Sign means

Reciprocal

      ÷ 1 2 3
1 0.5 0.333333

Dyadic Divide Sign means

Divided By

      1 2 3 ÷ 4 5 7
0.25 0.4 0.428571

      10 ÷ ¯2 0.5
¯5 20

Language Elements


Domino

Domino;Quad Divide ⌹

Monadic Domino means

Matrix Inverse Of

      mat
1 2
3 4
      ⌹ mat
¯2    1
 1.5 ¯0.5

Dyadic Domino means

Matrix Division By

      5 6 ⌹ mat
¯4 4.5

Language Elements


Dot .

Dot can be used as a Dyadic operator with Dyadic operands

Operator Dot means

Inner Product

      1 2 3 +.× 4 5 6
32
      3 ∧.= 3 3 3 3
1
      mat
1 2
3 4
      mat +.× mat   ⍝ matrix product
 7 10
15 22

Used with Jot in place of the left operand Jot Dot means

Outer Product

      1 2 3 ∘.× 4 5 6 7
 4  5  6  7
 8 10 12 14
12 15 18 21

N.B. Dot is also used as a decimal point and as a name separator in namespace reference syntax.

Language Elements


Down Arrow

Down Arrow ↓

Monadic Down Arrow means

Split

      mat
1  2  3  4
5  6  7  8
9 10 11 12

      ↓ mat
┌───────┬───────┬──────────┐
│1 2 3 4│5 6 7 8│9 10 11 12│
└───────┴───────┴──────────┘

      ↓[1] mat
┌─────┬──────┬──────┬──────┐
│1 5 9│2 6 10│3 7 11│4 8 12│
└─────┴──────┴──────┴──────┘

Dyadic Down Arrow means

Drop

      4 ↓ 'Pineapple'
apple
      ¯5 ↓ 'Pineapple'
Pine
      1 ¯2 ↓ mat
5  6
9 10
      1 ↓ mat
5  6  7  8
9 10 11 12

Language Elements


Downstile ⌊

Monadic Downstile means

Floor

      ⌊ 3.4 ¯3.4 3 0
3 ¯4 3 0

Dyadic Downstile means

Minimum

      1.1 ¯2 ⌊ 8.1 ¯3.4
1.1 ¯3.4

      ⌊/ 3 1 4 1
1

Language Elements


Down Tack Symbol

Down Tack ⊤

Monadic Down Tack is not defined

Dyadic Down Tack means

Encode

      2 2 2 2 ⊤ 5 7 12   ⍝ binary encode
0 0 1
1 1 1
0 1 0
1 1 0

⍝ mixed radix: encode of 10000 seconds
⍝ to hours, minutes and seconds:

      24 60 60 ⊤ 10000
2 46 40

Language Elements


Epsilon ∊

Monadic Epsilon means

If ⎕ML=0 Type Of

      ∊ 3 3⍴1 'abc'
   0         0
        0
   0         0

If ⎕ML≥1 Enlist

      mat
1 2 3
4 5 6
      ∊ 0 mat (7 8) 9
0 1 2 3 4 5 6 7 8 9

      ∊ 2 3⍴1 'abc'
1 abc 1 abc 1 abc

Dyadic Epsilon means

Member Of

      'abc' 4 ∊ 4 'ab' 'abcd'
0 1
      mat ∊ 6 2 7 4
0 1 0
1 0 1

Language Elements


Epsilon Underbar ⍷

Monadic Epsilon Underbar is not defined

Dyadic Epsilon Underbar means

Find

      'ana' ⍷ 'Banana'
0 1 0 1 0 0

      X Y
┌───┬───────┐
│0 1│0 1 0 0│
│1 0│1 0 0 1│
│   │0 0 1 0│
│   │0 1 0 0│
└───┴───────┘

      X ⍷ Y
1 0 0 0
0 0 1 0
0 1 0 0
0 0 0 0

Language Elements


Equal Sign =

Monadic Equal Sign is not defined

Dyadic Equal Sign means

Equal To

      1 2 3 = 4 2 ¯1
0 1 0

      0 1 0 1 = 0 0 1 1
1 0 0 1

      'Banana' = 'a'
0 1 0 1 0 1

      7 = '7'
0

Language Elements


Equal Underbar Sign

Equal Underbar ≡

Monadic Equal Underbar means

Depth

      ≡ 7
0
      ≡ 'abc'
1
      ≡ (1 2)(3 4)
2
      ≡ (1 2)(3 4)5
¯2

Note: Result is always positive if ⎕ML is greater than or equal to 2

Dyadic Equal Underbar means

Match

      'b' 'e' 'x' ≡ 'bex'
1
      1 ≡ 1 1
0

Language Elements


Equal Underbar Slash ≢

Monadic Not Equal Underbar means

Tally

      ≢ 'a'
1
      ≢ 7 4 2
3
      ≢ 5 4 3⍴0
5
      ≢ (1 2)(3 4)
2
     mat
1 2 3
4 5 6
      ≢ mat   ⍝ note how "tally"
2
      ⍴ mat   ⍝ differs from "shape"
2 3

Dyadic Not Equal Underbar means

Not Match

      'bex' ≢ 'b','e','x'
0
      1 ≢ 1 1
1

Language Elements


Exclamation Mark

Exclamation Mark;Quote Dot !

Monadic Exclamation Mark means

Factorial

      ! 3 9 ¯0.11
6 362880 1.07683

Dyadic Exclamation Mark means

Binomial

      2 1 3 ! 3 10 ¯0.11
3 10 ¯0.0429385

Language Elements


Hydrant Symbol

Hydrant ⍎

Monadic Hydrant means

Execute expression

      ⍎ '1+1'
2
      V ← 1 2 3
      ⍎ 'V'
1 2 3

Dyadic Hydrant means

Execute expression in given namespace

      '#' ⍎ '⎕PP ⎕CT ⎕RL'
10 1E¯14 1131570933

Language Elements


Grade Down ⍒

Monadic Grade Down means

Grade Down

      ⍒ 33 11 44 66 22
4 3 1 5 2

      names←'Joe' 'Sue' 'Sam'
      ages←34 22 25

      names[⍒ages]
┌───┬───┬───┐
│Joe│Sam│Sue│
└───┴───┴───┘

      ⍒ 'ABC' ⎕NULL ⍬ ¯3j4 'A'
1 5 4 2 3

Dyadic Grade Down means

Dyadic Grade Down

Provide collating sequence for character data.

      ⍒ 'Banana'
3 5 2 4 6 1

      'an' ⍒ 'Banana'
1 3 5 2 4 6

Language Elements


Grade Up ⍋

Monadic Grade Up means

Grade Up

      ⍋ 33 11 44 66 22
2 5 1 3 4

      names←'Joe' 'Sue' 'Sam'
      ages←34 22 25

      names[⍋ages]
┌───┬───┬───┐
│Sue│Sam│Joe│
└───┴───┴───┘

      ⍋ 'ABC' ⎕NULL ⍬ ¯3j4 'A'
3 2 4 5 1

Dyadic Grade Up means

Dyadic Grade Up

      ⍋ 'Banana'
1 2 4 6 3 5

      'an' ⍋ 'Banana'
2 4 6 3 5 1

Language Elements


Greater Than Or Equal To Sign ≥

Monadic Greater Than or Equal To Sign is not defined

Dyadic Greater Than or Equal To Sign means

Is Greater Or Equal To

      1 2 3 ≥ 4 2 ¯1
0 1 1
      1 2 3 ≥ 2
0 1 1

Language Elements


Greater Than Sign

Monadic Greater Than Sign is not defined

Dyadic Greater Than Sign means

Greater Than

      1 2 3 > 4 2 ¯1
0 0 1
      1 2 3 > 2
0 0 1

Language Elements


I-Beam ⌶

I-Beam is a monadic operator that provides a range of system related services.

Examples

Monadic operator: I-Beam Provides a system-related service determined by the left-operand value.

Language Elements


Squad Symbol

Squad ⌷

Squad means

Materialise

      ⌷ ⍵
If ⍵ is an array, returns ⍵.
If ⍵ is ref to an instance of a Class with a
Default property, all items of the Default
property are returned.
If ⍵ is a collection, returns all elements
in the collection as an array.

Index with Axes means

Index

      mat
1  2  3  4
5  6  7  8
9 10 11 12

      2 3 ⌷ mat
7
      2 ⌷ mat
5 6 7 8

      2 ⌷[2] mat
2 6 10

Language Elements


Iota ⍳

Monadic Iota means

Index Generator

      ⍳ 10
1 2 3 4 5 6 7 8 9 10

      ⍳ 2 3
┌───┬───┬───┐
│1 1│1 2│1 3│
├───┼───┼───┤
│2 1│2 2│2 3│
└───┴───┴───┘

Dyadic Iota means

Index Of

      'ABCDABCDEF' ⍳ 'ACF'
1 3 10

      mat
1 2
3 4
5 6
      mat ⍳ 5 6
3

Language Elements


Iota Underbar ⍸

Monadic Iota Underbar means

Where

      ⍸ 1 0 0 1 1
1 4 5
      bmat
0 1 0
1 0 1
      ⍸ bmat
┌───┬───┬───┐
│1 2│2 1│2 3│
└───┴───┴───┘

Dyadic Iota Underbar means

Interval Index

      'AEIOU' ⍸ 'DYALOG'
1 5 1 3 4 2

      2 4 6 ⍸ 1 2 3 4 5 6 7
0 1 1 2 2 3 3

      mat
1 2
3 4
5 6
      mat ⍸ 3 3
1
      mat ⍸ 3 5
2

Language Elements


Jot ∘

Jot is a Dyadic operator

Operator Jot means

Composition

Form f∘g (function composition)

      ⌽∘⍳¨ 3 4 5
┌─────┬───────┬─────────┐
│3 2 1│4 3 2 1│5 4 3 2 1│
└─────┴───────┴─────────┘

      ¯1 ⌽∘⍳¨ 3 4 5
┌─────┬───────┬─────────┐
│3 1 2│4 1 2 3│5 1 2 3 4│
└─────┴───────┴─────────┘

      +∘÷/ 40⍴1    ⍝ continued fraction
1.61803

Form A∘g (left argument currying)

       next ← 1∘+
       next 23
24

N.B. Jot is also used in conjunction with Dot to mean Outer Product.

Language Elements


Jot Diaeresis ⍤

Jot Diaeresis is a Dyadic operator with an ambivalent left operand and an integer right operand

Operator Jot Diaeresis means

Rank

      cube    ⍝ 3D array
 1  2  3
 4  5  6

 7  8  9
10 11 12

      (,⍤2) cube
1 2 3  4  5  6
7 8 9 10 11 12

      cmat    ⍝ character matrix
abc
zxy
      (⍋⍤1) cmat    ⍝ grade-up by row
1 2 3
2 3 1
      nmat     ⍝ numeric matrix
1  2  3  4
5  6  7  8
9 10 11 12

      10 20 30 (+⍤0 1) nmat  ⍝ scalars plus vectors
11 12 13 14
25 26 27 28
39 40 41 42

Language Elements


Left Arrow

Left Arrow ←

Dyadic Left Arrow means

Naming

    V ← 5 6 7
    (i(j k)) ← 4(5 6)
    sum ← +⌿
    product ← {×/⍵}
    inverse ← ⍣¯1

Operator Left Arrow means

Modified Assignment

    V +← 1
    V[2] ← 0
    (⊃V) ← 2

Language Elements


Left Shoe ⊂

Monadic Left Shoe means

Enclose

      1(2 3)
┌─┬───┐
│1│2 3│
└─┴───┘
      ⊂ 1(2 3)
┌───────┐
│┌─┬───┐│
││1│2 3││
│└─┴───┘│
└───────┘
      ⊂⊂ 1(2 3)
┌─────────┐
│┌───────┐│
││┌─┬───┐││
│││1│2 3│││
││└─┴───┘││
│└───────┘│
└─────────┘

Dyadic Left Shoe means

If ⎕ML<3 Partitioned Enclose

       0 1 0 1 ⊂ 1 2 3 4
┌───┬─┐
│2 3│4│
└───┴─┘

If ⎕ML≥3 Partition

      0 1 0 1 ⊂ 1 2 3 4
┌─┬─┐
│2│4│
└─┴─┘

Language Elements


Left Shoe Underbar ⊆

Monadic Left Shoe Underbar means

Nest

      ⊆ 'this'
┌────┐
│this│
└────┘
      ⊆ 'this' 'that'
┌────┬────┐
│this│that│
└────┴────┘

Dyadic Left Shoe Underbar means

Partition

      1 0 0 1 1 ⊆ 1 2 3 4 5
┌─┬───┐
│1│4 5│
└─┴───┘
      1 1 2 2 2 ⊆ 1 2 3 4 5
┌───┬─────┐
│1 2│3 4 5│
└───┴─────┘
      ' ' (≠⊆⊢) ' many a  time'
┌────┬─┬────┐
│many│a│time│
└────┴─┴────┘

Language Elements


Left Tack ⊣

Monadic Left Tack means

Same

      ⊣  1 2 3
1 2 3

Dyadic Left Tack means

Left

      'L' ⊣ 'R'
L
      ⊣/ 1 2 3
1

Language Elements


Less Than Or Equal To Sign ≤

Monadic Less Than Or Equal To Sign is not defined

Dyadic Less Than or Equal To Sign means

Is Less Or Equal To

      1 2 3 ≤ 4 2 ¯1
1 1 0
      1 2 3 ≤ 2
1 1 0

Language Elements


Less Than Sign

Monadic Less Than Sign is not defined

Dyadic Less Than Sign means

Less Than

      1 2 3 < 4 2 ¯1
1 0 0
      1 2 3 < 2
1 0 0

Language Elements


Log

Log;Circle Star ⍟

Monadic Log means

Natural Logarithm

      ⍟ 1 2 3 2.7182818285
0 0.693147 1.09861 1

Dyadic Log means

Logarithm

      2 10 ⍟ 32 1000
5 3

Language Elements


Logical AND ∧

Monadic Logical AND is not defined.

Dyadic Logical AND means

Lowest Common Multiple (AND)

      0 1 0 1 ∧ 0 0 1 1
0 0 0 1

      15 1 2 7 ∧ 35 1 4 0
105 1 4 0

Language Elements


Logical Or ∨

Monadic Logical Or is not defined.

Dyadic Logical Or means

Greatest Common Divisor (Or)

      0 1 0 1 ∨ 0 0 1 1
0 1 1 1

      15 1 2 7 ∨ 35 1 4 0
5 1 2 7

Language Elements


Minus Sign

Minus Sign;Bar -

Monadic Minus Sign means

Negate

      - 3.2 ¯7 0
¯3.2 7 0

Dyadic Minus Sign means

Minus;Subtract

      3 7 9 - 5
¯2 2 4

      5 1 4 - 2 3 4
3 ¯2 0

Language Elements


Logical NAND Symbol

Logical NAND ⍲

Monadic Logical NAND is not defined

Dyadic Logical NAND means

NAND

      0 1 0 1 ⍲ 0 0 1 1
1 1 1 0

Language Elements


Logical NOR Symbol

Logical NOR ⍱

Monadic Logical NOR is not defined

Dyadic Logical NOR means

NOR

      0 1 0 1 ⍱ 0 0 1 1
1 0 0 0

Language Elements


Not Equal To

Not Equal ≠

Monadic Not Equal is not defined

Dyadic Not Equal means

Not Equal To

      1 2 3 ≠ 4 2 ¯1
1 0 1

      0 1 0 1 ≠ 0 0 1 1
0 1 1 0

      'Banana' ≠ 'a'
1 0 1 0 1 0

      7 ≠ '7'
1

Language Elements


Plus Sign +

Monadic Plus Sign means

Conjugate

      + 1.2 0j4 ¯5j¯6
1.2 0J¯4 ¯5J6

Dyadic Plus Sign means

Plus

      1 2 3 4 + 10
11 12 13 14

      1 2 3 + 2 ¯4 1
3 ¯2 4

      +/ 1 2 3
6

Language Elements


Quad Diamond ⌺

Quad Diamond is a Dyadic operator

Operator Quad Diamond means

Stencil

Dyadic operator:  Stencil

      mat
 1  2  3  4
 5  6  7  8
 9 10 11 12
13 14 15 16

      ({⊂⍵}⌺3 3) mat
┌───────┬────────┬────────┬───────┐
│0 0 0  │0 0 0   │0 0 0   │0 0 0  │
│0 1 2  │1 2 3   │2 3 4   │3 4 0  │
│0 5 6  │5 6 7   │6 7 8   │7 8 0  │
├───────┼────────┼────────┼───────┤
│0 1  2 │1  2  3 │ 2  3  4│ 3  4 0│
│0 5  6 │5  6  7 │ 6  7  8│ 7  8 0│
│0 9 10 │9 10 11 │10 11 12│11 12 0│
├───────┼────────┼────────┼───────┤
│0  5  6│ 5  6  7│ 6  7  8│ 7  8 0│
│0  9 10│ 9 10 11│10 11 12│11 12 0│
│0 13 14│13 14 15│14 15 16│15 16 0│
├───────┼────────┼────────┼───────┤
│0  9 10│ 9 10 11│10 11 12│11 12 0│
│0 13 14│13 14 15│14 15 16│15 16 0│
│0  0  0│ 0  0  0│ 0  0  0│ 0  0 0│
└───────┴────────┴────────┴───────┘

      ({+/,⍵}⌺3 3) mat
14 24 30 22
33 54 63 45
57 90 99 69
46 72 78 54

Language Elements


Quad Equal ⌸

Quad Equal is a Monadic operator with an ambivalent operand

Operator Quad Equal means

Key

      'Banana' {⍺ ⍵}⌸ 3 1 4 1 5 9
┌─┬─────┐
│B│3    │
├─┼─────┤
│a│1 1 9│
├─┼─────┤
│n│4 5  │
└─┴─────┘
      'Banana' {⍺,+/⍵}⌸ 3 1 4 1 5 9
B  3
a 11
n  9
      'Banana' {⍺ ⍵}⌸ 1 2 3 4 5 6
┌─┬─────┐
│B│1    │
├─┼─────┤
│a│2 4 6│
├─┼─────┤
│n│3 5  │
└─┴─────┘
      {⍺ ⍵}⌸ 'Banana'  ⍝ (same as above)
┌─┬─────┐
│B│1    │
├─┼─────┤
│a│2 4 6│
├─┼─────┤
│n│3 5  │
└─┴─────┘

Language Elements


Question Mark

Question Mark;Query ?

Monadic Question Mark means

Roll

      ? 6 6 6 6 6
4 3 6 3 5

      ? 0 0
0.260561 0.929928

Dyadic Question Mark means

Deal

      13 ? 52
36 31 44 11 27 42 13 8 2 33 19 34 6

Language Elements


Rho ⍴

Monadic Rho means

Shape Of

      mat
1  2  3  4
5  6  7  8
9 10 11 12

      ⍴ mat
3 4
      ⍴⍴ mat
2
      ⍴ 'your boat'
9
      ⍴ 7

      ⍴⍴ 7
0

Dyadic Rho means

Reshape

      2 3 4 ⍴ 1 2 3 4 5 6 7
1 2 3 4
5 6 7 1
2 3 4 5

6 7 1 2
3 4 5 6
7 1 2 3

Language Elements


Right Arrow

Monadic Right Arrow means

Branch

Syntax:  Branch (Clear suspension)

      → Label  ⍝ branch to Label:
      → ⎕LC    ⍝ resume suspended execution
      → 0      ⍝ exit current function and resume calling line
      →        ⍝ clear one stack suspension

Branching is superseded by the more modern
control structures such as :If ... :EndIf

Language Elements


Right Shoe ⊃

Monadic Right Shoe means

If ⎕ML<2 Disclose;First

      ⊃ 'Word'
W
      ⊃ (1 2)(3 4 5)
1 2

If ⎕ML≥2 Mix

      ⊃ (2 2)(3 3 3)
2 2 0
3 3 3

Dyadic Right Shoe means

Pick

      3 ⊃ 'Word'
r
      2 ⊃ (1 2)(3 4 5)
3 4 5

      2 1 ⊃ (1 2)(3 4 5)
3

Language Elements


Right Tack ⊢

Monadic Right Tack means

Same

      ⊢  1 2 3
1 2 3

Dyadic Right Tack means

Right

      'L' ⊢ 'R'
R
      ⊢/ 1 2 3
3

Language Elements


Up Shoe ∩

Monadic Set Intersection is not defined

Dyadic Set Intersection means

Intersection

      22 'ab' 'fg' ∩ 'a' 'ab' 22
┌──┬──┐
│22│ab│
└──┴──┘

Language Elements


Set Union

Down Shoe ∪

Monadic Set Union means

Unique

      ∪ 'ab' 'ba' 'ab' 1 1 2
┌──┬──┬─┬─┐
│ab│ba│1│2│
└──┴──┴─┴─┘
      mat
flywheel
shyster
flywheel
     ∪mat
flywheel
shyster

Dyadic Set Union means

Union

      'ab' 'cde' 'fg' ∪ 'a' 'ab'
┌──┬───┬──┬─┐
│ab│cde│fg│a│
└──┴───┴──┴─┘

Language Elements


Slash

Used as a Function

Monadic Slash is not defined

Dyadic Slash means

Replicate

      3 1 ¯2 2 / 6 7 8 9
6 6 6 7 0 0 9 9

      1 0 1 0 1 / 'Heart'
Hat

Used as an Operator

Slash is a Monadic operator with a Dyadic operand

Operator Slash means

Reduce, N-Wise Reduce

      +/ 1 2 3 4 5
15
      2 +/ 1 2 3 4 5   ⍝ pair-wise sum
3 5 7 9

      cube    ⍝ 3D array
 1  2  3  4
 5  6  7  8
 9 10 11 12

13 14 15 16
17 18 19 20
21 22 23 24

      +/ cube
10 26 42
58 74 90

      +/[1] cube    ⍝ sum of planes
14 16 18 20
22 24 26 28
30 32 34 36

      +/[2] cube    ⍝ column sums
15 18 21 24
51 54 57 60

Language Elements


Slash Bar ⌿

Used as a Function

Monadic Slash Bar is not defined

Dyadic Slash Bar means

Replicate First (Compress First)

      mat
1  2  3  4
5  6  7  8
9 10 11 12

      1 0 2 ⌿ mat
1  2  3  4
9 10 11 12
9 10 11 12

Used as an Operator

Slash Bar is a Monadic operator with a Dyadic operand

Operator Slash Bar means

Reduce First, Reduce First N-Wise

      +⌿ mat
15 18 21 24

      2 +⌿ mat     ⍝ pair-wise
 6  8 10 12
14 16 18 20

Language Elements


Slope

Used as a Function

Monadic Back Slash is not defined

Dyadic Back Slash means

Expand

      3 ¯2 4 \ 7 8
7 7 7 0 0 8 8 8 8

      1 0 1 0 1 \ 'Hat'
H a t

Used as an Operator

Back Slash is a Monadic operator with a Dyadic operand

Operator Back Slash means

Scan

      +\ 1 2 3 4 5
1 3 6 10 15

      mat
1  2  3  4
5  6  7  8
9 10 11 12

      +\ mat
1  3  6 10
5 11 18 26
9 19 30 42

      +\[1] mat
 1  2  3  4
 6  8 10 12
15 18 21 24

Language Elements


Slope Bar

Back Slash Bar ⍀

Used as a Function

Monadic Back Slash Bar is not defined

Dyadic Back Slash Bar means

Expand First

      mat
1  2  3  4
5  6  7  8
9 10 11 12

      1 0 2 1 ⍀ mat
1  2  3  4
0  0  0  0
5  6  7  8
5  6  7  8
9 10 11 12

Used as an Operator

Back Slash Bar is a Monadic operator with a Dyadic operand

Operator Slope Bar means

Scan First

      +⍀ mat
 1  2  3  4
 6  8 10 12
15 18 21 24

Language Elements


Star *

Monadic Star means

Exponential

      * 0 1 2
1 2.71828 7.38906

Dyadic Star means

Power

      49 5 ¯4 * 0.5 2 0.5
7 25 0J2

Language Elements


Stile

Monadic Stile means

Magnitude

      | 2.3 ¯4 0 3j4
2.3 4 0 5

Dyadic Stile means

Residue;Modulus

      2 10 ¯2.5 | 7 ¯13 8
1 7 ¯2

Language Elements


Thorn Symbol

Thorn ⍕

Monadic Format means

Format

NB: In the following examples space characters
    are represented by small dots: ···

      4 5 6          ⍝ numeric vector
4 5 6
      ⍕ 4 5 6        ⍝ equivalent character vector
4·5·6

      mat            ⍝ numeric matrix
1 2 3
4 5 6

      ⍕ mat          ⍝ equivalent character matrix
1·2·3
4·5·6

N.B. depends on ⎕PP

Dyadic Format means

Format By Specification

Field-width and number of decimal places:

      6 2 ⍕ 3.125 0.002
··3.13··0.00

      6 2 ⍕ mat
··1.00··2.00··3.00
··4.00··5.00··6.00

      6 2 ⍕ 1234   ⍝ (field not wide enough)
******

Language Elements


Tilde ~

Monadic Tilde means

Not

      ~ 0 1 0 1
1 0 1 0

Dyadic Tilde means

Without;Excluding

      3 1 4 1 5 ~ 5 1
3 4

      'aa' 'bb' 'cc' 'bb'  ~ 'bb' 'xx'
┌──┬──┐
│aa│cc│
└──┴──┘

Language Elements


Times Sign ×

Monadic Times Sign means

Direction

      × 3.1 ¯2 0 3j4
1 ¯1 0 0.6J0.8

Dyadic Times Sign means

Times

      2 ¯3 4.5 × ¯3 ¯4 2
¯6 12 9

      3 1 4 × 10
30 10 40

      ×/ 2 3 4
24

Language Elements


Circle Backslash ⍉

Monadic Transpose means

Transpose

      mat
1 2 3
4 5 6

      ⍉ mat
1 4
2 5
3 6
      cube    ⍝ 3D array
 1  2  3  4
 5  6  7  8
 9 10 11 12

13 14 15 16
17 18 19 20
21 22 23 24

      ⍉ cube
 1 13
 5 17
 9 21

 2 14
 6 18
10 22

 3 15
 7 19
11 23

 4 16
 8 20
12 24

      ⍴ cube
2 3 4
      ⍴ ⍉ cube    ⍝ transpose reverses shape
4 3 2

Dyadic Transpose means

DyadicTranspose

       2 1 3 ⍉ cube    ⍝ swap of first two axes
 1  2  3  4
13 14 15 16

 5  6  7  8
17 18 19 20

 9 10 11 12
21 22 23 24

      1 1 ⍉ mat       ⍝ diagonal
1 5
      1 1 2 ⍉ cube    ⍝ diagonal of first two axes
 1  2  3  4
17 18 19 20

Language Elements


Up Arrow

Monadic Up Arrow means

If ⎕ML<2 Mix

      ↑ 'Hip' 'Hop'
Hip
Hop
      ↑ (6 4) 5 3
6 4
5 0
3 0
      ↑[0.5] 'Hip' 'Hop'
HH
io
pp

If ⎕ML≥2 First

      ↑ (6 4) 5 3
6 4

Dyadic Up Arrow means

Take

      4 ↑ 'Pineapple'
Pine
      ¯5 ↑ 'Pineapple'
apple

      mat
1  2  3  4
5  6  7  8
9 10 11 12

      2 ¯3 ↑ mat
2 3 4
6 7 8

      ¯2 ↑ mat
5  6  7  8
9 10 11 12

      ¯2 3 ↑ 7
0 0 0
7 0 0

Language Elements


Upstile ⌈

Monadic Upstile means

Ceiling

      ⌈ 3.4 ¯3.4 3 0
4 ¯3 3 0

Dyadic Upstile means

Maximum

      1.1 ¯2 ⌈ 8.1 ¯3.4
8.1 ¯2

      ⌈/ 3 1 4 1
4

Language Elements


Variant ⍠

The Variant operator specifies the value of an option to be used by its left operand function.

Examples

      ('a' ⎕R 'x') 'ABC'           ⍝ 'a' replaced with 'x'
ABC

      ('a' ⎕R 'x' ⍠ 'IC' 1) 'ABC'  ⍝ .. Ignoring Case
xBC

      IgnCase ← ⍠ 'IC' 1

      'a' ⎕R 'x' IgnCase 'ABC'
xBC

The following derived function returns the location of the word 'variant' within its right argument using default values for all the options.

      f1 ← 'variant' ⎕S 0
      f1 'The variant Variant operator'
4

It may be modified to perform a case-insensitive search:

      (f1 ⍠ 1) 'The variant Variant operator'
4 12

This modified function may be named:

      f2 ← f1 ⍠ 1
      f2 'The variant Variant operator'
4 12

The modified function may itself be modified, in this case to revert to a case sensitive search:

      f3 ← f2 ⍠ 0
      f3 'The variant Variant operator'
4

This is equivalent to:

      (f1 ⍠ 1 ⍠ 0) 'The variant Variant operator'
4

Language Elements


Zilde Symbol

Zilde; ⍬

Niladic Zilde is

Zilde

      ⍬≡⍳0
1
      ⍬≡0⍴0
1
      ⍬≡0 0⍴0
0
      ⍬≡''
0

Language Elements


Windows Command

Windows Command ⎕CMD

Monadic ⎕CMD means

Execute Windows Command

      ⎕CMD'dir'
 Volume in drive C is OS
 Volume Serial Number is B438-9B76

 Directory of C:\Users\Pete\Documents\Dyalog APL-64 17.0 Unicode Files

23/06/2018  15:59    <DIR>          .
23/06/2018  15:59    <DIR>          ..
23/06/2018  14:53           181,488 default.dlf
13/06/2018  20:13         1,262,296 def_uk.dse
14/06/2018  14:36           108,976 UserCommand20.cache
               3 File(s)      1,552,760 bytes
               2 Dir(s)  101,371,097,088 bytes free

Dyadic ⎕CMD means

Start Windows Auxiliary Processor

      )CLEAR
clear ws
      'xutils' ⎕CMD ''
      )fns
avx     box     dbr     getenv  hex     ltom    ltov    mtol    ss      vtol

Language Elements


Data Representation

Data Representation ⎕DR

Monadic ⎕DR means

Query Data Type

      A←10
      ⎕DR A
83

Dyadic ⎕DR means

Change Data Type

      A←10
      11 ⎕DR A
0 0 0 0 1 0 1 0

Language Elements


Format

Format ⎕FMT

Monadic ⎕FMT means

Display Form

      ⎕FMT 2 4⍴⍳8
1 2 3 4
5 6 7 8

Dyadic ⎕FMT means

Format

     'I3,F5.2' ⎕FMT 2 4⍴⍳8
  1 2.00  3 4.00
  5 6.00  7 8.00

Language Elements


Monitor Controls

Monitor Controls ⎕MONITOR

Dyadic ⎕MONITOR means

Set Monitor Controls

      +(0,⍳10) ⎕MONITOR 'FOO'
0 1 2 3 4 5

Monadic ⎕MONITOR means

Query Monitor Controls

      ⎕MONITOR 'FOO'
0 1 1418 1000 0
1 1   83    0 0
2 1  400    0 0
3 1  397    0 0
4 1  467 1000 0
5 1  100    0 0

Language Elements


UNIX Command

UNIX Shell ⎕SH

Monadic ⎕SH means

Execute UNIX Command

       ⎕SH'ls'
FILES WS temp

Dyadic ⎕SH means

Start UNIX Auxiliary Processor

      )CLEAR
clear ws
      'xutils' ⎕SH 'xutils'
      )fns
avx     box     dbr     getenv  hex     ltom    ltov    mtol    ss      vtol

Language Elements


Stop Controls

Stop Controls ⎕STOP

Dyadic ⎕STOP means

Set Stop Controls

      ⊢(0,⍳10) ⎕STOP 'FOO'
0 1

Monadic ⎕STOP means

Query Stop Controls

      ⎕STOP 'FOO'
0 1

Language Elements


Shared Variable Access Control

Shared Variable Access Control ⎕SVC

Dyadic ⎕SVC means

Set Access Control

      1 ⎕SVC 'X EXTNAME'
1 1 1 1

Monadic ⎕SVC means

Query Access Control

      ⎕SVC 'X'
1 1 1 1

Language Elements


Trace Controls

Trace Controls ⎕TRACE

Dyadic ⎕TRACE means

Set Trace Controls

      +(0,⍳10) ⎕TRACE 'foo'
0 1 2 3 4 5

Monadic ⎕TRACE means

Query Trace Controls

      ⎕TRACE 'foo'
0 1 2 3 4 5

Language Elements


External Variables

External Variables ⎕XT

Dyadic ⎕XT means

Set External Variable

      'EXT\ARRAY' ⎕XT 'V'

Monadic ⎕XT means

Query External Variable

      ⎕XT'V'
EXT\ARRAY

Language Elements


Colour Selection Dialog

The Colour Selection dialog box allows you to select colours for:

  • Syntax colouring
  • Edit, Trace and Session windows
  • Status window

The colour selection dialog box is selected by the [ChooseColor] system action which by default is attached to the Options/Colours menu item on the Session menubar and to the Colours menu item in the Session pop-up menu.

Syntax Colouring

Syntax colouring allows you to visually identify various components in the function edit and session windows by assigning different colours to them, such as:

  • Global references (functions and variables)
  • Local references (functions and variables)
  • Primitive functions
  • System functions
  • Localised System Variables
  • Comments
  • Character constants
  • Numeric constants
  • Labels
  • Control Structures
  • Unmatched parentheses, quotes, and braces

Schemes

You may define a number of different syntax colouring schemes which are suitable for different purposes and a selection of schemes is provided. Choose the scheme you wish to use from the Combo box provided. If you change a colour allocation, you may overwrite an existing Colour Scheme or define a new one by clicking Save As and then entering the name of the Scheme. You may delete a Colour Scheme using the Delete button.

Changing Colours

To allocate a colour to a syntax element, you must first select the syntax element. You may select a syntax element from the Combo box provided, or by clicking on an example in the sample function provided. Having selected a syntax element, choose a colour using the Foreground or Background selectors as appropriate.

Show Idioms

The Show Idioms checkbox allows you to choose whether or not idioms are to be identified by syntax colouring.

Single Background

The Single Background checkbox allows you to choose whether to impose a single background colour, or to allow the use of different background colours for different syntax elements.

Function Editor

Check this box if you want to enable syntax colouring in Edit windows.

Function Tracer

Check this box if you want to enable syntax colouring in Trace windows.

Session Input

Check this box if you want to enable syntax colouring in the Session window. Note that the colour scheme used for the Session may differ from the colour scheme selected for Edit windows and is specified by the Session Colour Scheme box on the Session/Trace tab.

Only current input line

This option only applies if Session syntax colouring is enabled. Check this box if you want syntax colouring to apply only to the current input line. Clear this box, if you want to apply syntax colouring to all the input lines in the current Session window. Note that syntax colouring of input lines is not remembered in the Session log, so input lines from previous sessions do not have syntax colouring.

HotKeys

You may associate a different hot key with any or all of your colour schemes.

When you depress a hot key over a function in an Edit window, the function is displayed using the scheme associated with the hot key. Releasing the hot key causes it to be displayed in the normal scheme.

This feature is intended to allow you to quickly check for certain syntax elements. For example, you may define a special scheme that only highlights global names and associate a hot key with it. Pressing the hot key will temporarily highlight the globals for you.

To associate a hot key with a colour scheme, click on the Hotkey field, and then make the desired keystroke. To disassociate a hot key, use <backspace>.


Configuration_Dialog

The Configuration Dialog Box

General Tab

Table 58: Configuration dialog: General

Label | Parameter | Description
Recently used file list size | file_stack_size | Specifies the number of the most recently used workspaces displayed in the File menu.
Show message box if text wraps |  | Specifies whether or not a message box is displayed to inform the user when the search wraps. See also: Allow search to wrap.
Underline URLs and links | URLHighlight | Specifies whether or not URLs and links are highlighted in Session and Edit windows.
Display Value Tips after | ValueTips/Delay | Specifies the delay before APL will display the value of a variable or the code for a function when the user hovers the mouse over its name.
Colour Scheme | ValueTips/ ColourScheme | Specifies the colour scheme used to display the value of a variable or the code for a function when the user hovers the mouse over its name.
Enable Native Look and Feel | XPLookAndFeel | Specifies whether or not Native Look and Feel is enabled. This changes the appearance of user-interface controls such as Buttons in both the Session and the Dyalog GUI.
Enable DPI Scaling of the interpreter and development environment | AUTODPI | Enables or disables DPI scaling for the APL Session
Enable DPI scaling of GUI application | DYALOG_PIXEL_TYPE | Sets the value of the DYALOG_PIXEL_TYPE parameter which determines whether Coord 'Pixel' is treated as ScaledPixel or RealPixel.
Configuration saved in | inifile | Specifies the full pathname of the registry folder used by APL

Underline URLs and links

If this option is selected, valid URLs are identified when the cursor is in the Session or in an Edit or Trace window. When the mouse pointer is over a URL, the URL is underscored and the appropriate items in the Session Popup menu are activated. These allow you to open the link or copy it to the clipboard.

You may also open a URL using Ctrl+Click (Left Mouse button).

Currently a URL string is defined to be a string starting with any of the following strings:

  • http://
  • https://
  • www.
  • mailto:

Unicode Input Tab (Unicode Edition Only)

Unicode Edition can optionally select your APL keyboard each time you start APL.

To choose this option, select one of your installed APL keyboards, enable the Activate selected keyboard checkbox, then click OK

Label | Parameter | Description
Activate selected keyboard | InitialKeyboardLayoutInUse | 1 = automatically select the specified APL keyboard on start-up. 0 = no action
Show keyboards for all Languages | InitialKeyboardLayoutShowAll | 1 = show list of all installed keyboards 0 = show only the Dyalog keyboards
Keyboard | InitialKeyboardLayout | the name of the APL keyboard to be selected.
Configure Layout |  | Displays the Dyalog APL Input Method Editor Properties dialog (see below)

Input Method Editor Properties

Table 59: Dyalog APL Input Method Editor Properties

Label | Parameter | Description
Use Ctrl-X,C,V for clipboard | UseCSV | 0 = process Ctrl+X, Ctrl+C and Ctrl+V normally (via the appropriate .DIN file) 1 = pass Ctrl+X, Ctrl+C and Ctrl+V untranslated to the host application
Enable Overstrikes | ResolveOverstrikes | 1 = enable overstrikes. 0 = disable overstrikes
Overstrikes do not require the <OS> key |  | 1 = IME identifies overstrike operation automatically 0 = IME requires the <OS> key to signal an overstrike operation
Use Overstrike popup | OverstrikesPopup | 1 = enable the overstrike popup. 0 = disable the overstrike popup

Notes

The UseCSV parameter is defined for the IME in the Registry section HKEY_CURRENT_USER\Software\Dyalog\UnicodeIME\

When UseCSV is 1, the keystrokes Ctrl+X, Ctrl+C and Ctrl+V are passed untranslated to dyalog.exe which treats them as CT, CP and PT respectively. This is likely to be true for other host applications using the Dyalog keyboard.

The standard Dyalog keyboard (*.din) files map Shift+Del to CT, Ctrl+Ins to CP, and Shift+Ins to PT. These will therefore work independently of the UseXCV option.

The standard Dyalog keyboard (*.din) files map BOTH Ctrl+X and Ctrl+Shift+Xto ⊃ So if UseCSV is set to 1, you must use Ctrl+Shift+X to obtain ⊃. Likewise for C and V.

Input Tab (Classic Edition Only)

Table 60: Configuration dialog: Keyboard

Label | Parameter | Description
Input table search path | aplkeys | A list of directories to be searched for the specified input table
Input table file | aplk | The name of the input table file (.DIN)

Output Tab (Classic Edition Only)

Table 61: Configuration dialog: Output

Label | Parameter | Description
Output table search path | apltrans | A list of directories to be searched for the specified output table
Output table file | aplt | The name of the output table file (.DOT)

Keyboard Shortcuts Tab

To alter the keystroke associated with a particular action, simply select the action required and press the keystroke. For example, to change the keystroke associated with the action <UA> (undo all changes) from (None) to Ctrl+Shift+u, simply select the corresponding row in the list and press Ctrl+Shift+u. If Confirm before Overwrite is checked, you will be prompted to confirm or cancel before each and every change is written back to the registry.

Note that clicking on the column headings will sort on that column; shift and mouse click will sort in reverse order.

Workspace Tab

Table 62: Configuration dialog: Workspace

Label | Parameter | Description
Workspace search path | WSPATH | A list of directories to be searched for the specified workspace when the user executes )LOAD . "." must be included in order to load workspaces from the current directory
Maximum workspace size | maxws | The maximum size of the workspace.

Note

Workspace size is specified by an integer value followed by one of K, M, or G which stand for Kilobytes, Megabytes and Gigabytes respectively. If no character is included, units default to K (Kilobytes). MAXWS defaults to 64M on the Raspberry Pi, and 256M on all other platforms.

Help/DMX Tab

Table 63: Configuration dialog: Help/DMX

Label | Parameter | Description
DMX messages should go to | DMXOUTPUTONERROR | If checked, these boxes cause APL to display ⎕DMX messages in the corresponding window(s).
Use Microsoft's documentation centre for non-Dyalog topics | UseDefaultHelpCollection | If this option is checked, APL will look for help for external objects at Microsoft's documentation center, which is identified by the specified URL.
URL | ExternalHelpURL | The URL for the documentation centre.

Windows Tab

Table 64: Configuration dialog: Windows (Edit Windows)

Label | Parameter | Description
Width | edit_cols | The maximum number of rows displayed in a new edit window.
Height | edit_rows | The maximum number of columns displayed in a new edit window.
X Pos | edit_first_x | The initial horizontal position in characters of the first edit window.
Y Pos | edit_first_y | The initial vertical position in characters of the first edit window.
X Offset | edit_offset_x | The initial horizontal position in characters of the second and subsequent edit windows relative to the previous one.
Y Offset | edit_offset_y | The initial vertical position in characters of the second and subsequent edit windows relative to the previous one.

Table 65: Configuration dialog: Windows (Trace Windows)

Label | Parameter | Description
X Pos | trace_first_x | The initial horizontal position in characters of the first trace window.
Y Pos | trace_first_y | The initial vertical position in characters of the first trace window.
X Offset | trace_offset_x | The initial horizontal position in characters of the second and subsequent trace windows relative to the previous one.
Y Offset | trace_offset_y | The initial vertical position in characters of the second and subsequent trace windows relative to the previous one.

Table 66: Configuration dialog: Windows (QuadSM Window)

Label | Parameter | Description
Width | sm_cols | The width of the ⎕SM and prefect windows.
Height | sm_rows | The height of the ⎕SM and prefect windows.

Session Tab

Table 67: Configuration dialog: Session

Label | Parameter | Description
⎕IO | default_io | The default value of ⎕IO in a clear ws.
⎕ML | default_ml | The default value of ⎕ML in a clear ws
⎕PP | default_pp | The default value of ⎕PP in a clear ws.
⎕RTL | default_rtl | The default value of ⎕RTL in a clear ws.
⎕DIV | default_div | The default value of ⎕DIV in a clear ws.
⎕WX | default_wx | The default value of ⎕WX in a clear ws.
Auto PW | auto_pw | If checked, the value of ⎕PW is dynamic and depends on the width of the Session Window.
Session file | session_file | The name of the Session file in which the definition of your session (⎕SE) is stored.

Log Tab

Table 68: Configuration dialog: Log

Label | Parameter | Description
Use Session log file | log_file_inuse | Specifies whether or not the Session log is saved in a session log file
Use Session log file | log_file | The full pathname of the Session log file
Confirm on Deletion from Session log | confirm_session_delete | Specifies whether or not you are prompted to confirm the deletion of a line from the Session (and Session log).
Session log size | log_size | The size of the Session log buffer.
Input buffer size | input_size | The size of the buffer used to store marked lines (lines awaiting execution) in the Session.
History size | history_size | The size of the buffer used to store previously entered (input) lines in the Session
PFKey buffer size | pfkey_size | The size of the buffer used to store PFKey definitions (⎕PFKEY)

Note: The value of size-related values defined in the above table is specified as an integer value followed by one of K, M, G, T, P or E. The default, where no character is included, is K (Kilobytes).

Trace/Edit Tab

Table 69: Configuration dialog: Trace/Edit

Label | Parameter | Description
Classic Dyalog mode | ClassicMode | Selects pre-Version 9 behaviour for Edit and Trace windows. Note that in this mode, a maximum of 50 Trace windows may be displayed.
Allow session above edit windows | SessionOnTop | Specifies whether or not the Session may appear on top of Edit and Trace Windows
Single trace window | SingleTrace | Specifies whether or not there is a single Trace window
Remember previous window position | ClassicModeSavePosition | Specifies whether or not the current size and location of the first of the editor and tracer windows are remembered in the registry for next time.
Allow floating edit windows | DockableEditWindows | Allows individual Edit windows to be undocked from (and re-docked in) the main Edit window
Show status bars | StatusOnEdit | Specifies whether or not status bars are displayed along the bottom of individual Edit windows
Show tool bars | ToolBarsOnEdit | Specifies whether or not tool bars are displayed along the top of individual Edit windows
Show trace stack on error | Trace_on_error | Specifies whether or not the Tracer is automatically invoked when an error or stop occurs in a defined function
Allow search to wrap | WrapSearch | Specifies whether or not Search/Replace in the Editor stops at the top or bottom of the text, or continues from the start or end as appropriate. See also: Show message box if text wraps.
Warn if trace stack bigger than | Trace_level_warn | Specifies the maximum stack size for automatic deployment of the Tracer.
Confirm edit window close on Close | confirm_close | Specifies whether or not a confirmation dialog is displayed if the user alters the contents of an edit window, then closes it without saving
Confirm edit window close on Edit (and Fix) | confirm_fix | Specifies whether or not a confirmation dialog is displayed if the user alters the contents of an edit window, then saves it using Fix or Exit
Confirm edit window close on Abort | confirm_abort | Specifies whether or not a confirmation dialog is displayed if the user alters the contents of an edit window, then aborts using
Autoformat functions | AutoFormat | Selects automatic indentation for Control Structures when function is opened for editing
Autoindent | AutoIndent | Selects semi-automatic indentation for Control Structures while editing
Double-click to Edit | DoubleClickEdit | Specifies whether or not double-clicking over a name invokes the editor
Skip blank lines when tracing | SkipBlankLines | If enabled, this causes the Tracer to automatically skip blank lines.
Skip comment lines when tracing | SkipBlankLines | If enabled, this causes the Tracer to automatically skip comment lines.
Limit tracer display to current function in script | AddClassHeaders | When Tracing the execution of a function in a script, the Tracer displays either just the first line of the script and the function in question (option enabled), or the entire script (option disabled).
Paste text as Unicode (Classic Edition only) | UnicodeToClipboard | Specifies whether or not text transferred to and from the Windows clipboard is to be treated as Unicode
Tab stops every | TabStops | The number of spaces inserted by pressing Tab in an edit window
Exit and fix ... | InitFullScriptSusp | See Fixing Scripts below
If not ... | InitFullScriptNormal | See Fixing Scripts below

Fixing Scripts

When using the Editor to edit a script such as a Class or Namespace you can specify whether, when you Fix the script and Exit the Editor, just the functions in the script are re-fixed, or whether the whole script is re-executed, thereby re-initialising any Fields or variables defined within.

These two actions always appear in the Editor File menu, but you can specify which is associated with the <EP> (Esc) key by selecting the appropriate option in the drop-downs labelled:

  • Exit and save changes (EP) in a suspended class or namespace should fix:
  • If not suspended fix:

In both cases, you may select either Only Functions or Everything.

The label for the corresponding items on the Editor File menu (see UI Guide: Editor (The File Menu, editing a script)) will change according to which behaviour applies. Note that if you specify a keystroke for <S1> in the Keyboard Shortcuts tab, this will be associated with the unselected action.

Auto Complete Tab

Note: To enter values in the OK Key and Cancel Keyfields, click on the field with the mouse and then press the desired keystroke.

Table 70: Configuration dialog: Auto Complete

Label | Parameter | Description
Use Auto Complete | Enabled | Specifies whether or not Auto Completion is enabled.
Make suggestions after | PrefixSize | Specifies the number of characters you must enter before Auto Completion begins to make suggestions
Delay completion for | KeyboardInputDelay | Specifies the delay in milliseconds before Auto Completion begins to make suggestions
Suggest up to | Rows | Specifies the maximum number of rows (height) in the AutoComplete pop-up suggestions box.
Show up to | Cols | Specifies the maximum number of columns (width) in the AutoComplete pop-up suggestion box
Keep History | History | Specifies whether or not AutoComplete maintains a list of previous AutoCompletions.
History Length | HistorySize | Specifies the number of previous AutoCompletions that are maintained
Include filenames | ShowFiles | Specifies whether or not AutoCompletion suggests directory and file names for )LOAD, )COPY and )DROP system commands.
OK Key | CompleteKey1 CompleteKey2 | Specifies two possible keys that may be used to select the current option from the Auto Complete suggestion box.
Cancel Key | CancelKey1 CancelKey2 | Specifies two possible keys that may be used to cancel (hide) the Auto Complete suggestion box.
Common Key | CommonKey1 | Specifies the key that will auto-complete the common prefix. This is defined to be the longest string of leading characters in the currently selected name that is shared by at least one other name in the Auto Complete suggestion box.

SALT

SALT is the Simple APL Library Toolkit, a simple source code management system for Classes and script-based Namespaces. SPICE uses SALT to manage development tools which "plug in" to the Dyalog session

Table 71: Configuration dialog: SALT

Label | Parameter | Description
Enable Salt | AddSALT | Specifies whether or not SALT is enabled
Compare command line | CompareCMD | The command line for a 3rd party file comparison tool to be used to compare two versions of a file. See note.
Editor | Editor | Name of the program to be used to edit script files (default "Notepad").
Class source folders | SourceFolder | Sets the SALT working directory; a list of folders to be searched for source code. Include "." on a separate line to include source files from the current working directory

User Commands Tab

This page is used to specify and organise a list of folders that contain User-Command files. When you issue a User Command, these folders will be searched for the source of the command in the order in which they appear in this list.

Table 72: Configuration dialog: User Commands

Label | Parameter | Description
Source Folders | SALT\CommandFolder | Use this field to add folders to the list of folders that will be searched for User Commands.

Object Syntax Tab

The Object Syntax tab of the Configuration dialog is used to set your default preferences for Object Syntax.

The Object Syntax settings for the current workspace are reflected by the Object Syntax submenu of the Options menu. Use Options/Object Syntax to change them. These settings are saved in the workspace.

Table 73: Configuration dialog: Object Syntax

Label | Parameter | Description
Expose properties of GUI Namespaces | default_wx | Specifies the value of ⎕WX in a clear workspace. This in turn determines whether or not the names of properties, methods and events of GUI objects are exposed. If set (⎕WX is 1), you may query/set properties and invoke methods directly as if they were variables and functions respectively. As a consequence, these names may not be used for global variables in GUI objects.
Expose properties of Root | PropertyExposeRoot | Specifies whether or not the names of properties, methods and events of the Root object are exposed. If set, you may query/set the properties of Root and invoke the Root methods directly as if they were variables and functions respectively. As a consequence, these names may not be used for global variables in your workspace.
Expose properties of Session Namespace | PropertyExposeSE | Specifies whether or not the names of properties, methods and events of the Session object are exposed. If set, you may query/set the properties of ⎕SE and invoke ⎕SE methods directly as if they were variables and functions respectively. As a consequence, these names may not be used for global variables in the ⎕SE namespace.

Saved ResponsesTab

The Saved Responses tab of the Configuration dialog is used to remove preferences that the user has previously established.

In the example illustrated above, the user has at some point chosen to save a text file with a .h extension as text in the workspace and, by checking the option Save this response for all files with a ".h" extension, saved this as a preference for all such text files. Similarly, the user has checked the option Do not show this message again when responding to the warning dialog Saving as text will ....

If the user wishes to reverse these decisions, even temporarily, it is necessary to select the corresponding option /preference name(s) and click Delete. The names are intended to be self-explanatory and are not listed here.


Print Configuration

Print Configuration Dialog Box

The Print Configuration dialog box is displayed by the system operation [PrintSetup] that is associated with the File/Print Setup menu item. It is also available from Edit windows and from the Workspace Explorer and Find Objects tools.

There are four separate tabs namely Setup, Margins, Header/Footer and Printer.

Note that the printing parameters are stored in the Registry in the Printing sub-folder

Setup Tab

Table 54: Print Configuration dialog: Setup

Label | Parameter | Description
Color scheme | InColour | Check this box if you want to print functions with syntax colouring. Note that that printing in colour is slower than printing without colour.
Color scheme | SchemeName | Select the colour scheme to be used for printing.
This text | WrapWithText | Check this option button if you wish to prefix wrapped lines (lines that exceed the width of the paper) with a particular text string
This text | WrapLeadText | Specifies the text for prefixing wrapped lines
This many spaces | WrapWithSpaces | Check this option button if you wish to prefix wrapped lines with spaces.
This many spaces | WrapLeadSpaces | Specifies the number of spaces to be inserted at the beginning of wrapped lines.
Line numbers on functions | LineNumsFns | Check this box if you want line numbers to be printed in defined functions.
Line numbers on variables | LineNumsVars | Check this box if you want line numbers to be printed in variables. If you choose this option, line numbering starts at ⎕IO.
Font | Font | Click to select the font to be used for printing. Note that only fixed-pitch fonts are supported.

Margins Tab

Table 55: Print Configuration dialog: Margins

Label | Parameter | Description
Use margins | UseMargins | Check this box if you want margins to apply
Left margin | MarginLeft | Specifies the width of the left margin
Right margin | MarginRight | Specifies the width of the right margin
Top margin | MarginTop | Specifies the height of the top margin
Bottom margin | MarginBottom | Specifies the height of the bottom margin
Inches | MarginInch | Specifies that the margin units are inches
Centimetres | MarginCM | Specifies that the margin units are centimetres

Header/Footer Tab

Table 56: Print Configuration dialog: Header/Footer

Label | Parameter | Description
Header | DoHeader | Specifies whether or not a header is printed at the top of each page
Header | HeaderText | The header text
Footer | DoFooter | Specifies whether or not a footer is printed at the bottom of each page
Footer | FooterText | The footer text
Prefix functions with | DoSepFn | Specifies whether or not text is printed before each defined function
Prefix functions with | SepFnText | The text to be printed before each defined function. This can include its name, timestamp and author
Prefix variables with | DoSepVar | Specifies whether or not text is printed before each variable.
Prefix variables with | SepVarText | The text to be printed before each variable. This can include its name.
Prefix other objects with | DoSepOther | Specifies whether or not text is printed before other objects. These include locked functions, external functions, ⎕NA functions, derived functions and namespaces.
Prefix other objects with | SepOtherText | The text to be printed before other objects. This can include its name.

The specification for headers and footers may include a mixture of your own text, and keywords which are enclosed in braces, e.g. {objname}. Keywords act like variables and are replaced at print time by corresponding values.

Any of the following fields may be included in headers, footers and separators.

{WSName} | {WS} | Workspace name
{NSName} | {NS} | Namespace name
{ObjName} | {OB} | Object name
{Author} | {AU} | Author
{FixDate} | {FD} | Date function was last fixed
{FixTime} | {FT} | Time function was fixed
{PrintDate} | {PD} | Today's date
{PrintTime} | {PT} | Current time
{CurrentPage} | {CP} | Current page number
{TotalPages} | {TP} | Total number of pages
{RightJustify} | {RJ} | Right-justifies subsequent text/fields
{HorizontalLine} | {HL} | Inserts a horizontal line
{CarriageReturn} | {CR} | Inserts a new-line

For example, the specification:

Workspace: {wsname} {objname} {rj} Printed {PrintTime} {PrintDate}

would cause the following header, footer or separator to be printed at the appropriate position in each page of output:

Workspace: U:\WS\WDESIGN WIZ_change_toolbar Printed 14:40:11 02 March 1998

Printer Tab

Table 57: Print Configuration dialog: Print

Label | Parameter | Description
Name | PrinterField | The name of the printer to be used for printing from Dyalog APL.
Properties |  | Click this to set Printer options.
Where |  | Reports the printer device
Print |  | Allows you to choose between printing all of the current object or just the selection. Note that this option is present only when the dialog box is displayed in response to selecting Print.